Search code examples
bashcordovaautomationphonegap-cli

Phonegap CLI runs from SSH session but not from bash script


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.


Solution

  • 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