1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-29 20:05:35 +02:00

[404967] More changes to implement filestore and processbuilder

functionality.

Signed-off-by: Greg Watson <g.watson@computer.org>
This commit is contained in:
Greg Watson 2013-08-21 13:35:26 -04:00
parent 631bc231ad
commit c3bf5ecaa5
23 changed files with 1108 additions and 260 deletions

View file

@ -8,8 +8,7 @@ Bundle-Vendor: %pluginProvider
Require-Bundle: org.eclipse.core.runtime, Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.filesystem, org.eclipse.core.filesystem,
org.eclipse.core.resources, org.eclipse.core.resources,
org.eclipse.core.variables, org.eclipse.core.variables
org.eclipse.cdt.core
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
Export-Package: org.eclipse.internal.remote.core;x-friends:="org.eclipse.remote.ui", Export-Package: org.eclipse.internal.remote.core;x-friends:="org.eclipse.remote.ui",
org.eclipse.internal.remote.core.messages;x-internal:=true, org.eclipse.internal.remote.core.messages;x-internal:=true,

View file

@ -3,6 +3,7 @@
<plugin> <plugin>
<extension-point id="remoteServices" name="Remote Services" schema="schema/remoteServices.exsd"/> <extension-point id="remoteServices" name="Remote Services" schema="schema/remoteServices.exsd"/>
<extension-point id="remoteResources" name="Remote Resources" schema="schema/remoteResources.exsd"/> <extension-point id="remoteResources" name="Remote Resources" schema="schema/remoteResources.exsd"/>
<extension-point id="processFactory" name="Process Factory" schema="schema/processFactory.exsd"/>
<extension <extension
point="org.eclipse.remote.core.remoteServices"> point="org.eclipse.remote.core.remoteServices">
<remoteServices <remoteServices

View file

@ -0,0 +1,98 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Schema file written by PDE -->
<schema targetNamespace="org.eclipse.remote.core" xmlns="http://www.w3.org/2001/XMLSchema">
<annotation>
<appInfo>
<meta.schema plugin="org.eclipse.remote.core" id="processFactory" name="Process Factory"/>
</appInfo>
<documentation>
This extension point allows an alternate implementation of the java.lang.Runtime#exec() methods to be supplied. This is useful because the Java runtime provides limited support for controlling external processes.
</documentation>
</annotation>
<element name="extension">
<annotation>
<appInfo>
<meta.element />
</appInfo>
</annotation>
<complexType>
<sequence>
<element ref="processFactory"/>
</sequence>
<attribute name="point" type="string" use="required">
<annotation>
<documentation>
</documentation>
</annotation>
</attribute>
<attribute name="id" type="string">
<annotation>
<documentation>
</documentation>
</annotation>
</attribute>
<attribute name="name" type="string">
<annotation>
<documentation>
</documentation>
<appInfo>
<meta.attribute translatable="true"/>
</appInfo>
</annotation>
</attribute>
</complexType>
</element>
<element name="processFactory">
<complexType>
<attribute name="class" type="string" use="required">
<annotation>
<documentation>
the fully qualified name of a class that implements &lt;code&gt;org.eclipse.remote.core.IProcessFactory&lt;/code&gt;
</documentation>
<appInfo>
<meta.attribute kind="java" basedOn=":org.eclipse.remote.core.IProcessFactory"/>
</appInfo>
</annotation>
</attribute>
</complexType>
</element>
<annotation>
<appInfo>
<meta.section type="examples"/>
</appInfo>
<documentation>
&lt;pre&gt;
&lt;extension point=&quot;org.eclipse.remote.core.processFactory&quot;&gt;
&lt;processFactory class=&quot;MyProcessFactoryClass&quot;/&gt;
&lt;/extension&gt;
&lt;/pre&gt;
</documentation>
</annotation>
<annotation>
<appInfo>
<meta.section type="apiinfo"/>
</appInfo>
<documentation>
The value of the class attribute must implement the interface &lt;code&gt;org.eclipse.remote.core.IProcessFactory&lt;/code&gt;
</documentation>
</annotation>
<annotation>
<appInfo>
<meta.section type="copyright"/>
</appInfo>
<documentation>
Copyright (c) 2013 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
</documentation>
</annotation>
</schema>

View file

