1

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.

2
  • 2
    Each call to Kernel#system is run in its own subshell for example 3.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. Commented Aug 7, 2024 at 17:45
  • Each system command spawns a new shell so what you can do is use the rvm binary and the commands you need to run in a single command. like system("~/.rvm/bin/rvm use ruby-3.3.3@my-app-1; bundle exec rake {task_name}") Commented Aug 12, 2024 at 13:27

1 Answer 1

2

Based on the comment by @engineersmnky (dated Aug 7, 2024 at 17:45) I decided to run the rake tasks through a bash script and run that bash script itself through my ruby script. Sharing here the code I implemented

run_rake_tasks.sh

rubyVersion=$(cat ../.ruby-version)
rubyGemsetName=$(cat ../.ruby-gemset)

#echo $rubyVersion
#echo $rubyGemsetName

rvmUseGemsetCommand="rvm use ${rubyVersion}@${rubyGemsetName}"

#echo $rvmUseGemsetCommand

source ~/.rvm/scripts/rvm

$rvmUseGemsetCommand

#gem env

#rvm gemset name

echo "Starting running rake tasks."

rakeTasks=('task_1' 'task_2')

for str in ${rakeTasks[@]}; do
  #echo $str

  bundle exec rake $str
done

echo "Finished running rake tasks."

# Like following you can also run other ruby scripts which may depend on gems in the gemset. 

echo "Starting running ruby script rs_1."

ruby rs_1.rb

echo "Finished running ruby script rs_1."

Note: The bash script must be made executable. For that use following command from the directory in which the script is present:

$chmod u+x run_rake_tasks.sh

Then I modified my run_rake_tasks in following manner:

def run_rake_tasks
  this_script_dir = Dir.pwd

  Dir.chdir('<app_root>')

  system('./run_rake_tasks.sh')

  Dir.chdir(this_script_dir)
 end

and it ran the rake tasks as expected. Hope this helps others having similar needs.

Thanks.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.