Package org.jruby

Source Code of org.jruby.RubyInstanceConfig$LoadServiceCreator

/***** BEGIN LICENSE BLOCK *****
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Common Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/cpl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2007 Nick Sieger <nicksieger@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the CPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the CPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/
package org.jruby;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import java.util.Set;
import java.util.StringTokenizer;
import org.jruby.ast.executable.Script;
import org.jruby.exceptions.MainExitException;
import org.jruby.runtime.Constants;
import org.jruby.runtime.load.LoadService;
import org.jruby.util.ClassCache;
import org.jruby.util.JRubyFile;
import org.jruby.util.KCode;
import org.jruby.util.NormalizedFile;
import org.jruby.util.SafePropertyAccessor;
import org.objectweb.asm.Opcodes;

public class RubyInstanceConfig {

    /**
     * The max count of active methods eligible for JIT-compilation.
     */
    private static final int JIT_MAX_METHODS_LIMIT = 4096;

    /**
     * The max size of JIT-compiled methods (full class size) allowed.
     */
    private static final int JIT_MAX_SIZE_LIMIT = Integer.MAX_VALUE;

    /**
     * The JIT threshold to the specified method invocation count.
     */
    private static final int JIT_THRESHOLD = 50;
   
    /** The version to use for generated classes. Set to current JVM version by default */
    public static final int JAVA_VERSION;
   
    /**
     * Default size for chained compilation.
     */
    private static final int CHAINED_COMPILE_LINE_COUNT_DEFAULT = 500;
   
    /**
     * The number of lines at which a method, class, or block body is split into
     * chained methods (to dodge 64k method-size limit in JVM).
     */
    public static final int CHAINED_COMPILE_LINE_COUNT
            = SafePropertyAccessor.getInt("jruby.compile.chainsize", CHAINED_COMPILE_LINE_COUNT_DEFAULT);

    public enum CompileMode {
        JIT, FORCE, OFF;

        public boolean shouldPrecompileCLI() {
            switch (this) {
            case JIT: case FORCE:
                return true;
            }
            return false;
        }

        public boolean shouldJIT() {
            switch (this) {
            case JIT: case FORCE:
                return true;
            }
            return false;
        }

        public boolean shouldPrecompileAll() {
            return this == FORCE;
        }
    }
    private InputStream input          = System.in;
    private PrintStream output         = System.out;
    private PrintStream error          = System.err;
    private Profile profile            = Profile.DEFAULT;
    private boolean objectSpaceEnabled
            = SafePropertyAccessor.getBoolean("jruby.objectspace.enabled", false);

    private CompileMode compileMode = CompileMode.JIT;
    private boolean runRubyInProcess   = true;
    private String currentDirectory;
    private Map environment;
    private String[] argv = {};

    private final boolean jitLogging;
    private final boolean jitLoggingVerbose;
    private final int jitLogEvery;
    private final int jitThreshold;
    private final int jitMax;
    private final int jitMaxSize;
    private final boolean samplingEnabled;
    private CompatVersion compatVersion;

    private ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
    private ClassLoader loader = contextLoader == null ? RubyInstanceConfig.class.getClassLoader() : contextLoader;

    private ClassCache<Script> classCache;

    // from CommandlineParser
    private List<String> loadPaths = new ArrayList<String>();
    private Set<String> excludedMethods = new HashSet<String>();
    private StringBuffer inlineScript = new StringBuffer();
    private boolean hasInlineScript = false;
    private String scriptFileName = null;
    private List<String> requiredLibraries = new ArrayList<String>();
    private boolean benchmarking = false;
    private boolean argvGlobalsOn = false;
    private boolean assumeLoop = false;
    private boolean assumePrinting = false;
    private Map optionGlobals = new HashMap();
    private boolean processLineEnds = false;
    private boolean split = false;
    // This property is a Boolean, to allow three values, so it can match MRI's nil, false and true
    private Boolean verbose = Boolean.FALSE;
    private boolean debug = false;
    private boolean showVersion = false;
    private boolean showBytecode = false;
    private boolean showCopyright = false;
    private boolean endOfArguments = false;
    private boolean shouldRunInterpreter = true;
    private boolean shouldPrintUsage = false;
    private boolean shouldPrintProperties=false;
    private boolean yarv = false;
    private boolean rubinius = false;
    private boolean yarvCompile = false;
    private KCode kcode = KCode.NONE;
    private String recordSeparator = "\n";
    private boolean shouldCheckSyntax = false;
    private String inputFieldSeparator = null;
    private boolean managementEnabled = true;

    private int safeLevel = 0;

    private String jrubyHome;

    public static final boolean FASTEST_COMPILE_ENABLED
            = SafePropertyAccessor.getBoolean("jruby.compile.fastest");
    public static final boolean BOXED_COMPILE_ENABLED
            = FASTEST_COMPILE_ENABLED
            || SafePropertyAccessor.getBoolean("jruby.compile.boxed");
    public static final boolean FASTOPS_COMPILE_ENABLED
            = FASTEST_COMPILE_ENABLED
            || SafePropertyAccessor.getBoolean("jruby.compile.fastops");
    public static final boolean FRAMELESS_COMPILE_ENABLED
            = FASTEST_COMPILE_ENABLED
            || SafePropertyAccessor.getBoolean("jruby.compile.frameless");
    public static final boolean POSITIONLESS_COMPILE_ENABLED
            = FASTEST_COMPILE_ENABLED
            || SafePropertyAccessor.getBoolean("jruby.compile.positionless");
    public static final boolean THREADLESS_COMPILE_ENABLED
            = FASTEST_COMPILE_ENABLED
            || SafePropertyAccessor.getBoolean("jruby.compile.threadless");
    public static final boolean FASTCASE_COMPILE_ENABLED =
            SafePropertyAccessor.getBoolean("jruby.compile.fastcase");
    public static final boolean LAZYHANDLES_COMPILE = SafePropertyAccessor.getBoolean("jruby.compile.lazyHandles", false);
    public static final boolean FORK_ENABLED
            = SafePropertyAccessor.getBoolean("jruby.fork.enabled");
    public static final boolean POOLING_ENABLED
            = SafePropertyAccessor.getBoolean("jruby.thread.pool.enabled");
    public static final int POOL_MAX
            = SafePropertyAccessor.getInt("jruby.thread.pool.max", Integer.MAX_VALUE);
    public static final int POOL_MIN
            = SafePropertyAccessor.getInt("jruby.thread.pool.min", 0);
    public static final int POOL_TTL
            = SafePropertyAccessor.getInt("jruby.thread.pool.ttl", 60);

    public static final boolean NATIVE_NET_PROTOCOL
            = SafePropertyAccessor.getBoolean("jruby.native.net.protocol", false);

    public static boolean FULL_TRACE_ENABLED
            = SafePropertyAccessor.getBoolean("jruby.debug.fullTrace", false);

    public static final String COMPILE_EXCLUDE
            = SafePropertyAccessor.getProperty("jruby.jit.exclude");
    public static boolean nativeEnabled = true;
   

    public static interface LoadServiceCreator {
        LoadService create(Ruby runtime);

        LoadServiceCreator DEFAULT = new LoadServiceCreator() {
                public LoadService create(Ruby runtime) {
                    return new LoadService(runtime);
                }
            };
    }

    private LoadServiceCreator creator = LoadServiceCreator.DEFAULT;


    static {
        String specVersion = null;
        try {
            specVersion = System.getProperty("jruby.bytecode.version");
            if (specVersion == null) {
                specVersion = System.getProperty("java.specification.version");
            }
            if (System.getProperty("jruby.native.enabled") != null) {
                nativeEnabled = Boolean.getBoolean("jruby.native.enabled");
            }
        } catch (SecurityException se) {
            nativeEnabled = false;
            specVersion = "1.5";
        }
       
        if (specVersion.equals("1.5")) {
            JAVA_VERSION = Opcodes.V1_5;
        } else {
            JAVA_VERSION = Opcodes.V1_6;
        }
    }

    public int characterIndex = 0;

    public RubyInstanceConfig() {
        if (Ruby.isSecurityRestricted())
            currentDirectory = "/";
        else {
            currentDirectory = JRubyFile.getFileProperty("user.dir");
        }

        samplingEnabled = SafePropertyAccessor.getBoolean("jruby.sampling.enabled", false);
        String compatString = SafePropertyAccessor.getProperty("jruby.compat.version", "RUBY1_8");
        if (compatString.equalsIgnoreCase("RUBY1_8")) {
            compatVersion = CompatVersion.RUBY1_8;
        } else if (compatString.equalsIgnoreCase("RUBY1_9")) {
            compatVersion = CompatVersion.RUBY1_9;
        } else {
            System.err.println("Compatibility version `" + compatString + "' invalid; use RUBY1_8 or RUBY1_9. Using RUBY1_8.");
            compatVersion = CompatVersion.RUBY1_8;
        }

        if (Ruby.isSecurityRestricted()) {
            compileMode = CompileMode.OFF;
            jitLogging = false;
            jitLoggingVerbose = false;
            jitLogEvery = 0;
            jitThreshold = -1;
            jitMax = 0;
            jitMaxSize = -1;
            managementEnabled = false;
        } else {
            String threshold = SafePropertyAccessor.getProperty("jruby.jit.threshold");
            String max = SafePropertyAccessor.getProperty("jruby.jit.max");
            String maxSize = SafePropertyAccessor.getProperty("jruby.jit.maxsize");
           
            if (COMPILE_EXCLUDE != null) {
                String[] elements = COMPILE_EXCLUDE.split(",");
                for (String element : elements) excludedMethods.add(element);
            }
           
            managementEnabled = SafePropertyAccessor.getBoolean("jruby.management.enabled", true);
            runRubyInProcess = SafePropertyAccessor.getBoolean("jruby.launch.inproc", true);
            boolean jitProperty = SafePropertyAccessor.getProperty("jruby.jit.enabled") != null;
            if (jitProperty) {
                error.print("jruby.jit.enabled property is deprecated; use jruby.compile.mode=(OFF|JIT|FORCE) for -C, default, and +C flags");
                compileMode = SafePropertyAccessor.getBoolean("jruby.jit.enabled") ? CompileMode.JIT : CompileMode.OFF;
            } else {
                String jitModeProperty = SafePropertyAccessor.getProperty("jruby.compile.mode", "JIT");

                if (jitModeProperty.equals("OFF")) {
                    compileMode = CompileMode.OFF;
                } else if (jitModeProperty.equals("JIT")) {
                    compileMode = CompileMode.JIT;
                } else if (jitModeProperty.equals("FORCE")) {
                    compileMode = CompileMode.FORCE;
                } else {
                    error.print("jruby.compile.mode property must be OFF, JIT, FORCE, or unset; defaulting to JIT");
                    compileMode = CompileMode.JIT;
                }
            }
            jitLogging = SafePropertyAccessor.getBoolean("jruby.jit.logging");
            jitLoggingVerbose = SafePropertyAccessor.getBoolean("jruby.jit.logging.verbose");
            String logEvery = SafePropertyAccessor.getProperty("jruby.jit.logEvery");
            jitLogEvery = logEvery == null ? 0 : Integer.parseInt(logEvery);
            jitThreshold = threshold == null ?
                    JIT_THRESHOLD : Integer.parseInt(threshold);
            jitMax = max == null ?
                    JIT_MAX_METHODS_LIMIT : Integer.parseInt(max);
            jitMaxSize = maxSize == null ?
                    JIT_MAX_SIZE_LIMIT : Integer.parseInt(maxSize);
        }

        // default ClassCache using jitMax as a soft upper bound
        classCache = new ClassCache<Script>(loader, jitMax);

        if (FORK_ENABLED) {
            error.print("WARNING: fork is highly unlikely to be safe or stable on the JVM. Have fun!\n");
        }
    }

    public LoadServiceCreator getLoadServiceCreator() {
        return creator;
    }

    public void setLoadServiceCreator(LoadServiceCreator creator) {
        this.creator = creator;
    }

    public LoadService createLoadService(Ruby runtime) {
        return this.creator.create(runtime);
    }

    public String getBasicUsageHelp() {
        StringBuilder sb = new StringBuilder();
        sb
                .append("Usage: jruby [switches] [--] [programfile] [arguments]\n")
                .append("  -0[octal]       specify record separator (\0, if no argument)\n")
                .append("  -a              autosplit mode with -n or -p (splits $_ into $F)\n")
                .append("  -b              benchmark mode, times the script execution\n")
                .append("  -c              check syntax only\n")
                .append("  -Cdirectory     cd to directory, before executing your script\n")
                .append("  -d              set debugging flags (set $DEBUG to true)\n")
                .append("  -e 'command'    one line of script. Several -e's allowed. Omit [programfile]\n")
                .append("  -Fpattern       split() pattern for autosplit (-a)\n")
                //.append("  -i[extension]   edit ARGV files in place (make backup if extension supplied)\n")
                .append("  -Idirectory     specify $LOAD_PATH directory (may be used more than once)\n")
                .append("  -J[java option] pass an option on to the JVM (e.g. -J-Xmx512m)\n")
                .append("                    use --properties to list JRuby properties\n")
                .append("                    run 'java -help' for a list of other Java options\n")
                .append("  -Kkcode         specifies code-set (e.g. -Ku for Unicode\n")
                .append("  -l              enable line ending processing\n")
                .append("  -n              assume 'while gets(); ... end' loop around your script\n")
                .append("  -p              assume loop like -n but print line also like sed\n")
                .append("  -rlibrary       require the library, before executing your script\n")
                .append("  -s              enable some switch parsing for switches after script name\n")
                .append("  -S              look for the script in bin or using PATH environment variable\n")
                .append("  -T[level]       turn on tainting checks\n")
                .append("  -v              print version number, then turn on verbose mode\n")
                .append("  -w              turn warnings on for your script\n")
                .append("  -W[level]       set warning level; 0=silence, 1=medium, 2=verbose (default)\n")
                //.append("  -x[directory]   strip off text before #!ruby line and perhaps cd to directory\n")
                .append("  -X[option]      enable extended option (omit option to list)\n")
                .append("  --copyright     print the copyright\n")
                .append("  --debug         sets the execution mode most suitable for debugger functionality\n")
                .append("  --jdb           runs JRuby process under JDB\n")
                .append("  --properties    List all configuration Java properties (pass -J-Dproperty=value)\n")
                .append("  --sample        run with profiling using the JVM's sampling profiler\n")
                .append("  --client        use the non-optimizing \"client\" JVM (improves startup; default)\n")
                .append("  --server        use the optimizing \"server\" JVM (improves perf)\n")
                .append("  --manage        enable remote JMX management and monitoring of the VM and JRuby\n")
                .append("  --headless      do not launch a GUI window, no matter what\n")
                .append("  --1.8           specify Ruby 1.8.x compatibility (default)\n")
                .append("  --1.9           specify Ruby 1.9.x compatibility\n")
                .append("  --bytecode      show the JVM bytecode produced by compiling specified code\n")
                .append("  --version       print the version\n");

        return sb.toString();
    }

    public String getExtendedHelp() {
        StringBuilder sb = new StringBuilder();
        sb
                .append("These flags are for extended JRuby options.\n")
                .append("Specify them by passing -X<option>\n")
                .append("  -O              run with ObjectSpace disabled (default; improves performance)\n")
                .append("  +O              run with ObjectSpace enabled (reduces performance)\n")
                .append("  -C              disable all compilation\n")
                .append("  +C              force compilation of all scripts before they are run (except eval)\n")
                .append("  -y              read a YARV-compiled Ruby script and run that (EXPERIMENTAL)\n")
                .append("  -Y              compile a Ruby script into YARV bytecodes and run this (EXPERIMENTAL)\n")
                .append("  -R              read a Rubinius-compiled Ruby script and run that (EXPERIMENTAL)\n");

        return sb.toString();
    }

    public String getPropertyHelp() {
        StringBuilder sb = new StringBuilder();
        sb
                .append("These properties can be used to alter runtime behavior for perf or compatibility.\n")
                .append("Specify them by passing -J-D<property>=<value>\n")
                .append("\nCOMPILER SETTINGS:\n")
                .append("    jruby.compile.mode=JIT|FORCE|OFF\n")
                .append("       Set compilation mode. JIT is default; FORCE compiles all, OFF disables\n")
                .append("    jruby.compile.fastest=true|false\n")
                .append("       (EXPERIMENTAL) Turn on all experimental compiler optimizations\n")
                .append("    jruby.compile.boxed=true|false\n")
                .append("       (EXPERIMENTAL) Use boxed variables; this can speed up some methods. Default is false\n")
                .append("    jruby.compile.frameless=true|false\n")
                .append("       (EXPERIMENTAL) Turn on frameless compilation where possible\n")
                .append("    jruby.compile.positionless=true|false\n")
                .append("       (EXPERIMENTAL) Turn on compilation that avoids updating Ruby position info. Default is false\n")
                .append("    jruby.compile.threadless=true|false\n")
                .append("       (EXPERIMENTAL) Turn on compilation without polling for \"unsafe\" thread events. Default is false\n")
                .append("    jruby.compile.fastops=true|false\n")
                .append("       (EXPERIMENTAL) Turn on fast operators for Fixnum. Default is false\n")
                .append("    jruby.compile.fastcase=true|false\n")
                .append("       (EXPERIMENTAL) Turn on fast case/when for all-Fixnum whens. Default is false\n")
                .append("    jruby.compile.chainsize=<line count>\n")
                .append("       Set the number of lines at which compiled bodies are \"chained\". Default is " + CHAINED_COMPILE_LINE_COUNT_DEFAULT + "\n")
                .append("    jruby.compile.lazyHandles=true|false\n")
                .append("       Generate method bindings (handles) for compiled methods lazily. Default is false.\n")
                .append("\nJIT SETTINGS:\n")
                .append("    jruby.jit.threshold=<invocation count>\n")
                .append("       Set the JIT threshold to the specified method invocation count. Default is " + JIT_THRESHOLD + ".\n")
                .append("    jruby.jit.max=<method count>\n")
                .append("       Set the max count of active methods eligible for JIT-compilation.\n")
                .append("       Default is " + JIT_MAX_METHODS_LIMIT + " per runtime. A value of 0 disables JIT, -1 disables max.\n")
                .append("    jruby.jit.maxsize=<jitted method size (full .class)>\n")
                .append("       Set the maximum full-class byte size allowed for jitted methods. Default is Integer.MAX_VALUE\n")
                .append("    jruby.jit.logging=true|false\n")
                .append("       Enable JIT logging (reports successful compilation). Default is false\n")
                .append("    jruby.jit.logging.verbose=true|false\n")
                .append("       Enable verbose JIT logging (reports failed compilation). Default is false\n")
                .append("    jruby.jit.logEvery=<method count>\n")
                .append("       Log a message every n methods JIT compiled. Default is 0 (off).\n")
                .append("    jruby.jit.exclude=<ClsOrMod,ClsOrMod::method_name,-::method_name>\n")
                .append("       Exclude methods from JIT by class/module short name, c/m::method_name,\n")
                .append("       or -::method_name for anon/singleton classes/modules. Comma-delimited.\n")
                .append("\nNATIVE SUPPORT:\n")
                .append("    jruby.native.enabled=true|false\n")
                .append("       Enable/disable native extensions (like JNA for non-Java APIs; Default is true\n")
                .append("       (This affects all JRuby instances in a given JVM)\n")
                .append("    jruby.native.verbose=true|false\n")
                .append("       Enable verbose logging of native extension loading. Default is false.\n")
                .append("    jruby.fork.enabled=true|false\n")
                .append("       (EXPERIMENTAL, maybe dangerous) Enable fork(2) on platforms that support it.\n")
                .append("\nTHREAD POOLING:\n")
                .append("    jruby.thread.pool.enabled=true|false\n")
                .append("       Enable reuse of native backing threads via a thread pool. Default is false.\n")
                .append("    jruby.thread.pool.min=<min thread count>\n")
                .append("       The minimum number of threads to keep alive in the pool. Default is 0.\n")
                .append("    jruby.thread.pool.max=<max thread count>\n")
                .append("       The maximum number of threads to allow in the pool. Default is unlimited.\n")
                .append("    jruby.thread.pool.ttl=<time to live, in seconds>\n")
                .append("       The maximum number of seconds to keep alive an idle thread. Default is 60.\n")
                .append("\nMISCELLANY:\n")
                .append("    jruby.compat.version=RUBY1_8|RUBY1_9\n")
                .append("       Specify the major Ruby version to be compatible with; Default is RUBY1_8\n")
                .append("    jruby.objectspace.enabled=true|false\n")
                .append("       Enable or disable ObjectSpace.each_object (default is disabled)\n")
                .append("    jruby.launch.inproc=true|false\n")
                .append("       Set in-process launching of e.g. system('ruby ...'). Default is true\n")
                .append("    jruby.bytecode.version=1.5|1.6\n")
                .append("       Set bytecode version for JRuby to generate. Default is current JVM version.\n")
                .append("    jruby.management.enabled=true|false\n")
                .append("       Set whether JMX management is enabled. Default is true.\n")
                .append("    jruby.debug.fullTrace=true|false\n")
                .append("       Set whether full traces are enabled (c-call/c-return). Default is false.\n");

        return sb.toString();
    }

    public String getVersionString() {
        String ver = Constants.RUBY_VERSION;
        switch (compatVersion) {
        case RUBY1_8:
            ver = Constants.RUBY_VERSION;
            break;
        case RUBY1_9:
            ver = Constants.RUBY1_9_VERSION;
            break;
        }

        String fullVersion = String.format(
                "jruby %s (ruby %s patchlevel %s) (%s rev %s) [%s-java]\n",
                Constants.VERSION, ver, Constants.RUBY_PATCHLEVEL,
                Constants.COMPILE_DATE, Constants.REVISION,
                SafePropertyAccessor.getProperty("os.arch", "unknown")
                );

        return fullVersion;
    }

    public String getCopyrightString() {
        return "JRuby - Copyright (C) 2001-2008 The JRuby Community (and contribs)\n";
    }

    public void processArguments(String[] arguments) {
        new ArgumentProcessor(arguments).processArguments();
    }

    public CompileMode getCompileMode() {
        return compileMode;
    }

    public void setCompileMode(CompileMode compileMode) {
        this.compileMode = compileMode;
    }

    public boolean isJitLogging() {
        return jitLogging;
    }

    public boolean isJitLoggingVerbose() {
        return jitLoggingVerbose;
    }

    public int getJitLogEvery() {
        return jitLogEvery;
    }

    public boolean isSamplingEnabled() {
        return samplingEnabled;
    }

    public int getJitThreshold() {
        return jitThreshold;
    }

    public int getJitMax() {
        return jitMax;
    }

    public int getJitMaxSize() {
        return jitMaxSize;
    }

    public boolean isRunRubyInProcess() {
        return runRubyInProcess;
    }

    public void setRunRubyInProcess(boolean flag) {
        this.runRubyInProcess = flag;
    }

    public void setInput(InputStream newInput) {
        input = newInput;
    }

    public InputStream getInput() {
        return input;
    }

    public CompatVersion getCompatVersion() {
        return compatVersion;
    }

    public void setOutput(PrintStream newOutput) {
        output = newOutput;
    }

    public PrintStream getOutput() {
        return output;
    }

    public void setError(PrintStream newError) {
        error = newError;
    }

    public PrintStream getError() {
        return error;
    }

    public void setCurrentDirectory(String newCurrentDirectory) {
        currentDirectory = newCurrentDirectory;
    }

    public String getCurrentDirectory() {
        return currentDirectory;
    }

    public void setProfile(Profile newProfile) {
        profile = newProfile;
    }

    public Profile getProfile() {
        return profile;
    }

    public void setObjectSpaceEnabled(boolean newObjectSpaceEnabled) {
        objectSpaceEnabled = newObjectSpaceEnabled;
    }

    public boolean isObjectSpaceEnabled() {
        return objectSpaceEnabled;
    }

    public void setEnvironment(Map newEnvironment) {
        environment = newEnvironment;
    }

    public Map getEnvironment() {
        return environment;
    }

    public ClassLoader getLoader() {
        return loader;
    }

    public void setLoader(ClassLoader loader) {
        // Setting the loader needs to reset the class cache
        if(this.loader != loader) {
            this.classCache = new ClassCache<Script>(loader, this.classCache.getMax());
        }
        this.loader = loader;
    }

    public String[] getArgv() {
        return argv;
    }

    public void setArgv(String[] argv) {
        this.argv = argv;
    }

    public String getJRubyHome() {
        if (jrubyHome == null) {
            if (Ruby.isSecurityRestricted()) {
                return "SECURITY RESTRICTED";
            }
            jrubyHome = verifyHome(SafePropertyAccessor.getProperty("jruby.home",
                    SafePropertyAccessor.getProperty("user.home") + "/.jruby"));

            try {
                // This comment also in rbConfigLibrary
                // Our shell scripts pass in non-canonicalized paths, but even if we didn't
                // anyone who did would become unhappy because Ruby apps expect no relative
                // operators in the pathname (rubygems, for example).
                jrubyHome = new NormalizedFile(jrubyHome).getCanonicalPath();
            } catch (IOException e) { }

            jrubyHome = new NormalizedFile(jrubyHome).getAbsolutePath();
        }
        return jrubyHome;
    }

    public void setJRubyHome(String home) {
        jrubyHome = verifyHome(home);
    }

    // We require the home directory to be absolute
    private String verifyHome(String home) {
        if (home.equals(".")) {
            home = System.getProperty("user.dir");
        }
        if (!home.startsWith("file:")) {
            NormalizedFile f = new NormalizedFile(home);
            if (!f.isAbsolute()) {
                home = f.getAbsolutePath();
            }
            f.mkdirs();
        }
        return home;
    }

    private class ArgumentProcessor {
        private String[] arguments;
        private int argumentIndex = 0;

        public ArgumentProcessor(String[] arguments) {
            this.arguments = arguments;
        }

        public void processArguments() {
            while (argumentIndex < arguments.length && isInterpreterArgument(arguments[argumentIndex])) {
                processArgument();
                argumentIndex++;
            }

            if (!hasInlineScript && scriptFileName == null) {
                if (argumentIndex < arguments.length) {
                    setScriptFileName(arguments[argumentIndex]); //consume the file name
                    argumentIndex++;
                }
            }

            processArgv();
        }

        private void processArgv() {
            List<String> arglist = new ArrayList<String>();
            for (; argumentIndex < arguments.length; argumentIndex++) {
                String arg = arguments[argumentIndex];
                if (argvGlobalsOn && arg.startsWith("-")) {
                    arg = arg.substring(1);
                    if (arg.indexOf('=') > 0) {
                        String[] keyvalue = arg.split("=", 2);
                        optionGlobals.put(keyvalue[0], keyvalue[1]);
                    } else {
                        optionGlobals.put(arg, null);
                    }
                } else {
                    argvGlobalsOn = false;
                    arglist.add(arg);
                }
            }

            // Remaining arguments are for the script itself
            argv = arglist.toArray(new String[arglist.size()]);
        }

        private boolean isInterpreterArgument(String argument) {
            return (argument.charAt(0) == '-' || argument.charAt(0) == '+') && !endOfArguments;
        }

        private String getArgumentError(String additionalError) {
            return "jruby: invalid argument\n" + additionalError + "\n";
        }

        private void processArgument() {
            String argument = arguments[argumentIndex];
            FOR : for (characterIndex = 1; characterIndex < argument.length(); characterIndex++) {
                switch (argument.charAt(characterIndex)) {
                case '0': {
                    String temp = grabOptionalValue();
                    if (null == temp) {
                        recordSeparator = "\u0000";
                    } else if (temp.equals("0")) {
                        recordSeparator = "\n\n";
                    } else if (temp.equals("777")) {
                        recordSeparator = "\uFFFF"; // Specify something that can't separate
                    } else {
                        try {
                            int val = Integer.parseInt(temp, 8);
                            recordSeparator = "" + (char) val;
                        } catch (Exception e) {
                            MainExitException mee = new MainExitException(1, getArgumentError(" -0 must be followed by either 0, 777, or a valid octal value"));
                            mee.setUsageError(true);
                            throw mee;
                        }
                    }
                    break FOR;
                }
                case 'a':
                    split = true;
                    break;
                case 'b':
                    benchmarking = true;
                    break;
                case 'c':
                    shouldCheckSyntax = true;
                    break;
                case 'C':
                    try {
                        String saved = grabValue(getArgumentError(" -C must be followed by a directory expression"));
                        File base = new File(currentDirectory);
                        File newDir = new File(saved);
                        if (newDir.isAbsolute()) {
                            currentDirectory = newDir.getCanonicalPath();
                        } else {
                            currentDirectory = new File(base, newDir.getPath()).getCanonicalPath();
                        }
                        if (!(new File(currentDirectory).isDirectory())) {
                            MainExitException mee = new MainExitException(1, "jruby: Can't chdir to " + saved + " (fatal)");
                            mee.setUsageError(true);
                            throw mee;
                        }
                    } catch (IOException e) {
                        MainExitException mee = new MainExitException(1, getArgumentError(" -C must be followed by a valid directory"));
                        mee.setUsageError(true);
                        throw mee;
                    }
                    break;
                case 'd':
                    debug = true;
                    verbose = Boolean.TRUE;
                    break;
                case 'e':
                    inlineScript.append(grabValue(getArgumentError(" -e must be followed by an expression to evaluate")));
                    inlineScript.append('\n');
                    hasInlineScript = true;
                    break FOR;
                case 'F':
                    inputFieldSeparator = grabValue(getArgumentError(" -F must be followed by a pattern for input field separation"));
                    break;
                case 'h':
                    shouldPrintUsage = true;
                    shouldRunInterpreter = false;
                    break;
                // FIXME: -i flag not supported
//                    case 'i' :
//                        break;
                case 'I':
                    String s = grabValue(getArgumentError("-I must be followed by a directory name to add to lib path"));
                    String[] ls = s.split(java.io.File.pathSeparator);
                    for (int i = 0; i < ls.length; i++) {
                        loadPaths.add(ls[i]);
                    }
                    break FOR;
                case 'K':
                    // FIXME: No argument seems to work for -K in MRI plus this should not
                    // siphon off additional args 'jruby -K ~/scripts/foo'.  Also better error
                    // processing.
                    String eArg = grabValue(getArgumentError("provide a value for -K"));
                    kcode = KCode.create(null, eArg);
                    break;
                case 'l':
                    processLineEnds = true;
                    break;
                case 'n':
                    assumeLoop = true;
                    break;
                case 'p':
                    assumePrinting = true;
                    assumeLoop = true;
                    break;
                case 'r':
                    requiredLibraries.add(grabValue(getArgumentError("-r must be followed by a package to require")));
                    break FOR;
                case 's' :
                    argvGlobalsOn = true;
                    break;
                case 'S':
                    runBinScript();
                    break FOR;
                case 'T' :{
                    String temp = grabOptionalValue();
                    int value = 1;

                    if(temp!=null) {
                        try {
                            value = Integer.parseInt(temp, 8);
                        } catch(Exception e) {
                            value = 1;
                        }
                    }

                    safeLevel = value;

                    break FOR;
                }
                case 'v':
                    verbose = Boolean.TRUE;
                    setShowVersion(true);
                    break;
                case 'w':
                    verbose = Boolean.TRUE;
                    break;
                case 'W': {
                    String temp = grabOptionalValue();
                    int value = 2;
                    if (null != temp) {
                        if (temp.equals("2")) {
                            value = 2;
                        } else if (temp.equals("1")) {
                            value = 1;
                        } else if (temp.equals("0")) {
                            value = 0;
                        } else {
                            MainExitException mee = new MainExitException(1, getArgumentError(" -W must be followed by either 0, 1, 2 or nothing"));
                            mee.setUsageError(true);
                            throw mee;
                        }
                    }
                    switch (value) {
                    case 0:
                        verbose = null;
                        break;
                    case 1:
                        verbose = Boolean.FALSE;
                        break;
                    case 2:
                        verbose = Boolean.TRUE;
                        break;
                    }


                    break FOR;
                }
                // FIXME: -x flag not supported
//                    case 'x' :
//                        break;
                case 'X':
                    String extendedOption = grabOptionalValue();

                    if (extendedOption == null) {
                        throw new MainExitException(0, "jruby: missing extended option, listing available options\n" + getExtendedHelp());
                    } else if (extendedOption.equals("-O")) {
                        objectSpaceEnabled = false;
                    } else if (extendedOption.equals("+O")) {
                        objectSpaceEnabled = true;
                    } else if (extendedOption.equals("-C")) {
                        compileMode = CompileMode.OFF;
                    } else if (extendedOption.equals("+C")) {
                        compileMode = CompileMode.FORCE;
                    } else if (extendedOption.equals("-y")) {
                        yarv = true;
                    } else if (extendedOption.equals("-Y")) {
                        yarvCompile = true;
                    } else if (extendedOption.equals("-R")) {
                        rubinius = true;
                    } else {
                        MainExitException mee =
                                new MainExitException(1, "jruby: invalid extended option " + extendedOption + " (-X will list valid options)\n");
                        mee.setUsageError(true);

                        throw mee;
                    }
                    break FOR;
                case '-':
                    if (argument.equals("--command") || argument.equals("--bin")) {
                        characterIndex = argument.length();
                        runBinScript();
                        break;
                    } else if (argument.equals("--compat")) {
                        characterIndex = argument.length();
                        compatVersion = CompatVersion.getVersionFromString(grabValue(getArgumentError("--compat must be RUBY1_8 or RUBY1_9")));
                        if (compatVersion == null) {
                            compatVersion = CompatVersion.RUBY1_8;
                        }
                        break FOR;
                    } else if (argument.equals("--copyright")) {
                        setShowCopyright(true);
                        shouldRunInterpreter = false;
                        break FOR;
                    } else if (argument.equals("--debug")) {
                        compileMode = CompileMode.OFF;
                        FULL_TRACE_ENABLED = true;
                        System.setProperty("jruby.reflection", "true");
                        break FOR;
                    } else if (argument.equals("--jdb")) {
                        debug = true;
                        verbose = Boolean.TRUE;
                        break;
                    } else if (argument.equals("--help")) {
                        shouldPrintUsage = true;
                        shouldRunInterpreter = false;
                        break;
                    } else if (argument.equals("--properties")) {
                        shouldPrintProperties = true;
                        shouldRunInterpreter = false;
                        break;
                    } else if (argument.equals("--version")) {
                        setShowVersion(true);
                        break FOR;
                    } else if (argument.equals("--bytecode")) {
                        setShowBytecode(true);
                        break FOR;
                    } else {
                        if (argument.equals("--")) {
                            // ruby interpreter compatibilty
                            // Usage: ruby [switches] [--] [programfile] [arguments])
                            endOfArguments = true;
                            break;
                        }
                    }
                default:
                    throw new MainExitException(1, "jruby: unknown option " + argument);
                }
            }
        }

        private void runBinScript() {
            String scriptName = grabValue("jruby: provide a bin script to execute");
            if (scriptName.equals("irb")) {
                scriptName = "jirb";
            }

            scriptFileName = scriptName;

            if (!new File(scriptFileName).exists()) {
                try {
                    String jrubyHome = JRubyFile.create(System.getProperty("user.dir"), JRubyFile.getFileProperty("jruby.home")).getCanonicalPath();
                    scriptFileName = JRubyFile.create(jrubyHome + JRubyFile.separator + "bin", scriptName).getCanonicalPath();
                } catch (IOException io) {
                    MainExitException mee = new MainExitException(1, "jruby: Can't determine script filename");
                    mee.setUsageError(true);
                    throw mee;
                }
            }

            // route 'gem' through ruby code in case we're running out of the complete jar
            if (scriptName.equals("gem") || !new File(scriptFileName).exists()) {
                requiredLibraries.add("jruby/commands");
                inlineScript.append("JRuby::Commands." + scriptName);
                inlineScript.append("\n");
                hasInlineScript = true;
            }
            endOfArguments = true;
        }

        private String grabValue(String errorMessage) {
            characterIndex++;
            if (characterIndex < arguments[argumentIndex].length()) {
                return arguments[argumentIndex].substring(characterIndex);
            }
            argumentIndex++;
            if (argumentIndex < arguments.length) {
                return arguments[argumentIndex];
            }

            MainExitException mee = new MainExitException(1, errorMessage);
            mee.setUsageError(true);

            throw mee;
        }

        private String grabOptionalValue() {
            characterIndex++;
            if (characterIndex < arguments[argumentIndex].length()) {
                return arguments[argumentIndex].substring(characterIndex);
            }
            return null;
        }
    }

    public byte[] inlineScript() {
        return inlineScript.toString().getBytes();
    }

    public List<String> requiredLibraries() {
        return requiredLibraries;
    }

    public List<String> loadPaths() {
        return loadPaths;
    }

    public boolean shouldRunInterpreter() {
        if(isShowVersion() && (hasInlineScript || scriptFileName != null)) {
            return true;
        }
        return isShouldRunInterpreter();
    }

    public boolean shouldPrintUsage() {
        return shouldPrintUsage;
    }

    public boolean shouldPrintProperties() {
        return shouldPrintProperties;
    }

    private boolean isSourceFromStdin() {
        return getScriptFileName() == null;
    }

    public boolean isInlineScript() {
        return hasInlineScript;
    }

    public InputStream getScriptSource() {
        try {
            // KCode.NONE is used because KCODE does not affect parse in Ruby 1.8
            // if Ruby 2.0 encoding pragmas are implemented, this will need to change
            if (hasInlineScript) {
                return new ByteArrayInputStream(inlineScript());
            } else if (isSourceFromStdin()) {
                // can't use -v and stdin
                if (isShowVersion()) {
                    return null;
                }
                return getInput();
            } else {
                File file = JRubyFile.create(getCurrentDirectory(), getScriptFileName());
                return new BufferedInputStream(new FileInputStream(file));
            }
        } catch (IOException e) {
            throw new MainExitException(1, "Error opening script file: " + e.getMessage());
        }
    }

    public String displayedFileName() {
        if (hasInlineScript) {
            if (scriptFileName != null) {
                return scriptFileName;
            } else {
                return "-e";
            }
        } else if (isSourceFromStdin()) {
            return "-";
        } else {
            return getScriptFileName();
        }
    }

    private void setScriptFileName(String scriptFileName) {
        this.scriptFileName = scriptFileName;
    }

    public String getScriptFileName() {
        return scriptFileName;
    }

    public boolean isBenchmarking() {
        return benchmarking;
    }

    public boolean isAssumeLoop() {
        return assumeLoop;
    }

    public boolean isAssumePrinting() {
        return assumePrinting;
    }

    public boolean isProcessLineEnds() {
        return processLineEnds;
    }

    public boolean isSplit() {
        return split;
    }

    public boolean isVerbose() {
        return verbose == Boolean.TRUE;
    }

    public Boolean getVerbose() {
        return verbose;
    }

    public boolean isDebug() {
        return debug;
    }

    public boolean isShowVersion() {
        return showVersion;
    }
   
    public boolean isShowBytecode() {
        return showBytecode;
    }

    public boolean isShowCopyright() {
        return showCopyright;
    }

    protected void setShowVersion(boolean showVersion) {
        this.showVersion = showVersion;
    }
   
    protected void setShowBytecode(boolean showBytecode) {
        this.showBytecode = showBytecode;
    }

    protected void setShowCopyright(boolean showCopyright) {
        this.showCopyright = showCopyright;
    }

    public boolean isShouldRunInterpreter() {
        return shouldRunInterpreter;
    }

    public boolean isShouldCheckSyntax() {
        return shouldCheckSyntax;
    }

    public boolean isYARVEnabled() {
        return yarv;
    }

    public String getInputFieldSeparator() {
        return inputFieldSeparator;
    }

    public boolean isRubiniusEnabled() {
        return rubinius;
    }

    public boolean isYARVCompileEnabled() {
        return yarvCompile;
    }

    public KCode getKCode() {
        return kcode;
    }

    public String getRecordSeparator() {
        return recordSeparator;
    }

    public int getSafeLevel() {
        return safeLevel;
    }

    public void setRecordSeparator(String recordSeparator) {
        this.recordSeparator = recordSeparator;
    }

    public ClassCache getClassCache() {
        return classCache;
    }

    public void setClassCache(ClassCache classCache) {
        this.classCache = classCache;
    }

    public Map getOptionGlobals() {
        return optionGlobals;
    }
   
    public boolean isManagementEnabled() {
        return managementEnabled;
    }
   
    public Set getExcludedMethods() {
        return excludedMethods;
    }
   
}
TOP

Related Classes of org.jruby.RubyInstanceConfig$LoadServiceCreator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.