Rspec not found when running from shell script - ruby

I'm trying to write a shell script to execute my rspecs in a project, but the script gives the error rspec: not found.
This is the script...
#!/bin/sh
command rspec spec spec/pos_spec.rb
$SHELL
...outputs
/home/joebloggs/GitHub/repo/test: 2: /home/joebloggs/GitHub/repo/test: rspec: not found
The line rspec spec repo/pos_spec.rb works if I type it directly into the shell, so I'm not sure why it can't find rspec. How can I get this to work?

$ echo 'rspec spec/models/employers_spec.rb' > my_shell.sh
$ sh my_shell.sh
Output:
Finished in 4.48 seconds
1 example, 0 failures
Randomized with seed 9820

So I kinda got it to work, and thought I'd share.
If I double click on the sh file, it opens a terminal, but fails. And I determined that it was due to the PATH variable being incomplete. More specifically it was missing these entries...
/home/joebloggs/.rvm/gems/ruby-2.3.0/bin:
/home/joebloggs/.rvm/gems/ruby-2.3.0#global/bin:
/home/joebloggs/.rvm/rubies/ruby-2.3.0/bin:
However, if I then used the exact same terminal that failed the script because it couldn't find the rspec command, and then ran ./test.sh, it worked. I could also directly type rspec spec spec/pos_spec.rb and it would also work. So it just seems that starting the script from a double click changes the PATH variable momentarily?
Anyway, I wont mark this as the correct answer, as it doesn't solve the original problem.
TLDR: Don't double click the sh file, run it from terminal using ./script.sh.

Related

How does this Ruby command line work? Seemingly running a CMD script with Ruby

