/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. * * Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common * Development and Distribution License("CDDL") (collectively, the * "License"). You may not use this file except in compliance with the * License. You can obtain a copy of the License at * http://www.netbeans.org/cddl-gplv2.html * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the * specific language governing permissions and limitations under the * License. When distributing the software, include this License Header * Notice in each file and include the License file at * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the * License Header, with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL * or only the GPL Version 2, indicate your decision by adding * "[Contributor] elects to include this software in this distribution * under the [CDDL or GPL Version 2] license." If you do not indicate a * single choice of license, a recipient has the option to distribute * your version of this file under either the CDDL, the GPL Version 2 or * to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. */ package org.netbeans.modules.ruby.platform.execution; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.netbeans.api.ruby.platform.RubyPlatform; import org.netbeans.api.extexecution.ExecutionDescriptor; import org.netbeans.api.extexecution.ExecutionDescriptor.InputProcessorFactory; import org.netbeans.api.extexecution.ExecutionDescriptor.LineConvertorFactory; import org.netbeans.api.extexecution.print.LineConvertor; import org.netbeans.api.extexecution.print.LineConvertors.FileLocator; import org.netbeans.modules.ruby.platform.gems.GemManager; import org.openide.filesystems.FileObject; import org.openide.util.Utilities; /** * A RubyExecutionDescriptor describes a program to be executed, the arguments * and environment to be used, as well as preferences such as whether the * running process should be in the background (no progress bar), and so on. * * @author Tor Norbye */ public class RubyExecutionDescriptor { File pwd; File cmd; boolean addBinPath; boolean inputVisible; private String displayName; Runnable postBuildAction; private final RubyPlatform platform; private FileLocator fileLocator; String script; private String scriptPrefix; private Map<String, String> additionalEnv; private String[] additionalArgs; private String initialArgs; private String jvmArgs; private FileObject fileObject; private String classPath; boolean showProgress = true; boolean showSuspended; boolean frontWindow = true; boolean debug; private boolean fastDebugRequired; private boolean appendJdkToPath; private String encoding; private boolean useInterpreter; private boolean runThroughRuby = true; private final List<LineConvertor> outConvertors = new ArrayList<LineConvertor>(); private final List<LineConvertor> errConvertors = new ArrayList<LineConvertor>(); private InputProcessorFactory outProcessorFactory; private InputProcessorFactory errProcessorFactory; private boolean addStandardConvertors; private boolean lineBased; private boolean ansiStrippging; /** * Defines whether rerun should be allowed. <i>Currently needed * only because rerunning rake test tasks in the test runner does not * work reliably (might be causing #145228), likely will become obsolete * once that issue has been solved</i>. */ private boolean rerun = true; public RubyExecutionDescriptor(final RubyPlatform platform) { this(platform, null, null); } public RubyExecutionDescriptor(final RubyPlatform platform, final String displayName, final File pwd) { this(platform, displayName, pwd, null); } public RubyExecutionDescriptor(final RubyPlatform platform, final String displayName, final File pwd, final String script) { this.platform = platform; this.displayName = displayName; this.pwd = pwd; this.script = script; this.useInterpreter = true; assert (pwd == null) || pwd.isDirectory() : pwd + " is a directory"; if (platform.hasRubyGemsInstalled()) { Map<String, String> env = new HashMap<String, String>(); GemManager.adjustEnvironment(platform, env); addAdditionalEnv(env); } if (platform.isJRuby()) { Map<String, String> env = new HashMap<String, String>(); String home = platform.getHome().getAbsolutePath(); env.put("JRUBY_HOME", home); // NOI18N env.put("JRUBY_BASE", home); // NOI18N env.put("JAVA_HOME", ExecutionUtils.getJavaHome()); // NOI18N addAdditionalEnv(env); } } /** * Constructs a new RubyExecutionDescriptor with the same initial values * as in the given <code>template</code>, i.e. effectively constructs * a copy of it. * * @param template */ public RubyExecutionDescriptor(RubyExecutionDescriptor template) { this.pwd = template.pwd; this.cmd = template.cmd; this.addBinPath = template.addBinPath; this.inputVisible = template.inputVisible; this.displayName = template.displayName; this.postBuildAction = template.postBuildAction; this.platform = template.platform; this.fileLocator = template.fileLocator; this.script = template.script; this.scriptPrefix = template.scriptPrefix; this.additionalEnv = template.additionalEnv; this.additionalArgs = template.additionalArgs; this.initialArgs = template.initialArgs; this.jvmArgs = template.jvmArgs; this.fileObject = template.fileObject; this.classPath = template.classPath; this.showSuspended = template.showSuspended; this.debug = template.debug; this.fastDebugRequired = template.fastDebugRequired; this.appendJdkToPath = template.appendJdkToPath; this.encoding = template.encoding; this.useInterpreter = template.useInterpreter; this.outProcessorFactory = template.outProcessorFactory; this.errProcessorFactory = template.errProcessorFactory; this.outConvertors.addAll(template.outConvertors); this.errConvertors.addAll(template.errConvertors); this.addStandardConvertors = template.addStandardConvertors; this.lineBased = template.lineBased; } public RubyExecutionDescriptor cmd(final File cmd) { this.cmd = cmd; assert (cmd != null) && cmd.isFile() : cmd + " must be a file"; return this; } public RubyExecutionDescriptor postBuild(Runnable postBuildAction) { this.postBuildAction = postBuildAction; return this; } public RubyExecutionDescriptor fileLocator(FileLocator fileLocator) { this.fileLocator = fileLocator; return this; } /** Set FileObject associated with this execution (typically the source file). * This is not injected in the argument list in any way, but for example * the Rerun action will get disabled if this file is deleted. */ public RubyExecutionDescriptor fileObject(FileObject fileObject) { this.fileObject = fileObject; return this; } public RubyExecutionDescriptor addStandardRecognizers() { addStandardConvertors = true; return this; } public RubyExecutionDescriptor allowInput() { this.inputVisible = true; return this; } public RubyExecutionDescriptor script(String script) { this.script = script; return this; } public RubyExecutionDescriptor showProgress(boolean showProgress) { this.showProgress = showProgress; return this; } public RubyExecutionDescriptor showSuspended(boolean showSuspended) { this.showSuspended = showSuspended; return this; } /** * Arguments that will be appended <em>AFTER</em> the target. Usually * arguments and options to the Ruby script (target, application, ..) * itself. Note that this will wipe out any existing additionalArgs in * this descriptor, i.e. the given <code>additionalArgs</code> are <b>not</b> * appended to the existing args. */ public RubyExecutionDescriptor additionalArgs(final String... additionalArgs) { this.additionalArgs = additionalArgs; return this; } /** * Arguments that will be parsed and prepended <em>BEFORE</em> the target. * Usually arguments and options for the Ruby interpreter. <strong>Note * that any already existing <code>initialArgs</code> will be wiped out</strong>. * * @see #addInitialArgs(java.lang.String) */ public RubyExecutionDescriptor initialArgs(String initialArgs) { this.initialArgs = initialArgs; return this; } /** * Adds the given <code>initialArgs</code> as an initial arg for this * descriptor. In contrast with {@link #initialArgs(java.lang.String)} this * method does not erase existing <code>initialArgs</code>. * * @param initialArgs the args to add. May be <code>null</code>; in that * case the arg is ignored. * * @return */ public RubyExecutionDescriptor addInitialArgs(String initialArgs) { if (initialArgs == null || "".equals(initialArgs)) { //NOI18N return this; } if (this.initialArgs == null || "".equals(this.initialArgs)) { //NOI18N this.initialArgs = initialArgs; } else { this.initialArgs += " " + initialArgs; //NOI18N } return this; } public RubyExecutionDescriptor jvmArguments(final String jvmArgs) { this.jvmArgs = jvmArgs; return this; } public RubyExecutionDescriptor addBinPath(boolean addBinPath) { this.addBinPath = addBinPath; return this; } public RubyExecutionDescriptor frontWindow(boolean frontWindow) { this.frontWindow = frontWindow; return this; } public RubyExecutionDescriptor debug(boolean debug) { this.debug = debug; return this; } public RubyExecutionDescriptor fastDebugRequired(boolean fastDebugRequired) { this.fastDebugRequired = fastDebugRequired; return this; } public RubyExecutionDescriptor runThroughRuby(boolean runThroughRuby) { this.runThroughRuby = runThroughRuby; return this; } /** * Builder property which sets whether the JDK should be added to the PATH * for the executed process. The default is false. If it is set, it will be * added at the end of the PATH, so any existing JDKs on the PATH will take * precedence. * @param addJdkToPath Whether the JDK should be appended to the path. */ public RubyExecutionDescriptor appendJdkToPath(boolean appendJdkToPath) { this.appendJdkToPath = appendJdkToPath; return this; } /** Extra class path to be used in case the execution process is a VM */ public RubyExecutionDescriptor classPath(String classPath) { this.classPath = classPath; return this; } public String getDisplayName() { return debug ? displayName + " (debug)" : displayName; // NOI18N } public RubyPlatform getPlatform() { return platform; } public boolean isRunThroughRuby() { return runThroughRuby; } public File getCmd() { return cmd; } public String getScript() { return script; } public void scriptPrefix(String sp) { scriptPrefix = sp; } public String getScriptPrefix() { return scriptPrefix; } public Runnable getPostBuild() { return postBuildAction; } /** * Arguments to be appended <em>AFTER</em> the target. Usually arguments and * options to the Ruby script (target, application, ..) itself. */ public String[] getAdditionalArgs() { return additionalArgs; } /** * Arguments to be prepended <em>BEFORE</em> the target. Usually arguments * and options for the Ruby interpreter. */ public String[] getInitialArgs() { return initialArgs == null ? null : Utilities.parseParameters(initialArgs); } public String getInitialArgsPlain() { return initialArgs; } /** Arguments to be passed to the JVM running the JRuby process. */ public String[] getJVMArguments() { return jvmArgs == null ? null : Utilities.parseParameters(jvmArgs); } public File getPwd() { return pwd; } /** * Sets the working directory. * @param pwd the working directory to set. */ public void setPwd(File pwd) { this.pwd = pwd; } public boolean isFastDebugRequired() { return fastDebugRequired; } public String getClassPath() { return classPath; } public FileLocator getFileLocator() { return fileLocator; } public FileObject getFileObject() { return fileObject; } public void setEncoding(String encoding) { this.encoding = encoding; } String getEncoding() { return encoding; } /** * Should the JDK be appended to the PATH? * @return True iff the JDK should be appended to the PATH. */ public boolean getAppendJdkToPath() { return appendJdkToPath; } public void addAdditionalEnv(Map<String, String> additionalEnv) { if (this.additionalEnv == null) { this.additionalEnv = new HashMap<String, String>(); } this.additionalEnv.putAll(additionalEnv); } /** * @return the additional env or an empty map if no additional was defined; * never <code>null</code>. */ public Map<String, String> getAdditionalEnvironment() { return additionalEnv != null ? additionalEnv : Collections.<String, String>emptyMap(); } public boolean useInterpreter() { return useInterpreter; } public void useInterpreter(final boolean useInterpreter) { this.useInterpreter = useInterpreter; } /** * @see #rerun */ public boolean isRerun() { return rerun; } /** * @see #rerun */ public void setRerun(boolean rerun) { this.rerun = rerun; } public RubyExecutionDescriptor addOutConvertor(LineConvertor convertor) { this.outConvertors.add(convertor); return this; } public RubyExecutionDescriptor addErrConvertor(LineConvertor convertor) { this.errConvertors.add(convertor); return this; } public void setErrProcessorFactory(InputProcessorFactory errProcessorFactory) { this.errProcessorFactory = errProcessorFactory; } public void setOutProcessorFactory(InputProcessorFactory outProcessorFactory) { this.outProcessorFactory = outProcessorFactory; } public RubyExecutionDescriptor lineBased(boolean lineBased) { this.lineBased = lineBased; return this; } public ExecutionDescriptor toExecutionDescriptor() { return new ExecutionDescriptor() .showProgress(showProgress) .controllable(isRerun()) .inputVisible(inputVisible) .frontWindow(frontWindow) .showSuspended(showSuspended) .postExecution(postBuildAction) .errLineBased(lineBased) .outLineBased(lineBased) .outConvertorFactory(lineConvertorFactory(outConvertors)) .errConvertorFactory(lineConvertorFactory(errConvertors)) .outProcessorFactory(outProcessorFactory) .errProcessorFactory(errProcessorFactory); } private LineConvertorFactory lineConvertorFactory(List<LineConvertor> convertors) { LineConvertor[] convertorArray = convertors.toArray(new LineConvertor[convertors.size()]); if (addStandardConvertors) { return RubyLineConvertorFactory.withStandardConvertors(fileLocator, convertorArray); } return RubyLineConvertorFactory.create(fileLocator, convertorArray); } }