4

I am in the process of setting up a Ubuntu 14.04 server to automate hybrid Android app builds with Phonegap CLI. Having written up all the relevant scripts I ran into a rather strange problem - when I SSH in to my server I can run the script and run all Phonegap commands successfully in my interactive shell session. However, every attempt to run those same commands in an automated script that gets triggered by some other - visitor generated - event fails. To pin down the problem I reduced it down to a simple experiment which I outline below.

Step 1 - write a startup script, pgtest in /etc/init.d

#! /bin/bash 
source ~/.nvm/nvm.sh;
nvm use stable;
cd /home;
ls >> /tmp/ls;
which node >> /tmp/node;
which git >> /tmp/git;
which phonegap >> /tmp/pgp;
phonegap -v >> /tmp/pgpv 2>/tmp/pgpe;

Explanations

  • I use NVM to manage Node so I am making sure that the system knows where to find nvm.sh
  • I am firing up NVM to use the stable (4.1.1.) version of Node + NPM
  • I want to make sure that my batch file is actually being executed so I do ls /home and pipe its output to the /tmp/ls file.
  • I want to be sure that node, git and phonegap are actually available so I do pipe the output from which node|git|phonegap to files in the /tmp folder.
  • Little point in complicating things so I am issuing the simplest of Phonegap commands, phonegap -v to report the current version number. Any errors that might happen when doing this are being piped into the file /tmp/pgpe.

Step 2 - Make sure that pgtest is run last ln -s /etc/init.d/pgtest /etc/rc2.d/S04PGTest

Explanation - I only want this script to be run after everything else on my server has had a chance to startup

With all of this in place I rebooted by server and examined the contents of the /tmp folder. My findings

  • ls - the folder listing for the /home folder present and correct.
  • node, git and pgp point to the locations of Node, Git and Phonegap
  • pgpv, which should contain the Phonegap version number, is EMPTY
  • pgpe is present and NOT empty

That last implies that the system encountered an error whilst attempting to execute phonegap -v. Here are the contents of pgpe.

path.js:8

