All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.nativeexecution.NbNativeProcess Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.netbeans.modules.nativeexecution;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import org.netbeans.modules.nativeexecution.api.HostInfo;
import org.netbeans.modules.nativeexecution.api.NativeProcessBuilder;
import org.netbeans.modules.nativeexecution.api.ProcessStatusEx;
import org.netbeans.modules.nativeexecution.api.pty.Pty;
import org.netbeans.modules.nativeexecution.api.util.MacroMap;
import org.netbeans.modules.nativeexecution.api.util.ProcessUtils;
import org.netbeans.modules.nativeexecution.api.util.ProcessUtils.ExitStatus;
import org.netbeans.modules.nativeexecution.api.util.Signal;
import org.netbeans.modules.nativeexecution.api.util.UnbufferSupport;
import org.netbeans.modules.nativeexecution.api.util.WindowsSupport;
import org.netbeans.modules.nativeexecution.pty.NbStartUtility;
import org.netbeans.modules.nativeexecution.signals.SignalSupport;
import org.netbeans.modules.nativeexecution.support.Logger;

/**
 *
 * An implementation of NativeProcess that uses NbStartUtility as a trampoline.
 *
 * Supported platforms: MacOSX
 *
 * @author Andrew
 */
public abstract class NbNativeProcess extends AbstractNativeProcess {

    private final String nbStartPath;
    private volatile ProcessStatusEx statusEx;

    public NbNativeProcess(final NativeProcessInfo info) {
        super(new NativeProcessInfo(info, true));
        String _nbStartPath = null;
        try {
            _nbStartPath = NbStartUtility.getInstance().getPath(getExecutionEnvironment());
        } catch (IOException ex) {
        } finally {
            nbStartPath = _nbStartPath;
        }
    }

    @Override
    protected final void create() throws Throwable {
        createProcessImpl(getCommand());
        readProcessInfo(getInputStream());
    }

    private List getCommand() {
        List command = new ArrayList<>();

        command.add(nbStartPath);

        String wdir = info.getWorkingDirectory(true);
        if (wdir != null && !wdir.isEmpty()) {
            command.add("--dir"); // NOI18N
            command.add(fixForWindows(wdir));
        }

        if (!info.isPtyMode()) {
            command.add("--no-pty"); // NOI18N
        } else {
            Pty pty = info.getPty();
            if (FIX_ERASE_KEY_IN_TERMINAL) {
                command.add("--set-erase-key"); // NOI18N;
            }
            if (pty != null) {
                command.add("-p"); // NOI18N
                command.add(pty.getSlaveName());
            }
        }

        if (!info.isPtyMode() && info.isUnbuffer()) {
            try {
                UnbufferSupport.initUnbuffer(info.getExecutionEnvironment(), info.getEnvironment());
            } catch (IOException ex) {
                Logger.getInstance().log(Level.FINE, "initUnbuffer failed", ex); // NOI18N
            }
        }

        if (info.getInitialSuspend()) {
            command.add("-w"); // NOI18N
        }

        boolean getStatus = info.isStatusEx();
        if (getStatus) {
            command.add("--report"); // NOI18N
            // hostInfo.getTempDir() is already in 'shell' format for Windows
            command.add(hostInfo.getTempDir() + "/status"); // NOI18N
        }

        String envFile = hostInfo.getEnvironmentFile();
        if (envFile != null) {
            // envFile is already in 'shell' format for Windows
            command.add("--readenv"); // NOI18N
            command.add(envFile);
        }

        if (info.isRedirectError()) {
            command.add("--redirect-error"); // NOI18N
        }

        MacroMap userEnv = info.getEnvironment();
        if (userEnv != null) {
            Map userDefinedMap = userEnv.getUserDefinedMap();

            for (Map.Entry entry : userDefinedMap.entrySet()) {
                if (isWindows() && entry.getKey().equalsIgnoreCase("PATH")) { // NOI18N
                    command.add("--env"); // NOI18N
                    command.add(entry.getKey() + "=" + WindowsSupport.getInstance().convertToAllShellPaths(entry.getValue())); // NOI18N
                    continue;
                }
                command.add("--env"); // NOI18N
                command.add(entry.getKey() + "=" + entry.getValue()); // NOI18N
            }
        }

        if (info.isCommandLineDefined()) {
            command.add(hostInfo.getShell());
            command.add("-c"); // NOI18N
            final String origCommand = info.getCommandLineForShell();
            command.add("exec " + origCommand); // NOI18N
        } else {
            command.add(fixForWindows(info.getExecutable()));
            command.addAll(info.getArguments());
        }
        return command;
    }

    private void readProcessInfo(InputStream fromProcessStream) throws IOException {
        String line;

        while (!(line = readLine(fromProcessStream).trim()).isEmpty()) {
            addProcessInfo(line);
        }

        String pidProperty = getProcessInfo("PID"); // NOI18N

        if (pidProperty == null) {
            InputStream error = getErrorStream();
            while (!(line = readLine(error).trim()).isEmpty()) {
                LOG.info(line);
            }
            throw new InternalError("Failed to get process PID"); // NOI18N
        }

        setPID(Integer.parseInt(pidProperty)); // NOI18N    
    }

    @Override
    protected final int waitResult() throws InterruptedException {
        int result = waitResultImpl();

        String reportFile = getProcessInfo("REPORT"); // NOI18N

        if (reportFile != null) {
            // NbNativeProcess works in either *nix or cygwin environment;
            // So it is safe to call /bin/sh here in any case
            NativeProcessBuilder npb = NativeProcessBuilder.newProcessBuilder(info.getExecutionEnvironment());
            npb.setExecutable("/bin/sh"); // NOI18N
            npb.setArguments("-c", "cat " + reportFile + " && rm " + reportFile); // NOI18N
            ExitStatus st = ProcessUtils.execute(npb);
            if (st.isOK()) {
                statusEx = ProcessStatusAccessor.getDefault().create(st.getOutputString().split("\n")); // NOI18N
                result = statusEx.getExitCode();
            }
        }

        return result;
    }

    @Override
    public ProcessStatusEx getExitStatusEx() {
        // Ensure that process is finished
        exitValue();
        return statusEx;
    }

    private String readLine(final InputStream is) throws IOException {
        int c;
        StringBuilder sb = new StringBuilder(20);

        while (!isInterrupted()) {
            c = is.read();

            if (c < 0 || c == '\n') {
                break;
            }

            sb.append((char) c);
        }

        return sb.toString().trim();
    }

    protected abstract int waitResultImpl() throws InterruptedException;

    protected abstract void createProcessImpl(List command) throws Throwable;

    @Override
    protected int destroyImpl() {
        if (destroyed()) {
            return 0;
        }

        // signal using env
        String env = getProcessInfo("NBMAGIC"); // NOI18N
        if (env != null) {
            String magicEnv = "NBMAGIC=" + env; // NOI18N
            SignalSupport.signalProcessesByEnv(info.getExecutionEnvironment(), magicEnv, Signal.SIGTERM);
        }

        return 0;
    }

    protected boolean isWindows() {
        return HostInfo.OSFamily.WINDOWS.equals(hostInfo.getOSFamily());
    }

    protected String fixForWindows(String path) {
        return isWindows() ? WindowsSupport.getInstance().convertToCygwinPath(path) : path;
    }

    private boolean destroyed() {
        try {
            exitValue();
            return true;
        } catch (IllegalThreadStateException ex) {
            return false;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy