Why is my Ruby Git script hook run with the wrong $PATH? - ruby

I'm using RVM. I wrote a Git pre-commit hook for a project:
#!/usr/bin/env ruby
puts RUBY_VERSION
puts `echo $PATH`
exit(1)
which outputs this when run by Git:
$ git ci -m 'foo'
1.8.7
/usr/libexec/git-core:/usr/bin:/usr/local/heroku/bin:/Users/mgoerlich/.rvm/gems/ruby-2.0.0-p195#global/bin:/Users/mgoerlich/.rvm/rubies/ruby-2.0.0-p195/bin:/Users/mgoerlich/.rvm/bin:/Users/mgoerlich/adt-bundle-mac-x86_64-20130219/sdk/platform-tools:/Users/mgoerlich/adt-bundle-mac-x86_64-20130219/sdk/tools:/usr/local/bin:/usr/local/sbin:/Users/mgoerlich/.dotfiles/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/bin/core_perl:/Users/mgoerlich/bin:/usr/local/share/npm/bin:/usr/local/share/npm/bin
It seems to run with the wrong version of Ruby because $PATH is not the same as in bash or zsh or sh. It seems like git is manipulating $PATH. When run manually, I get this:
$ .git/hooks/pre-commit
2.0.0
/usr/local/heroku/bin:/Users/mgoerlich/.rvm/gems/ruby-2.0.0-p195#global/bin:/Users/mgoerlich/.rvm/rubies/ruby-2.0.0-p195/bin:/Users/mgoerlich/.rvm/bin:/Users/mgoerlich/adt-bundle-mac-x86_64-20130219/sdk/platform-tools:/Users/mgoerlich/adt-bundle-mac-x86_64-20130219/sdk/tools:/usr/local/bin:/usr/local/sbin:/Users/mgoerlich/.dotfiles/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/bin/core_perl:/Users/mgoerlich/bin:/usr/local/share/npm/bin:/usr/local/share/npm/bin
In the output of the commit hook, there are two paths prepended, one of them /usr/bin where the system Ruby's executable is placed.
Is this a known behavior? Can I manipulate that somehow? I know I could specify the full path to the correct Ruby version in the shebang, but this is not what I want.

The reason i didn't wanted to use env instead of a fixed path to ruby or a rvm wrapper was that this is for a Team Project and not everyone in the Team is using RVM.
My final solution was to write my own wrapper script an add it to that project.
All client-side git hooks 're living in $PROJECT/bin/hooks, all of them ruby scripts.
Now, i've just put that mentioned wrapper in there, and created a symlink to that wrapper in $PROJECT/.git/hooks for all the hooks.
The script check's if RVM is used and if so fixes the $PATH var and if there are .ruby-version and/or .ruby-gemset files in the project root it loads the according version/gemset.
Then it'll run the according ruby script
Here's the wrapper in case you're interested:
#!/bin/bash
if [ -d "$HOME/.rvm/bin" ]; then
PATH="$HOME/.rvm/bin:$PATH"
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
if [ -f ".ruby-version" ]; then
rvm use "$(cat .ruby-version)"
fi
if [ -f ".ruby-gemset" ]; then
rvm gemset use "$(cat .ruby-gemset)"
fi
fi
ruby "bin/hooks/$(basename "$0").rb"
So, i'll get my rvm version/gemset and everybody else the ruby version they have in their PATH, and everyone is Happy.

you need to set ruby to a wrapper:
#!$rvm_path/wrappers/ruby-2.0.0-p195/ruby
You can simplify it with an alias:
rvm alias create git_hooks 2.0.0-p195
And then the ne shebang will look like this:
#!$rvm_path/wrappers/git_hooks/ruby
In the file just make sure to replace $rvm_path with /Users/mgoerlich/.rvm so finally it looks like:
#!/Users/mgoerlich/.rvm/wrappers/git_hooks/ruby

