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
andpgp
point to the locations of Node, Git and Phonegappgpv
, which should contain the Phonegap version number, is EMPTYpgpe
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/pgpv
reports5.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
.