Is it possible to reset rbenv in a sub-shell - ruby

I have a ruby script which I am using to collect information from several other source repositories. The code looks something like this:
def grab_deps(repo)
Dir.chdir(repo) do
if system('bundle check')
raise "#{repo} does not have all dependencies installed, run `bundle install`"
else
`ruby -e 'Gem.loaded_specs.keys.each{ ... }'`
end
end
end
Each of these repos has a different .ruby-version specified. Unfortunately because this script runs in my shell where I've already done the rbenv init shell integration, those .ruby-versions are not honored, and I get version mismatches.
I have pored over the docs and Google and have not found any way of resetting the rbenv for a subshell. Ideally I would like something like Bundler.with_clean_env.
I have two semi-solutions:
Remove the shell integration and use the rbenv command internally in the script. This might be the most reliable, but it also is bad for my workflow since I normally want rbenv in all my shells by default.
Hacking the PATH, RBENV_VERSION and other vars directly in the ruby script. I was able to at least get the sub-shell using a different ruby version this way, but it's dirty, brittle and violates rbenv internals something fierce.
I'm fairly close to giving up and making the top-level script a shell-script, but it will be quite a bit uglier than the ruby version and I would really like to get this working cleanly. Any ideas?

Related

Ruby script: shebang with absolute path to ruby not working

I am using Mac OS X. I have two versions (2.1.5 and 2.0.0) of Ruby installed. The former installed at /another/.path/to/ruby (there is a dot before "path" to mimic the fact that the path contains a dot-headed directory in between), in addition to the default system one (version 2.0.0) at /usr/bin/ruby. I used rbenv to install Ruby.
After I manually set the PATH environment variable so the default ruby command will be found in another directory: /another/.path/to/ruby. Now I check
which -a ruby
It is using correct ruby first, as output.
/another/.path/to/ruby
/usr/bin/ruby
Now I create a script, rbs, with the first line of shebang specifying the ruby to use.
#!/usr/bin/env ruby
puts 'hey there'
Then I run
./rbs
it outputs 'hey there'. Good. Meanwhile, the Ruby is using the correct version.
/usr/bin/env ruby --version
as well as
ruby --version
both output 2.1.5. So it does great job to use the new version.
However, here is where the problem occurs: now I update rbs file to be:
#!/another/.path/to/ruby
puts 'hey there'
Note that I updated the shebang to use the absolute path to the desired ruby. then I run
./rbs
It outputs:
./rbs: line 2: puts: command not found
which is too weird;
but if I run
ruby ./rbs
it outputs 'hey there' as normal. It looks like the shebang works perfect using /usr/bin/env ruby, but not for absolute path for the newly install ruby?
Why is this? Is there a way to fix it so the updated script can still work by typing the following?
./rbs
Thanks!
The puts: command not found message indicates that your script is not being run by Ruby, but by the shell instead. So first, I would double-check your shebang line's syntax and path.
Second, note that rbenv uses shims that dynamically find and run the right version of ruby (and associated programs like gem, etc). But the shims are scripts, and scripts can't themselves be shebang interpreters; you have to find and use the actual path to the ruby executable (as output by rbenv which ruby).
On the other hand, since /usr/bin/env is an executable, you can always use something like #!/usr/bin/env ruby, which will work even if the ruby it finds in the path is itself a script.
I can't comment, (otherwise I'd add as a comment) but I think its worthwhile to add that the
#!/usr/bin/env ruby
MUST be the first line of the file. This tripped me up for a while.
source

ruby script specific gemset backick