@ -10,6 +10,7 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.internal.remote.core.services.local; package org.eclipse.internal.remote.core.services.local;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
@ -17,24 +18,33 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.eclipse.cdt.utils.spawner.ProcessFactory;
import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.internal.remote.core.RemoteCorePlugin;
import org.eclipse.remote.core.AbstractRemoteProcessBuilder; import org.eclipse.remote.core.AbstractRemoteProcessBuilder;
import org.eclipse.remote.core.IProcessFactory;
import org.eclipse.remote.core.IRemoteConnection; import org.eclipse.remote.core.IRemoteConnection;
import org.eclipse.remote.core.IRemoteProcess; import org.eclipse.remote.core.IRemoteProcess;
public class LocalProcessBuilder extends AbstractRemoteProcessBuilder { public class LocalProcessBuilder extends AbstractRemoteProcessBuilder {
private final ProcessFactory localProcessBuilder; private static final String EXTENSION_POINT_ID = "processFactory"; //$NON-NLS-1$
private final Map<String, String> remoteEnv = new HashMap<String, String>(); private static final String ATTR_CLASS = "class"; //$NON-NLS-1$
private final IProcessFactory fProcessFactory;
private final Map<String, String> fRemoteEnv = new HashMap<String, String>();
public LocalProcessBuilder(IRemoteConnection conn, List<String> command) { public LocalProcessBuilder(IRemoteConnection conn, List<String> command) {
super(conn, command); super(conn, command);
remoteEnv.putAll(System.getenv()); fRemoteEnv.putAll(System.getenv());
localProcessBuilder = ProcessFactory.getFactory(); fProcessFactory = getProcessFactory();
} }
public LocalProcessBuilder(IRemoteConnection conn, String... command) { public LocalProcessBuilder(IRemoteConnection conn, String... command) {
@ -64,7 +74,7 @@ public class LocalProcessBuilder extends AbstractRemoteProcessBuilder {
*/ */
@Override @Override
public Map<String, String> environment() { public Map<String, String> environment() {
return remoteEnv; return fRemoteEnv;
} }
/* /*
@ -95,14 +105,69 @@ public class LocalProcessBuilder extends AbstractRemoteProcessBuilder {
Process localProc; Process localProc;
if (directory() != null) { if (directory() != null) {
try { try {
localProc = localProcessBuilder.exec(commandArray, environmentArray, localProc = fProcessFactory.exec(commandArray, environmentArray,
directory().toLocalFile(EFS.NONE, new NullProgressMonitor())); directory().toLocalFile(EFS.NONE, new NullProgressMonitor()));
} catch (CoreException e) { } catch (CoreException e) {
throw new IOException(e.getMessage()); throw new IOException(e.getMessage());
} }
} else { } else {
localProc = localProcessBuilder.exec(commandArray, environmentArray); localProc = fProcessFactory.exec(commandArray, environmentArray);
} }
return new LocalProcess(localProc, redirectErrorStream()); return new LocalProcess(localProc, redirectErrorStream());
} }
private IProcessFactory getProcessFactory() {
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint extensionPoint = registry.getExtensionPoint(RemoteCorePlugin.getUniqueIdentifier(), EXTENSION_POINT_ID);
IProcessFactory processFactory = null;
for (IExtension ext : extensionPoint.getExtensions()) {
final IConfigurationElement[] elements = ext.getConfigurationElements();
for (IConfigurationElement ce : elements) {
try {
processFactory = (IProcessFactory) ce.createExecutableExtension(ATTR_CLASS);
} catch (CoreException e) {
// Use default factory
}
}
}
if (processFactory == null) {
processFactory = new IProcessFactory() {
@Override
public Process exec(String cmd) throws IOException {
return Runtime.getRuntime().exec(cmd);
}
@Override
public Process exec(String[] cmdarray) throws IOException {
return Runtime.getRuntime().exec(cmdarray);
}
@Override
public Process exec(String[] cmdarray, String[] envp) throws IOException {
return Runtime.getRuntime().exec(cmdarray, envp);
}
@Override
public Process exec(String cmd, String[] envp) throws IOException {
return Runtime.getRuntime().exec(cmd, envp);
}
@Override
public Process exec(String cmd, String[] envp, File dir) throws IOException {
return Runtime.getRuntime().exec(cmd, envp, dir);
}
@Override
public Process exec(String[] cmdarray, String[] envp, File dir) throws IOException {
return Runtime.getRuntime().exec(cmdarray, envp, dir);
}
};
}
return processFactory;
}
} }

View file

@ -0,0 +1,32 @@
/*******************************************************************************
* Copyright (c) 2013 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 - Initial API and implementation
*******************************************************************************/
package org.eclipse.remote.core;
import java.io.File;
import java.io.IOException;
/**
* Abstraction of the java.lang.Runtime exec() methods to allow different implementations to be supplied.
*/
public interface IProcessFactory {
public Process exec(String cmd) throws IOException;
public Process exec(String[] cmdarray) throws IOException;
public Process exec(String[] cmdarray, String[] envp) throws IOException;
public Process exec(String cmd, String[] envp) throws IOException;
public Process exec(String cmd, String[] envp, File dir) throws IOException;
public Process exec(String cmdarray[], String[] envp, File dir) throws IOException;
}

View file

@ -11,14 +11,17 @@
package org.eclipse.internal.remote.jsch.core; package org.eclipse.internal.remote.jsch.core;
import java.net.PasswordAuthentication; import java.net.PasswordAuthentication;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.internal.remote.jsch.core.commands.ExecCommand;
import org.eclipse.internal.remote.jsch.core.messages.Messages; import org.eclipse.internal.remote.jsch.core.messages.Messages;
import org.eclipse.jsch.core.IJSchLocation; import org.eclipse.jsch.core.IJSchLocation;
import org.eclipse.jsch.core.IJSchService; import org.eclipse.jsch.core.IJSchService;
@ -31,6 +34,7 @@ import org.eclipse.remote.core.exception.AddressInUseException;
import org.eclipse.remote.core.exception.RemoteConnectionException; import org.eclipse.remote.core.exception.RemoteConnectionException;
import org.eclipse.remote.core.exception.UnableToForwardPortException; import org.eclipse.remote.core.exception.UnableToForwardPortException;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException; import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session; import com.jcraft.jsch.Session;
@ -43,19 +47,20 @@ public class JSchConnection implements IRemoteConnection {
private static int DEFAULT_PORT = 22; private static int DEFAULT_PORT = 22;
private String fWorkingDir; private String fWorkingDir;
private Map<String, String> fEnv; private final Map<String, String> fEnv = new HashMap<String, String>();
private Map<String, String> fProperties; private final Map<String, String> fProperties = new HashMap<String, String>();
private String fHost; private String fHost;
private String fUsername; private String fUsername;
private String fPassword; private String fPassword;
private int fPort = DEFAULT_PORT; private int fPort = DEFAULT_PORT;
private Session fSession;
private String fConnName; private String fConnName;
private boolean fIsOpen; private boolean fIsOpen;
private IUserAuthenticator fAuthenticator;
private final IJSchService fJSchService; private final IJSchService fJSchService;
private final IRemoteServices fRemoteServices; private final IRemoteServices fRemoteServices;
private final ListenerList fListeners = new ListenerList(); private final ListenerList fListeners = new ListenerList();
private final List<Session> fSessions = new ArrayList<Session>();
public JSchConnection(String name, IRemoteServices services) { public JSchConnection(String name, IRemoteServices services) {
fConnName = name; fConnName = name;
@ -92,7 +97,12 @@ public class JSchConnection implements IRemoteConnection {
*/ */
public synchronized void close() { public synchronized void close() {
if (isOpen()) { if (isOpen()) {
fSession.disconnect(); for (Session session : fSessions) {
if (session.isConnected()) {
session.disconnect();
}
}
fIsOpen = false;
fireConnectionChangeEvent(this, IRemoteConnectionChangeEvent.CONNECTION_CLOSED); fireConnectionChangeEvent(this, IRemoteConnectionChangeEvent.CONNECTION_CLOSED);
} }
} }
@ -127,7 +137,7 @@ public class JSchConnection implements IRemoteConnection {
throw new RemoteConnectionException(Messages.JSchConnection_connectionNotOpen); throw new RemoteConnectionException(Messages.JSchConnection_connectionNotOpen);
} }
try { try {
fSession.setPortForwardingL(localPort, fwdAddress, fwdPort); fSessions.get(0).setPortForwardingL(localPort, fwdAddress, fwdPort);
} catch (JSchException e) { } catch (JSchException e) {
throw new RemoteConnectionException(e.getMessage()); throw new RemoteConnectionException(e.getMessage());
} }
@ -178,7 +188,7 @@ public class JSchConnection implements IRemoteConnection {
throw new RemoteConnectionException(Messages.JSchConnection_connectionNotOpen); throw new RemoteConnectionException(Messages.JSchConnection_connectionNotOpen);
} }
try { try {
fSession.setPortForwardingR(remotePort, fwdAddress, fwdPort); fSessions.get(0).setPortForwardingR(remotePort, fwdAddress, fwdPort);
} catch (JSchException e) { } catch (JSchException e) {
throw new RemoteConnectionException(e.getMessage()); throw new RemoteConnectionException(e.getMessage());
} }
@ -233,9 +243,6 @@ public class JSchConnection implements IRemoteConnection {
* @see org.eclipse.remote.core.IRemoteConnection#getAttributes() * @see org.eclipse.remote.core.IRemoteConnection#getAttributes()
*/ */
public Map<String, String> getAttributes() { public Map<String, String> getAttributes() {
if (fProperties == null) {
fProperties = new HashMap<String, String>();
}
return Collections.unmodifiableMap(fProperties); return Collections.unmodifiableMap(fProperties);
} }
@ -245,12 +252,22 @@ public class JSchConnection implements IRemoteConnection {
* @see org.eclipse.remote.core.IRemoteConnection#getEnv() * @see org.eclipse.remote.core.IRemoteConnection#getEnv()
*/ */
public Map<String, String> getEnv() { public Map<String, String> getEnv() {
if (fEnv == null) {
fEnv = new HashMap<String, String>();
}
return Collections.unmodifiableMap(fEnv); return Collections.unmodifiableMap(fEnv);
} }
private void loadEnv(IProgressMonitor monitor) throws RemoteConnectionException {
SubMonitor subMon = SubMonitor.convert(monitor, 10);
ExecCommand exec = new ExecCommand(this);
String env = exec.setCommand("printenv").getResult(subMon.newChild(10)).trim(); //$NON-NLS-1$
String[] vars = env.split("\n"); //$NON-NLS-1$
for (String var : vars) {
String[] kv = var.split("="); //$NON-NLS-1$
if (kv.length == 2) {
fEnv.put(kv[0], kv[1]);
}
}
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
@ -328,14 +345,49 @@ public class JSchConnection implements IRemoteConnection {
* <dl> * <dl>
* *
*/ */
private Map<String, String> getProperties() { private void loadProperties(IProgressMonitor monitor) throws RemoteConnectionException {
if (fProperties == null) { SubMonitor subMon = SubMonitor.convert(monitor, 100);
fProperties = new HashMap<String, String>(); fProperties.put(FILE_SEPARATOR_PROPERTY, "/"); //$NON-NLS-1$
fProperties.put(FILE_SEPARATOR_PROPERTY, "/"); //$NON-NLS-1$ fProperties.put(PATH_SEPARATOR_PROPERTY, ":"); //$NON-NLS-1$
fProperties.put(PATH_SEPARATOR_PROPERTY, ":"); //$NON-NLS-1$ fProperties.put(LINE_SEPARATOR_PROPERTY, "\n"); //$NON-NLS-1$
fProperties.put(LINE_SEPARATOR_PROPERTY, "\n"); //$NON-NLS-1$ fProperties.put(USER_HOME_PROPERTY, getPwd());
ExecCommand exec = new ExecCommand(this);
String osVersion;
String osArch;
String osName = exec.setCommand("uname").getResult(subMon.newChild(10)).trim(); //$NON-NLS-1$
if (osName.equalsIgnoreCase("Linux")) { //$NON-NLS-1$
osArch = exec.setCommand("uname -m").getResult(subMon.newChild(10)).trim(); //$NON-NLS-1$
osVersion = exec.setCommand("uname -r").getResult(subMon.newChild(10)).trim(); //$NON-NLS-1$
} else if (osName.equalsIgnoreCase("Darwin")) { //$NON-NLS-1$
osName = exec.setCommand("sw_vers -productName").getResult(subMon.newChild(10)).trim(); //$NON-NLS-1$
osVersion = exec.setCommand("sw_vers -productVersion").getResult(subMon.newChild(10)).trim(); //$NON-NLS-1$
osArch = exec.setCommand("uname -m").getResult(subMon.newChild(10)).trim(); //$NON-NLS-1$
if (osArch.equalsIgnoreCase("i386")) { //$NON-NLS-1$
String opt = exec.setCommand("sysctl -n hw.optional.x86_64").getResult(subMon.newChild(10)).trim(); //$NON-NLS-1$
if (opt.equals("1")) { //$NON-NLS-1$
osArch = "x86_64"; //$NON-NLS-1$
}
}
} else if (osName.equalsIgnoreCase("AIX")) { //$NON-NLS-1$
osArch = exec.setCommand("uname -p").getResult(subMon.newChild(10)).trim(); //$NON-NLS-1$
osVersion = exec.setCommand("oslevel").getResult(subMon.newChild(10)).trim(); //$NON-NLS-1$
if (osArch.equalsIgnoreCase("powerpc")) { //$NON-NLS-1$
/* Make the architecture match what Linux produces: either ppc or ppc64 */
osArch = "ppc"; //$NON-NLS-1$
/* Get Kernel type either 32-bit or 64-bit */
String opt = exec.setCommand("prtconf -k").getResult(subMon.newChild(10)).trim(); //$NON-NLS-1$
if (opt.indexOf("64-bit") > 0) { //$NON-NLS-1$
osArch += "64"; //$NON-NLS-1$
}
}
} else {
osVersion = "unknown"; //$NON-NLS-1$
osArch = "unknown"; //$NON-NLS-1$
} }
return fProperties; fProperties.put(OS_NAME_PROPERTY, osName);
fProperties.put(OS_VERSION_PROPERTY, osVersion);
fProperties.put(OS_ARCH_PROPERTY, osArch);
} }
/* /*
@ -344,7 +396,7 @@ public class JSchConnection implements IRemoteConnection {
* @see org.eclipse.remote.core.IRemoteConnection#getProperty(java.lang.String ) * @see org.eclipse.remote.core.IRemoteConnection#getProperty(java.lang.String )
*/ */
public String getProperty(String key) { public String getProperty(String key) {
return getProperties().get(key); return fProperties.get(key);
} }
/** /**
@ -407,51 +459,17 @@ public class JSchConnection implements IRemoteConnection {
* @see org.eclipse.remote.core.IRemoteConnection#open() * @see org.eclipse.remote.core.IRemoteConnection#open()
*/ */
public void open(IProgressMonitor monitor) throws RemoteConnectionException { public void open(IProgressMonitor monitor) throws RemoteConnectionException {
if (!isOpen()) { open(null, monitor);
checkIsConfigured();
SubMonitor progress = SubMonitor.convert(monitor, 10);
try {
fSession = fJSchService.createSession(fHost, fPort, fUsername);
fSession.setPassword(fPassword);
fJSchService.connect(fSession, 0, progress.newChild(10));
} catch (JSchException e) {
throw new RemoteConnectionException(e.getMessage());
}
fIsOpen = true;
fireConnectionChangeEvent(this, IRemoteConnectionChangeEvent.CONNECTION_OPENED);
}
} }
private ChannelSftp fSftpChannel; private Session newSession(final IUserAuthenticator authenticator, IProgressMonitor monitor) throws RemoteConnectionException {
SubMonitor progress = SubMonitor.convert(monitor, 10);
public ChannelSftp getSftpChannel() throws RemoteConnectionException {
try { try {
if (fSftpChannel == null) { final IJSchLocation location = fJSchService.getLocation(fUsername, fHost, fPort);
fSftpChannel = (ChannelSftp) fSession.openChannel("sftp"); //$NON-NLS-1$ location.setPassword(fPassword);
} UserInfo userInfo = null;
if (!fSftpChannel.isConnected()) { if (authenticator != null) {
fSftpChannel.connect(); userInfo = new UserInfo() {
}
} catch (JSchException e) {
throw new RemoteConnectionException(e.getMessage());
}
return fSftpChannel;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnection#open(org.eclipse.remote.core.IUserAuthenticator,
* org.eclipse.core.runtime.IProgressMonitor)
*/
public void open(final IUserAuthenticator authenticator, IProgressMonitor monitor) throws RemoteConnectionException {
if (!isOpen()) {
checkIsConfigured();
SubMonitor progress = SubMonitor.convert(monitor, 10);
try {
final IJSchLocation location = fJSchService.getLocation(fUsername, fHost, fPort);
location.setPassword(fPassword);
fSession = fJSchService.createSession(location, new UserInfo() {
public String getPassphrase() { public String getPassphrase() {
return null; return null;
@ -485,14 +503,136 @@ public class JSchConnection implements IRemoteConnection {
authenticator.prompt(IUserAuthenticator.INFORMATION, Messages.AuthInfo_Authentication_message, message, authenticator.prompt(IUserAuthenticator.INFORMATION, Messages.AuthInfo_Authentication_message, message,
new int[] { IUserAuthenticator.OK }, IUserAuthenticator.OK); new int[] { IUserAuthenticator.OK }, IUserAuthenticator.OK);
} }
}); };
fJSchService.connect(fSession, 0, progress.newChild(10)); }
} catch (JSchException e) { Session session = fJSchService.createSession(location, userInfo);
session.setPassword(fPassword);
fJSchService.connect(session, 0, progress.newChild(10));
if (!progress.isCanceled()) {
fSessions.add(session);
fAuthenticator = authenticator;
return session;
}
return null;
} catch (JSchException e) {
throw new RemoteConnectionException(e.getMessage());
}
}
private ChannelSftp fSftpChannel;
private ChannelExec fExecChannel;
/**
* Open an sftp channel to the remote host. Always use the second session if available.
*
* @return sftp channel or null if the progress monitor was cancelled
* @throws RemoteConnectionException
* if a channel could not be opened
*/
public ChannelSftp getSftpChannel() throws RemoteConnectionException {
Session session = fSessions.get(0);
if (fSessions.size() > 1) {
session = fSessions.get(1);
}
ChannelSftp channel = openSftpChannel(session);
if (channel == null) {
throw new RemoteConnectionException("Unable to open sftp channel: check sftp is enabled on remote host");
}
return channel;
}
private ChannelSftp openSftpChannel(Session session) throws RemoteConnectionException {
try {
ChannelSftp channel = (ChannelSftp) session.openChannel("sftp"); //$NON-NLS-1$
channel.connect();
return channel;
} catch (JSchException e) {
if (!e.getMessage().contains("channel is not opened")) { //$NON-NLS-1$
throw new RemoteConnectionException(e.getMessage()); throw new RemoteConnectionException(e.getMessage());
} }
fIsOpen = true;
fireConnectionChangeEvent(this, IRemoteConnectionChangeEvent.CONNECTION_OPENED);
} }
return null;
}
private ChannelExec openExecChannel(Session[] sessions) throws RemoteConnectionException {
for (Session session : sessions) {
try {
ChannelExec channel = (ChannelExec) session.openChannel("exec"); //$NON-NLS-1$
if (!channel.isConnected()) {
channel.connect();
return channel;
}
} catch (JSchException e) {
if (!e.getMessage().contains("channel is not opened")) { //$NON-NLS-1$
throw new RemoteConnectionException(e.getMessage());
}
}
}
return null;
}
/**
* Open an exec channel to the remote host.
*
* @return exec channel or null if the progress monitor was cancelled
*
* @throws RemoteConnectionException
* if a channel could not be opened
*/
public ChannelExec getExecChannel() throws RemoteConnectionException {
try {
return (ChannelExec) fSessions.get(0).openChannel("exec"); //$NON-NLS-1$
} catch (JSchException e) {
throw new RemoteConnectionException(e.getMessage());
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnection#open(org.eclipse.remote.core.IUserAuthenticator,
* org.eclipse.core.runtime.IProgressMonitor)
*/
public void open(final IUserAuthenticator authenticator, IProgressMonitor monitor) throws RemoteConnectionException {
if (!isOpen()) {
checkIsConfigured();
SubMonitor subMon = SubMonitor.convert(monitor, 30);
Session session = newSession(authenticator, subMon.newChild(10));
if (!subMon.isCanceled()) {
if (!checkConfiguration(session, subMon.newChild(20))) {
newSession(authenticator, subMon.newChild(10));
loadEnv(subMon.newChild(10));
}
loadProperties(subMon.newChild(10));
fIsOpen = true;
fireConnectionChangeEvent(this, IRemoteConnectionChangeEvent.CONNECTION_OPENED);
}
}
}
private boolean checkConfiguration(Session session, IProgressMonitor monitor) throws RemoteConnectionException {
SubMonitor subMon = SubMonitor.convert(monitor, 10);
/*
* First, check if sftp is supported at all. This is required for EFS, so throw exception if not supported.
*/
ChannelSftp sftp = openSftpChannel(session);
if (sftp == null) {
throw new RemoteConnectionException(
"Remote host does not support sftp. Remote functionality requires sftp to be enabled");
}
/*
* While sftp channel is open, try opening an exec channel. If it doesn't succeed, then MaxSession is < 2 so we need at
* least one additional session.
*/
try {
loadEnv(subMon.newChild(10));
} catch (RemoteConnectionException e) {
if (e.getMessage().contains("channel is not opened")) {
return false;
}
}
sftp.disconnect();
return true;
} }
/* /*
@ -515,7 +655,7 @@ public class JSchConnection implements IRemoteConnection {
throw new RemoteConnectionException(Messages.JSchConnection_connectionNotOpen); throw new RemoteConnectionException(Messages.JSchConnection_connectionNotOpen);
} }
try { try {
fSession.delPortForwardingL(port); fSessions.get(0).delPortForwardingL(port);
} catch (JSchException e) { } catch (JSchException e) {
throw new RemoteConnectionException(e.getMessage()); throw new RemoteConnectionException(e.getMessage());
} }
@ -531,7 +671,7 @@ public class JSchConnection implements IRemoteConnection {
throw new RemoteConnectionException(Messages.JSchConnection_connectionNotOpen); throw new RemoteConnectionException(Messages.JSchConnection_connectionNotOpen);
} }
try { try {
fSession.delPortForwardingR(port); fSessions.get(0).delPortForwardingR(port);
} catch (JSchException e) { } catch (JSchException e) {
throw new RemoteConnectionException(e.getMessage()); throw new RemoteConnectionException(e.getMessage());
} }
@ -625,8 +765,4 @@ public class JSchConnection implements IRemoteConnection {
} }
return str + "]"; //$NON-NLS-1$ return str + "]"; //$NON-NLS-1$
} }
public Session getSession() {
return fSession;
}
} }

View file

@ -11,6 +11,7 @@
package org.eclipse.internal.remote.jsch.core; package org.eclipse.internal.remote.jsch.core;
import java.net.URI; import java.net.URI;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -22,7 +23,8 @@ import org.eclipse.remote.core.exception.RemoteConnectionException;
public class JSchConnectionManager implements IRemoteConnectionManager { public class JSchConnectionManager implements IRemoteConnectionManager {
private final IRemoteServices fRemoteServices; private final IRemoteServices fRemoteServices;
private final Map<String, IRemoteConnection> fConnections = new HashMap<String, IRemoteConnection>(); private final Map<String, IRemoteConnection> fConnections = Collections
.synchronizedMap(new HashMap<String, IRemoteConnection>());
/** /**
* @since 4.0 * @since 4.0
@ -103,6 +105,6 @@ public class JSchConnectionManager implements IRemoteConnectionManager {
if (conn.isOpen()) { if (conn.isOpen()) {
throw new RemoteConnectionException(Messages.JSchConnectionManager_cannotRemoveOpenConnection); throw new RemoteConnectionException(Messages.JSchConnectionManager_cannotRemoveOpenConnection);
} }
fConnections.remove(conn); fConnections.remove(conn.getName());
} }
} }

View file

@ -25,13 +25,20 @@ package org.eclipse.internal.remote.jsch.core;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.provider.FileSystem; import org.eclipse.core.filesystem.provider.FileSystem;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import com.jcraft.jsch.ChannelSftp;
public class JSchFileSystem extends FileSystem { public class JSchFileSystem extends FileSystem {
private final Map<String, ChannelSftp> fChannels = new HashMap<String, ChannelSftp>();
/** /**
* Return the connection name encoded in the URI. * Return the connection name encoded in the URI.
* *
@ -125,4 +132,21 @@ public class JSchFileSystem extends FileSystem {
public IFileStore getStore(IPath path) { public IFileStore getStore(IPath path) {
return null; return null;
} }
/**
* Get an sftp channel for the connection being used for the file stores. We only want one channel per connection so that all
* file stores using that connection also use the same channel.
*
* @return sftp channel or null if monitor is cancelled
* @throws RemoteConnectionException
* if a channel can't be obtained
*/
public synchronized ChannelSftp getChannel(JSchConnection connection) throws RemoteConnectionException {
ChannelSftp channel = fChannels.get(connection.getName());
if (channel == null) {
channel = connection.getSftpChannel();
fChannels.put(connection.getName(), channel);
}
return channel;
}
} }

View file

@ -18,10 +18,13 @@ import java.io.PipedOutputStream;
import org.eclipse.remote.core.AbstractRemoteProcess; import org.eclipse.remote.core.AbstractRemoteProcess;
import com.jcraft.jsch.ChannelExec;
public class JSchProcess extends AbstractRemoteProcess { public class JSchProcess extends AbstractRemoteProcess {
private static int WAIT_TIMEOUT = 1000;
private static int refCount = 0; private static int refCount = 0;
private final Process fRemoteProcess; private final ChannelExec fChannel;
private InputStream fProcStdout; private InputStream fProcStdout;
private InputStream fProcStderr; private InputStream fProcStderr;
private Thread fStdoutReader; private Thread fStdoutReader;
@ -76,8 +79,8 @@ public class JSchProcess extends AbstractRemoteProcess {
} }
} }
public JSchProcess(Process proc, boolean merge) throws IOException { public JSchProcess(ChannelExec channel, boolean merge) throws IOException {
fRemoteProcess = proc; fChannel = channel;
if (merge) { if (merge) {
PipedOutputStream pipedOutput = new PipedOutputStream(); PipedOutputStream pipedOutput = new PipedOutputStream();
@ -85,14 +88,14 @@ public class JSchProcess extends AbstractRemoteProcess {
fProcStdout = new PipedInputStream(pipedOutput); fProcStdout = new PipedInputStream(pipedOutput);
fProcStderr = new NullInputStream(); fProcStderr = new NullInputStream();
fStderrReader = new Thread(new ProcReader(proc.getErrorStream(), pipedOutput)); fStderrReader = new Thread(new ProcReader(channel.getErrStream(), pipedOutput));
fStdoutReader = new Thread(new ProcReader(proc.getInputStream(), pipedOutput)); fStdoutReader = new Thread(new ProcReader(channel.getInputStream(), pipedOutput));
fStderrReader.start(); fStderrReader.start();
fStdoutReader.start(); fStdoutReader.start();
} else { } else {
fProcStdout = proc.getInputStream(); fProcStdout = channel.getInputStream();
fProcStderr = proc.getErrorStream(); fProcStderr = channel.getErrStream();
} }
} }
@ -104,7 +107,7 @@ public class JSchProcess extends AbstractRemoteProcess {
*/ */
@Override @Override
public void destroy() { public void destroy() {
fRemoteProcess.destroy(); fChannel.disconnect();
} }
/* /*
@ -114,7 +117,7 @@ public class JSchProcess extends AbstractRemoteProcess {
*/ */
@Override @Override
public int exitValue() { public int exitValue() {
return fRemoteProcess.exitValue(); return fChannel.getExitStatus();
} }
/* /*
@ -144,7 +147,11 @@ public class JSchProcess extends AbstractRemoteProcess {
*/ */
@Override @Override
public OutputStream getOutputStream() { public OutputStream getOutputStream() {
return fRemoteProcess.getOutputStream(); try {
return fChannel.getOutputStream();
} catch (IOException e) {
return null;
}
} }
/* /*
@ -154,7 +161,10 @@ public class JSchProcess extends AbstractRemoteProcess {
*/ */
@Override @Override
public int waitFor() throws InterruptedException { public int waitFor() throws InterruptedException {
return fRemoteProcess.waitFor(); while (!isCompleted()) {
Thread.sleep(WAIT_TIMEOUT);
}
return exitValue();
} }
/* /*
@ -164,11 +174,6 @@ public class JSchProcess extends AbstractRemoteProcess {
*/ */
@Override @Override
public boolean isCompleted() { public boolean isCompleted() {
try { return !fChannel.isClosed();
fRemoteProcess.exitValue();
return true;
} catch (IllegalThreadStateException e) {
return false;
}
} }
} }

View file

@ -11,7 +11,6 @@
package org.eclipse.internal.remote.jsch.core; package org.eclipse.internal.remote.jsch.core;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.text.CharacterIterator; import java.text.CharacterIterator;
import java.text.StringCharacterIterator; import java.text.StringCharacterIterator;
import java.util.ArrayList; import java.util.ArrayList;
@ -26,8 +25,9 @@ import java.util.Set;
import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.remote.core.AbstractRemoteProcessBuilder; import org.eclipse.remote.core.AbstractRemoteProcessBuilder;
import org.eclipse.remote.core.IRemoteProcess; import org.eclipse.remote.core.IRemoteProcess;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import com.jcraft.jsch.ChannelShell; import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException; import com.jcraft.jsch.JSchException;
public class JSchProcessBuilder extends AbstractRemoteProcessBuilder { public class JSchProcessBuilder extends AbstractRemoteProcessBuilder {
@ -133,10 +133,10 @@ public class JSchProcessBuilder extends AbstractRemoteProcessBuilder {
* list. * list.
*/ */
List<String> env = new ArrayList<String>(); final List<String> env = new ArrayList<String>();
boolean clearEnv = false;
if (fNewRemoteEnv != null) { if (fNewRemoteEnv != null) {
boolean clearEnv = false;
/* /*
* See if any of the existing variables have been removed * See if any of the existing variables have been removed
@ -168,20 +168,35 @@ public class JSchProcessBuilder extends AbstractRemoteProcessBuilder {
} }
} }
ChannelShell shell;
try { try {
shell = (ChannelShell) fConnection.getSession().openChannel("shell"); ChannelExec command = fConnection.getExecChannel();
shell.connect(); command.setCommand(buildCommand(remoteCmd, env, clearEnv));
OutputStream shellInput = shell.getOutputStream(); command.setPty((flags & ALLOCATE_PTY) == ALLOCATE_PTY);
command.setXForwarding((flags & FORWARD_X11) == FORWARD_X11);
command.connect();
return new JSchProcess(command, redirectErrorStream());
} catch (RemoteConnectionException e) {
throw new IOException(e.getMessage());
} catch (JSchException e) { } catch (JSchException e) {
// TODO Auto-generated catch block throw new IOException(e.getMessage());
e.printStackTrace();
} }
}
// script.setAllocateTerminal((flags & ALLOCATE_PTY) == ALLOCATE_PTY); private String buildCommand(String cmd, List<String> environment, boolean clearEnv) {
// script.setForwardX11((flags & FORWARD_X11) == FORWARD_X11); StringBuffer sb = new StringBuffer();
if (clearEnv) {
return null; 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);
return sb.toString();
} }
private String charEscapify(String inputString, Set<Character> charSet) { private String charEscapify(String inputString, Set<Character> charSet) {

View file

@ -0,0 +1,19 @@
/*******************************************************************************
* Copyright (c) 2013 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.internal.remote.jsch.core;
import com.jcraft.jsch.ChannelExec;
public class JSchUtils {
public static String execWithOutput(ChannelExec channel, String command) {
return null;
}
}

View file

@ -31,12 +31,19 @@ import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.internal.remote.jsch.core.commands.ChildInfosCommand; import org.eclipse.internal.remote.jsch.core.commands.ChildInfosCommand;
import org.eclipse.internal.remote.jsch.core.commands.DeleteCommand; import org.eclipse.internal.remote.jsch.core.commands.DeleteCommand;
import org.eclipse.internal.remote.jsch.core.commands.FetchInfoCommand; import org.eclipse.internal.remote.jsch.core.commands.FetchInfoCommand;
import org.eclipse.internal.remote.jsch.core.commands.GetInputStreamCommand;
import org.eclipse.internal.remote.jsch.core.commands.GetOutputStreamCommand;
import org.eclipse.internal.remote.jsch.core.commands.MkdirCommand; import org.eclipse.internal.remote.jsch.core.commands.MkdirCommand;
import org.eclipse.internal.remote.jsch.core.commands.PutInfoCommand;
import org.eclipse.internal.remote.jsch.core.messages.Messages;
import org.eclipse.osgi.util.NLS; import org.eclipse.osgi.util.NLS;
import org.eclipse.remote.core.IRemoteConnection; import org.eclipse.remote.core.IRemoteConnection;
import org.eclipse.remote.core.IRemoteConnectionManager; import org.eclipse.remote.core.IRemoteConnectionManager;
import org.eclipse.remote.core.IRemoteServices; import org.eclipse.remote.core.IRemoteServices;
import org.eclipse.remote.core.RemoteServices; import org.eclipse.remote.core.RemoteServices;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import com.jcraft.jsch.ChannelSftp;
public class JschFileStore extends FileStore { public class JschFileStore extends FileStore {
private static Map<String, JschFileStore> instanceMap = new HashMap<String, JschFileStore>(); private static Map<String, JschFileStore> instanceMap = new HashMap<String, JschFileStore>();
@ -86,8 +93,9 @@ public class JschFileStore extends FileStore {
*/ */
@Override @Override
public IFileInfo[] childInfos(int options, IProgressMonitor monitor) throws CoreException { public IFileInfo[] childInfos(int options, IProgressMonitor monitor) throws CoreException {
ChildInfosCommand command = new ChildInfosCommand(fConnection.getSftpChannel(), fRemotePath); SubMonitor subMon = SubMonitor.convert(monitor, 10);
return command.getResult(monitor); ChildInfosCommand command = new ChildInfosCommand(fConnection, fRemotePath);
return command.getResult(subMon.newChild(10));
} }
/* /*
@ -98,7 +106,8 @@ public class JschFileStore extends FileStore {
*/ */
@Override @Override
public String[] childNames(int options, IProgressMonitor monitor) throws CoreException { public String[] childNames(int options, IProgressMonitor monitor) throws CoreException {
IFileInfo[] infos = childInfos(options, monitor); SubMonitor subMon = SubMonitor.convert(monitor, 10);
IFileInfo[] infos = childInfos(options, subMon.newChild(10));
String[] names = new String[infos.length]; String[] names = new String[infos.length];
for (int i = 0; i < infos.length; i++) { for (int i = 0; i < infos.length; i++) {
names[i] = infos[i].getName(); names[i] = infos[i].getName();
@ -114,8 +123,12 @@ public class JschFileStore extends FileStore {
*/ */
@Override @Override
public void delete(int options, IProgressMonitor monitor) throws CoreException { public void delete(int options, IProgressMonitor monitor) throws CoreException {
DeleteCommand command = new DeleteCommand(fConnection.getSftpChannel(), fRemotePath); SubMonitor subMon = SubMonitor.convert(monitor, 20);
command.getResult(monitor); IFileInfo info = fetchInfo(EFS.NONE, subMon.newChild(10));
if (!subMon.isCanceled() && info.exists()) {
DeleteCommand command = new DeleteCommand(fConnection, fRemotePath);
command.getResult(subMon.newChild(10));
}
} }
/* /*
@ -126,8 +139,9 @@ public class JschFileStore extends FileStore {
*/ */
@Override @Override
public IFileInfo fetchInfo(int options, IProgressMonitor monitor) throws CoreException { public IFileInfo fetchInfo(int options, IProgressMonitor monitor) throws CoreException {
FetchInfoCommand command = new FetchInfoCommand(fConnection.getSftpChannel(), fRemotePath); SubMonitor subMon = SubMonitor.convert(monitor, 10);
return command.getResult(monitor); FetchInfoCommand command = new FetchInfoCommand(fConnection, fRemotePath);
return command.getResult(subMon.newChild(10));
} }
/* /*
@ -191,24 +205,26 @@ public class JschFileStore extends FileStore {
*/ */
@Override @Override
public IFileStore mkdir(int options, IProgressMonitor monitor) throws CoreException { public IFileStore mkdir(int options, IProgressMonitor monitor) throws CoreException {
SubMonitor progress = SubMonitor.convert(monitor, 10); SubMonitor subMon = SubMonitor.convert(monitor, 20);
IFileInfo info = fetchInfo(EFS.NONE, progress.newChild(10)); IFileInfo info = fetchInfo(EFS.NONE, subMon.newChild(10));
if (!subMon.isCanceled()) {
if (!info.exists()) { if (!info.exists()) {
if ((options & EFS.SHALLOW) == EFS.SHALLOW) { if ((options & EFS.SHALLOW) == EFS.SHALLOW) {
IFileStore parent = getParent(); IFileStore parent = getParent();
if (parent != null && !parent.fetchInfo(EFS.NONE, progress.newChild(10)).exists()) { if (parent != null && !parent.fetchInfo(EFS.NONE, subMon.newChild(10)).exists()) {
throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), EFS.ERROR_WRITE, NLS.bind( throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), EFS.ERROR_WRITE,
"The parent of directory {0} does not exist", fRemotePath.toString()), null)); NLS.bind(Messages.JschFileStore_The_parent_of_directory_does_not_exist, fRemotePath.toString()),
null));
}
} }
}
MkdirCommand command = new MkdirCommand(fConnection.getSftpChannel(), fRemotePath); MkdirCommand command = new MkdirCommand(fConnection, fRemotePath);
command.getResult(monitor); command.getResult(subMon.newChild(10));
} else if (!info.isDirectory()) { } else if (!info.isDirectory()) {
throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), EFS.ERROR_WRONG_TYPE, NLS.bind( throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), EFS.ERROR_WRONG_TYPE, NLS.bind(
"A file of name {0} already exists", fRemotePath.toString()), null)); Messages.JschFileStore_The_file_of_name_already_exists, fRemotePath.toString()), null));
}
} }
return this; return this;
@ -222,6 +238,20 @@ public class JschFileStore extends FileStore {
*/ */
@Override @Override
public InputStream openInputStream(int options, IProgressMonitor monitor) throws CoreException { public InputStream openInputStream(int options, IProgressMonitor monitor) throws CoreException {
SubMonitor subMon = SubMonitor.convert(monitor, 30);
IFileInfo info = fetchInfo(EFS.NONE, subMon.newChild(10));
if (!subMon.isCanceled()) {
if (!info.exists()) {
throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), EFS.ERROR_READ, NLS.bind(
Messages.JschFileStore_File_doesnt_exist, fRemotePath.toString()), null));
}
if (info.isDirectory()) {
throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), EFS.ERROR_WRONG_TYPE, NLS.bind(
Messages.JschFileStore_Is_a_directory, fRemotePath.toString()), null));
}
GetInputStreamCommand command = new GetInputStreamCommand(fConnection, fRemotePath);
return command.getResult(subMon.newChild(10));
}
return null; return null;
} }
@ -233,6 +263,16 @@ public class JschFileStore extends FileStore {
*/ */
@Override @Override
public OutputStream openOutputStream(int options, IProgressMonitor monitor) throws CoreException { public OutputStream openOutputStream(int options, IProgressMonitor monitor) throws CoreException {
SubMonitor subMon = SubMonitor.convert(monitor, 30);
IFileInfo info = fetchInfo(EFS.NONE, subMon.newChild(10));
if (!subMon.isCanceled()) {
if (info.isDirectory()) {
throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), EFS.ERROR_WRONG_TYPE, NLS.bind(
Messages.JschFileStore_Is_a_directory, fRemotePath.toString()), null));
}
GetOutputStreamCommand command = new GetOutputStreamCommand(fConnection, options, fRemotePath);
return command.getResult(subMon.newChild(10));
}
return null; return null;
} }
@ -245,6 +285,9 @@ public class JschFileStore extends FileStore {
*/ */
@Override @Override
public void putInfo(IFileInfo info, int options, IProgressMonitor monitor) throws CoreException { public void putInfo(IFileInfo info, int options, IProgressMonitor monitor) throws CoreException {
SubMonitor subMon = SubMonitor.convert(monitor, 10);
PutInfoCommand command = new PutInfoCommand(fConnection, info, options, fRemotePath);
command.getResult(subMon.newChild(10));
} }
/* /*
@ -257,4 +300,9 @@ public class JschFileStore extends FileStore {
return JSchFileSystem.getURIFor(fConnection.getName(), fRemotePath.toString()); return JSchFileSystem.getURIFor(fConnection.getName(), fRemotePath.toString());
} }
private ChannelSftp getChannel(IProgressMonitor monitor) throws RemoteConnectionException {
JSchFileSystem fileSystem = (JSchFileSystem) getFileSystem();
return fileSystem.getChannel(fConnection);
}
} }

View file

@ -23,28 +23,55 @@ import java.util.concurrent.TimeoutException;
import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.provider.FileInfo; import org.eclipse.core.filesystem.provider.FileInfo;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.internal.remote.jsch.core.Activator; import org.eclipse.internal.remote.jsch.core.JSchConnection;
import org.eclipse.internal.remote.jsch.core.messages.Messages;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException; import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpATTRS; import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException; import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.SftpProgressMonitor;
/** /**
* @author greg * @author greg
* *
*/ */
public abstract class AbstractRemoteCommand<T> { public abstract class AbstractRemoteCommand<T> {
private static ExecutorService fPool = Executors.newSingleThreadExecutor(); protected static class CommandProgressMonitor implements SftpProgressMonitor {
private final IProgressMonitor fMonitor;
public CommandProgressMonitor(IProgressMonitor monitor) {
fMonitor = monitor;
}
public boolean count(long count) {
fMonitor.worked((int) count);
return !(fMonitor.isCanceled());
}
public void end() {
fMonitor.done();
}
public void init(int op, String src, String dest, long max) {
String srcFile = new Path(src).lastSegment();
String desc = srcFile;
fMonitor.beginTask(desc, (int) max);
}
}
protected abstract class SftpCallable<T1> implements Callable<T1> { protected abstract class SftpCallable<T1> implements Callable<T1> {
private Future<T1> asyncCmdInThread(String jobName) throws CoreException { private IProgressMonitor fProgressMonitor;
private ChannelSftp fSftpChannel;
private Future<T1> asyncCmdInThread() throws RemoteConnectionException {
setChannel(fConnection.getSftpChannel());
return fPool.submit(this); return fPool.submit(this);
} }
@ -56,44 +83,45 @@ public abstract class AbstractRemoteCommand<T> {
public abstract T1 call() throws JSchException, SftpException, IOException; public abstract T1 call() throws JSchException, SftpException, IOException;
private void finalizeCmdInThread() { private void finalizeCmdInThread() {
setChannel(null);
} }
public ChannelSftp getChannel() throws JSchException { public ChannelSftp getChannel() {
return getSftpChannel(); return fSftpChannel;
}
public IProgressMonitor getProgressMonitor() {
return fProgressMonitor;
} }
/** /**
* Function opens sftp channel and then executes the sftp operation. If * Function opens sftp channel and then executes the sftp operation. If
* run on the main thread it executes it on a separate thread * run on the main thread it executes it on a separate thread
*/ */
public T1 getResult(String jobName, IProgressMonitor monitor) throws SftpException, CoreException { public T1 getResult(IProgressMonitor monitor) throws SftpException, RemoteConnectionException {
Future<T1> future = null; Future<T1> future = null;
SubMonitor progress = SubMonitor.convert(monitor, 10); fProgressMonitor = SubMonitor.convert(monitor, 10);
try { try {
future = asyncCmdInThread(jobName); future = asyncCmdInThread();
return waitCmdInThread(future, progress.newChild(10)); return waitCmdInThread(future);
} finally { } finally {
finalizeCmdInThread(); finalizeCmdInThread();
if (monitor != null) {
monitor.done();
}
} }
} }
private T1 waitCmdInThread(Future<T1> future, IProgressMonitor monitor) throws SftpException, CoreException { public void setChannel(ChannelSftp channel) {
fSftpChannel = channel;
}
private T1 waitCmdInThread(Future<T1> future) throws SftpException, RemoteConnectionException {
T1 ret = null; T1 ret = null;
boolean bInterrupted = Thread.interrupted(); boolean bInterrupted = Thread.interrupted();
while (ret == null) { while (!future.isDone()) {
try { try {
if (monitor.isCanceled()) { if (getProgressMonitor().isCanceled()) {
future.cancel(true); future.cancel(true);
try { getChannel().quit();
getSftpChannel().quit(); throw new RemoteConnectionException(Messages.AbstractRemoteCommand_Operation_cancelled_by_user);
} catch (JSchException e) {
// Ignore
}
throw new CoreException(new Status(IStatus.CANCEL, Activator.getUniqueIdentifier(),
"Operation cancelled by user"));
} }
ret = future.get(100, TimeUnit.MILLISECONDS); ret = future.get(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -108,18 +136,13 @@ public abstract class AbstractRemoteCommand<T> {
* undefined state because of * undefined state because of
* exception * exception
*/ */
try { getChannel().quit();
getSftpChannel().quit();
} catch (JSchException e1) {
// Ignore
}
if (e.getCause() instanceof SftpException) { if (e.getCause() instanceof SftpException) {
throw (SftpException) e.getCause(); throw (SftpException) e.getCause();
} }
throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), "Execution exception", throw new RemoteConnectionException(e.getMessage());
e.getCause()));
} }
monitor.worked(1); getProgressMonitor().worked(1);
} }
if (bInterrupted) { if (bInterrupted) {
Thread.currentThread().interrupt(); // set current thread flag Thread.currentThread().interrupt(); // set current thread flag
@ -128,60 +151,89 @@ public abstract class AbstractRemoteCommand<T> {
} }
} }
protected ChannelSftp getSftpChannel() throws JSchException { protected abstract class ExecCallable<T1> implements Callable<T1> {
if (!fSftpChannel.isConnected()) { private IProgressMonitor fProgressMonitor;
fSftpChannel.connect(); private ChannelExec fExecChannel;
private Future<T1> asyncCmdInThread() throws RemoteConnectionException {
setChannel(fConnection.getExecChannel());
return fPool.submit(this);
} }
return fSftpChannel;
}
protected abstract T getResult(IProgressMonitor monitor) throws CoreException; /*
* (non-Javadoc)
*
* @see java.util.concurrent.Callable#call()
*/
public abstract T1 call() throws JSchException, IOException;
private final ChannelSftp fSftpChannel; private void finalizeCmdInThread() {
setChannel(null);
}
protected IFileInfo convertToFileInfo(final IPath path, SftpATTRS attrs, IProgressMonitor monitor) throws CoreException { public ChannelExec getChannel() {
return convertToFileInfo(path.lastSegment(), path.removeLastSegments(1), attrs, monitor); return fExecChannel;
} }
protected IFileInfo convertToFileInfo(final String name, final IPath parentPath, SftpATTRS attrs, IProgressMonitor monitor) public IProgressMonitor getProgressMonitor() {
throws CoreException { return fProgressMonitor;
FileInfo fileInfo = new FileInfo(name); }
fileInfo.setExists(true);
fileInfo.setDirectory(attrs.isDir()); /**
fileInfo.setAttribute(EFS.ATTRIBUTE_OWNER_EXECUTE, (attrs.getPermissions() & 0100) != 0); * Function opens exec channel and then executes the exec operation. If
fileInfo.setAttribute(EFS.ATTRIBUTE_OWNER_WRITE, (attrs.getPermissions() & 0200) != 0); * run on the main thread it executes it on a separate thread
fileInfo.setAttribute(EFS.ATTRIBUTE_OWNER_READ, (attrs.getPermissions() & 0400) != 0); */
fileInfo.setAttribute(EFS.ATTRIBUTE_GROUP_EXECUTE, (attrs.getPermissions() & 0010) != 0); public T1 getResult(IProgressMonitor monitor) throws RemoteConnectionException {
fileInfo.setAttribute(EFS.ATTRIBUTE_GROUP_WRITE, (attrs.getPermissions() & 0020) != 0); Future<T1> future = null;
fileInfo.setAttribute(EFS.ATTRIBUTE_GROUP_READ, (attrs.getPermissions() & 0040) != 0); fProgressMonitor = SubMonitor.convert(monitor, 10);
fileInfo.setAttribute(EFS.ATTRIBUTE_OTHER_EXECUTE, (attrs.getPermissions() & 0001) != 0);
fileInfo.setAttribute(EFS.ATTRIBUTE_OTHER_WRITE, (attrs.getPermissions() & 0002) != 0);
fileInfo.setAttribute(EFS.ATTRIBUTE_OTHER_READ, (attrs.getPermissions() & 0004) != 0);
fileInfo.setAttribute(EFS.ATTRIBUTE_SYMLINK, attrs.isLink());
if (attrs.isLink()) {
SftpCallable<String> c2 = new SftpCallable<String>() {
@Override
public String call() throws JSchException, SftpException {
return getChannel().readlink(parentPath.append(name).toString());
}
};
String target;
try { try {
target = c2.getResult("Get symlink target", monitor); future = asyncCmdInThread();
fileInfo.setStringAttribute(EFS.ATTRIBUTE_LINK_TARGET, target); return waitCmdInThread(future);
} catch (SftpException e) { } finally {
// Ignore finalizeCmdInThread();
} }
} }
fileInfo.setLastModified(attrs.getMTime());
fileInfo.setLength(attrs.getSize()); public void setChannel(ChannelExec channel) {
return fileInfo; fExecChannel = channel;
}
private T1 waitCmdInThread(Future<T1> future) throws RemoteConnectionException {
boolean bInterrupted = Thread.interrupted();
while (!getProgressMonitor().isCanceled()) {
try {
return future.get(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
bInterrupted = true;
} catch (TimeoutException e) {
// ignore
} catch (ExecutionException e) {
getChannel().disconnect();
throw new RemoteConnectionException(e.getMessage());
}
getProgressMonitor().worked(1);
}
if (bInterrupted) {
Thread.currentThread().interrupt(); // set current thread flag
}
future.cancel(true);
getChannel().disconnect();
throw new RemoteConnectionException(Messages.AbstractRemoteCommand_Operation_cancelled_by_user);
}
} }
private static ExecutorService fPool = Executors.newSingleThreadExecutor();
private final JSchConnection fConnection;
public static final int UNKNOWN = 0; public static final int UNKNOWN = 0;
public static final int SUCCESS_OK = 1; public static final int SUCCESS_OK = 1;
public static final int SUCCESS_ERROR = 2; public static final int SUCCESS_ERROR = 2;
public static final int ERROR_NOT_EXECUTABLE = 126; public static final int ERROR_NOT_EXECUTABLE = 126;
public static final int ERROR_NOT_FOUND = 127; public static final int ERROR_NOT_FOUND = 127;
public static final int INVALID_EXIT_CODE = 128; public static final int INVALID_EXIT_CODE = 128;
public static final int SIGHUP = 129; public static final int SIGHUP = 129;
@ -215,8 +267,50 @@ public abstract class AbstractRemoteCommand<T> {
public static final int SIGIO = 157; public static final int SIGIO = 157;
public static final int SIGPWR = 158; public static final int SIGPWR = 158;
public AbstractRemoteCommand(ChannelSftp channel) { public AbstractRemoteCommand(JSchConnection connection) {
fSftpChannel = channel; fConnection = connection;
}
protected IFileInfo convertToFileInfo(final IPath path, SftpATTRS attrs, IProgressMonitor monitor)
throws RemoteConnectionException {
return convertToFileInfo(path.lastSegment(), path.removeLastSegments(1), attrs, monitor);
}
protected IFileInfo convertToFileInfo(final String name, final IPath parentPath, SftpATTRS attrs, IProgressMonitor monitor)
throws RemoteConnectionException {
SubMonitor progress = SubMonitor.convert(monitor, 10);
FileInfo fileInfo = new FileInfo(name);
fileInfo.setExists(true);
fileInfo.setDirectory(attrs.isDir());
fileInfo.setAttribute(EFS.ATTRIBUTE_OWNER_EXECUTE, (attrs.getPermissions() & 0100) != 0);
fileInfo.setAttribute(EFS.ATTRIBUTE_OWNER_WRITE, (attrs.getPermissions() & 0200) != 0);
fileInfo.setAttribute(EFS.ATTRIBUTE_OWNER_READ, (attrs.getPermissions() & 0400) != 0);
fileInfo.setAttribute(EFS.ATTRIBUTE_GROUP_EXECUTE, (attrs.getPermissions() & 0010) != 0);
fileInfo.setAttribute(EFS.ATTRIBUTE_GROUP_WRITE, (attrs.getPermissions() & 0020) != 0);
fileInfo.setAttribute(EFS.ATTRIBUTE_GROUP_READ, (attrs.getPermissions() & 0040) != 0);
fileInfo.setAttribute(EFS.ATTRIBUTE_OTHER_EXECUTE, (attrs.getPermissions() & 0001) != 0);
fileInfo.setAttribute(EFS.ATTRIBUTE_OTHER_WRITE, (attrs.getPermissions() & 0002) != 0);
fileInfo.setAttribute(EFS.ATTRIBUTE_OTHER_READ, (attrs.getPermissions() & 0004) != 0);
fileInfo.setAttribute(EFS.ATTRIBUTE_SYMLINK, attrs.isLink());
if (attrs.isLink()) {
SftpCallable<String> c2 = new SftpCallable<String>() {
@Override
public String call() throws JSchException, SftpException {
return getChannel().readlink(parentPath.append(name).toString());
}
};
String target;
try {
progress.subTask(Messages.AbstractRemoteCommand_Get_symlink_target);
target = c2.getResult(progress.newChild(10));
fileInfo.setStringAttribute(EFS.ATTRIBUTE_LINK_TARGET, target);
} catch (SftpException e) {
// Ignore
}
}
fileInfo.setLastModified(attrs.getMTime());
fileInfo.setLength(attrs.getSize());
return fileInfo;
} }
public int getFinishStatus() { public int getFinishStatus() {
@ -299,4 +393,9 @@ public abstract class AbstractRemoteCommand<T> {
} }
} }
protected abstract T getResult(IProgressMonitor monitor) throws RemoteConnectionException;
public JSchConnection getConnection() {
return fConnection;
}
} }

View file

@ -6,15 +6,13 @@ import java.util.List;
import java.util.Vector; import java.util.Vector;
import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor; 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.core.runtime.SubMonitor;
import org.eclipse.internal.remote.jsch.core.Activator; import org.eclipse.internal.remote.jsch.core.JSchConnection;
import org.eclipse.internal.remote.jsch.core.messages.Messages;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry; import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.JSchException; import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException; import com.jcraft.jsch.SftpException;
@ -23,13 +21,13 @@ public class ChildInfosCommand extends AbstractRemoteCommand<IFileInfo[]> {
private final IPath fRemotePath; private final IPath fRemotePath;
public ChildInfosCommand(ChannelSftp channel, IPath path) { public ChildInfosCommand(JSchConnection connection, IPath path) {
super(channel); super(connection);
fRemotePath = path; fRemotePath = path;
} }
@Override @Override
public IFileInfo[] getResult(IProgressMonitor monitor) throws CoreException { public IFileInfo[] getResult(IProgressMonitor monitor) throws RemoteConnectionException {
final SubMonitor subMon = SubMonitor.convert(monitor, 20); final SubMonitor subMon = SubMonitor.convert(monitor, 20);
Vector<LsEntry> files = getResult(fRemotePath.toString(), subMon.newChild(10)); Vector<LsEntry> files = getResult(fRemotePath.toString(), subMon.newChild(10));
@ -52,7 +50,8 @@ public class ChildInfosCommand extends AbstractRemoteCommand<IFileInfo[]> {
return result.toArray(new IFileInfo[result.size()]); return result.toArray(new IFileInfo[result.size()]);
} }
private Vector<LsEntry> getResult(String path, IProgressMonitor monitor) throws CoreException { private Vector<LsEntry> getResult(String path, IProgressMonitor monitor) throws RemoteConnectionException {
final SubMonitor subMon = SubMonitor.convert(monitor, 10);
SftpCallable<Vector<LsEntry>> c = new SftpCallable<Vector<LsEntry>>() { SftpCallable<Vector<LsEntry>> c = new SftpCallable<Vector<LsEntry>>() {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
@ -61,9 +60,10 @@ public class ChildInfosCommand extends AbstractRemoteCommand<IFileInfo[]> {
} }
}; };
try { try {
return c.getResult("Get file attributes", monitor); subMon.subTask(Messages.ChildInfosCommand_Get_file_attributes);
return c.getResult(subMon.newChild(10));
} catch (SftpException e) { } catch (SftpException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage(), e)); throw new RemoteConnectionException(e.getMessage());
} }
} }
} }

View file

@ -1,14 +1,12 @@
package org.eclipse.internal.remote.jsch.core.commands; package org.eclipse.internal.remote.jsch.core.commands;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor; 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.core.runtime.SubMonitor;
import org.eclipse.internal.remote.jsch.core.Activator; import org.eclipse.internal.remote.jsch.core.JSchConnection;
import org.eclipse.internal.remote.jsch.core.messages.Messages;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException; import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException; import com.jcraft.jsch.SftpException;
@ -16,13 +14,13 @@ public class DeleteCommand extends AbstractRemoteCommand<Void> {
private final IPath fRemotePath; private final IPath fRemotePath;
public DeleteCommand(ChannelSftp channel, IPath path) { public DeleteCommand(JSchConnection connection, IPath path) {
super(channel); super(connection);
fRemotePath = path; fRemotePath = path;
} }
@Override @Override
public Void getResult(IProgressMonitor monitor) throws CoreException { public Void getResult(IProgressMonitor monitor) throws RemoteConnectionException {
final SubMonitor subMon = SubMonitor.convert(monitor, 10); final SubMonitor subMon = SubMonitor.convert(monitor, 10);
SftpCallable<Void> c = new SftpCallable<Void>() { SftpCallable<Void> c = new SftpCallable<Void>() {
@Override @Override
@ -32,9 +30,10 @@ public class DeleteCommand extends AbstractRemoteCommand<Void> {
} }
}; };
try { try {
c.getResult("Remove file", subMon.newChild(10)); subMon.subTask(Messages.DeleteCommand_Remove_file);
c.getResult(subMon.newChild(10));
} catch (SftpException e) { } catch (SftpException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage(), e)); throw new RemoteConnectionException(e.getMessage());
} }
return null; return null;
} }

View file

@ -0,0 +1,53 @@
package org.eclipse.internal.remote.jsch.core.commands;
import java.io.ByteArrayOutputStream;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.internal.remote.jsch.core.JSchConnection;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import com.jcraft.jsch.JSchException;
public class ExecCommand extends AbstractRemoteCommand<String> {
private String fCommand;
public ExecCommand(JSchConnection connection) {
super(connection);
}
public ExecCommand setCommand(String command) {
fCommand = command;
return this;
}
@Override
public String getResult(IProgressMonitor monitor) throws RemoteConnectionException {
final SubMonitor subMon = SubMonitor.convert(monitor, 10);
ExecCallable<String> c = new ExecCallable<String>() {
@Override
public String call() throws JSchException {
getChannel().setCommand(fCommand);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
getChannel().setOutputStream(stream);
getChannel().connect();
while (!getChannel().isClosed() && !getProgressMonitor().isCanceled()) {
synchronized (this) {
try {
wait(100);
} catch (InterruptedException e) {
// Ignore
}
}
}
if (getProgressMonitor().isCanceled()) {
return ""; //$NON-NLS-1$
}
return stream.toString();
}
};
subMon.subTask("Exec command");
return c.getResult(subMon.newChild(10));
}
}

View file

@ -2,13 +2,12 @@ package org.eclipse.internal.remote.jsch.core.commands;
import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.provider.FileInfo; import org.eclipse.core.filesystem.provider.FileInfo;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor; 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.core.runtime.SubMonitor;
import org.eclipse.internal.remote.jsch.core.Activator; import org.eclipse.internal.remote.jsch.core.JSchConnection;
import org.eclipse.internal.remote.jsch.core.messages.Messages;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException; import com.jcraft.jsch.JSchException;
@ -19,13 +18,13 @@ public class FetchInfoCommand extends AbstractRemoteCommand<IFileInfo> {
private final IPath fRemotePath; private final IPath fRemotePath;
public FetchInfoCommand(ChannelSftp channel, IPath path) { public FetchInfoCommand(JSchConnection connection, IPath path) {
super(channel); super(connection);
fRemotePath = path; fRemotePath = path;
} }
@Override @Override
public IFileInfo getResult(IProgressMonitor monitor) throws CoreException { public IFileInfo getResult(IProgressMonitor monitor) throws RemoteConnectionException {
SubMonitor subMon = SubMonitor.convert(monitor, 20); SubMonitor subMon = SubMonitor.convert(monitor, 20);
SftpCallable<SftpATTRS> c = new SftpCallable<SftpATTRS>() { SftpCallable<SftpATTRS> c = new SftpCallable<SftpATTRS>() {
@Override @Override
@ -35,7 +34,8 @@ public class FetchInfoCommand extends AbstractRemoteCommand<IFileInfo> {
}; };
SftpATTRS attrs; SftpATTRS attrs;
try { try {
attrs = c.getResult("Fetch info", subMon.newChild(10)); subMon.subTask(Messages.FetchInfoCommand_Fetch_info);
attrs = c.getResult(subMon.newChild(10));
return convertToFileInfo(fRemotePath, attrs, subMon.newChild(10)); return convertToFileInfo(fRemotePath, attrs, subMon.newChild(10));
} catch (SftpException e) { } catch (SftpException e) {
if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) { if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
@ -43,7 +43,7 @@ public class FetchInfoCommand extends AbstractRemoteCommand<IFileInfo> {
info.setExists(false); info.setExists(false);
return info; return info;
} }
throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage(), e)); throw new RemoteConnectionException(e.getMessage());
} }
} }
} }