I'm examining how ridk enable works in order to figure out how to hook it into Travis CI build logic. (The Ruby installation I'm studying is a RubyInstaller+Devkit installed locally; the commands are run from the "Start Command Prompt with Ruby" prompt.)
I've got stuck at a Ruby command line executed under the hood whose working is a mystery to me:
"C:\Ruby24-x64\bin\ruby" --disable-gems -x 'C:\Ruby24-x64\bin\ridk.cmd' enable
It seems to run a CMD script (?!) with Ruby -- which isn't supposed to be possible. Running it with -rtracer in place of --disable-gems shows that the execution somehow ends up jumping into C:/Ruby24-x64/lib/ruby/site_ruby/2.4.0/ruby_installer/runtime/ridk.rb.
Could someone explain to me how this command line works?
From man ruby:
-x[directory]
Tells Ruby that the script is embedded in a message. Leading garbage will be discarded until the first line that starts with #!
and contains the string, ruby
Any meaningful switches on that line
will be applied. The end of the script must be specified with either
EOF ^D ( control-D ^Z ( control-Z or the reserved word __END__ If the
directory name is specified, Ruby will switch to that directory before
executing script.
Which means the ridk.cmd has embedded ruby code.
The directory is optional, as indicated by both the square brackets around the name and the description. If provided, it should be directly after -x without any space, which effectively allows it to be an optional argument.

Launch interactive Bash shell in Ruby script, with initial command

I'm working on an interactive Ruby script, which build and packages resources. In the middle of the process, I'd like to drop into an interactive shell, but pre-cd'd into a specific working directory, as well as with an explanatory message (CTRL-D to continue). The interactive bash + given initial command is what's problematic.
Per the answer for doing something like this in Bash, given at https://stackoverflow.com/a/36152028, I've tried
system '/bin/bash', '--init-file', '<(echo "cd ~/src/devops; pwd")'
However, bash runs interactively but completely ignores the '<(echo "cd ~/src/devops; pwd")' section.
Interestingly system '/bin/bash', '--init-file complains if no argument is given, but literally anything runs bash, but with no initial command.
*Note that (--rcfile instead of --init-file) has the same effect.
Change the working directory of the Ruby script first, so that bash inherits the correct working directory.
curr_dir = Dir.pwd
Dir.chdir("#{Dir.home}/src/devops")
system "/bin/bash"
Dir.chdir(curr_dir) # Restore the original working directory if desired
Oh, this is probably far better (you can probably guess how little familiarity I have with Ruby):
system("/bin/bash", :chdir=>"#{Dir.home}/src/devops")

Problems running bash script from incron

I have a simple incron task setup to run a command whenever a particular .json file is written-to, then closed.
/var/www/html/api/private/resources/myfile.json IN_CLOSE_WRITE,IN NO LOOP /var/www/html/api/private/resources/run_service.sh
I can see that whenever the file to written to, there is a syslog entry for the event, and the command that was triggered - along the lines of <date> - incrond: CMD (/var/www/html/api/private/resources/run_service.sh).
But nothing seems to happen...
initially I thought this would be caused by an issue with the script, but replacing the script command to something simple such as echo "hello world" > /tmp/mylog.log still yields no output or results. I seem to have hit a brick wall with this one!
Update
Changing the incron command to read "/bin/bash /var/www/html/api/private/resources/run_service.sh" now seems to triggering the script correctly, as I can now get output from the script.
A simple mistake on my part, despite all examples online showing that using the script as the command should run it, for me it only works if I explicitly call bash to execute it
"<my directory/file to watch> <trigger condition> /bin/bash /var/www/html/api/private/resources/run_service.sh

Running `cucumber feature/test.feature` in ruby shows weird behaviour

#!/usr/bin/ruby
`cucumber feature/test.feature`
running the above code issue lots of cucumber feature/test.feature commands.. why ?
When i see processes list there are 30 to 50 processes running cucumber command
also ruby program never terminates
Try running your feature files from outside the 'features' folder. Think this will solve the issue.(tested using the command line)
User:project user$ ls
features
User:project user$cucumber example.feature
The first line instructs the shell to run myapp.rb, which is, AFAIU, this script itself. Namely, each execution of the script recursively runs itself again.
Try the following:
#!/usr/bin/ruby
`cucumber feature/test.feature`
Or, even better, directly from the CLI:
cucumber feature/test.feature
To run all the tests simply issue the cucumber command without args:
cucumber

How to test things in crontab

This keeps happening to me all the time:
1) I write a script(ruby, shell, etc).
2) run it, it works.
3) put it in crontab so it runs in a few minutes so I know it runs from there.
4) It doesnt, no error trace, back to step 2 or 3 a 1000 times.
When I ruby script fails in crontab, I can't really know why it fails cause when I pipe output like this:
ruby script.rb >& /path/to/output
I sorta get the output of the script, but I don't get any of the errors from it and I don't get the errors coming from bash (like if ruby is not found or file isn't there)
I have no idea what environmental variables are set and whether or not it's a problem. Turns out that to run a ruby script from crontab you have to export a ton of environment variables.
Is there a way for me to just have crontab run a script as if I ran it myself from my terminal?
When debugging, I have to reset the timer and go back to waiting. Very time consuming.
How to test things in crontab better or avoid these problems?
"Is there a way for me to just have crontab run a script as if I ran it myself from my terminal?"
Yes:
bash -li -c /path/to/script
From the man page:
[vindaloo:pgl]:~/p/test $ man bash | grep -A2 -m1 -- -i
-i If the -i option is present, the shell is interactive.
-l Make bash act as if it had been invoked as a login shell (see
INVOCATION below).
G'day,
One of the basic problems with cron is that you get a minimal environment being set by cron. In fact, you only get four env. var's set and they are:
SHELL - set to /bin/sh
LOGNAME - set to your userid as found in /etc/passwd
HOME - set to your home dir. as found in /etc/passwd
PATH - set to "/usr/bin:/bin"
That's it.
However, what you can do is take a snapshot of the environment you want and save that to a file.
Now make your cronjob source a trivial shell script that sources this env. file and then executes your Ruby script.
BTW Having a wrapper source a common env. file is an excellent way to enforce a consistent environment for multiple cronjobs. This also enforces the DRY principle because it gives you just one point to update things as required, instead of having to search through a bunch of scripts and search for a specific string if, say, a logging location is changed or a different utility is now being used, e.g. gnutar instead of vanilla tar.
Actually, this technique is used very successfully with The Build Monkey which is used to implement Continuous Integration for a major software project that is common to several major world airlines. 3,500kSLOC being checked out and built several times a day and over 8,000 regression tests run once a day.
HTH
'Avahappy,
Run a 'set' command from inside of the ruby script, fire it from crontab, and you'll see exactly what's set and what's not.
To find out the environment in which cron runs jobs, add this cron job:
{ echo "\nenv\n" && env|sort ; echo "\nset\n" && set; } | /usr/bin/mailx -s 'my env' you#example.com
Or send the output to a file instead of email.
You could write a wrapper script, called for example rbcron, which looks something like:
#!/bin/bash
RUBY=ruby
export VAR1=foo
export VAR2=bar
export VAR3=baz
$RUBY "$*" 2>&1
This will redirect standard error from ruby to the standard output. Then you run rbcron in your cron job, and the standard output contains out+err of ruby, but also the "bash" errors existing from rbcron itself. In your cron entry, redirect 2>&1 > /path/to/output to get output+error messages to go to /path/to/output.
If you really want to run it as yourself, you may want to invoke ruby from a shell script that sources your .profile/.bashrc etc. That way it'll pull in your environment.
However, the downside is that it's not isolated from your environment, and if you change that, you may find your cron jobs suddenly stop working.

Resources