JRuby 1.5.0 problem with -S switch

After installing rails on JRuby, I was surprised that I couldn’t execute jruby -S rails

GEM_PATH=gem
# rails is in GEM_PATHbinrails
java -jar jruby-complete-1.5.0.jar -S rails
jruby - no such directory, file or command

I decided to whip out the trusty JD-GUI and jdb and a do bit of source diving.

The routine responsible for locating the script is in org.jruby.RubyInstanceConfig.argumentProcessor$.resolveScript().
First, it searches the script in the current directory, then in jruby.homebin, and finally in PATH.

    private String resolveScript(String scriptName)
    {
      try
      {
        File fullName = JRubyFile.create(RubyInstanceConfig.this.currentDirectory, scriptName);
        if ((fullName.exists()) && (fullName.isFile())) {
          return scriptName;
        }

        fullName = JRubyFile.create(RubyInstanceConfig.this.getJRubyHome(), "bin/" + scriptName);
        if ((fullName.exists()) && (fullName.isFile())) {
          return fullName.getAbsolutePath();
        }
        try
        {
          String path = System.getenv("PATH");
          if (path != null) {
            String[] paths = path.split(System.getProperty("path.separator"));
            for (int i = 0; i < paths.length; ++i) {
              fullName = JRubyFile.create(paths[i], scriptName);
              if ((fullName.exists()) && (fullName.isFile()))
                return fullName.getAbsolutePath();
            }
          }
        }
        catch (SecurityException se) {
        }
      }
      catch (IllegalArgumentException iae) {
        if (RubyInstanceConfig.this.debug) System.err.println("warning: could not resolve -S script on filesystem: " + scriptName);
      }
      return null;
    }

The problem occurs because jruby.home is located inside a jar file, and there was a check called isAbsolute() that fails with jar! paths.

JRubyFile ends up throwing an IllegalArgumentException when it couldn't find file:E:binjrubyjruby-complete-1.5.0.jar!META-INFjruby.homebinrails.

class JRubyFile
{
private static JRubyFile createNoUnicodeConversion(String cwd, String pathname)
  {
    if ((pathname == null) || (pathname.equals("")) || (Ruby.isSecurityRestricted())) {
      return JRubyNonExistentFile.NOT_EXIST;
    }
    File internal = new JavaSecuredFile(pathname);
    if (!(internal.isAbsolute())) {
      internal = new JavaSecuredFile(cwd, pathname);
      if (!(internal.isAbsolute())) {
        throw new IllegalArgumentException("Neither current working directory (" + cwd + ") nor pathname (" + pathname + ") led to an absolute path");
      }
    }
    return new JRubyFile(internal);
  }
}

If you have a close look at resolveScript(), the IllegalArgumentException short-circuits resolveScript, and bypasses the code that subsequently searches through PATH, and jumps straight to the error handler.


About this entry