View file

@ -0,0 +1,46 @@
package org.eclipse.internal.remote.jsch.core.commands;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.internal.remote.jsch.core.JSchConnection;
import org.eclipse.internal.remote.jsch.core.messages.Messages;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;
public class GetInputStreamCommand extends AbstractRemoteCommand<InputStream> {
private final IPath fRemotePath;
public GetInputStreamCommand(JSchConnection connection, IPath path) {
super(connection);
fRemotePath = path;
}
@Override
public InputStream getResult(IProgressMonitor monitor) throws RemoteConnectionException {
final SubMonitor subMon = SubMonitor.convert(monitor, 10);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
SftpCallable<Void> c = new SftpCallable<Void>() {
@Override
public Void call() throws JSchException, SftpException, IOException {
getChannel().get(fRemotePath.toString(), out, new CommandProgressMonitor(getProgressMonitor()));
out.close();
return null;
}
};
try {
subMon.subTask(Messages.GetInputStreamCommand_Get_input_stream);
c.getResult(subMon.newChild(10));
return new ByteArrayInputStream(out.toByteArray());
} catch (SftpException e) {
throw new RemoteConnectionException(e.getMessage());
}
}
}

View file

@ -0,0 +1,71 @@
package org.eclipse.internal.remote.jsch.core.commands;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.internal.remote.jsch.core.JSchConnection;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;
public class GetOutputStreamCommand extends AbstractRemoteCommand<OutputStream> {
private final IPath fRemotePath;
private final int fOptions;
private boolean fIsClosed;
public GetOutputStreamCommand(JSchConnection connection, int options, IPath path) {
super(connection);
fRemotePath = path;
fOptions = options;
fIsClosed = false;
}
@Override
public OutputStream getResult(IProgressMonitor monitor) throws RemoteConnectionException {
final SubMonitor subMon = SubMonitor.convert(monitor, 10);
return new ByteArrayOutputStream() {
@Override
public void close() throws IOException {
if (!fIsClosed) {
super.close();
final InputStream input = new ByteArrayInputStream(this.toByteArray());
try {
SftpCallable<Integer> c = new SftpCallable<Integer>() {
@Override
public Integer call() throws JSchException, SftpException, IOException {
try {
int mode = ChannelSftp.OVERWRITE;
if ((fOptions & EFS.APPEND) != 0) {
mode = ChannelSftp.APPEND;
}
getChannel().put(input, fRemotePath.toString(),
new CommandProgressMonitor(getProgressMonitor()), mode);
input.close();
} finally {
fIsClosed = true;
}
return 0;
}
};
c.getResult(subMon.newChild(10));
} catch (SftpException e) {
throw new IOException(e.getMessage());
} catch (CoreException e) {
throw new IOException(e.getMessage());
}
}
}
};
}
}