What I ended up doing is: the .git file structure:
.git/hooks/pre-commit
.git/hooks/pre-commit-main.rb
.git/hooks/pre-commit:
#!/usr/bin/env bash
export PATH="$THE_GOOD_PATH"
ruby "$GIT_DIR/hooks/pre-commit-main.rb"
.git/hooks/pre-commit-main.rb:
#!/usr/bin/env ruby
puts RUBY_VERSION
Then, when you call git commit, make sure that THE_GOOD_PATH, is defined:
export THE_GOOD_PATH="$PATH"
git commit
You could also export THE_GOOD_PATH="$PATH" from your .profile or the toplevel of your application and symlink all hooks to a single file.
This method has the advantage of being rbenv agnostic: it also works with RVM or Python virtualenv.
I wrote to the Git developers at: http://permalink.gmane.org/gmane.comp.version-control.git/258454 asking them to leave our PATH alone, but the initial reply was WONTFIX.

Related

RVM and Gemfile - not always loading correct ruby, only when 'cd .. & cd myproject'

TL;DR: Every time I open a new iterm2 tab, rvm goes back to default version, it doesn't use the Gemfile ruby version
My Gemfile has
source 'https://rubygems.org'
ruby '2.0.0'
and I use rvm 1.25.14.
RVM is smart and reads the ruby version in gemfile, except for this edge case
Doing
# NOTE: iterm2
$ cd myproject
$ ruby -v
> ruby 2.0.0p353 (2013-11-22 revision 43784) [x86_64-darwin12.5.0]
but cmd+t, creating a new tab, staying in that directoy,
$ pwd
>../myproject
$ ruby -v
> ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-darwin12.3.0]
ruby 1.9.3 is my default, which is fine. What am I missing in my bash (or .zshrc ) ? to make this work?
#FILE .zshrc
#...stuff
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into a shell session *as a function*
PATH=$PATH:$HOME/.rvm/bin # Add RVM to PATH for scripting
Using cmd+d, splitting the terminal vertically, has the same problem. rvm goes to default, ignoring Gemfile. Thanks for helping guys !
This should be shell- and terminal-agnostic (unfortunately I can't test it on iterm2 since I don't have any Mac machine):
Add cd ${PWD} to your .zshrc and this should force RVM to load current gemset.
Just add cd . in .zlogin after the RVM script.
Use RVM's Built-In Ability to Reload Configuration Files in the Current Directory
RVM leverages the cd command, so while there may be a specific solution for your situation the more general solution is to use direnv, dotenv, or similar to ensure that you're triggering RVM properly when changing directories.
In my personal experience, one of the two placed into your project's .envrc or similar will resolve many issues, and highly recommend direnv with or without its standard library's ruby layout or use commands. For example:
read in the current directory's .ruby-* or .rvmrc files
rvm use .
Reload RVM, which will re-read various dotfiles if the relevant ~/.rvmrc variables have been exported (see dotfile settings in next section).
rvm reload
The first option is best IMHO, and seems to "just work" on all my Bourne-compatible shells, but the other should work too.
Some Key ~/.rvmrc Dotfile Settings
With either of the solutions above, you may need some of the following items set in your global ~/.rvmrc file:
export rvm_gemset_create_on_use_flag=1
export rvm_install_on_use_flag=1
export rvm_project_rvmrc_default=1
Which ones you really need will somewhat depend on how you expect RVM to behave under any given set of circumstances. However, I've found that using RVM's ability to reload its settings (rather than relying on the cd hooks, and calling that functionality directly to be much more reliable. Your mileage may vary.
See Also
https://rvm.io/workflow/rvmrc
https://rvm.io/workflow/projects
I seems that for a local open terminal rvm don't load its scripts. Add the code to the end of .bashrc, it then should:
if [ -z "$MY_RUBY_HOME" ]; then
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
fi

Ruby and Xcode - wrong ruby version [duplicate]

Outside of Xcode I use a specific version of Ruby, using RVM to manage multiple Ruby installations.
Apple's command line dev tools install Ruby at /usr/bin/ruby and is version 1.8.7.
I use 1.9.3 through RVM.
Is there a way to force Xcode to use my 1.9.3 installation when running its Run Script build phases?
I already tried setting the Shell path to the full path of my specific Ruby, but that didn't seem to make a difference, by which I mean that the particular Gems I have installed in my 1.9.3 weren't available/visible to the script when run within Xcode.
If I run my project through xcodebuild on the command line, the Run Script phase uses my specific Ruby because it's being run from within my shell environment (even if the Shell path in the project file is set to /usr/bin/ruby, it still uses my 1.9.3).
What can I do to make the IDE use my 1.9.3 Ruby install?
I had the same (well, worse) problem, and the code that follows worked for me.
The key thing to realize is that, on the command line, you are using <something>/bin/rvm, but in a shell script, in order for rvm to change that environment, you must use a function, and you must first load that function to your shell script by calling source <something>/scripts/rvm. More on all this here.
This code is also gisted.
#!/usr/bin/env bash
# Xcode scripting does not invoke rvm. To get the correct ruby,
# we must invoke rvm manually. This requires loading the rvm
# *shell function*, which can manipulate the active shell-script
# environment.
# cf. http://rvm.io/workflow/scripting
# Load RVM into a shell session *as a function*
if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then
# First try to load from a user install
source "$HOME/.rvm/scripts/rvm"
elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then
# Then try to load from a root install
source "/usr/local/rvm/scripts/rvm"
else
printf "ERROR: An RVM installation was not found.\n"
exit 128
fi
# rvm will use the controlling versioning (e.g. .ruby-version) for the
# pwd using this function call.
rvm use .
As a protip, I find embedding shell code in a project.pbxproj file yucky. For all but the most trivial stuff, my actual run script step is usually just a one-line call out to an external script:
Try this at the beginning of your script in Xcode:
source "$HOME/.rvm/scripts/rvm"

Use rvm to force specific Ruby in Xcode Run Script build phase

Outside of Xcode I use a specific version of Ruby, using RVM to manage multiple Ruby installations.
Apple's command line dev tools install Ruby at /usr/bin/ruby and is version 1.8.7.
I use 1.9.3 through RVM.
Is there a way to force Xcode to use my 1.9.3 installation when running its Run Script build phases?
I already tried setting the Shell path to the full path of my specific Ruby, but that didn't seem to make a difference, by which I mean that the particular Gems I have installed in my 1.9.3 weren't available/visible to the script when run within Xcode.
If I run my project through xcodebuild on the command line, the Run Script phase uses my specific Ruby because it's being run from within my shell environment (even if the Shell path in the project file is set to /usr/bin/ruby, it still uses my 1.9.3).
What can I do to make the IDE use my 1.9.3 Ruby install?
I had the same (well, worse) problem, and the code that follows worked for me.
The key thing to realize is that, on the command line, you are using <something>/bin/rvm, but in a shell script, in order for rvm to change that environment, you must use a function, and you must first load that function to your shell script by calling source <something>/scripts/rvm. More on all this here.
This code is also gisted.
#!/usr/bin/env bash
# Xcode scripting does not invoke rvm. To get the correct ruby,
# we must invoke rvm manually. This requires loading the rvm
# *shell function*, which can manipulate the active shell-script
# environment.
# cf. http://rvm.io/workflow/scripting
# Load RVM into a shell session *as a function*
if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then
# First try to load from a user install
source "$HOME/.rvm/scripts/rvm"
elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then
# Then try to load from a root install
source "/usr/local/rvm/scripts/rvm"
else
printf "ERROR: An RVM installation was not found.\n"
exit 128
fi
# rvm will use the controlling versioning (e.g. .ruby-version) for the
# pwd using this function call.
rvm use .
As a protip, I find embedding shell code in a project.pbxproj file yucky. For all but the most trivial stuff, my actual run script step is usually just a one-line call out to an external script:
Try this at the beginning of your script in Xcode:
source "$HOME/.rvm/scripts/rvm"

RVM and Jenkins setup

I am new to Jenkins CI. I'm install RVM in my remote Jenkins and when I execute below shell.
#!/bin/bash -x
source ~/.bashrc
rvm use 1.9.3#rails-3.2.3
I get following errors.
+ source /var/lib/jenkins/.bashrc
++ PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/var/lib/jenkins/.rvm/bin:/var/lib/jenkins/.rvm/bin
+ rvm use 1.9.3#rails-3.2.3
RVM is not a function, selecting rubies with 'rvm use ...' will not work.
You need to change your terminal settings to allow shell login.
Please visit https://rvm.io/workflow/screen/ for example.
What does it mean? I don't have any idea. Please help me.
UPDATED: I'm tried below script but I still get errors:
#!/bin/bash -x
source /home/zeck/.bashrc
[[ -s ".rvmrc" ]] && source .rvmrc
export RAILS_ENV=test
bundle install
Errors:
/tmp/hudson457106939700368111.sh: line 5: bundle: command not found
Build step 'Execute shell' marked build as failure
Finished: FAILURE
Jenkins build shell can't detect RVM, gemsets and gems. What should I do?
UPDATED 2: Therefore jenkins can't detect ruby.
+ ruby -v
/tmp/hudson2505951775163045158.sh: line 5: ruby: command not found
Build step 'Execute shell' marked build as failure
Finished: FAILUR
I'm not using any jenkins plugn and I'm just run script from Build->Execute shell section.
As the error message suggests, RVM expects an login shell. Changing the hashbang line to #!/bin/bash -xl should resolve this.
try:
. $(/home/RVM_USER/.rvm/bin/rvm env 1.9.3#rails-3.2.3 --path)
make sure you run the stable RVM:
rvm get stable
NOTE:
Last Jenkins version does not always accept "source", but ".".
RVM_USER is the user that installed RVM.
Alternatively you can also export the RVM command in the main PATH.
Yes, apparently you miss the $HOME/.rvm/bin in your PATH. I am using rvm successfully from Hudson on Mac OS X. First thing to notice is that, unless you define BASH_ENV environment variable (ENV for sh), .bashrc is called automatically only with interactive non-login shell. Such a shell is started when you do - for example - the following from the command line:
$ /bin/bash
When you use #!/bin/bash in your script, .bashrc will not be called.
To make rvm work with Hudson, I have the following in my .bash_profile:
PATH=$PATH:$HOME/.rvm/bin # Add RVM to PATH for scripting
export PATH
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
Thanks to [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" I have rvm enabled every time I start new terminal window (interactive, login shell).
I do not put anything in my .bashrc, especially I am not sourcing rvm scripts there. Nothing wrong with that, but if any other scripts makes something stupid like setting `export BASH_ENV=$HOME/.bashrc' and then invoke non-interactive shell, you see what may happen - it is actually easy to forget.
Therefore, instead of loading things to your .bashrc, it is better to keep your script independent from any shell startup file and make sure that the correct environment is set up within the script. I still keep $HOME/.rvm/bin in my .bash_profile, but then I include the following at the beginning of my script:
#!/bin/bash
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
rvm use 1.9.3-head#MyGemSet
set -ex
cucumber # just an example
Notice the -e option which forces the script to exit with error code if any command following set -ex fails. This is behavior you may want when using the script with Hudson.
It is incorrect to say that RVM expects a login shell. Although using #!/bin/bash -l in your script will work, it does not seem like the best approach.
Just add this code in your shell script, i think rvm is loading from your source so it should work else need to export PATH variable
#!/bin/bash -l
source ~/.bashrc
rvm use 1.9.3#rails-3.2.3
l is for login shel, if you include x then it would be for debugging too.
adding a shebang to the build commands in jenkins fixed this for me
#!/usr/bin/env bash
rvm use 2.0.0
bundle install
rake test
...
Jenkins nodes don't load paths the same way, so it's not using the proper path to find rvm's version of ruby. You can set the path for a given agent.
Find your current PATH by doing echo $PATH
Assuming you've set up rvm properly, find where rvm's version of ruby is located by running which ruby
There's a setting in the Configuration of your agent where you can set environmental variables. Set PATH to be 1 and 2 concatenated.

does cd command in a shell script load the rvmrc inside the destination directory?

when you have something like..
given inside projectx an .rvmrc file specifying ruby 1.9.2 and having two rubies on my system (ree-1.8.7 and ruby1.9.2)
#!/bin/bash
cd applications/projectx
which ruby
ruby -v
the last two lines output ree-1.8.7 and its path which was not I intended to use.
Yes
Rvm does define a wrapper around cd that looks like this:
cd ()
{
builtin cd "$#";
local result=$?;
__rvm_project_rvmrc;
__rvm_after_cd;
return $result
}
It's difficult to tell why your .rvmrc isn't working. Rvm does support project-specific .rvmrc files, but you didn't post yours.
You need to source rvm inside your script, when you run a script it doesn't load your .bashrc. Simply add a line like
[[ -s $HOME/.rvm/scripts/rvm ]] && source $HOME/.rvm/scripts/rvm
to the start of your script.
If you are using RVM 1.7.0 or later you need to enable project specific .rvmrc files by adding this line to ~/.rvmrc (or system .rvmrc):
rvm_project_rvmrc=1
See: https://rvm.io/workflow/rvmrc/

Resources