Skip to content

Commit

Permalink
have no side effects when creating instance of IsolatedScriptingConta…
Browse files Browse the repository at this point in the history
…iner

backport and improve the implementation from 9k. also sets the current directory
to uri:classloader:/ if this directory exists. same with jruby.home which will
only be set into the classloader when it exists.

Sponsored by Lookout Inc.
  • Loading branch information
mkristian committed Jul 23, 2015
1 parent a1a99aa commit 13a5e41
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 22 deletions.
33 changes: 22 additions & 11 deletions core/src/main/java/org/jruby/embed/IsolatedScriptingContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
*/
public class IsolatedScriptingContainer extends ScriptingContainer {

private static final String URI_CLASSLOADER = "uri:classloader:/";
private static final String JRUBYDIR = "/.jrubydir";
private static final String JRUBY_HOME = "/META-INF/jruby.home";

Expand Down Expand Up @@ -69,16 +70,18 @@ public IsolatedScriptingContainer( LocalContextScope scope,
if (cl == null) cl = Thread.currentThread().getContextClassLoader();
setClassLoader( cl );

setLoadPaths( Arrays.asList( "uri:classloader:" ) );
setLoadPaths( Arrays.asList( URI_CLASSLOADER ) );

// set the right jruby home
setHomeDirectory( "uri:classloader:" + JRUBY_HOME );
URL url = getResource(cl, JRUBY_HOME + JRUBYDIR);
if (url != null){
setHomeDirectory( URI_CLASSLOADER + JRUBY_HOME );
}

// setup the isolated GEM_PATH, i.e. without $HOME/.gem/**
runScriptlet("require 'rubygems/defaults/jruby';"
+ "Gem::Specification.reset;"
+ "Gem::Specification.add_dir 'uri:classloader:" + JRUBY_HOME + "/lib/ruby/gems/shared';"
+ "Gem::Specification.add_dir 'uri:classloader:';");
url = getResource(cl, JRUBYDIR);
if (url != null){
setCurrentDirectory( URI_CLASSLOADER );
}

// setup the isolated GEM_PATH, i.e. without $HOME/.gem/**
setEnvironment(null);
Expand All @@ -87,11 +90,11 @@ public IsolatedScriptingContainer( LocalContextScope scope,
@Override
public void setEnvironment(Map environment) {
if (environment == null || !environment.containsKey("GEM_PATH")
|| !environment.containsKey("GEM_HOME")|| !environment.containsKey("JARS_HOME")) {
|| !environment.containsKey("GEM_HOME") || !environment.containsKey("JARS_HOME")) {
Map<String,String> env = environment == null ? new HashMap<String,String>() : new HashMap<String,String>(environment);
if (!env.containsKey("GEM_PATH")) env.put("GEM_PATH", "uri:classloader://");
if (!env.containsKey("GEM_HOME")) env.put("GEM_HOME", "uri:classloader://");
if (!env.containsKey("JARS_HOME")) env.put("JARS_HOME", "uri:classloader://jars");
if (!env.containsKey("GEM_PATH")) env.put("GEM_PATH", URI_CLASSLOADER);
if (!env.containsKey("GEM_HOME")) env.put("GEM_HOME", URI_CLASSLOADER);
if (!env.containsKey("JARS_HOME")) env.put("JARS_HOME", URI_CLASSLOADER + "jars");
super.setEnvironment(env);
}
else {
Expand Down Expand Up @@ -130,6 +133,14 @@ private String createUri(ClassLoader cl, String ref) {
return "uri:" + url.toString().replaceFirst( ref + "$", "" );
}

private URL getResource(ClassLoader cl, String ref) {
URL url = cl.getResource( ref );
if ( url == null && ref.startsWith( "/" ) ) {
url = cl.getResource( ref.substring( 1 ) );
}
return url;
}

protected void addGemPath(String uri) {
runScriptlet( "Gem::Specification.add_dir '" + uri + "' unless Gem::Specification.dirs.member?( '" + uri + "' )" );
}
Expand Down
8 changes: 6 additions & 2 deletions lib/ruby/shared/rubygems/defaults/jruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def dirs
@@dirs ||= Gem.path.collect {|dir|
if File.file?(dir) && dir =~ /\.jar$/
"file:#{dir}!/specifications"
elsif File.directory?(dir) || dir =~ /^file:/
elsif File.directory?(File.join(dir, "specifications")) || dir =~ /^file:/
File.join(dir, "specifications")
end
}.compact + spec_directories_from_classpath
Expand All @@ -108,7 +108,11 @@ def dirs= dirs
end

def spec_directories_from_classpath
stuff = JRuby::Util.classloader_resources("specifications")
stuff = [ 'uri:classloader://specifications' ] + JRuby::Util.classloader_resources("specifications")
# some classloader return directory info. use only the "protocols"
# which jruby understands
stuff.select! { |s| File.directory?( s ) }
stuff
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ public void testJRubyCreate() throws Exception {
System.err.println();
System.err.println();

// System.setProperty( "jruby.debug.loadService", "true" );
//System.setProperty( "jruby.native.enabled", "true" );
//System.setProperty( "jruby.debug.loadService", "true" );
//System.setProperty( "jruby.native.enabled", "true" );

OSGiIsolatedScriptingContainer jruby = new OSGiIsolatedScriptingContainer();
jruby.addBundleToLoadPath( "org.jruby.osgi.scripts-bundle" );
jruby.addBundleToGemPath( FrameworkUtil.getBundle( Gems.class ) );
jruby.addBundleToLoadPath( "org.jruby.osgi.scripts-bundle" );
jruby.addBundleToGemPath( FrameworkUtil.getBundle( Gems.class ) );

// run a script from LOAD_PATH
String hello = (String) jruby.runScriptlet( "require 'hello'; Hello.say" );
assertEquals( hello, "world" );
Expand All @@ -93,7 +93,7 @@ public void testJRubyCreate() throws Exception {

String gemPath = (String) jruby.runScriptlet( "Gem::Specification.dirs.inspect" );
gemPath = gemPath.replaceAll( "bundle[^:]*://[^/]*", "bundle:/" );
assertEquals( gemPath, "[\"uri:bundle://specifications\", \"uri:classloader:/specifications\", \"uri:classloader:/META-INF/jruby.home/lib/ruby/gems/shared/specifications\"]" );
assertEquals( gemPath, "[\"uri:bundle://specifications\"]" );

// ensure we can load rake from the default gems
boolean loaded = (Boolean) jruby.runScriptlet( "require 'rake'" );
Expand All @@ -110,15 +110,15 @@ public void testJRubyCreate() throws Exception {
loaded = (Boolean) jruby.runScriptlet( "require 'openssl'" );
assertEquals(true, loaded);

jruby.runScriptlet( "require 'jar-dependencies'" );
jruby.runScriptlet( "require 'jar-dependencies'" );
list = (String) jruby.runScriptlet( "Gem.loaded_specs.keys.inspect" );
assertEquals(list, "[\"rake\", \"jruby-openssl\", \"jar-dependencies\"]");

// ensure we can load can load embedded gems
loaded = (Boolean) jruby.runScriptlet( "require 'virtus'" );
assertEquals(true, loaded);

list = (String) jruby.runScriptlet( "Gem.loaded_specs.keys.inspect" );
list = (String) jruby.runScriptlet( "Gem.loaded_specs.keys.inspect" );
assertEquals(list, "[\"rake\", \"jruby-openssl\", \"jar-dependencies\", \"thread_safe\", \"descendants_tracker\", \"equalizer\", \"coercible\", \"ice_nine\", \"axiom-types\", \"virtus\"]");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,10 @@ public void testJRubyCreate() throws InterruptedException {
assertEquals(true, loaded);

String gemPath = (String) jruby.runScriptlet( "Gem::Specification.dirs.inspect" );

gemPath = gemPath.replaceAll( "bundle[^:]*://[^/]*", "bundle:/" );
assertEquals( gemPath, "[\"uri:classloader:/specifications\", \"uri:classloader:/META-INF/jruby.home/lib/ruby/gems/shared/specifications\"]" );
// TODO fix the URLResource to produce uri:classloader:// urls only
assertEquals( gemPath, "[\"uri:classloader:/specifications\", \"uri:classloader://specifications\"]" );

jruby.runScriptlet( "require 'jar-dependencies'" );
list = (String) jruby.runScriptlet( "Gem.loaded_specs.keys.inspect" );
Expand Down

0 comments on commit 13a5e41

Please sign in to comment.