I am on Ubuntu 18.04.
I have a Rack-based application at /home/jignesh/webapps/my-app-1 (henceforth this will be referred to as app_root).
app_root contains following files
.ruby-version
3.3.3
.ruby-gemset
my-app-1
Rakefile
task_1 definition
task_2 definition
I want to run those tasks from a stand-alone ruby script which is located at /home/jignesh/Desktop/my_script.rb (henceforth this will be referred to as my_script).
my_script looks like following:
RUN_RAKE_TASKS = [
'task_1',
'task_2'
].freeze
def run_rake_tasks
this_script_dir = Dir.pwd
Dir.chdir('<app_root>')
RUN_RAKE_TASKS.each do |task_name|
cmd = "bundle exec rake {task_name}"
system(cmd)
end
Dir.chdir(this_script_dir)
end
Running that script I see the output
Run `bundle install` to install missing gems.
That's strange because I have ruby 3.3.3 installed and also gemset my-app-1 created and in it all my gems are installed.
So I opened a terminal and changed directory to app_root and ran bundle exec rake task_1 and it worked.
To investigate what is the problem with the script unable to find the gems I modified my run_rake_tasks method like following
def run_rake_tasks
this_script_dir = Dir.pwd
Dir.chdir('<app_root>')
system('gem env')
system('rvm gemset name')
end
and when I ran the script following was the output
RubyGems Environment:
- RUBYGEMS VERSION: 3.5.17
- RUBY VERSION: 3.3.3 (2024-06-12 patchlevel 89) [x86_64-linux]
- INSTALLATION DIRECTORY: /home/jignesh/.rvm/gems/ruby-3.3.3
- USER INSTALLATION DIRECTORY: /home/jignesh/.gem/ruby/3.3.0
- RUBY EXECUTABLE: /home/jignesh/.rvm/rubies/ruby-3.3.3/bin/ruby
- GIT EXECUTABLE: /usr/bin/git
- EXECUTABLE DIRECTORY: /home/jignesh/.rvm/gems/ruby-3.3.3/bin
- SPEC CACHE DIRECTORY: /home/jignesh/.gem/specs
- SYSTEM CONFIGURATION DIRECTORY: /etc
- RUBYGEMS PLATFORMS:
- ruby
- x86_64-linux
- GEM PATHS:
- /home/jignesh/.rvm/gems/ruby-3.3.3
- /home/jignesh/.rvm/rubies/ruby-3.3.3/lib/ruby/gems/3.3.0
- GEM CONFIGURATION:
- :update_sources => true
- :verbose => true
- :backtrace => true
- :bulk_threshold => 1000
- REMOTE SOURCES:
- https://rubygems.org/
- SHELL PATH:
- /home/jignesh/.rvm/gems/ruby-3.3.3/bin
- /home/jignesh/.rvm/gems/ruby-3.3.3@global/bin
- /home/jignesh/.rvm/rubies/ruby-3.3.3/bin
- /home/jignesh/.rvm/bin
- /usr/local/sbin
- /usr/local/bin
- /usr/sbin
- /usr/bin
- /sbin
- /bin
- /usr/games
- /usr/local/games
- /snap/bin
/home/jignesh/.rvm/gems/ruby-3.3.3
Then I manually ran gem env and rvm gemset name commands on terminal and I got following output
RubyGems Environment:
- RUBYGEMS VERSION: 3.5.17
- RUBY VERSION: 3.3.3 (2024-06-12 patchlevel 89) [x86_64-linux]
- INSTALLATION DIRECTORY: /home/jignesh/.rvm/gems/ruby-3.3.3@my-app-1
- USER INSTALLATION DIRECTORY: /home/jignesh/.gem/ruby/3.3.0
- RUBY EXECUTABLE: /home/jignesh/.rvm/rubies/ruby-3.3.3/bin/ruby
- GIT EXECUTABLE: /usr/bin/git
- EXECUTABLE DIRECTORY: /home/jignesh/.rvm/gems/ruby-3.3.3@my-app-1/bin
- SPEC CACHE DIRECTORY: /home/jignesh/.gem/specs
- SYSTEM CONFIGURATION DIRECTORY: /etc
- RUBYGEMS PLATFORMS:
- ruby
- x86_64-linux
- GEM PATHS:
- /home/jignesh/.rvm/gems/ruby-3.3.3@my-app-1
- /home/jignesh/.rvm/rubies/ruby-3.3.3/lib/ruby/gems/3.3.0
- GEM CONFIGURATION:
- :update_sources => true
- :verbose => true
- :backtrace => true
- :bulk_threshold => 1000
- REMOTE SOURCES:
- https://rubygems.org/
- SHELL PATH:
- /home/jignesh/.rvm/gems/ruby-3.3.3@my-app-1/bin
- /home/jignesh/.rvm/gems/ruby-3.3.3@global/bin
- /home/jignesh/.rvm/rubies/ruby-3.3.3/bin
- /home/jignesh/.rvm/bin
- /usr/local/sbin
- /usr/local/bin
- /usr/sbin
- /usr/bin
- /sbin
- /bin
- /usr/games
- /usr/local/games
- /snap/bin
my-app-1
Comparing that with the output generated by the script I concluded that the process in the script is not taking into account the rvm gemset which is automatically
done when running commands from terminal. So I modified my run_rake_tasks method like following
def run_rake_tasks
this_script_dir = Dir.pwd
Dir.chdir('<app_root>')
ruby_version = `cat .ruby-version`
ruby_gemset = `cat .ruby-gemset`
# `chop` important because the backtick output contains newline chars at the end.
ruby_version.chop!
ruby_gemset.chop!
rvm_use_gemset_command = "rvm use #{ruby_version}@#{ruby_gemset}"
system(rvm_use_gemset_command)
system('gem env')
system('rvm gemset name')
end
When I ran the script, in the output I saw following:
RVM is not a function, selecting rubies with 'rvm use ...' will not work.
You need to change your terminal emulator preferences to allow login shell.
Sometimes it is required to use `/bin/bash --login` as the command.
Please visit https://rvm.io/integration/gnome-terminal/ for an example.
Searching for that error I found https://stackoverflow.com/a/11105199/936494 and based on that I modified my method like following
def run_rake_tasks
this_script_dir = Dir.pwd
Dir.chdir('<app_root>')
system('source ~/.rvm/scripts/rvm')
system('type rvm | head -n 1')
ruby_version = `cat .ruby-version`
ruby_gemset = `cat .ruby-gemset`
# `chop` important because the backtick output contains newline chars at the end.
ruby_version.chop!
ruby_gemset.chop!
rvm_use_gemset_command = "rvm use #{ruby_version}@#{ruby_gemset}"
system(rvm_use_gemset_command)
system('gem env')
system('rvm gemset name')
end
When I ran the script, in the output I saw following:
sh: 1: source: not found
rvm is /home/jignesh/.rvm/bin/rvm
Searching for that I found following
source command not found in sh shell "source" in ruby subshells
Based on them I made changed
system('source ~/.rvm/scripts/rvm')
to
system('. ~/.rvm/scripts/rvm')
When I ran the script, in the output I saw following:
sh: 10: /home/jignesh/.rvm/scripts/rvm: builtin: not found
rvm is /home/jignesh/.rvm/bin/rvm
Searching for that I found following
"builtin: not found" when I source a script via PHP passthru()
Based on that changed
system('source ~/.rvm/scripts/rvm')
system('type rvm | head -n 1')
to
system("/bin/bash -c '. ~/.rvm/scripts/rvm && type rvm | head -n 1'")
When I ran the script, in the output I saw following:
rvm is a function
But despite that the subsequent commands
system(rvm_use_gemset_command)
system('gem env')
system('rvm gemset name')
emitted RVM is not a function, selecting rubies with 'rvm use ...' will not work. and the gem env and gemset as mentioned before.
I have understood the problem as when running the commands from script the rvm gemset is not being found.
So how do I make my script work so that I am able to successfully run the desired rake tasks and possibly other run other commands as well which I can do by manually running them from terminal?
Thanks.
Kernel#systemis run in its own subshell for example3.times { system('echo $$')}will show 3 different process ids. While there may be workarounds (I honestly didn't try) is there a specific reason the script needs to be written in ruby? It seems to me, based on what the script actually does, making this a bash script would be easier and more appropriate.system("~/.rvm/bin/rvm use ruby-3.3.3@my-app-1; bundle exec rake {task_name}")