throw new TypeError('Path must be a string. Received ' +

^

TypeError: Path must be a string. Received undefined

at assertPath (path.js:8:11)

at Object.posix.join (path.js:477:5)

at Object.

(/root/.nvm/versions/node/v4.1.1/lib/node_modules/phonegap/node_modules/phonegap-build/lib/common/config/global.js:17:28)

at Module._compile (module.js:434:26)

at Object.Module._extensions..js (module.js:452:10)

at Module.load (module.js:355:32)

at Function.Module._load (module.js:310:12)

at Module.require (module.js:365:17)

at require (module.js:384:17)

at Object. (/root/.nvm/versions/node/v4.1.1/lib/node_modules/phonegap/node_modules/phonegap-build/lib/common/config.js:9:13)

Now here is the curious thing. If I clear out the /tmp folder and issue a /etc/init.d/pgtest in an interactive shell session I get the following results

  • /tmp/ls present and populated with the /home folder listing as before
  • /tmp/node, /tmp/git /tmp/pgp present and correct
  • /tmp/pgpvreports 5.3.6 - the current Phonegap version number
  • /tmp/pgpe is EMPTY , i.e, no errors are reported

Clearly, the interactive bash shell environment has something that is not present when I run an automated script - at startup in this case but it also happens when I trigger the process via an automated script in any other way.

With all of this I am moving closer to pinning down the cause of the problem. However, there my knowledge of how these systems work is letting me down. What is the difference between the interactive shell environment and the one that is encountered by my automated script? Just how do I interpret the errors reported in /tmp/pgpe? What do I do to fix them?

I'd be most grateful to anyone who might be able to put me on the right track here.


Edit in light of @Eduardo's suggestions. I grabbed the two sets of environments (interactive & init.d). The results of doing a DIFF (interactive vs init.d) can be found in this fiddle. A somewhat less accessible dump of the DIFF result is shown below

--- /home/env.inter 2015-11-11 08:30:40.314172560 +0000 +++ /home/env.auto 2015-11-11 08:32:55.240906000 +0000 @@ -1,48 +1,38 @@ BASH=/bin/bash BASHOPTS=cmdhist:complete_fullquote:extquote:force_fignore:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath BASH_ALIASES=() -BASH_ARGC=() -BASH_ARGV=() +BASH_ARGC=([0]="1") +BASH_ARGV=([0]="start") BASH_CMDS=() BASH_LINENO=([0]="0") -BASH_SOURCE=([0]="/etc/init.d/pgtest") +BASH_SOURCE=([0]="/etc/rc2.d/S04pgtest") BASH_VERSINFO=([0]="4" 1="3" [2]="11" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu") BASH_VERSION='4.3.11(1)-release' DIRSTACK=() EUID=0 GROUPS=() -HOME=/root HOSTNAME=example.com HOSTTYPE=x86_64 IFS=$' \t\n' -LANG=en_US.UTF-8 -LESSCLOSE='/usr/bin/lesspipe %s %s' -LESSOPEN='| /usr/bin/lesspipe %s' -LOGNAME=root -LS_COLORS='rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:.tar=01;31:.tgz=01;31:.arj=01;31:.taz=01;31:.lzh=01;31:.lzma=01;31:.tlz=01;31:.txz=01;31:.zip=01;31:.z=01;31:.Z=01;31:.dz=01;31:.gz=01;31:.lz=01;31:.xz=01;31:.bz2=01;31:.bz=01;31:.tbz=01;31:.tbz2=01;31:.tz=01;31:.deb=01;31:.rpm=01;31:.jar=01;31:.war=01;31:.ear=01;31:.sar=01;31:.rar=01;31:.ace=01;31:.zoo=01;31:.cpio=01;31:.7z=01;31:.rz=01;31:.jpg=01;35:.jpeg=01;35:.gif=01;35:.bmp=01;35:.pbm=01;35:.pgm=01;35:.ppm=01;35:.tga=01;35:.xbm=01;35:.xpm=01;35:.tif=01;35:.tiff=01;35:.png=01;35:.svg=01;35:.svgz=01;35:.mng=01;35:.pcx=01;35:.mov=01;35:.mpg=01;35:.mpeg=01;35:.m2v=01;35:.mkv=01;35:.webm=01;35:.ogm=01;35:.mp4=01;35:.m4v=01;35:.mp4v=01;35:.vob=01;35:.qt=01;35:.nuv=01;35:.wmv=01;35:.asf=01;35:.rm=01;35:.rmvb=01;35:.flc=01;35:.avi=01;35:.fli=01;35:.flv=01;35:.gl=01;35:.dl=01;35:.xcf=01;35:.xwd=01;35:.yuv=01;35:.cgm=01;35:.emf=01;35:.axv=01;35:.anx=01;35:.ogv=01;35:.ogx=01;35:.aac=00;36:.au=00;36:.flac=00;36:.mid=00;36:.midi=00;36:.mka=00;36:.mp3=00;36:.mpc=00;36:.ogg=00;36:.ra=00;36:.wav=00;36:.axa=00;36:.oga=00;36:.spx=00;36:.xspf=00;36:' MACHTYPE=x86_64-pc-linux-gnu -MAIL=/var/mail/root -NVM_DIR=/root/.nvm -NVM_IOJS_ORG_MIRROR=https://iojs.org/dist -NVM_NODEJS_ORG_MIRROR=https://nodejs.org/dist -NVM_RC_VERSION= OPTERR=1 OPTIND=1 OSTYPE=linux-gnu -PATH=/opt/android/platform-tools:/opt/android/tools:/opt/android:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games +PATH=/sbin:/usr/sbin:/bin:/usr/bin PIPESTATUS=([0]="0") -PPID=4801 +PPID=911 +PREVLEVEL=N PS4='+ ' -PWD=/etc/init.d +PWD=/ +RUNLEVEL=2 SHELL=/bin/bash SHELLOPTS=braceexpand:hashall:interactive-comments -SHLVL=3 -SSH_CLIENT='nn.nn.nn.nn nnnn nnnn' -SSH_CONNECTION='nn.nn.nn.nn nnnn nn.nn.nn.nn nnnn' -SSH_TTY=/dev/pts/0 -TERM=xterm +SHLVL=1 +TERM=linux UID=0 -USER=root -XDG_RUNTIME_DIR=/run/user/1000 -XDG_SESSION_ID=5 +UPSTART_EVENTS=runlevel +UPSTART_INSTANCE= +UPSTART_JOB=rc _=n +previous=N +runlevel=2

The only things I have changed here - masked the Host name and the SSH client IP address.

I am pretty sure I had tried this in my own experiments prior to posting this question but following @Eduardo's suggestion below I tried sticking in a

EXPORT PATH=/opt/android/platform-tools:/opt/android/tools:/opt/android:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

at the top of the script - just below the source ~/.nvm... line. A reboot later the result was still the same: an empty /tmp/pgpv and the same errors reported in /tmp/pgpe.

DroidOS
  • 8,530
  • 16
  • 99
  • 171
  • `man bash`. An interactive bash shell come with `profile`s or `rc`s sourced, depending on whether it's a login shell or not. – 4ae1e1 Nov 03 '15 at 09:32
  • This might be the problem: pgpv 2> as it contains space and greater sign. – Lajos Arpad Nov 03 '15 at 09:34
  • @4ae1e1 your comment is probably useful but not to me. As I mentioned I have reached the limits of my understanding of bash. Just what does that man bash entry mean and how is it relevant to what I am observing? – DroidOS Nov 03 '15 at 09:34
  • @LajosArpad. Ummm... did I imply somewhere in my question that my script is not running and I need help with it? `pgpv>` has nothing to do with the problem at hand. – DroidOS Nov 03 '15 at 09:36
  • You asked "What is the difference between the interactive shell environment and the one that is encountered by my automated script?" And I answered that. Other than that, I'm not interested in debugging your script. I'm not a JS guy. – 4ae1e1 Nov 03 '15 at 10:48
  • @4ae1e1 - not sure where I suggested that you debug my script... – DroidOS Nov 03 '15 at 16:53
  • 1
    What do you believe `~` is resolving to in that `init.d` script when it is run at system startup? Which user has the appropriate phonegap configuration for what you want to be doing? Are you setting phonegap/node/etc. related settings in your normal user's shell initialization files? (Installation may have set them up for you automatically.) – Etan Reisner Nov 09 '15 at 12:20
  • @EtanReisner - NVM and Phonegap on my installation can only be run as the root user. What user does `~` resolve to when run from the reboot `init.d` script. I changed the line `cd /home` to `cd ~` and rebooted. This time round the `/tmp/ls` file was empty - when I do `ls -la ~` from an interactive shell I get a listing that contains `.android, .cordova, .npm....`. `whoami` still report `root`. I am not setting PG, node etc settings myself. I simply lt **NVM** run and it launches Nod etc. This provides a valuable clue but I am not clear how to interpret it or to fix the problem. – DroidOS Nov 11 '15 at 04:42
  • Run from `init.d` `~` almost certainly doesn't expand to anything useful. Don't use it. Use an explicit path. Also **please** use *code* formatting (the `{}` tool) for whitespace sensitive blocks of input and not the blockquote tool. – Etan Reisner Nov 11 '15 at 13:37

1 Answers1

1

Just make sure to set the PATH variable inside your script to the same, longer one, you see on the diff, then retry automated.

I would probably also define the HOME and NVM* variables. As a test I'd create a test.sh script at the same directory of phonegap, with this content:

#!/bin/bash
set > /tmp/env_vars.log

And have your script as:

#!/bin/bash 
export TERM=linux
export USER=root
export HOME=/root
export NVM_DIR=/root/.nvm
export NVM_IOJS_ORG_MIRROR=https://iojs.org/dist
export NVM_NODEJS_ORG_MIRROR=https://nodejs.org/dist
export NVM_RC_VERSION=
export PATH=/opt/android/platform-tools:/opt/android/tools:/opt/android:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
source ~/.nvm/nvm.sh
nvm use stable
cd /home
ls > /tmp/ls
which node > /tmp/node
which git > /tmp/git
which phonegap > /tmp/pgp
phonegap -v > /tmp/pgpv 2>/tmp/pgpe;
test.sh
Eduardo
  • 7,631
  • 2
  • 30
  • 31
  • Thank you. I had already tried the `-l` flag with no change in the results. I just tried your second suggestion. It just reported `env: phonegap: No such file or directory`. – DroidOS Nov 11 '15 at 04:36
  • OK, so try the full path of phonegap on that env command line, let's see what the response is. – Eduardo Nov 11 '15 at 05:03
  • see the edit to my question above. The diff results are available in a more readable form in [this fiddle](http://jsfiddle.net/tvzf00zf/) – DroidOS Nov 11 '15 at 09:04
  • I tried the path setting (I am sure I had in fact done tht at some point in my own experiments) with exactly the same result. `/tmp/pgpv` is empty and `/tmp/pgpe` reports the errors reported in my question – DroidOS Nov 11 '15 at 16:17
  • How did you set the PATH? Did you export it? How? – Eduardo Nov 11 '15 at 16:35
  • thank you for all your efforts. I am assuming that accepting your answer ensures that the bounty is automatically yours. – DroidOS Nov 15 '15 at 05:59