Skip to content

Commit

Permalink
Merge branch 'jruby-1_7'
Browse files Browse the repository at this point in the history
Conflicts:
	.travis.yml
	core/src/main/java/org/jruby/RubyInstanceConfig.java
	core/src/main/java/org/jruby/embed/ScriptingContainer.java
	core/src/main/java/org/jruby/ext/zlib/JZlibRubyGzipReader.java
	core/src/main/java/org/jruby/util/JRubyFile.java
	core/src/main/java/org/jruby/util/cli/ArgumentProcessor.java
	core/src/test/java/org/jruby/embed/ScriptingContainerTest.java
	lib/ruby/shared/rubygems.rb
	lib/ruby/shared/rubygems/remote_fetcher.rb
	maven/jruby-complete/src/it/extended/Mavenfile
	test/test_file.rb
  • Loading branch information
mkristian committed Jun 18, 2015
2 parents c8a1836 + 7f1739b commit 2e28c9c
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 141 deletions.
16 changes: 16 additions & 0 deletions core/src/main/java/org/jruby/RubyFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@ public static IRubyObject dirname(ThreadContext context, IRubyObject recv, IRuby
return runtime.newString(dirname(context, jfilename)).infectBy(filename);
}

private static Pattern PROTOCOL_PATTERN = Pattern.compile("^([a-z]+:)?[a-z]+:/.*");
public static String dirname(ThreadContext context, String jfilename) {
String name = jfilename.replace('\\', '/');
int minPathLength = 1;
Expand All @@ -639,6 +640,21 @@ public static String dirname(ThreadContext context, String jfilename) {
minPathLength = 3;
}

// jar like paths
if (name.contains("!/")) {
int start = name.indexOf("!/") + 1;
String path = dirname(context, name.substring(start));
if (path.equals(".") || path.equals("/")) path = "";
return name.substring(0, start) + path;
}
// address all the url like paths first
if (PROTOCOL_PATTERN.matcher(name).matches()) {
int start = name.indexOf(":/") + 2;
String path = dirname(context, name.substring(start));
if (path.equals(".")) path = "";
return name.substring(0, start) + path;
}

while (name.length() > minPathLength && name.charAt(name.length() - 1) == '/') {
trimmedSlashes = true;
name = name.substring(0, name.length() - 1);
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/RubyInstanceConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ public InputStream getScriptSource() {
return getInput();
} else {
final String script = getScriptFileName();
FileResource resource = JRubyFile.createResource(null, getCurrentDirectory(), getScriptFileName());
FileResource resource = JRubyFile.createRestrictedResource(getCurrentDirectory(), getScriptFileName());
if (resource != null && resource.exists()) {
if (resource.isFile() || resource.isSymLink()) {
if (isXFlag()) {
Expand Down
114 changes: 63 additions & 51 deletions core/src/main/java/org/jruby/embed/ScriptingContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import org.jruby.embed.internal.EmbedRubyInterfaceAdapterImpl;
import org.jruby.embed.internal.EmbedRubyObjectAdapterImpl;
import org.jruby.embed.internal.EmbedRubyRuntimeAdapterImpl;
import org.jruby.embed.internal.LocalContextProvider;
import org.jruby.embed.internal.SingleThreadLocalContextProvider;
import org.jruby.embed.internal.SingletonLocalContextProvider;
import org.jruby.embed.internal.ThreadSafeLocalContextProvider;
Expand All @@ -83,61 +84,69 @@
* For example, a local context scope, local variable behavior, load paths are
* per-container properties. Please see {@link PropertyName} and {@link AttributeName}
* for more details. Be aware that the per-container properties should be set prior to
* get Ruby runtime be instantiated; otherwise, default values are applied to.
* get Ruby runtime being instantiated; otherwise, default values are applied to.
*
* ScriptingContainer delays Ruby runtime initialization as much as possible to
* improve startup time. When values are put into the ScriptingContainer, or runScriptlet
* method gets run Ruby runtime is created internally. However, the default, singleton
* local context scope behave slightly different. If Ruby runtime has been already instantiated
* by another ScriptingContainer, application, etc, the same runtime will be used.
* method gets run the runtime is created internally. However, the default, singleton
* local context scope behave slightly different. If a Ruby runtime has been already
* instantiated by another ScriptingContainer, application, etc, the same runtime
* will be re-used.
*
* Below are examples.
*
* The first Example is a very simple Hello World. After initializing a ScriptingContainer,
* a Ruby script, puts "Hello World!", runs and produces "Hello World!."
* <pre>Example 1:
*
* ScriptingContainer container = new ScriptingContainer();
* container.runScriptlet("puts \"Hello World!\"");
*
* <pre>
* Example 1:
* {@code
* ScriptingContainer container = new ScriptingContainer();
* container.runScriptlet("puts \"Hello World!\"");
* }
* Produces:
* Hello World!</pre>
* Hello World!
* </pre>
*
* The second example shows how to share variables between Java and Ruby.
* In this example, a local variable "x" is shared. To make this happen, a local variable
* behavior should be transient or persistent. As for JSR223 JRuby engine, set these
* types using System property, org.jruby.embed.localvariable.behavior. If the local
* variable behavior is one of transient or persistent,
* In this example, a local variable {@code "x"} is shared. To make this happen,
* a local variable behavior should be transient or persistent.
* As for JSR223 JRuby engine, set these types using a System property,
* <b>org.jruby.embed.localvariable.behavior</b>.
* If the local variable behavior is one of transient or persistent,
* Ruby's local, instance, global variables and constants are available to share
* between Java and Ruby. (A class variable sharing does not work on current version)
* Thus, "x" in Java is also "x" in Ruby.
*
* <pre>Example 2:
*
* ScriptingContainer container = new ScriptingContainer();
* container.put("x", 12345);
* container.runScriptlet("puts x.to_s(2)");
* Thus, {@code "x"} in Java is also {@code "x"} in Ruby.
*
* <pre>
* Example 2:
* {@code
* ScriptingContainer container = new ScriptingContainer();
* container.put("x", 12345);
* container.runScriptlet("puts x.to_s(2)");
* }
* Produces:
* 11000000111001</pre>
* 11000000111001
* </pre>
*
* The third examples shows how to keep local variables across multiple evaluations.
* This feature simulates BSF engine for JRuby. In terms of Ruby semantics,
* local variables should not survive after the evaluation has completed. Thus,
* this behavior is optional, and users need to specify LocalVariableBehavior.PERSISTENT
* when the container is instantiated.
*
* <pre>Example 3:
*
* ScriptingContainer container = new ScriptingContainer(LocalVariableBehavior.PERSISTENT);
* container.runScriptlet("p=9.0");
* container.runScriptlet("q = Math.sqrt p");
* container.runScriptlet("puts \"square root of #{p} is #{q}\"");
* System.out.println("Ruby used values: p = " + container.get("p") +
* ", q = " + container.get("q"));
*
* <pre>
* Example 3:
* {@code
* ScriptingContainer container = new ScriptingContainer(LocalVariableBehavior.PERSISTENT);
* container.runScriptlet("p=9.0");
* container.runScriptlet("q = Math.sqrt p");
* container.runScriptlet("puts \"square root of #{p} is #{q}\"");
* System.out.println("Ruby used values: p = " + container.get("p") + ", q = " + container.get("q"));
* }
* Produces:
* square root of 9.0 is 3.0
* Ruby used values: p = 9.0, q = 3.0</pre>
* Ruby used values: p = 9.0, q = 3.0
* </pre>
*
* Also, ScriptingContainer provides better i18n support. For example,
* Unicode Escape Sequence can be included in Ruby scripts.
Expand All @@ -146,28 +155,31 @@
* invoking methods defined by Ruby, and getting an instance of a specified interface
* that has been implemented by Ruby.
*
* <pre>Example 4:
* ScriptingContainer container = new ScriptingContainer();
* script =
* "def message\n" +
* "\"message: #{@message}\"\n" +
* "end\n" +
* "message";
* container.put("@message", "What's up?");
* EvalUnit unit = container.parse(script);
* IRubyObject ret = unit.run();
* System.out.println(JavaEmbedUtils.rubyToJava(ret));
* container.put("@message", "Fabulous!");
* ret = unit.run();
* System.out.println(JavaEmbedUtils.rubyToJava(ret));
* container.put("@message", "That's the way you are.");
* ret = unit.run();
* System.out.println(JavaEmbedUtils.rubyToJava(ret));
*
* <pre>
* Example 4:
* {@code
* ScriptingContainer container = new ScriptingContainer();
* String script =
* "def message\n" +
* "\"message: #{@message}\"\n" +
* "end\n" +
* "message";
* container.put("@message", "What's up?");
* JavaEmbedUtils.EvalUnit unit = container.parse(script);
* IRubyObject msg = unit.run(); // a RubyString instance
* System.out.println(JavaEmbedUtils.rubyToJava(msg));
* container.put("@message", "Fabulous!");
* msg = unit.run();
* System.out.println(JavaEmbedUtils.rubyToJava(msg));
* container.put("@message", "That's the way you are.");
* msg = unit.run();
* System.out.println(JavaEmbedUtils.rubyToJava(msg));
* }
* Produces:
* message: What's up?
* message: Fabulous!
* message: That's the way you are.</pre>
* message: That's the way you are.
* </pre>
*
* See more details at project's
* {@see <a href="https://github.com/jruby/jruby/wiki/RedBridge">Wiki</a>}
Expand Down
15 changes: 8 additions & 7 deletions core/src/main/java/org/jruby/util/JRubyFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ public static FileResource createResourceAsFile(Ruby runtime, String pathname) {
return createResource(runtime, runtime.getCurrentDirectory(), pathname, true);
}

public static FileResource createRestrictedResource(String cwd, String pathname) {
return createResource(null, cwd, pathname);
}

public static FileResource createResource(Ruby runtime, String pathname) {
return createResource(runtime, runtime.getCurrentDirectory(), pathname, false);
}
Expand Down Expand Up @@ -104,13 +108,13 @@ private static FileResource createResource(Ruby runtime, String cwd, String path
}
}

JRubyFile f = create(cwd, pathname);
if (cwd != null && cwd.startsWith("uri:")){
return createResource(runtime, null, f.getPath());
if (cwd != null && (cwd.startsWith("uri:") || cwd.startsWith("file:"))) {
return createResource(runtime, null, cwd + "/" + pathname);
}

// If any other special resource types fail, count it as a filesystem backed resource.
return new RegularFileResource(runtime == null ? null : runtime.getPosix(), f);
JRubyFile f = create(cwd, pathname);
return new RegularFileResource(runtime != null ? runtime.getPosix() : null, f);
}

public static String normalizeSeps(String path) {
Expand All @@ -128,9 +132,6 @@ private static JRubyFile createNoUnicodeConversion(String cwd, String pathname)
if(pathname.startsWith("file:")) {
pathname = pathname.substring(5);
}
if(pathname.startsWith("uri:")) {
return new JRubyFile(pathname);
}
File internal = new JavaSecuredFile(pathname);
if(cwd != null && cwd.startsWith("uri:") && !pathname.startsWith("uri:") && !pathname.contains("!/") && !internal.isAbsolute()) {
return new JRubyFile(cwd + "/" + pathname);
Expand Down
78 changes: 34 additions & 44 deletions core/src/main/java/org/jruby/util/cli/ArgumentProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.jruby.exceptions.MainExitException;
import org.jruby.runtime.profile.builtin.ProfileOutput;
import org.jruby.util.JRubyFile;
import org.jruby.util.FileResource;
import org.jruby.util.KCode;
import org.jruby.util.SafePropertyAccessor;

Expand Down Expand Up @@ -620,59 +621,48 @@ private void runBinScript() {
endOfArguments = true;
}

private String resolveScript(String scriptName) {
// These try/catches are to allow failing over to the "commands" logic
// when running from within a jruby-complete jar file, which has
// jruby.home = a jar file URL that does not resolve correctly with
// JRubyFile.create.
File fullName = null;
try {
// try cwd first
fullName = JRubyFile.create(config.getCurrentDirectory(), scriptName);
if (fullName.exists() && fullName.isFile()) {
logScriptResolutionSuccess(fullName.getAbsolutePath());
return scriptName;
} else {
logScriptResolutionFailure(config.getCurrentDirectory());
}
} catch (Exception e) {
// keep going, try bin/#{scriptName}
private String resolve(String path, String scriptName) {
if (RubyInstanceConfig.DEBUG_SCRIPT_RESOLUTION) {
config.getError().println("Trying path: " + path);
}
try {
fullName = JRubyFile.create(config.getJRubyHome(), "bin/" + scriptName);
FileResource fullName = JRubyFile.createRestrictedResource(path, scriptName);
if (fullName.exists() && fullName.isFile()) {
logScriptResolutionSuccess(fullName.getAbsolutePath());
return fullName.getAbsolutePath();
} else {
logScriptResolutionFailure(config.getJRubyHome() + "/bin");
if (RubyInstanceConfig.DEBUG_SCRIPT_RESOLUTION) {
config.getError().println("Found: " + fullName.absolutePath());
}
return fullName.absolutePath();
}
} catch (Exception e) {
// keep going, try PATH
// keep going
}
String resolved = resolveScriptUsingClassLoader(scriptName);
if (resolved != null) {
return resolved;
}
try {
Object pathObj = config.getEnvironment().get("PATH");
String path = pathObj.toString();
if (path != null) {
String[] paths = path.split(System.getProperty("path.separator"));
for (int i = 0; i < paths.length; i++) {
fullName = JRubyFile.create(new File(paths[i]).getAbsolutePath(), scriptName);
if (fullName.exists() && fullName.isFile()) {
logScriptResolutionSuccess(fullName.getAbsolutePath());
return fullName.getAbsolutePath();
}
}
logScriptResolutionFailure("PATH=" + path);
return null;
}

private String resolveScript(String scriptName) {
// These try/catches are to allow failing over to the "commands" logic
// when running from within a jruby-complete jar file, which has
// jruby.home = a jar file URL that does not resolve correctly with
// JRubyFile.create.
String result = resolve(config.getCurrentDirectory(), scriptName);
if (result != null) return scriptName;// use relative filename
result = resolve(config.getJRubyHome() + "/bin", scriptName);
if (result != null) return result;
result = resolve("uri:classloader:/bin", scriptName);
if (result != null) return result;

String path = config.getEnvironment().get("PATH").toString();
if (path != null) {
String[] paths = path.split(System.getProperty("path.separator"));
for (int i = 0; i < paths.length; i++) {
result = resolve(paths[i], scriptName);
if (result != null) return result;
}
} catch (Exception e) {
// will fall back to JRuby::Commands
}
if (config.isDebug() || RubyInstanceConfig.DEBUG_SCRIPT_RESOLUTION) {
config.getError().println("warning: could not resolve -S script on filesystem: " + scriptName);
if (config.isDebug()) {
config.getError().println("warning: could not resolve -S script: " + scriptName);
}
// fall back to JRuby::Commands
return null;
}

Expand Down
Loading

0 comments on commit 2e28c9c

Please sign in to comment.