View file

@ -1,15 +1,13 @@
package org.eclipse.internal.remote.jsch.core.commands; package org.eclipse.internal.remote.jsch.core.commands;
import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor; 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.core.runtime.SubMonitor;
import org.eclipse.internal.remote.jsch.core.Activator; import org.eclipse.internal.remote.jsch.core.JSchConnection;
import org.eclipse.internal.remote.jsch.core.messages.Messages;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException; import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException; import com.jcraft.jsch.SftpException;
@ -17,29 +15,24 @@ public class MkdirCommand extends AbstractRemoteCommand<Void> {
private final IPath fRemotePath; private final IPath fRemotePath;
public MkdirCommand(ChannelSftp channel, IPath path) { public MkdirCommand(JSchConnection connection, IPath path) {
super(channel); super(connection);
fRemotePath = path; fRemotePath = path;
} }
@Override @Override
public Void getResult(IProgressMonitor monitor) throws CoreException { public Void getResult(IProgressMonitor monitor) throws RemoteConnectionException {
createDirectory(fRemotePath, monitor); createDirectory(fRemotePath, monitor);
return null; return null;
} }
private void createDirectory(IPath path, IProgressMonitor monitor) throws CoreException { private void createDirectory(IPath path, IProgressMonitor monitor) throws RemoteConnectionException {
final SubMonitor subMon = SubMonitor.convert(monitor, 20); final SubMonitor subMon = SubMonitor.convert(monitor, 20);
/* /*
* Recursively create parent directories * Recursively create parent directories
*/ */
FetchInfoCommand command; FetchInfoCommand command = new FetchInfoCommand(getConnection(), path.removeLastSegments(1));
try {
command = new FetchInfoCommand(getSftpChannel(), path.removeLastSegments(1));
} catch (JSchException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage(), e));
}
IFileInfo info = command.getResult(subMon.newChild(10)); IFileInfo info = command.getResult(subMon.newChild(10));
if (!info.exists()) { if (!info.exists()) {
createDirectory(path.removeLastSegments(1), subMon.newChild(10)); createDirectory(path.removeLastSegments(1), subMon.newChild(10));
@ -56,9 +49,10 @@ public class MkdirCommand extends AbstractRemoteCommand<Void> {
} }
}; };
try { try {
c.getResult("Create directory", subMon.newChild(10)); subMon.subTask(Messages.MkdirCommand_Create_directory);
c.getResult(subMon.newChild(10));
} catch (SftpException e) { } catch (SftpException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage(), e)); throw new RemoteConnectionException(e.getMessage());
} }
} }
} }

