mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-08 10:16:03 +02:00
Bug 457493 - Add support for window terminal size and signals.
Change-Id: Iceb1786796c43c70584d6e01824ffe56e9bed255 Signed-off-by: Greg Watson <g.watson@computer.org>
This commit is contained in:
parent
fab5645c94
commit
d5cb7731db
21 changed files with 804 additions and 230 deletions
|
@ -33,6 +33,16 @@
|
|||
factory="org.eclipse.remote.internal.core.services.local.LocalProcessService$Factory"
|
||||
service="org.eclipse.remote.core.IRemoteProcessService">
|
||||
</connectionService>
|
||||
<processService
|
||||
connectionTypeId="org.eclipse.remote.LocalServices"
|
||||
factory="org.eclipse.remote.internal.core.services.local.LocalProcess$Factory"
|
||||
service="org.eclipse.remote.core.IRemoteProcessControlService">
|
||||
</processService>
|
||||
<processService
|
||||
connectionTypeId="org.eclipse.remote.LocalServices"
|
||||
factory="org.eclipse.remote.internal.core.services.local.LocalProcess$Factory"
|
||||
service="org.eclipse.remote.internal.core.services.local.LocalProcess">
|
||||
</processService>
|
||||
</extension>
|
||||
<extension
|
||||
point="org.eclipse.core.runtime.adapters">
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<element ref="connectionType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<element ref="connectionTypeService" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<element ref="connectionService" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<element ref="processService" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</sequence>
|
||||
<attribute name="point" type="string" use="required">
|
||||
<annotation>
|
||||
|
@ -173,6 +174,46 @@
|
|||
</complexType>
|
||||
</element>
|
||||
|
||||
<element name="processService">
|
||||
<annotation>
|
||||
<documentation>
|
||||
This is a service that implements the given service interface for processes of a given connection type.
|
||||
</documentation>
|
||||
</annotation>
|
||||
<complexType>
|
||||
<attribute name="connectionTypeId" type="string" use="required">
|
||||
<annotation>
|
||||
<documentation>
|
||||
The connection type for the connections that this service applies to.
|
||||
</documentation>
|
||||
<appInfo>
|
||||
<meta.attribute kind="identifier" basedOn="org.eclipse.remote.core.remoteServices/connectionType/@id"/>
|
||||
</appInfo>
|
||||
</annotation>
|
||||
</attribute>
|
||||
<attribute name="service" type="string" use="required">
|
||||
<annotation>
|
||||
<documentation>
|
||||
The interface class that this service implements. The service is found by calling the getService() method on the IRemoteProcess object with this interface class as the parameter.
|
||||
</documentation>
|
||||
<appInfo>
|
||||
<meta.attribute kind="java"/>
|
||||
</appInfo>
|
||||
</annotation>
|
||||
</attribute>
|
||||
<attribute name="factory" type="string" use="required">
|
||||
<annotation>
|
||||
<documentation>
|
||||
The factory class used to instantiate the service.
|
||||
</documentation>
|
||||
<appInfo>
|
||||
<meta.attribute kind="java" basedOn=":org.eclipse.remote.core.IRemoteProcess$Service$Factory"/>
|
||||
</appInfo>
|
||||
</annotation>
|
||||
</attribute>
|
||||
</complexType>
|
||||
</element>
|
||||
|
||||
|
||||
<annotation>
|
||||
<appInfo>
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.remote.core;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Abstract base class for remote processes. Implementors can use this class to provide a default remote process implementation.
|
||||
*/
|
||||
public abstract class AbstractRemoteProcess extends Process implements IRemoteProcess {
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Process#destroy()
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Process#exitValue()
|
||||
*/
|
||||
@Override
|
||||
public int exitValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Process#getErrorStream()
|
||||
*/
|
||||
@Override
|
||||
public InputStream getErrorStream() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Process#getInputStream()
|
||||
*/
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Process#getOutputStream()
|
||||
*/
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Process#waitFor()
|
||||
*/
|
||||
@Override
|
||||
public int waitFor() throws InterruptedException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.remote.core.IRemoteProcess#isCompleted()
|
||||
*/
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -25,15 +25,24 @@ import org.eclipse.core.filesystem.IFileStore;
|
|||
*/
|
||||
public abstract class AbstractRemoteProcessBuilder implements IRemoteProcessBuilder {
|
||||
private List<String> fCommandArgs;
|
||||
private IFileStore fRemoteDir = null;
|
||||
private boolean fRedirectErrorStream = false;
|
||||
private IFileStore fRemoteDir;
|
||||
private boolean fRedirectErrorStream;
|
||||
|
||||
public AbstractRemoteProcessBuilder(List<String> command) {
|
||||
private final IRemoteConnection fConnection;
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
public AbstractRemoteProcessBuilder(IRemoteConnection connection, List<String> command) {
|
||||
fCommandArgs = command;
|
||||
fConnection = connection;
|
||||
}
|
||||
|
||||
public AbstractRemoteProcessBuilder(String... command) {
|
||||
this(Arrays.asList(command));
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
public AbstractRemoteProcessBuilder(IRemoteConnection connection, String... command) {
|
||||
this(connection, Arrays.asList(command));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -173,4 +182,17 @@ public abstract class AbstractRemoteProcessBuilder implements IRemoteProcessBuil
|
|||
}
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.remote.core.IRemoteProcessBuilder#getRemoteConnection()
|
||||
*/
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
@Override
|
||||
public IRemoteConnection getRemoteConnection() {
|
||||
return fConnection;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,6 +110,15 @@ public interface IRemoteConnectionType {
|
|||
*/
|
||||
<T extends IRemoteConnection.Service> boolean hasConnectionService(Class<T> service);
|
||||
|
||||
/**
|
||||
* Do processes created by this connection type support the given service.
|
||||
*
|
||||
* @param service
|
||||
* the service to be tested
|
||||
* @return true if processes created by this connection type support this service
|
||||
*/
|
||||
<T extends IRemoteProcess.Service> boolean hasProcessService(Class<T> service);
|
||||
|
||||
/**
|
||||
* Gets the remote connection corresponding to the supplied name.
|
||||
*
|
||||
|
|
|
@ -14,21 +14,33 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Abstraction of a process running on a remote system. Remote process are created using the {@link IRemoteProcessBuilder}
|
||||
* interface.
|
||||
* Represents a process running on a remote system. Remote process are created using the {@link IRemoteProcessBuilder} interface.
|
||||
*/
|
||||
public interface IRemoteProcess {
|
||||
/**
|
||||
* The interface that is extend by services provided for this remote connection.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
interface Service {
|
||||
IRemoteProcess getRemoteProcess();
|
||||
|
||||
interface Factory {
|
||||
<T extends Service> T getService(IRemoteProcess remoteProcess, Class<T> service);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate the process
|
||||
*/
|
||||
public void destroy();
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Returns the exit value for the process
|
||||
*
|
||||
* @return the exit value
|
||||
*/
|
||||
public int exitValue();
|
||||
int exitValue();
|
||||
|
||||
/**
|
||||
* Gets the error output stream of the process
|
||||
|
@ -36,7 +48,7 @@ public interface IRemoteProcess {
|
|||
* @return the output stream connected to the standard
|
||||
* error of the process
|
||||
*/
|
||||
public InputStream getErrorStream();
|
||||
InputStream getErrorStream();
|
||||
|
||||
/**
|
||||
* Gets an InputStream which can be used to read the standard output stream of the process
|
||||
|
@ -44,7 +56,7 @@ public interface IRemoteProcess {
|
|||
* @return the input stream connected to the standard
|
||||
* output of the process
|
||||
*/
|
||||
public InputStream getInputStream();
|
||||
InputStream getInputStream();
|
||||
|
||||
/**
|
||||
* Gets an output stream which can be used to write to the standard input stream of the process
|
||||
|
@ -52,7 +64,27 @@ public interface IRemoteProcess {
|
|||
* @return the output stream connected to the standard
|
||||
* input of the process
|
||||
*/
|
||||
public OutputStream getOutputStream();
|
||||
OutputStream getOutputStream();
|
||||
|
||||
/**
|
||||
* Get the service for this remote process that implements the given interface.
|
||||
*
|
||||
* @param service
|
||||
* the interface the required service must implements
|
||||
* @return the desired service or null if there is no such service available
|
||||
* @since 2.0
|
||||
*/
|
||||
<T extends Service> T getService(Class<T> service);
|
||||
|
||||
/**
|
||||
* Does this remote process support the given service.
|
||||
*
|
||||
* @param service
|
||||
* The service to be tested
|
||||
* @return true if this connection supports the service
|
||||
* @since 2.0
|
||||
*/
|
||||
<T extends Service> boolean hasService(Class<T> service);
|
||||
|
||||
/**
|
||||
* Wait until the process has terminated
|
||||
|
@ -62,12 +94,28 @@ public interface IRemoteProcess {
|
|||
* if the current thread is
|
||||
* interrupted by another thread while it is waiting
|
||||
*/
|
||||
public int waitFor() throws InterruptedException;
|
||||
int waitFor() throws InterruptedException;
|
||||
|
||||
/**
|
||||
* Check if the remote process has completed
|
||||
*
|
||||
* @return true if remote process has completed
|
||||
*/
|
||||
public boolean isCompleted();
|
||||
boolean isCompleted();
|
||||
|
||||
/**
|
||||
* Get the connection that is used by this process
|
||||
*
|
||||
* @return connection used by this process
|
||||
* @since 2.0
|
||||
*/
|
||||
IRemoteConnection getRemoteConnection();
|
||||
|
||||
/**
|
||||
* Get the process builder used to create this process
|
||||
*
|
||||
* @return process builder used to create this process
|
||||
* @since 2.0
|
||||
*/
|
||||
IRemoteProcessBuilder getProcessBuilder();
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public interface IRemoteProcessBuilder {
|
|||
*
|
||||
* @return a list containing the program and arguments
|
||||
*/
|
||||
public List<String> command();
|
||||
List<String> command();
|
||||
|
||||
/**
|
||||
* Sets this process builder's operating system program and arguments.
|
||||
|
@ -54,7 +54,7 @@ public interface IRemoteProcessBuilder {
|
|||
* @param command
|
||||
* @return This process builder
|
||||
*/
|
||||
public IRemoteProcessBuilder command(List<String> command);
|
||||
IRemoteProcessBuilder command(List<String> command);
|
||||
|
||||
/**
|
||||
* Sets this process builder's operating system program and arguments.
|
||||
|
@ -62,14 +62,14 @@ public interface IRemoteProcessBuilder {
|
|||
* @param command
|
||||
* @return this process builder
|
||||
*/
|
||||
public IRemoteProcessBuilder command(String... command);
|
||||
IRemoteProcessBuilder command(String... command);
|
||||
|
||||
/**
|
||||
* Returns this process builder's working directory.
|
||||
*
|
||||
* @return an IFileStore reference to the working directory
|
||||
*/
|
||||
public IFileStore directory();
|
||||
IFileStore directory();
|
||||
|
||||
/**
|
||||
* Sets this process builder's working directory.
|
||||
|
@ -77,7 +77,7 @@ public interface IRemoteProcessBuilder {
|
|||
* @param directory
|
||||
* @return This process builder
|
||||
*/
|
||||
public IRemoteProcessBuilder directory(IFileStore directory);
|
||||
IRemoteProcessBuilder directory(IFileStore directory);
|
||||
|
||||
/**
|
||||
* Returns a string map view of this process builder's environment. The
|
||||
|
@ -85,7 +85,7 @@ public interface IRemoteProcessBuilder {
|
|||
*
|
||||
* @return the process builder's environment
|
||||
*/
|
||||
public Map<String, String> environment();
|
||||
Map<String, String> environment();
|
||||
|
||||
/**
|
||||
* Get the flags that are supported by this process builder.
|
||||
|
@ -93,7 +93,7 @@ public interface IRemoteProcessBuilder {
|
|||
* @return bitwise-or of the supported flags
|
||||
* @since 5.0
|
||||
*/
|
||||
public int getSupportedFlags();
|
||||
int getSupportedFlags();
|
||||
|
||||
/**
|
||||
* Tells whether this process builder merges standard error and standard
|
||||
|
@ -101,7 +101,7 @@ public interface IRemoteProcessBuilder {
|
|||
*
|
||||
* @return true if standard error and standard output will be merged
|
||||
*/
|
||||
public boolean redirectErrorStream();
|
||||
boolean redirectErrorStream();
|
||||
|
||||
/**
|
||||
* Sets this process builder's redirectErrorStream property.
|
||||
|
@ -109,7 +109,7 @@ public interface IRemoteProcessBuilder {
|
|||
* @param redirectErrorStream
|
||||
* @return This process builder
|
||||
*/
|
||||
public IRemoteProcessBuilder redirectErrorStream(boolean redirectErrorStream);
|
||||
IRemoteProcessBuilder redirectErrorStream(boolean redirectErrorStream);
|
||||
|
||||
/**
|
||||
* Starts a new process using the attributes of this process builder.
|
||||
|
@ -117,7 +117,7 @@ public interface IRemoteProcessBuilder {
|
|||
* @return remote process object
|
||||
* @throws IOException
|
||||
*/
|
||||
public IRemoteProcess start() throws IOException;
|
||||
IRemoteProcess start() throws IOException;
|
||||
|
||||
/**
|
||||
* Starts a new process using the attributes of this process builder. The
|
||||
|
@ -139,5 +139,13 @@ public interface IRemoteProcessBuilder {
|
|||
* @throws IOException
|
||||
* @since 5.0
|
||||
*/
|
||||
public IRemoteProcess start(int flags) throws IOException;
|
||||
IRemoteProcess start(int flags) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the connection that will be used by this process builder to create remote processes.
|
||||
*
|
||||
* @return connection used to create remote processes
|
||||
* @since 2.0
|
||||
*/
|
||||
IRemoteConnection getRemoteConnection();
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 QNX Software Systems 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:
|
||||
* QNX - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.remote.core;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* A service to control and report on the state of a process.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface IRemoteProcessControlService extends IRemoteProcess.Service {
|
||||
/**
|
||||
* Terminate the process
|
||||
*/
|
||||
public void destroy();
|
||||
|
||||
/**
|
||||
* Returns the exit value for the process
|
||||
*
|
||||
* @return the exit value
|
||||
*/
|
||||
public int exitValue();
|
||||
|
||||
/**
|
||||
* Gets the error output stream of the process
|
||||
*
|
||||
* @return the output stream connected to the standard
|
||||
* error of the process
|
||||
*/
|
||||
public InputStream getErrorStream();
|
||||
|
||||
/**
|
||||
* Gets an InputStream which can be used to read the standard output stream of the process
|
||||
*
|
||||
* @return the input stream connected to the standard
|
||||
* output of the process
|
||||
*/
|
||||
public InputStream getInputStream();
|
||||
|
||||
/**
|
||||
* Gets an output stream which can be used to write to the standard input stream of the process
|
||||
*
|
||||
* @return the output stream connected to the standard
|
||||
* input of the process
|
||||
*/
|
||||
public OutputStream getOutputStream();
|
||||
|
||||
/**
|
||||
* Wait until the process has terminated
|
||||
*
|
||||
* @return the exit value of the process
|
||||
* @throws InterruptedException
|
||||
* if the current thread is
|
||||
* interrupted by another thread while it is waiting
|
||||
*/
|
||||
public int waitFor() throws InterruptedException;
|
||||
|
||||
/**
|
||||
* Check if the remote process has completed
|
||||
*
|
||||
* @return true if remote process has completed
|
||||
*/
|
||||
public boolean isCompleted();
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.remote.core;
|
||||
|
||||
import org.eclipse.remote.core.exception.RemoteConnectionException;
|
||||
|
||||
/**
|
||||
* A service abstraction for signals.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface IRemoteProcessSignalService extends IRemoteProcess.Service {
|
||||
public static final int HUP = 1;
|
||||
public static final int INT = 2;
|
||||
public static final int QUIT = 3;
|
||||
public static final int ILL = 4;
|
||||
public static final int ABRT = 6;
|
||||
public static final int FPE = 8;
|
||||
public static final int KILL = 9;
|
||||
public static final int SEGV = 11;
|
||||
public static final int PIPE = 13;
|
||||
public static final int ALRM = 14;
|
||||
public static final int TERM = 15;
|
||||
public static final int STOP = 17;
|
||||
public static final int TSTP = 18;
|
||||
public static final int CONT = 19;
|
||||
public static final int USR1 = 30;
|
||||
public static final int USR2 = 31;
|
||||
|
||||
/**
|
||||
* Send a signal to the remote process.
|
||||
*
|
||||
* @param signal
|
||||
* signal to send.
|
||||
* @throws RemoteConnectionException
|
||||
* if the underlying connection fails
|
||||
* @since 2.0
|
||||
*/
|
||||
void sendSignal(int signal) throws RemoteConnectionException;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.remote.core;
|
||||
|
||||
/**
|
||||
* A service abstraction for remote terminals.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface IRemoteProcessTerminalService extends IRemoteProcess.Service {
|
||||
/**
|
||||
* Change the terminal window dimension interactively. Refer to RFC 4254 6.7. Window Dimension Change Message. The character/row
|
||||
* dimensions override the pixel dimensions (when nonzero). Pixel dimensions refer to the drawable area of the window.
|
||||
*
|
||||
* @param cols
|
||||
* terminal width in characters
|
||||
* @param rows
|
||||
* terminal height in characters
|
||||
* @param width
|
||||
* terminal width in pixels
|
||||
* @param height
|
||||
* terminal height in pixels
|
||||
*/
|
||||
void setTerminalSize(int cols, int rows, int width, int height);
|
||||
}
|
|
@ -22,6 +22,7 @@ import org.eclipse.equinox.security.storage.ISecurePreferences;
|
|||
import org.eclipse.remote.core.IRemoteConnection;
|
||||
import org.eclipse.remote.core.IRemoteConnectionType;
|
||||
import org.eclipse.remote.core.IRemoteConnectionWorkingCopy;
|
||||
import org.eclipse.remote.core.IRemoteProcess;
|
||||
import org.eclipse.remote.core.IRemoteServicesManager;
|
||||
import org.eclipse.remote.core.RemoteConnectionChangeEvent;
|
||||
import org.eclipse.remote.core.exception.ConnectionExistsException;
|
||||
|
@ -204,6 +205,44 @@ public class RemoteConnectionType implements IRemoteConnectionType {
|
|||
return serviceDefinitionMap.get(service.getName()) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the remote process to get a service object for that process.
|
||||
*
|
||||
* @param process
|
||||
* the process to which the service applies
|
||||
* @param service
|
||||
* the interface the service must implement
|
||||
* @return the service object
|
||||
* @throws CoreException
|
||||
*/
|
||||
public <T extends IRemoteProcess.Service> T getProcessService(IRemoteProcess process, Class<T> service) {
|
||||
// Both top level and connection services are stored in the serviceDefinitionMap.
|
||||
// In theory the two sets of interfaces can't collide.
|
||||
IConfigurationElement ce = serviceDefinitionMap.get(service.getName());
|
||||
if (ce != null) {
|
||||
try {
|
||||
IRemoteProcess.Service.Factory factory = (IRemoteProcess.Service.Factory) ce.createExecutableExtension("factory"); //$NON-NLS-1$
|
||||
if (factory != null) {
|
||||
return factory.getService(process, service);
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
RemoteCorePlugin.log(e.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.remote.core.IRemoteConnectionType#hasProcessService(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T extends IRemoteProcess.Service> boolean hasProcessService(Class<T> service) {
|
||||
return serviceDefinitionMap.get(service.getName()) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the remote service manager to register a service extension for
|
||||
* this remote services implementation
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.remote.internal.core;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.remote.core.IRemoteConnection;
|
||||
import org.eclipse.remote.core.IRemoteProcess;
|
||||
import org.eclipse.remote.core.IRemoteProcessBuilder;
|
||||
import org.eclipse.remote.core.IRemoteProcessControlService;
|
||||
|
||||
/**
|
||||
* Standard root class for remote processes.
|
||||
*/
|
||||
public class RemoteProcess extends Process implements IRemoteProcess {
|
||||
private final Map<String, Object> servicesMap = new HashMap<>();
|
||||
private final IRemoteConnection connection;
|
||||
private final IRemoteProcessBuilder builder;
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
public RemoteProcess(IRemoteConnection connection, IRemoteProcessBuilder builder) {
|
||||
this.connection = connection;
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Process#destroy()
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
|
||||
if (controlService != null) {
|
||||
controlService.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Process#exitValue()
|
||||
*/
|
||||
@Override
|
||||
public int exitValue() {
|
||||
IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
|
||||
if (controlService != null) {
|
||||
return controlService.exitValue();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Process#getErrorStream()
|
||||
*/
|
||||
@Override
|
||||
public InputStream getErrorStream() {
|
||||
IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
|
||||
if (controlService != null) {
|
||||
return controlService.getErrorStream();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Process#getInputStream()
|
||||
*/
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
|
||||
if (controlService != null) {
|
||||
return controlService.getInputStream();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Process#getOutputStream()
|
||||
*/
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
|
||||
if (controlService != null) {
|
||||
return controlService.getOutputStream();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends Service> T getService(Class<T> service) {
|
||||
String serviceName = service.getName();
|
||||
Object obj = servicesMap.get(serviceName);
|
||||
if (obj == null) {
|
||||
obj = getConnectionType().getProcessService(this, service);
|
||||
if (obj != null) {
|
||||
servicesMap.put(serviceName, obj);
|
||||
}
|
||||
}
|
||||
|
||||
return (T) obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
@Override
|
||||
public <T extends Service> boolean hasService(Class<T> service) {
|
||||
return servicesMap.get(service.getName()) != null || getConnectionType().hasProcessService(service);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Process#waitFor()
|
||||
*/
|
||||
@Override
|
||||
public int waitFor() throws InterruptedException {
|
||||
IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
|
||||
if (controlService != null) {
|
||||
return controlService.waitFor();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.remote.core.IRemoteProcess#isCompleted()
|
||||
*/
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
|
||||
if (controlService != null) {
|
||||
return controlService.isCompleted();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.remote.core.IRemoteProcess#getRemoteConnection()
|
||||
*/
|
||||
@Override
|
||||
public IRemoteConnection getRemoteConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.remote.core.IRemoteProcess#getProcessBuilder()
|
||||
*/
|
||||
@Override
|
||||
public IRemoteProcessBuilder getProcessBuilder() {
|
||||
return builder;
|
||||
}
|
||||
|
||||
private RemoteConnectionType getConnectionType() {
|
||||
return (RemoteConnectionType) getRemoteConnection().getConnectionType();
|
||||
}
|
||||
}
|
|
@ -83,7 +83,7 @@ public class RemoteServicesManager implements IRemoteServicesManager {
|
|||
for (IExtension ext : point.getExtensions()) {
|
||||
for (IConfigurationElement ce : ext.getConfigurationElements()) {
|
||||
String name = ce.getName();
|
||||
if (name.equals("connectionTypeService") || name.equals("connectionService")) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
if (name.equals("connectionTypeService") || name.equals("connectionService") || name.equals("processService")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
String id = ce.getAttribute("connectionTypeId"); //$NON-NLS-1$
|
||||
RemoteConnectionType services = connectionTypeMap.get(id);
|
||||
if (services != null) {
|
||||
|
|
|
@ -16,11 +16,13 @@ import java.io.OutputStream;
|
|||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
|
||||
import org.eclipse.remote.core.AbstractRemoteProcess;
|
||||
import org.eclipse.remote.core.IRemoteProcess;
|
||||
import org.eclipse.remote.core.IRemoteProcessControlService;
|
||||
|
||||
public class LocalProcess extends AbstractRemoteProcess {
|
||||
public class LocalProcess implements IRemoteProcessControlService {
|
||||
private static int refCount = 0;
|
||||
|
||||
private final IRemoteProcess remoteProcess;
|
||||
private final Process localProcess;
|
||||
private InputStream procStdout;
|
||||
private InputStream procStderr;
|
||||
|
@ -29,12 +31,35 @@ public class LocalProcess extends AbstractRemoteProcess {
|
|||
private final Thread completedChecker;
|
||||
private volatile boolean isCompleted;
|
||||
|
||||
public static class Factory implements IRemoteProcess.Service.Factory {
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.remote.core.IRemoteProcess.Service.Factory#getService(org.eclipse.remote.core.IRemoteProcess,
|
||||
* java.lang.Class)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends IRemoteProcess.Service> T getService(IRemoteProcess remoteProcess, Class<T> service) {
|
||||
// This little trick creates an instance of this class
|
||||
// then for each interface it implements, it returns the same object.
|
||||
// This works because the connection caches the service so only one gets created.
|
||||
// As a side effect, it makes this class a service too which can be used
|
||||
// by the this plug-in
|
||||
if (LocalProcess.class.equals(service)) {
|
||||
return (T) new LocalProcess(remoteProcess);
|
||||
}
|
||||
if (IRemoteProcessControlService.class.equals(service)) {
|
||||
return (T) remoteProcess.getService(LocalProcess.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread to merge stdout and stderr. Keeps refcount so that output stream
|
||||
* is not closed too early.
|
||||
*
|
||||
* @author greg
|
||||
*
|
||||
*/
|
||||
private class ProcOutputMerger implements Runnable {
|
||||
private final static int BUF_SIZE = 8192;
|
||||
|
@ -86,23 +111,28 @@ public class LocalProcess extends AbstractRemoteProcess {
|
|||
}
|
||||
}
|
||||
|
||||
public LocalProcess(Process proc, boolean merge) throws IOException {
|
||||
localProcess = proc;
|
||||
public LocalProcess(IRemoteProcess process) {
|
||||
remoteProcess = process;
|
||||
localProcess = ((LocalProcessBuilder) process.getProcessBuilder()).getProcess();
|
||||
|
||||
if (merge) {
|
||||
PipedOutputStream pipedOutput = new PipedOutputStream();
|
||||
try {
|
||||
if (process.getProcessBuilder().redirectErrorStream()) {
|
||||
PipedOutputStream pipedOutput = new PipedOutputStream();
|
||||
|
||||
procStderr = new NullInputStream();
|
||||
procStdout = new PipedInputStream(pipedOutput);
|
||||
procStderr = new NullInputStream();
|
||||
procStdout = new PipedInputStream(pipedOutput);
|
||||
|
||||
stderrReader = new Thread(new ProcOutputMerger(proc.getErrorStream(), pipedOutput));
|
||||
stdoutReader = new Thread(new ProcOutputMerger(proc.getInputStream(), pipedOutput));
|
||||
stderrReader = new Thread(new ProcOutputMerger(localProcess.getErrorStream(), pipedOutput));
|
||||
stdoutReader = new Thread(new ProcOutputMerger(localProcess.getInputStream(), pipedOutput));
|
||||
|
||||
stderrReader.start();
|
||||
stdoutReader.start();
|
||||
} else {
|
||||
procStderr = localProcess.getErrorStream();
|
||||
procStdout = localProcess.getInputStream();
|
||||
stderrReader.start();
|
||||
stdoutReader.start();
|
||||
} else {
|
||||
procStderr = localProcess.getErrorStream();
|
||||
procStdout = localProcess.getInputStream();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
localProcess.destroy();
|
||||
}
|
||||
|
||||
completedChecker = new Thread(new Runnable() {
|
||||
|
@ -185,10 +215,15 @@ public class LocalProcess extends AbstractRemoteProcess {
|
|||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.remote.core.AbstractRemoteProcess#isCompleted()
|
||||
* @see org.eclipse.remote.core.RemoteProcess#isCompleted()
|
||||
*/
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return isCompleted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IRemoteProcess getRemoteProcess() {
|
||||
return remoteProcess;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,8 +30,10 @@ import org.eclipse.core.runtime.Path;
|
|||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.remote.core.AbstractRemoteProcessBuilder;
|
||||
import org.eclipse.remote.core.IProcessFactory;
|
||||
import org.eclipse.remote.core.IRemoteConnection;
|
||||
import org.eclipse.remote.core.IRemoteProcess;
|
||||
import org.eclipse.remote.internal.core.RemoteCorePlugin;
|
||||
import org.eclipse.remote.internal.core.RemoteProcess;
|
||||
|
||||
public class LocalProcessBuilder extends AbstractRemoteProcessBuilder {
|
||||
private static final String EXTENSION_POINT_ID = "processFactory"; //$NON-NLS-1$
|
||||
|
@ -40,14 +42,16 @@ public class LocalProcessBuilder extends AbstractRemoteProcessBuilder {
|
|||
private final IProcessFactory fProcessFactory;
|
||||
private final Map<String, String> fRemoteEnv = new HashMap<String, String>();
|
||||
|
||||
public LocalProcessBuilder(List<String> command) {
|
||||
super(command);
|
||||
private Process localProcess;
|
||||
|
||||
public LocalProcessBuilder(IRemoteConnection connection, List<String> command) {
|
||||
super(connection, command);
|
||||
fRemoteEnv.putAll(System.getenv());
|
||||
fProcessFactory = getProcessFactory();
|
||||
}
|
||||
|
||||
public LocalProcessBuilder(String... command) {
|
||||
this(Arrays.asList(command));
|
||||
public LocalProcessBuilder(IRemoteConnection connection, String... command) {
|
||||
this(connection, Arrays.asList(command));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -104,18 +108,21 @@ public class LocalProcessBuilder extends AbstractRemoteProcessBuilder {
|
|||
for (Entry<String, String> entry : environment().entrySet()) {
|
||||
environmentArray[index++] = entry.getKey() + "=" + entry.getValue(); //$NON-NLS-1$
|
||||
}
|
||||
Process localProc;
|
||||
if (directory() != null) {
|
||||
try {
|
||||
localProc = fProcessFactory.exec(commandArray, environmentArray,
|
||||
localProcess = fProcessFactory.exec(commandArray, environmentArray,
|
||||
directory().toLocalFile(EFS.NONE, new NullProgressMonitor()));
|
||||
} catch (CoreException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
localProc = fProcessFactory.exec(commandArray, environmentArray);
|
||||
localProcess = fProcessFactory.exec(commandArray, environmentArray);
|
||||
}
|
||||
return new LocalProcess(localProc, redirectErrorStream());
|
||||
return new RemoteProcess(getRemoteConnection(), this);
|
||||
}
|
||||
|
||||
public Process getProcess() {
|
||||
return localProcess;
|
||||
}
|
||||
|
||||
private IProcessFactory getProcessFactory() {
|
||||
|
|
|
@ -46,12 +46,12 @@ public class LocalProcessService implements IRemoteProcessService {
|
|||
|
||||
@Override
|
||||
public IRemoteProcessBuilder getProcessBuilder(List<String> command) {
|
||||
return new LocalProcessBuilder(command);
|
||||
return new LocalProcessBuilder(remoteConnection, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IRemoteProcessBuilder getProcessBuilder(String... command) {
|
||||
return new LocalProcessBuilder(command);
|
||||
return new LocalProcessBuilder(remoteConnection, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -44,6 +44,26 @@
|
|||
factory="org.eclipse.remote.internal.jsch.core.JSchConnection$Factory"
|
||||
service="org.eclipse.remote.internal.jsch.core.JSchConnection">
|
||||
</connectionService>
|
||||
<processService
|
||||
connectionTypeId="org.eclipse.remote.JSch"
|
||||
factory="org.eclipse.remote.internal.jsch.core.JSchProcess$Factory"
|
||||
service="org.eclipse.remote.core.IRemoteProcessControlService">
|
||||
</processService>
|
||||
<processService
|
||||
connectionTypeId="org.eclipse.remote.JSch"
|
||||
factory="org.eclipse.remote.internal.jsch.core.JSchProcess$Factory"
|
||||
service="org.eclipse.remote.core.IRemoteProcessSignalService">
|
||||
</processService>
|
||||
<processService
|
||||
connectionTypeId="org.eclipse.remote.JSch"
|
||||
factory="org.eclipse.remote.internal.jsch.core.JSchProcess$Factory"
|
||||
service="org.eclipse.remote.core.IRemoteProcessTerminalService">
|
||||
</processService>
|
||||
<processService
|
||||
connectionTypeId="org.eclipse.remote.JSch"
|
||||
factory="org.eclipse.remote.internal.jsch.core.JSchProcess$Factory"
|
||||
service="org.eclipse.remote.internal.jsch.core.JSchProcess">
|
||||
</processService>
|
||||
</extension>
|
||||
<extension
|
||||
id="org.eclipse.remote.jsch.filesystem"
|
||||
|
|
|
@ -566,7 +566,7 @@ public class JSchConnection implements IRemoteConnectionControlService, IRemoteC
|
|||
*/
|
||||
@Override
|
||||
public IRemoteProcessBuilder getProcessBuilder(List<String> command) {
|
||||
return new JSchProcessBuilder(this, command);
|
||||
return new JSchProcessBuilder(getRemoteConnection(), command);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -576,7 +576,7 @@ public class JSchConnection implements IRemoteConnectionControlService, IRemoteC
|
|||
*/
|
||||
@Override
|
||||
public IRemoteProcessBuilder getProcessBuilder(String... command) {
|
||||
return new JSchProcessBuilder(this, command);
|
||||
return new JSchProcessBuilder(getRemoteConnection(), command);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -24,16 +24,13 @@ import org.eclipse.core.runtime.IProgressMonitor;
|
|||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.SubMonitor;
|
||||
import org.eclipse.remote.core.IRemoteConnection;
|
||||
import org.eclipse.remote.core.IRemoteProcess;
|
||||
import org.eclipse.remote.core.IRemoteProcessService;
|
||||
import org.eclipse.remote.core.IRemoteProcess;
|
||||
import org.eclipse.remote.core.IRemoteServicesManager;
|
||||
import org.eclipse.remote.core.exception.RemoteConnectionException;
|
||||
import org.eclipse.remote.internal.jsch.core.messages.Messages;
|
||||
|
||||
import com.jcraft.jsch.Channel;
|
||||
import com.jcraft.jsch.ChannelExec;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.Proxy;
|
||||
import com.jcraft.jsch.SocketFactory;
|
||||
|
||||
|
@ -49,12 +46,13 @@ public class JSchConnectionProxyFactory {
|
|||
private String command;
|
||||
private IRemoteProcess process;
|
||||
private JSchConnection connection;
|
||||
private IProgressMonitor monitor;
|
||||
private final IProgressMonitor monitor;
|
||||
private boolean connectCalled = false;
|
||||
|
||||
private CommandProxy(JSchConnection connection, String command, IProgressMonitor monitor) {
|
||||
if (command == null || monitor == null)
|
||||
if (command == null || monitor == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.command = command;
|
||||
this.connection = connection;
|
||||
this.monitor = monitor;
|
||||
|
@ -62,7 +60,7 @@ public class JSchConnectionProxyFactory {
|
|||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see com.jcraft.jsch.Proxy#close()
|
||||
*/
|
||||
@Override
|
||||
|
@ -72,12 +70,11 @@ public class JSchConnectionProxyFactory {
|
|||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see com.jcraft.jsch.Proxy#connect(com.jcraft.jsch.SocketFactory, java.lang.String, int, int)
|
||||
*/
|
||||
@Override
|
||||
public void connect(SocketFactory socket_factory, String host,
|
||||
int port, int timeout) throws IOException {
|
||||
public void connect(SocketFactory socket_factory, String host, int port, int timeout) throws IOException {
|
||||
assert !connectCalled : "connect should only be called once"; //$NON-NLS-1$
|
||||
try {
|
||||
if (timeout == 0) {
|
||||
|
@ -88,11 +85,14 @@ public class JSchConnectionProxyFactory {
|
|||
SubMonitor subMon = SubMonitor.convert(monitor, waitSteps * 2);
|
||||
final SubMonitor childMon = subMon.newChild(waitSteps);
|
||||
|
||||
if (connection == null) {
|
||||
IRemoteServicesManager manager = Activator.getService(IRemoteServicesManager.class);
|
||||
connection = (JSchConnection) manager.getLocalConnectionType().getConnections().get(0);
|
||||
}
|
||||
|
||||
// Open connection if it isn't already opened
|
||||
try {
|
||||
if (connection != null) {
|
||||
connection.openMinimal(childMon);
|
||||
}
|
||||
connection.openMinimal(childMon);
|
||||
} catch (RemoteConnectionException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
@ -102,22 +102,11 @@ public class JSchConnectionProxyFactory {
|
|||
command = command.replace("%h", host); //$NON-NLS-1$
|
||||
command = command.replace("%p", Integer.toString(port)); //$NON-NLS-1$
|
||||
|
||||
if (connection != null) {
|
||||
// The process-builder adds unnecessary extra commands (cd, export, ..) and might not work for restricted shells
|
||||
try {
|
||||
ChannelExec exec = connection.getExecChannel();
|
||||
exec.setCommand(command);
|
||||
exec.connect();
|
||||
process = new JSchProcess(exec, false);
|
||||
} catch (JSchException | RemoteConnectionException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
} else {
|
||||
List<String> cmd = new ArgumentParser(command).getTokenList();
|
||||
IRemoteServicesManager manager = Activator.getService(IRemoteServicesManager.class);
|
||||
IRemoteConnection connection = manager.getLocalConnectionType().getConnections().get(0);
|
||||
process = connection.getService(IRemoteProcessService.class).getProcessBuilder(cmd).start();
|
||||
}
|
||||
List<String> cmd = new ArgumentParser(command).getTokenList();
|
||||
JSchProcessBuilder processBuilder = (JSchProcessBuilder) connection.getRemoteConnection()
|
||||
.getService(IRemoteProcessService.class).getProcessBuilder(cmd);
|
||||
processBuilder.setPreamble(false);
|
||||
process = processBuilder.start();
|
||||
|
||||
// Wait on command to produce stdout output
|
||||
long endTime = System.currentTimeMillis() + timeout;
|
||||
|
@ -154,8 +143,8 @@ public class JSchConnectionProxyFactory {
|
|||
} else if (bCanceled) {
|
||||
cause = Messages.JSchConnectionProxyFactory_wasCanceled;
|
||||
}
|
||||
throw new IOException(MessageFormat.format(Messages.JSchConnectionProxyFactory_ProxyCommandFailed,
|
||||
command, cause, msg));
|
||||
throw new IOException(MessageFormat.format(Messages.JSchConnectionProxyFactory_ProxyCommandFailed, command,
|
||||
cause, msg));
|
||||
}
|
||||
|
||||
// Dump the stderr to log
|
||||
|
@ -166,8 +155,7 @@ public class JSchConnectionProxyFactory {
|
|||
String line;
|
||||
try {
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
log.log(new Status(IStatus.INFO, Activator.getUniqueIdentifier(),
|
||||
IStatus.OK, line, null));
|
||||
log.log(new Status(IStatus.INFO, Activator.getUniqueIdentifier(), IStatus.OK, line, null));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Activator.log(e);
|
||||
|
@ -181,7 +169,7 @@ public class JSchConnectionProxyFactory {
|
|||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see com.jcraft.jsch.Proxy#getInputStream()
|
||||
*/
|
||||
@Override
|
||||
|
@ -191,7 +179,7 @@ public class JSchConnectionProxyFactory {
|
|||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see com.jcraft.jsch.Proxy#getOutputStream()
|
||||
*/
|
||||
@Override
|
||||
|
@ -201,7 +189,7 @@ public class JSchConnectionProxyFactory {
|
|||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see com.jcraft.jsch.Proxy#getSocket()
|
||||
*/
|
||||
@Override
|
||||
|
@ -212,20 +200,21 @@ public class JSchConnectionProxyFactory {
|
|||
|
||||
private static class SSHForwardProxy implements Proxy {
|
||||
private Channel channel;
|
||||
private JSchConnection connection;
|
||||
private IProgressMonitor monitor;
|
||||
private final JSchConnection connection;
|
||||
private final IProgressMonitor monitor;
|
||||
private boolean connectCalled = false;
|
||||
|
||||
private SSHForwardProxy(JSchConnection proxyConnection, IProgressMonitor monitor) {
|
||||
if (proxyConnection == null || monitor == null)
|
||||
if (proxyConnection == null || monitor == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.connection = proxyConnection;
|
||||
this.monitor = monitor;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see com.jcraft.jsch.Proxy#close()
|
||||
*/
|
||||
@Override
|
||||
|
@ -235,12 +224,11 @@ public class JSchConnectionProxyFactory {
|
|||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see com.jcraft.jsch.Proxy#connect(com.jcraft.jsch.SocketFactory, java.lang.String, int, int)
|
||||
*/
|
||||
@Override
|
||||
public void connect(SocketFactory socket_factory, String host, int port,
|
||||
int timeout) throws Exception {
|
||||
public void connect(SocketFactory socket_factory, String host, int port, int timeout) throws Exception {
|
||||
assert !connectCalled : "connect should only be called once"; //$NON-NLS-1$
|
||||
try {
|
||||
if (!connection.hasOpenSession()) {
|
||||
|
@ -258,7 +246,7 @@ public class JSchConnectionProxyFactory {
|
|||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see com.jcraft.jsch.Proxy#getInputStream()
|
||||
*/
|
||||
@Override
|
||||
|
@ -273,7 +261,7 @@ public class JSchConnectionProxyFactory {
|
|||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see com.jcraft.jsch.Proxy#getOutputStream()
|
||||
*/
|
||||
@Override
|
||||
|
@ -288,7 +276,7 @@ public class JSchConnectionProxyFactory {
|
|||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see com.jcraft.jsch.Proxy#getSocket()
|
||||
*/
|
||||
@Override
|
||||
|
|
|
@ -16,20 +16,56 @@ import java.io.OutputStream;
|
|||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
|
||||
import org.eclipse.remote.core.AbstractRemoteProcess;
|
||||
import org.eclipse.remote.core.IRemoteProcess;
|
||||
import org.eclipse.remote.core.IRemoteProcessControlService;
|
||||
import org.eclipse.remote.core.IRemoteProcessSignalService;
|
||||
import org.eclipse.remote.core.IRemoteProcessTerminalService;
|
||||
import org.eclipse.remote.core.exception.RemoteConnectionException;
|
||||
|
||||
import com.jcraft.jsch.ChannelExec;
|
||||
|
||||
public class JSchProcess extends AbstractRemoteProcess {
|
||||
public class JSchProcess implements IRemoteProcessControlService, IRemoteProcessSignalService, IRemoteProcessTerminalService {
|
||||
@SuppressWarnings("nls")
|
||||
private final String signals[] = new String[] { "", "HUP", "INT", "QUIT", "ILL", "", "ABRT", "", "FPE", "KILL", "", "SEGV", "",
|
||||
"PIPE", "ALRM", "TERM", "", "STOP", "TSTP", "CONT", "", "", "", "", "", "", "", "", "", "", "USR1", "USR2" };
|
||||
|
||||
private static int WAIT_TIMEOUT = 1000;
|
||||
private static int refCount = 0;
|
||||
|
||||
private final ChannelExec fChannel;
|
||||
private final IRemoteProcess fProcess;
|
||||
|
||||
private InputStream fProcStdout;
|
||||
private InputStream fProcStderr;
|
||||
private Thread fStdoutReader;
|
||||
private Thread fStderrReader;
|
||||
|
||||
public static class Factory implements IRemoteProcess.Service.Factory {
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.remote.core.IRemoteProcess.Service.Factory#getService(org.eclipse.remote.core.IRemoteProcess,
|
||||
* java.lang.Class)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends IRemoteProcess.Service> T getService(IRemoteProcess remoteProcess, Class<T> service) {
|
||||
// This little trick creates an instance of this class
|
||||
// then for each interface it implements, it returns the same object.
|
||||
// This works because the connection caches the service so only one gets created.
|
||||
// As a side effect, it makes this class a service too which can be used
|
||||
// by the this plug-in
|
||||
if (JSchProcess.class.equals(service)) {
|
||||
return (T) new JSchProcess(remoteProcess);
|
||||
}
|
||||
if (IRemoteProcessControlService.class.equals(service) || IRemoteProcessSignalService.class.equals(service)
|
||||
|| IRemoteProcessTerminalService.class.equals(service)) {
|
||||
return (T) remoteProcess.getService(JSchProcess.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class ProcReader implements Runnable {
|
||||
private final static int BUF_SIZE = 8192;
|
||||
|
||||
|
@ -44,6 +80,7 @@ public class JSchProcess extends AbstractRemoteProcess {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
int len;
|
||||
byte b[] = new byte[BUF_SIZE];
|
||||
|
@ -79,23 +116,29 @@ public class JSchProcess extends AbstractRemoteProcess {
|
|||
}
|
||||
}
|
||||
|
||||
public JSchProcess(ChannelExec channel, boolean merge) throws IOException {
|
||||
fChannel = channel;
|
||||
public JSchProcess(IRemoteProcess process) {
|
||||
fProcess = process;
|
||||
fChannel = ((JSchProcessBuilder) process.getProcessBuilder()).getChannel();
|
||||
|
||||
if (merge) {
|
||||
PipedOutputStream pipedOutput = new PipedOutputStream();
|
||||
try {
|
||||
if (process.getProcessBuilder().redirectErrorStream()) {
|
||||
PipedOutputStream pipedOutput = new PipedOutputStream();
|
||||
|
||||
fProcStdout = new PipedInputStream(pipedOutput);
|
||||
fProcStderr = new NullInputStream();
|
||||
fProcStdout = new PipedInputStream(pipedOutput);
|
||||
fProcStderr = new NullInputStream();
|
||||
|
||||
fStderrReader = new Thread(new ProcReader(channel.getErrStream(), pipedOutput));
|
||||
fStdoutReader = new Thread(new ProcReader(channel.getInputStream(), pipedOutput));
|
||||
fStderrReader = new Thread(new ProcReader(fChannel.getErrStream(), pipedOutput));
|
||||
fStdoutReader = new Thread(new ProcReader(fChannel.getInputStream(), pipedOutput));
|
||||
|
||||
fStderrReader.start();
|
||||
fStdoutReader.start();
|
||||
} else {
|
||||
fProcStdout = channel.getInputStream();
|
||||
fProcStderr = channel.getErrStream();
|
||||
fStderrReader.start();
|
||||
fStdoutReader.start();
|
||||
} else {
|
||||
fProcStdout = fChannel.getInputStream();
|
||||
fProcStderr = fChannel.getErrStream();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Activator.log(e);
|
||||
destroy();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -170,10 +213,46 @@ public class JSchProcess extends AbstractRemoteProcess {
|
|||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.remote.core.AbstractRemoteProcess#isCompleted()
|
||||
* @see org.eclipse.remote.core.RemoteProcess#isCompleted()
|
||||
*/
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return fChannel.isClosed();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.remote.core.IRemoteProcess.Service#getRemoteProcess()
|
||||
*/
|
||||
@Override
|
||||
public IRemoteProcess getRemoteProcess() {
|
||||
return fProcess;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.remote.core.IRemoteProcessTerminalService#setTerminalSize(int, int, int, int)
|
||||
*/
|
||||
@Override
|
||||
public void setTerminalSize(int cols, int rows, int width, int height) {
|
||||
fChannel.setPtySize(cols, rows, width, height);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.remote.core.IRemoteProcessSignalService#sendSignal(int)
|
||||
*/
|
||||
@Override
|
||||
public void sendSignal(int signal) throws RemoteConnectionException {
|
||||
if (signal >= 0 && signal <= USR2) {
|
||||
try {
|
||||
fChannel.sendSignal(signals[signal]);
|
||||
} catch (Exception e) {
|
||||
throw new RemoteConnectionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,10 +24,12 @@ import java.util.Set;
|
|||
|
||||
import org.eclipse.core.filesystem.IFileStore;
|
||||
import org.eclipse.remote.core.AbstractRemoteProcessBuilder;
|
||||
import org.eclipse.remote.core.IRemoteConnection;
|
||||
import org.eclipse.remote.core.IRemoteFileService;
|
||||
import org.eclipse.remote.core.IRemoteProcess;
|
||||
import org.eclipse.remote.core.exception.RemoteConnectionException;
|
||||
import org.eclipse.remote.internal.core.RemoteDebugOptions;
|
||||
import org.eclipse.remote.internal.core.RemoteProcess;
|
||||
import org.eclipse.remote.internal.jsch.core.messages.Messages;
|
||||
|
||||
import com.jcraft.jsch.ChannelExec;
|
||||
|
@ -39,11 +41,13 @@ public class JSchProcessBuilder extends AbstractRemoteProcessBuilder {
|
|||
private final Map<String, String> fRemoteEnv = new HashMap<String, String>();
|
||||
private final Set<Character> charSet = new HashSet<Character>();
|
||||
|
||||
private Map<String, String> fNewRemoteEnv = null;
|
||||
private ChannelExec fChannel;
|
||||
private Map<String, String> fNewRemoteEnv;
|
||||
private boolean fPreamble = true;
|
||||
|
||||
public JSchProcessBuilder(JSchConnection connection, List<String> command) {
|
||||
super(command);
|
||||
fConnection = connection;
|
||||
public JSchProcessBuilder(IRemoteConnection connection, List<String> command) {
|
||||
super(connection, command);
|
||||
fConnection = connection.getService(JSchConnection.class);
|
||||
fRemoteEnv.putAll(fConnection.getEnv());
|
||||
|
||||
// Create set of characters not to escape
|
||||
|
@ -56,7 +60,7 @@ public class JSchProcessBuilder extends AbstractRemoteProcessBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
public JSchProcessBuilder(JSchConnection connection, String... command) {
|
||||
public JSchProcessBuilder(IRemoteConnection connection, String... command) {
|
||||
this(connection, Arrays.asList(command));
|
||||
}
|
||||
|
||||
|
@ -151,14 +155,14 @@ public class JSchProcessBuilder extends AbstractRemoteProcessBuilder {
|
|||
}
|
||||
|
||||
try {
|
||||
ChannelExec exec = fConnection.getExecChannel();
|
||||
fChannel = fConnection.getExecChannel();
|
||||
String command = buildCommand(remoteCmd, env, clearEnv);
|
||||
exec.setCommand(command);
|
||||
exec.setPty((flags & ALLOCATE_PTY) == ALLOCATE_PTY);
|
||||
exec.setXForwarding((flags & FORWARD_X11) == FORWARD_X11);
|
||||
exec.connect();
|
||||
fChannel.setCommand(command);
|
||||
fChannel.setPty((flags & ALLOCATE_PTY) == ALLOCATE_PTY);
|
||||
fChannel.setXForwarding((flags & FORWARD_X11) == FORWARD_X11);
|
||||
fChannel.connect();
|
||||
RemoteDebugOptions.trace(RemoteDebugOptions.DEBUG_REMOTE_COMMANDS, "executing command: " + command); //$NON-NLS-1$
|
||||
return new JSchProcess(exec, redirectErrorStream());
|
||||
return new RemoteProcess(getRemoteConnection(), this);
|
||||
} catch (RemoteConnectionException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
} catch (JSchException e) {
|
||||
|
@ -166,24 +170,34 @@ public class JSchProcessBuilder extends AbstractRemoteProcessBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
public ChannelExec getChannel() {
|
||||
return fChannel;
|
||||
}
|
||||
|
||||
public void setPreamble(boolean enable) {
|
||||
fPreamble = enable;
|
||||
}
|
||||
|
||||
private String buildCommand(String cmd, List<String> environment, boolean clearEnv) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
if (directory() != null) {
|
||||
sb.append("cd " + charEscapify(directory().toURI().getPath(), charSet) + " && "); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
if (clearEnv) {
|
||||
sb.append("env -i"); //$NON-NLS-1$
|
||||
for (String env : environment) {
|
||||
sb.append(" \"" + env + "\""); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
if (fPreamble) {
|
||||
if (directory() != null) {
|
||||
sb.append("cd " + charEscapify(directory().toURI().getPath(), charSet) + " && "); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
sb.append(" "); //$NON-NLS-1$
|
||||
} else {
|
||||
for (String env : environment) {
|
||||
sb.append("export \"" + env + "\"; "); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
if (clearEnv) {
|
||||
sb.append("env -i"); //$NON-NLS-1$
|
||||
for (String env : environment) {
|
||||
sb.append(" \"" + env + "\""); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
sb.append(" "); //$NON-NLS-1$
|
||||
} else {
|
||||
for (String env : environment) {
|
||||
sb.append("export \"" + env + "\"; "); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append(cmd);
|
||||
if (fConnection.useLoginShell()) {
|
||||
if (fPreamble && fConnection.useLoginShell()) {
|
||||
sb.insert(0, "/bin/bash -l -c '"); //$NON-NLS-1$
|
||||
sb.append("'"); //$NON-NLS-1$
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue