jruby/warbler

running bundle exec in a runnable .war

Opened this issue · 6 comments

How do I call bundle exec within a runnable .war file?

Our application here uses some local Git repos, so the data migration tool I've just written needs to be called with bundle exec, or else there will be require's that fail.

However when I try java -jar thing.war -S bundle exec projects/remedium/document_loader I get:

WARNING: `bundle exec' may drop out of the Warbler environment and into the system environment
Following files may not be writable, so sudo is needed:
  uri:classloader:/WEB-INF/gems
  uri:classloader:/WEB-INF/gems/bundler
  uri:classloader:/WEB-INF/gems/gems
  uri:classloader:/WEB-INF/gems/specifications

etc.

I tried doing a bundle install --binstubs and including the bin directory in the .war file. I still get the same error. Or I can try java -jar thing.war -S bin/bundle exec projects/remedium/document_loader, in which case I get:

bundler: not executable: projects/remedium/document_loader
ERROR: org.jruby.exceptions.RaiseException: (SystemExit) exit
rsov commented

Hello,

If the data migration tool that you wrote does not alter the application file structure, then you can change it to a rake task. That way java -jar thing.war -S rake remedium:document_loader will work.

When .war is created, it bundles all the necessary libraries inside it. It cannot be altered afterwards. The way it works is: java unpacks the .war contents into a temp directory, runs the code, and then deletes the exacted data. When doing bundle install --binstubs, it will write them to a temp directory and then delete them. This is the reason why that warning exists.

Your git gems should be able to work provided you bundled them with :git and not :local directive inside them Gemfile.

@rsov Can you expand on what you mean by a "rake task"?

I mean, presumably --

task :document_loader do
  sh 'document_loader'
end

...would fail in exactly the same way?

rsov commented

Is the document_loaded a ruby script?

If so, put the source inside the rake task.

For example, here is one of the ones we have in our system:

lib/tasks/migrate.rake

namespace :migrate do
  task :create_cases => :environment do
    User.where(case_id: nil).each(&:create_case!)
  end
end

java -jar app.war -S rake migrate:create_cases will run the code inside the task

You can add require on top of the file to load any libraries needed.

I can confirm that that works, although I'm not entirely sure what is going on here. Are we saying that we never need to type bundle exec rake? That would definitely be an advantage I would like to have heard about before now...

Many thanks.

rsov commented

bundle exec rake will execute the code in the context of current bundle. Meaning it will look up the version of rake specified by your application. Even though you may have multiple versions of rake installed on your system.

app.war IS the bundle. It is an archive of all the dependencies and libraries. When doing java -jar app.war -S rake there's only 1 version of rake, and it's the version that was specified by application when war was created.

So yes, there's no need to use bundle exec when executing commands from the war application

So yes, there's no need to use bundle exec when executing commands from the war application

For rake, yes, okay. Otherwise there might well be. See the issue I raised above?