View file

@ -0,0 +1,114 @@
package org.eclipse.internal.remote.jsch.core.commands;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.internal.remote.jsch.core.JSchConnection;
import org.eclipse.internal.remote.jsch.core.messages.Messages;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;
public class PutInfoCommand extends AbstractRemoteCommand<Void> {
private final IPath fRemotePath;
private final IFileInfo fFileInfo;
private final int fOptions;
public PutInfoCommand(JSchConnection connection, IFileInfo info, int options, IPath path) {
super(connection);
fFileInfo = info;
fOptions = options;
fRemotePath = path;
}
@Override
public Void getResult(IProgressMonitor monitor) throws RemoteConnectionException {
final SubMonitor subMon = SubMonitor.convert(monitor, 30);
FetchInfoCommand command = new FetchInfoCommand(getConnection(), fRemotePath);
IFileInfo info = command.getResult(subMon.newChild(10));
if ((fOptions & EFS.SET_ATTRIBUTES) != 0) {
fFileInfo.setAttribute(EFS.ATTRIBUTE_READ_ONLY, !info.getAttribute(EFS.ATTRIBUTE_READ_ONLY));
fFileInfo.setAttribute(EFS.ATTRIBUTE_EXECUTABLE, info.getAttribute(EFS.ATTRIBUTE_EXECUTABLE));
chmod(getPermissions(fFileInfo), fRemotePath.toString(), subMon.newChild(10));
}
if ((fOptions & EFS.SET_LAST_MODIFIED) != 0) {
long oldMTime = info.getLastModified();
int newMTime = (int) (oldMTime / 1000);
if (oldMTime != newMTime) {
setMTime(newMTime, fRemotePath.toString(), subMon.newChild(10));
}
}
return null;
}
private void chmod(final int permissions, final String path, IProgressMonitor monitor) throws RemoteConnectionException {
final SubMonitor subMon = SubMonitor.convert(monitor, 10);
SftpCallable<Void> c = new SftpCallable<Void>() {
@Override
public Void call() throws JSchException, SftpException {
getChannel().chmod(permissions, path);
return null;
}
};
try {
subMon.subTask(Messages.PutInfoCommand_Change_permissions);
c.getResult(subMon.newChild(10));
} catch (SftpException e) {
throw new RemoteConnectionException(e.getMessage());
}
}
private void setMTime(final int mtime, final String path, IProgressMonitor monitor) throws RemoteConnectionException {
final SubMonitor subMon = SubMonitor.convert(monitor, 10);
SftpCallable<Void> c = new SftpCallable<Void>() {
@Override
public Void call() throws JSchException, SftpException {
getChannel().setMtime(path, mtime);
return null;
}
};
try {
subMon.subTask(Messages.PutInfoCommand_Set_modified_time);
c.getResult(subMon.newChild(10));
} catch (SftpException e) {
throw new RemoteConnectionException(e.getMessage());
}
}
private int getPermissions(IFileInfo info) {
int permissions = 0;
if (info.getAttribute(EFS.ATTRIBUTE_OWNER_READ)) {
permissions |= 0400;
}
if (info.getAttribute(EFS.ATTRIBUTE_OWNER_WRITE)) {
permissions |= 0200;
}
if (info.getAttribute(EFS.ATTRIBUTE_OWNER_EXECUTE)) {
permissions |= 0100;
}
if (info.getAttribute(EFS.ATTRIBUTE_GROUP_READ)) {
permissions |= 0040;
}
if (info.getAttribute(EFS.ATTRIBUTE_GROUP_WRITE)) {
permissions |= 0020;
}
if (info.getAttribute(EFS.ATTRIBUTE_GROUP_EXECUTE)) {
permissions |= 0010;
}
if (info.getAttribute(EFS.ATTRIBUTE_OTHER_READ)) {
permissions |= 0004;
}
if (info.getAttribute(EFS.ATTRIBUTE_OTHER_WRITE)) {
permissions |= 0002;
}
if (info.getAttribute(EFS.ATTRIBUTE_OTHER_EXECUTE)) {
permissions |= 0001;
}
return permissions;
}
}