We have a rails sidekiq setup to run jobs.
I am trying to make a job as portable as possible by separating the actual script from the sidekiq call.
So sidekiq calls a small stub job that backtick calls the actual script and captures the output.
That part works fine. But sidekiq runs the job as root, rather than as the user who's environment has all the rvm parts, rubies, and gemsets. I'd like to use the existing user rvm rubies and gemsets.
in the calling script (sidekiq job):
output = `source /path/to/dudes/rvm/environment.file && rvm use \
2.0.0-pxxx#default do ruby /path/to/actual/script.rb`
and the called script gets run, but as root and it obviously doesn't work as I intended because my requires are not found.
If I take that same command string and run it as a local user from BASH, who also has no gemsets, it seems to work.
I've tried just backtick calling it like a shell script
output = `/path/to/actual/script.rb`
...and in the called script, various combinations of shebangs.
#!/usr/bin/env ruby
#!/usr/bin/env rvm use everything i found on the internets
Now, I've gotten ruby scripts to run in environments with linux upstart jobs by using bash script wrappers like this:
http://techhelplist.com/index.php/tech-tutorials/43-linux-adventures/85-upstart-ruby-job-with-rvm
But I am trying to find a way to do this with no wrappers. Is it possible?
No, it is not possible.
When you use the "backtick" operator you are essentially calling Kernel#system(...). This means the command you execute is run in a subshell which cannot change the environment of the parent process in the ways you want.
See this question for comparison: How to run code after ruby Kernel.exec
Also consider reading more about the UNIX process model.
According to Upstart Intro, Cookbook and Best Practises, point 4.2.2, you can set user jobs in $HOME/.init/.

RVM on Ruby Scripts

I need for a Ruby script to be run using an rvm-selected version. I cannot change how the script is invoked, but I can modify the script. The script starts with:
#!/usr/bin/env ruby
Now, based on some information I found (in this question, for example), I tried this:
#!/usr/bin/env rvm-shell ree-1.8.7-2012.02#gitorious
But this only gives me this error message:
/usr/bin/env: rvm-shell ree-1.8.7-2012.02#gitorious: No such file or directory
Now, rvm is available, because this works (but doesn't bring the required ruby/gemset):
#!/usr/bin/env rvm-shell
I've tried this as well:
#!/usr/local/rvm/bin/rvm-shell ree-1.8.7-2012.02#gitorious
But this doesn't bring in the environment ("gem", which is only installed inside that gemset, is not available, for example). If I run that on the command line itself, it does open a shell with the proper environment.
So, has anyone done something like this? How can I fix it?
Does this work?
#!/location/of/rvm/folder/rubies/ree-1.8.7-2012.02#gitorious/bin/ruby

Ruby 1.9.3 #OSX Lion and Cron

I installed Ruby 1.9.3p125 via this guide (up to point #5): LINK
Now I have this problem: my script works wonderfully from my command line, but if I execute it from Cron it seems to use a default environment and defaults to /usr/bin/ruby instead of mine (~/.rvm/rubies/ruby-1.9.3-p125/bin/ruby). What is the best way to have executed commands - manually or via cron - produce the same results?
PS: It seems to skip processing ~/.bash_login for example, where rvm is loaded into PATH
In your crontab line, you can source the .bash_login before you script is run.
source ~/.bash_login && <your original command here>
That way your script will have everything you have when you run it.
The usual way recommended to do this would be to put the full path to the executable in your crontab. E.g.
crontab should show:
/Users/Poochie/.rvm/rubies/ruby-1.9.3-p125/bin/ruby /full/path/to/script.rb
or whatever the full path is. It's much more robust than trying to get rvm loading, as here an rvm script is modifying your path for you. If you want to set it to whichever is the rvm default ruby (e.g. whatever was set by rvm use x.x.x --default), You can use: /Users/Poochie/.rvm/bin/ruby as the executable instead, e.g.:
/Users/Poochie/.rvm/bin/ruby /full/path/to/script.rb
I actually found this post which helped me a lot: LINK
I managed to run my script as I wanted but the questions is theoretically still open because the issue could still affect cron usage in general.

RVM | Running user scripts

Is it possible while using the Ruby version manager to run scripts not from the console but using other ways — at system startup or by a keyboard shortcut for example?
RVM installs a command rvm-shell. You can use rvm-shell, pass it whatever you would pass rvm use, then you can execute a shell command.
rvm-shell will set your environment for that shell script, or you can use rvm-shell on one line, and have it execute the parameter as a shell command.
For example:
rvm-shell rbx-2.0 -c 'which ruby'
Which should equal your rbx ruby.
It'd help to know the system, but the answer is yes, though you'd need to either know which is the current directory, or set the system ruby to be the one you needed for these scripts (especially startup). You might also need to experiment, as it would depend at which point in the startup you needed the scripts to run, but you can probably get more answers on that from the irc rvm channel.
rvm default do /path/to/ruby/script

Resources