/******************************************************************************* * Copyright (c) 2005, 2009, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Red Hat Inc. - modify to use with RDT *******************************************************************************/ package org.eclipse.linuxtools.internal.rdt.proxy; import java.io.IOException; import java.io.OutputStream; import java.net.URI; import java.util.Arrays; import java.util.Map; import org.eclipse.cdt.utils.pty.PTY; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.linuxtools.profiling.launch.IRemoteCommandLauncher; import org.eclipse.remote.core.IRemoteConnection; import org.eclipse.remote.core.IRemoteFileService; import org.eclipse.remote.core.IRemoteProcess; import org.eclipse.remote.core.IRemoteProcessBuilder; import org.eclipse.remote.core.IRemoteProcessService; import org.eclipse.remote.core.IRemoteResource; import org.eclipse.remote.core.RemoteProcessAdapter; import org.eclipse.remote.core.exception.RemoteConnectionException; /** * @noextend This class is not intended to be subclassed by clients. */ public class RDTCommandLauncher implements IRemoteCommandLauncher { private IRemoteProcess fProcess; private boolean fShowCommand; private String[] fCommandArgs; private String fErrorMessage = ""; //$NON-NLS-1$ private String lineSeparator; private URI uri; /** * The number of milliseconds to pause between polling. */ private static final long DELAY = 50L; /** * Creates a new launcher Fills in stderr and stdout output to the given * streams. Streams can be set to <code>null</code>, if output not * required */ public RDTCommandLauncher(IProject project) { fProcess = null; fShowCommand = false; try { if (project.hasNature(RDTProxyManager.SYNC_NATURE)) { IRemoteResource remoteRes = project.getAdapter(IRemoteResource.class); uri = remoteRes.getActiveLocationURI(); } else{ uri = project.getLocationURI(); } } catch (CoreException e) { uri = project.getLocationURI(); } lineSeparator = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Creates a new launcher Fills in stderr and stdout output to the given * streams. Streams can be set to <code>null</code>, if output not * required */ public RDTCommandLauncher(URI uri) { fProcess = null; fShowCommand = false; this.uri = uri; lineSeparator = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ } @Override public String getErrorMessage() { return fErrorMessage; } private String[] getCommandArgs() { return fCommandArgs; } /** * Constructs a command array that will be passed to the process */ private static String[] constructCommandArray(String command, String[] commandArgs) { String[] args = new String[1 + commandArgs.length]; args[0] = command; System.arraycopy(commandArgs, 0, args, 1, commandArgs.length); return args; } @Override public Process execute(IPath commandPath, String[] args, String[] env, IPath changeToDirectory, IProgressMonitor monitor, PTY pty) { try { // add platform specific arguments (shell invocation) fCommandArgs = constructCommandArray(commandPath.toOSString(), args); fShowCommand = true; IRemoteConnection connection = RDTProxyManager.getConnection(uri); if (connection == null) { fErrorMessage = Messages.RDTCommandLauncher_connection_not_found; return null; } else if (!connection.isOpen()) { try { connection.open(monitor); } catch (RemoteConnectionException e) { fErrorMessage = e.getMessage(); return null; } } IRemoteProcessService ps = connection.getService(IRemoteProcessService.class); IRemoteProcessBuilder builder = ps.getProcessBuilder(Arrays.asList(fCommandArgs)); if (changeToDirectory != null) { IRemoteFileService fm = connection.getService(IRemoteFileService.class); builder.directory(fm.getResource(changeToDirectory.toString())); } Map<String,String> envMap = builder.environment(); for (int i = 0; i < env.length; ++i) { String s = env[i]; String[] tokens = s.split("=", 2); //$NON-NLS-1$ switch (tokens.length) { case 1: envMap.put(tokens[0], null); break; case 2: envMap.put(tokens[0], tokens[1]); break; default: Activator.log(IStatus.WARNING, Messages.RDTCommandLauncher_malformed_env_var_string + s); } } fProcess = builder.start(); fErrorMessage = ""; //$NON-NLS-1$ } catch (IOException e) { fErrorMessage = e.getMessage(); return null; } return new RemoteProcessAdapter(fProcess); } @Override public int waitAndRead(OutputStream output, OutputStream err, IProgressMonitor monitor) { if (fShowCommand) { printCommandLine(output); } if (fProcess == null) { return ILLEGAL_COMMAND; } RemoteProcessClosure closure = new RemoteProcessClosure(fProcess, output, err); closure.runNonBlocking(); while (!monitor.isCanceled() && closure.isAlive()) { try { Thread.sleep(DELAY); } catch (InterruptedException ie) { // ignore } } int state = OK; // Operation canceled by the user, terminate abnormally. if (monitor.isCanceled()) { closure.terminate(); state = COMMAND_CANCELED; fErrorMessage = Activator.getResourceString("CommandLauncher.error.commandCanceled"); //$NON-NLS-1$ } try { fProcess.waitFor(); } catch (InterruptedException e) { // ignore } return state; } private void printCommandLine(OutputStream os) { if (os != null) { String cmd = getCommandLine(getCommandArgs()); try { os.write(cmd.getBytes()); os.flush(); } catch (IOException e) { // ignore; } } } private String getCommandLine(String[] commandArgs) { StringBuffer buf = new StringBuffer(); if (fCommandArgs != null) { for (String commandArg : commandArgs) { buf.append(commandArg); buf.append(' '); } buf.append(lineSeparator); } return buf.toString(); } @Override public Process execute(IPath commandPath, String[] args, String[] env, IPath changeToDirectory, IProgressMonitor monitor) { return execute(commandPath, args, env, changeToDirectory, monitor, null); } }