View file

@ -21,7 +21,14 @@ import org.eclipse.osgi.util.NLS;
public class Messages extends NLS { public class Messages extends NLS {
private static final String BUNDLE_ID = "org.eclipse.internal.remote.jsch.core.messages.messages"; //$NON-NLS-1$ private static final String BUNDLE_ID = "org.eclipse.internal.remote.jsch.core.messages.messages"; //$NON-NLS-1$
public static String AbstractRemoteCommand_Execution_exception;
public static String AbstractRemoteCommand_Get_symlink_target;
public static String AbstractRemoteCommand_Operation_cancelled_by_user;
public static String AuthInfo_Authentication_message; public static String AuthInfo_Authentication_message;
public static String ChildInfosCommand_Get_file_attributes;
public static String DeleteCommand_Remove_file;
public static String FetchInfoCommand_Fetch_info;
public static String GetInputStreamCommand_Get_input_stream;
public static String JSchConnection_connectionNotOpen; public static String JSchConnection_connectionNotOpen;
public static String JSchConnection_remote_address_must_be_set; public static String JSchConnection_remote_address_must_be_set;
public static String JSchConnection_remotePort; public static String JSchConnection_remotePort;
@ -31,6 +38,13 @@ public class Messages extends NLS {
public static String JSchConnectionManager_connection_with_this_name_exists; public static String JSchConnectionManager_connection_with_this_name_exists;
public static String JSchConnectionManager_cannotRemoveOpenConnection; public static String JSchConnectionManager_cannotRemoveOpenConnection;
public static String JSchConnectionManager_invalidConnectionType; public static String JSchConnectionManager_invalidConnectionType;
public static String JschFileStore_File_doesnt_exist;
public static String JschFileStore_Is_a_directory;
public static String JschFileStore_The_file_of_name_already_exists;
public static String JschFileStore_The_parent_of_directory_does_not_exist;
public static String MkdirCommand_Create_directory;
public static String PutInfoCommand_Change_permissions;
public static String PutInfoCommand_Set_modified_time;
public static String RemoteToolsFileStore_0; public static String RemoteToolsFileStore_0;
public static String RemoteToolsFileStore_1; public static String RemoteToolsFileStore_1;
public static String RemoteToolsFileStore_2; public static String RemoteToolsFileStore_2;

View file

@ -1,3 +1,5 @@
AbstractRemoteCommand_Get_symlink_target=Get symlink target
AbstractRemoteCommand_Operation_cancelled_by_user=Operation cancelled by user
############################################################################### ###############################################################################
# Copyright (c) 2006 IBM Corporation. # Copyright (c) 2006 IBM Corporation.
# All rights reserved. This program and the accompanying materials # All rights reserved. This program and the accompanying materials
@ -8,7 +10,12 @@
# Contributors: # Contributors:
# IBM Corporation - initial implementation # IBM Corporation - initial implementation
############################################################################### ###############################################################################
AbstractRemoteCommand_Execution_exception=Execution exception
AuthInfo_Authentication_message=Authentication Message AuthInfo_Authentication_message=Authentication Message
ChildInfosCommand_Get_file_attributes=Get file attributes
DeleteCommand_Remove_file=Remove file
FetchInfoCommand_Fetch_info=Fetch info
GetInputStreamCommand_Get_input_stream=Get input stream
JSchConnection_connectionNotOpen=Connection is not open JSchConnection_connectionNotOpen=Connection is not open
JSchConnection_remote_address_must_be_set=Remote address must be set before opening connection JSchConnection_remote_address_must_be_set=Remote address must be set before opening connection
JSchConnection_remotePort=Could not allocate remote port JSchConnection_remotePort=Could not allocate remote port
@ -18,6 +25,13 @@ JSchConnection_username_must_be_set=Username must be set before opening connecti
JSchConnectionManager_connection_with_this_name_exists=A connection with this name already exists JSchConnectionManager_connection_with_this_name_exists=A connection with this name already exists
JSchConnectionManager_cannotRemoveOpenConnection=Cannot remove an open connection JSchConnectionManager_cannotRemoveOpenConnection=Cannot remove an open connection
JSchConnectionManager_invalidConnectionType=Invalid connection type JSchConnectionManager_invalidConnectionType=Invalid connection type
JschFileStore_File_doesnt_exist=File {0} doesn't exist
JschFileStore_Is_a_directory={0} is a directory
JschFileStore_The_file_of_name_already_exists=A file of name {0} already exists
JschFileStore_The_parent_of_directory_does_not_exist=The parent of directory {0} does not exist
MkdirCommand_Create_directory=Create directory
PutInfoCommand_Change_permissions=Change permissions
PutInfoCommand_Set_modified_time=Set modified time
RemoteToolsFileStore_0=Could not delete file {0} RemoteToolsFileStore_0=Could not delete file {0}
RemoteToolsFileStore_1=The parent of directory {0} does not exist RemoteToolsFileStore_1=The parent of directory {0} does not exist
RemoteToolsFileStore_2=The directory {0} could not be created RemoteToolsFileStore_2=The directory {0} could not be created