diff --git a/tools/antcontrib/pom.xml b/tools/antcontrib/pom.xml
index b8b132697b..d229759bbb 100644
--- a/tools/antcontrib/pom.xml
+++ b/tools/antcontrib/pom.xml
@@ -33,11 +33,6 @@
-
- org.jboss.shrinkwrap
- shrinkwrap-impl-base
- 1.0.0-alpha-3
-
${project.groupId}
jclouds-scriptbuilder
diff --git a/tools/antcontrib/samples/javaoverssh/README.txt b/tools/antcontrib/samples/javaoverssh/README.txt
index 39800928bc..34cf2739c9 100755
--- a/tools/antcontrib/samples/javaoverssh/README.txt
+++ b/tools/antcontrib/samples/javaoverssh/README.txt
@@ -22,4 +22,4 @@
- ex. curl http://jclouds.rimuhosting.com/maven2/snapshots/org/jclouds/jclouds-antcontrib/1.0-SNAPSHOT/jclouds-antcontrib-1.0-20091215.023231-1-jar-with-dependencies.jar >jclouds-antcontrib-all.jar
2. invoke ant, adding the library above, and passing the properties 'host' 'username' 'keyfile' which corresponds to your remote credentials
- ex. ant -lib ~/.m2/repository/org/jclouds/jclouds-antcontrib/1.0-SNAPSHOT/jclouds-antcontrib-1.0-SNAPSHOT-jar-with-dependencies.jar -Dhost=67.202.42.237 -Dusername=root -Dkeyfile=$HOME/.ssh/id_dsa
- - ex. ant -lib jclouds-antcontrib-all.jar -Dhost=67.202.42.237 -Dusername=root -Dkeyfile=$HOME/.ssh/id_dsa
+ - ex. ant -lib ~/.m2/repository/org/jclouds/jclouds-antcontrib/1.0-SNAPSHOT/jclouds-antcontrib-1.0-SNAPSHOT-jar-with-dependencies.jar -Dhost=localhost -Dusername=$USER -Dkeyfile=$HOME/.ssh/id_dsa
diff --git a/tools/antcontrib/src/main/java/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java b/tools/antcontrib/src/main/java/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java
new file mode 100644
index 0000000000..2d91ee14b7
--- /dev/null
+++ b/tools/antcontrib/src/main/java/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java
@@ -0,0 +1,394 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.KeepAliveOutputStream;
+import org.apache.tools.ant.util.TeeOutputStream;
+
+import com.jcraft.jsch.ChannelExec;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+
+/**
+ * Executes a command on a remote machine via ssh.
+ * @since Ant 1.6 (created February 2, 2003)
+ */
+public class SSHExec extends SSHBase {
+
+ private static final int BUFFER_SIZE = 8192;
+ private static final int RETRY_INTERVAL = 500;
+
+ /** the command to execute via ssh */
+ private String command = null;
+
+ /** units are milliseconds, default is 0=infinite */
+ private long maxwait = 0;
+
+ /** for waiting for the command to finish */
+ private Thread thread = null;
+
+ private String outputProperty = null;
+ private File outputFile = null;
+ private String errorProperty = null;
+ private File errorFile = null;
+ private String resultProperty;
+ private boolean append = false;
+
+ private Resource commandResource = null;
+
+ private static final String TIMEOUT_MESSAGE =
+ "Timeout period exceeded, connection dropped.";
+
+ /**
+ * Constructor for SSHExecTask.
+ */
+ public SSHExec() {
+ super();
+ }
+
+ /**
+ * Sets the command to execute on the remote host.
+ *
+ * @param command The new command value
+ */
+ public void setCommand(String command) {
+ this.command = command;
+ }
+
+ /**
+ * Sets a commandResource from a file
+ * @param f the value to use.
+ * @since Ant 1.7.1
+ */
+ public void setCommandResource(String f) {
+ this.commandResource = new FileResource(new File(f));
+ }
+
+ /**
+ * The connection can be dropped after a specified number of
+ * milliseconds. This is sometimes useful when a connection may be
+ * flaky. Default is 0, which means "wait forever".
+ *
+ * @param timeout The new timeout value in seconds
+ */
+ public void setTimeout(long timeout) {
+ maxwait = timeout;
+ }
+
+ /**
+ * If used, stores the output of the command to the given file.
+ *
+ * @param output The file to write to.
+ */
+ public void setOutput(File output) {
+ outputFile = output;
+ }
+
+ /**
+ * If used, stores the error of the command to the given file.
+ *
+ * @param error The file to write to.
+ */
+ public void setError(File error) {
+ this.errorFile = error;
+ }
+
+ /**
+ * Determines if the output is appended to the file given in
+ * setOutput
. Default is false, that is, overwrite
+ * the file.
+ *
+ * @param append True to append to an existing file, false to overwrite.
+ */
+ public void setAppend(boolean append) {
+ this.append = append;
+ }
+
+ /**
+ * If set, the output of the command will be stored in the given property.
+ *
+ * @param property The name of the property in which the command output
+ * will be stored.
+ */
+ public void setOutputproperty(String property) {
+ outputProperty = property;
+ }
+
+ /**
+ * Set the property name whose value should be set to the error of
+ * the process.
+ *
+ * @param property The name of a property in which the standard error of
+ * the command should be stored.
+ */
+ public void setErrorproperty(String property) {
+ errorProperty = property;
+ }
+
+ /**
+ * Set the name of the property in which the return code of the
+ * command should be stored. Only of interest if failonerror=false.
+ *
+ * @param resultProperty name of property.
+ *
+ * @since Ant 1.6
+ */
+ public void setResultProperty(String resultProperty) {
+ this.resultProperty = resultProperty;
+ }
+
+ /**
+ * Execute the command on the remote host.
+ *
+ * @exception BuildException Most likely a network error or bad parameter.
+ */
+ public void execute() throws BuildException {
+ if (getHost() == null) {
+ throw new BuildException("Host is required.");
+ }
+ if (getUserInfo().getName() == null) {
+ throw new BuildException("Username is required.");
+ }
+ if (getUserInfo().getKeyfile() == null
+ && getUserInfo().getPassword() == null) {
+ throw new BuildException("Password or Keyfile is required.");
+ }
+ if (command == null && commandResource == null) {
+ throw new BuildException("Command or commandResource is required.");
+ }
+
+ Session session = null;
+
+ try {
+ session = openSession();
+ /* called once */
+ if (command != null) {
+ log("cmd : " + command, Project.MSG_INFO);
+ ExecResponse response = executeCommand(session, command);
+ if (outputProperty != null) {
+ getProject().setNewProperty(outputProperty, response.getOutput());
+ }
+ if (errorProperty != null) {
+ getProject().setNewProperty(outputProperty, response.getError());
+ }
+ if (resultProperty != null) {
+ getProject().setNewProperty(resultProperty, response.getCode()+"");
+ }
+ } else { // read command resource and execute for each command
+ try {
+ BufferedReader br = new BufferedReader(
+ new InputStreamReader(commandResource.getInputStream()));
+ String cmd;
+ StringBuilder output = new StringBuilder();
+ StringBuilder error = new StringBuilder();
+ int lastCode = -1;
+ while ((cmd = br.readLine()) != null) {
+ log("cmd : " + cmd, Project.MSG_INFO);
+ ExecResponse response = executeCommand(session, cmd);
+ output.append(response.getOutput());
+ error.append(response.getError());
+ lastCode = response.getCode();
+ }
+ if (outputProperty != null) {
+ getProject().setNewProperty(outputProperty, output.toString());
+ }
+ if (errorProperty != null) {
+ getProject().setNewProperty(outputProperty, error.toString());
+ }
+ if (resultProperty != null) {
+ getProject().setNewProperty(resultProperty, lastCode+"");
+ }
+ FileUtils.close(br);
+ } catch (IOException e) {
+ throw new BuildException(e);
+ }
+ }
+ } catch (JSchException e) {
+ throw new BuildException(e);
+ } finally {
+ if (session != null && session.isConnected()) {
+ session.disconnect();
+ }
+ }
+ }
+ private static class ExecResponse {
+
+ private final String output;
+ private final String error;
+ private final int code;
+
+ public ExecResponse(String output, String error, int code) {
+ this.output = output;
+ this.error = error;
+ this.code = code;
+ }
+
+ public String getError() {
+ return error;
+ }
+
+ public String getOutput() {
+ return output;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ }
+
+ private ExecResponse executeCommand(Session session, String cmd)
+ throws BuildException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ TeeOutputStream tee = new TeeOutputStream(out, new KeepAliveOutputStream(System.out));
+ ByteArrayOutputStream err = new ByteArrayOutputStream();
+ TeeOutputStream teeErr = new TeeOutputStream(err, new KeepAliveOutputStream(System.err));
+ int ec = -1;
+
+ try {
+ final ChannelExec channel;
+ session.setTimeout((int) maxwait);
+ /* execute the command */
+ channel = (ChannelExec) session.openChannel("exec");
+ channel.setCommand(cmd);
+ channel.setOutputStream(tee);
+ channel.setExtOutputStream(tee);
+ channel.setErrStream(teeErr);
+ channel.connect();
+ // wait for it to finish
+ thread =
+ new Thread() {
+ public void run() {
+ while (!channel.isClosed()) {
+ if (thread == null) {
+ return;
+ }
+ try {
+ sleep(RETRY_INTERVAL);
+ } catch (Exception e) {
+ // ignored
+ }
+ }
+ }
+ };
+
+ thread.start();
+ thread.join(maxwait);
+
+ if (thread.isAlive()) {
+ // ran out of time
+ thread = null;
+ if (getFailonerror()) {
+ throw new BuildException(TIMEOUT_MESSAGE);
+ } else {
+ log(TIMEOUT_MESSAGE, Project.MSG_ERR);
+ }
+ } else {
+ //success
+ if (outputFile != null) {
+ writeToFile(out.toString(), append, outputFile);
+ }
+ if (errorFile != null) {
+ writeToFile(err.toString(), append, errorFile);
+ }
+ // this is the wrong test if the remote OS is OpenVMS,
+ // but there doesn't seem to be a way to detect it.
+ ec = channel.getExitStatus();
+ if (ec != 0) {
+ String msg = "Remote command failed with exit status " + ec;
+ if (getFailonerror()) {
+ throw new BuildException(msg);
+ } else {
+ log(msg, Project.MSG_ERR);
+ }
+ }
+ }
+ } catch (BuildException e) {
+ throw e;
+ } catch (JSchException e) {
+ if (e.getMessage().indexOf("session is down") >= 0) {
+ if (getFailonerror()) {
+ throw new BuildException(TIMEOUT_MESSAGE, e);
+ } else {
+ log(TIMEOUT_MESSAGE, Project.MSG_ERR);
+ }
+ } else {
+ if (getFailonerror()) {
+ throw new BuildException(e);
+ } else {
+ log("Caught exception: " + e.getMessage(),
+ Project.MSG_ERR);
+ }
+ }
+ } catch (Exception e) {
+ if (getFailonerror()) {
+ throw new BuildException(e);
+ } else {
+ log("Caught exception: " + e.getMessage(), Project.MSG_ERR);
+ }
+ }
+ return new ExecResponse(out.toString(), err.toString(), ec);
+ }
+
+ /**
+ * Writes a string to a file. If destination file exists, it may be
+ * overwritten depending on the "append" value.
+ *
+ * @param from string to write
+ * @param to file to write to
+ * @param append if true, append to existing file, else overwrite
+ * @exception Exception most likely an IOException
+ */
+ private void writeToFile(String from, boolean append, File to)
+ throws IOException {
+ FileWriter out = null;
+ try {
+ out = new FileWriter(to.getAbsolutePath(), append);
+ StringReader in = new StringReader(from);
+ char[] buffer = new char[BUFFER_SIZE];
+ int bytesRead;
+ while (true) {
+ bytesRead = in.read(buffer);
+ if (bytesRead == -1) {
+ break;
+ }
+ out.write(buffer, 0, bytesRead);
+ }
+ out.flush();
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ }
+ }
+}
diff --git a/tools/antcontrib/src/main/java/org/jclouds/tools/ant/JavaOverSsh.java b/tools/antcontrib/src/main/java/org/jclouds/tools/ant/JavaOverSsh.java
index 86b82603f2..376f369fa6 100644
--- a/tools/antcontrib/src/main/java/org/jclouds/tools/ant/JavaOverSsh.java
+++ b/tools/antcontrib/src/main/java/org/jclouds/tools/ant/JavaOverSsh.java
@@ -21,324 +21,201 @@ package org.jclouds.tools.ant;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
-import java.io.ByteArrayOutputStream;
import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringReader;
+import java.security.SecureRandom;
import java.util.List;
-import java.util.zip.ZipFile;
import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Location;
import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Target;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.taskdefs.optional.ssh.SSHExec;
import org.apache.tools.ant.taskdefs.optional.ssh.SSHUserInfo;
+import org.apache.tools.ant.taskdefs.optional.ssh.Scp;
import org.apache.tools.ant.types.CommandlineJava;
import org.apache.tools.ant.types.Environment;
-import org.apache.tools.ant.util.KeepAliveOutputStream;
-import org.apache.tools.ant.util.TeeOutputStream;
-import org.jboss.shrinkwrap.api.Archives;
-import org.jboss.shrinkwrap.api.exporter.ZipExporter;
-import org.jboss.shrinkwrap.api.importer.ExplodedImporter;
-import org.jboss.shrinkwrap.api.importer.ZipImporter;
-import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
-import com.google.common.io.Closeables;
-import com.jcraft.jsch.ChannelExec;
-import com.jcraft.jsch.ChannelSftp;
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.JSchException;
-import com.jcraft.jsch.Session;
/**
- * Ported from Jsch SSHExec task.
+ * Version of the Java task that executes over ssh.
*
* @author Adrian Cole
*/
public class JavaOverSsh extends Java {
- /** Default listen port for SSH daemon */
- private static final int SSH_PORT = 22;
+ private final SSHExec exec;
+ private final Scp scp;
+ private final SSHUserInfo userInfo;
+
private String jvm = "/usr/bin/java";
private File localDirectory;
private File remoteDirectory;
private Environment env = new Environment();
- private String host;
- private String knownHosts;
- private int port = SSH_PORT;
- private SSHUserInfo userInfo = new SSHUserInfo();
+
private OsFamily osFamily = OsFamily.UNIX;
-
- /** units are milliseconds, default is 0=infinite */
- private long maxwait = 0;
-
- /** for waiting for the command to finish */
- private Thread watchDog = null;
- private File outputFile;
- private String outputProperty;
- private String resultProperty;
private File errorFile;
private String errorProperty;
+ private File outputFile;
+ private String outputProperty;
private boolean append;
- private static final String TIMEOUT_MESSAGE = "Timeout period exceeded, connection dropped.";
-
public JavaOverSsh() {
super();
setFork(true);
+ exec = new SSHExec();
+ scp = new Scp();
+ userInfo = new SSHUserInfo();
}
public JavaOverSsh(Task owner) {
- super(owner);
- setFork(true);
+ this();
+ bindToOwner(owner);
}
@Override
public int executeJava() throws BuildException {
- String command = convertJavaToScript(getCommandLine());
-
- InputStream classpathJar = (getCommandLine().getClasspath() != null) ? makeClasspathJarOrNull(getCommandLine()
- .getClasspath().list())
- : null;
-
- InputStream bootClasspathJar = (getCommandLine().getBootclasspath() != null) ? makeClasspathJarOrNull(getCommandLine()
- .getBootclasspath().list())
- : null;
-
- InputStream currentDirectoryZip = Archives.create("cwd.zip", ZipExporter.class).as(
- ExplodedImporter.class).importDirectory(localDirectory).as(ZipExporter.class)
- .exportZip();
-
- if (getHost() == null) {
- throw new BuildException("Host is required.");
- }
- if (getUserInfo().getName() == null) {
- throw new BuildException("Username is required.");
- }
- if (getUserInfo().getKeyfile() == null && getUserInfo().getPassword() == null) {
- throw new BuildException("Password or Keyfile is required.");
- }
-
- Session session = null;
- try {
- // execute the command
- session = openSession();
- session.setTimeout((int) maxwait);
- ChannelSftp sftp = null;
- sftp = (ChannelSftp) session.openChannel("sftp");
- sftp.connect();
- sftp.put(currentDirectoryZip, remoteDirectory + "/cwd.zip");
- Closeables.closeQuietly(currentDirectoryZip);
-
- if (classpathJar != null || bootClasspathJar != null) {
- if (classpathJar != null) {
- sftp.put(classpathJar, remoteDirectory + "/classpath.jar");
- Closeables.closeQuietly(classpathJar);
- }
- if (bootClasspathJar != null) {
- sftp.put(classpathJar, remoteDirectory + "/boot-classpath.jar");
- Closeables.closeQuietly(classpathJar);
- }
- }
-
- final ChannelExec channel = (ChannelExec) session.openChannel("exec");
- channel.setCommand(command);
-
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- TeeOutputStream teeOut = new TeeOutputStream(out, new KeepAliveOutputStream(System.out));
- ByteArrayOutputStream err = new ByteArrayOutputStream();
- TeeOutputStream teeErr = new TeeOutputStream(err, new KeepAliveOutputStream(System.err));
-
- channel.setOutputStream(teeOut);
- channel.setExtOutputStream(teeOut);
- channel.setErrStream(teeErr);
-
- channel.connect();
-
- // wait for it to finish
- watchDog = new Thread() {
- public void run() {
- while (!channel.isEOF()) {
- if (watchDog == null) {
- return;
- }
- try {
- sleep(500);
- } catch (Exception e) {
- // ignored
- }
- }
- }
- };
-
- watchDog.start();
- watchDog.join(maxwait);
-
- if (watchDog.isAlive()) {
- // ran out of time
-
- throw new BuildException(TIMEOUT_MESSAGE);
- } else {
- // completed successfully
- return writeOutputAndReturnExitStatus(channel, out, err);
- }
- } catch (BuildException e) {
- throw e;
- } catch (JSchException e) {
- if (e.getMessage().indexOf("session is down") >= 0) {
- throw new BuildException(TIMEOUT_MESSAGE, e);
- } else {
- throw new BuildException(e);
- }
- } catch (Exception e) {
- throw new BuildException(e);
- } finally {
- if (session != null && session.isConnected()) {
- session.disconnect();
- }
- }
- }
-
- InputStream makeClasspathJarOrNull(String... paths) {
- if (paths != null && paths.length > 0) {
- JavaArchive classpathArchive = Archives.create("classpath.jar", JavaArchive.class);
- for (String path : paths) {
- File file = new File(path);
- if (file.exists()) {
- if (file.isFile()) {
- try {
- classpathArchive.as(ZipImporter.class).importZip(
- new ZipFile(file.getAbsolutePath()));
- } catch (IOException e) {
- throw new BuildException(e);
- }
- } else {
- classpathArchive.as(ExplodedImporter.class).importDirectory(file);
- }
- }
- }
- return classpathArchive.as(ZipExporter.class).exportZip();
- }
- return null;
- }
-
- private int writeOutputAndReturnExitStatus(final ChannelExec channel, ByteArrayOutputStream out,
- ByteArrayOutputStream err) throws IOException {
- if (outputProperty != null) {
- getProject().setProperty(outputProperty, out.toString());
- }
- if (outputFile != null) {
- writeToFile(err.toString(), append, outputFile);
- }
- if (errorProperty != null) {
- getProject().setProperty(errorProperty, err.toString());
- }
- if (errorFile != null) {
- writeToFile(out.toString(), append, errorFile);
- }
- if (resultProperty != null) {
- getProject().setProperty(resultProperty, channel.getExitStatus() + "");
- }
- return channel.getExitStatus();
- }
-
- /**
- * Writes a string to a file. If destination file exists, it may be overwritten depending on the
- * "append" value.
- *
- * @param from
- * string to write
- * @param to
- * file to write to
- * @param append
- * if true, append to existing file, else overwrite
- * @exception Exception
- * most likely an IOException
- */
- private void writeToFile(String from, boolean append, File to) throws IOException {
- FileWriter out = null;
- try {
- out = new FileWriter(to.getAbsolutePath(), append);
- StringReader in = new StringReader(from);
- char[] buffer = new char[8192];
- int bytesRead;
- while (true) {
- bytesRead = in.read(buffer);
- if (bytesRead == -1) {
- break;
- }
- out.write(buffer, 0, bytesRead);
- }
- out.flush();
- } finally {
- if (out != null) {
- out.close();
- }
- }
- }
-
- String convertJavaToScript(CommandlineJava commandLine) {
checkNotNull(jvm, "jvm must be set");
- checkNotNull(localDirectory, "dir must be set");
checkNotNull(remoteDirectory, "remotedir must be set");
+ // must copy the files over first as we are changing the system properties based on this.
+
+ if (localDirectory != null) {
+ FileSet cwd = new FileSet();
+ cwd.setDir(localDirectory);
+ mkdirAndCopyTo(remoteDirectory.getAbsolutePath(), ImmutableList.of(cwd));
+ }
+
+ if (getCommandLine().getClasspath() != null) {
+ copyPathTo(getCommandLine().getClasspath(), remoteDirectory.getAbsolutePath()
+ + "/classpath");
+ }
+ if (getCommandLine().getBootclasspath() != null) {
+ copyPathTo(getCommandLine().getBootclasspath(), remoteDirectory.getAbsolutePath()
+ + "/bootclasspath");
+ }
+
+ String command = convertJavaToScriptNormalizingPaths(getCommandLine());
+
+ String random = new SecureRandom().nextInt() + "";
+ exec.setResultProperty(random);
+ exec.setFailonerror(false);
+ exec.setCommand(command);
+ exec.setError(errorFile);
+ exec.setErrorproperty(errorProperty);
+ exec.setOutput(outputFile);
+ exec.setOutputproperty(outputProperty);
+ exec.setAppend(append);
+ exec.execute();
+ return Integer.parseInt(getProject().getProperty(random));
+ }
+
+ private void mkdirAndCopyTo(String destination, Iterable sets) {
+ scp.init();
+ exec.setCommand(exec("{md} " + destination).render(osFamily));
+ exec.execute();
+ String scpDestination = getScpDir(destination);
+ System.out.println("Sending to: " + scpDestination);
+ for (FileSet set : sets)
+ scp.addFileset(set);
+ scp.setTodir(scpDestination);
+ scp.execute();
+ }
+
+ private String getScpDir(String path) {
+ return String.format("%s:%s@%s:%s", userInfo.getName(),
+ userInfo.getKeyfile() == null ? userInfo.getPassword() : userInfo.getPassphrase(),
+ scp.getHost(), path);
+ }
+
+ void resetPathToUnderPrefixIfExistsAndIsFileIfNotExistsAddAsIs(Path path, String prefix,
+ StringBuilder destination) {
+ if (path == null)
+ return;
+ String[] paths = path.list();
+ if (paths != null && paths.length > 0) {
+ for (int i = 0; i < paths.length; i++) {
+ File file = new File(paths[i]);
+ if (file.exists()) {
+ // directories are flattened under the prefix anyway, so there's no need to add them
+ // to the path
+ if (file.isFile())
+ destination.append("{ps}").append(file.getName());
+ } else {
+ // if the file doesn't exist, it is probably a "forward reference" to something that
+ // is already on the remote machine
+ destination.append("{ps}").append(file.getAbsolutePath());
+ }
+ }
+ }
+ }
+
+ void copyPathTo(Path path, String destination) {
+ List filesets = Lists.newArrayList();
+ if (path.list() != null && path.list().length > 0) {
+ for (String filepath : path.list()) {
+ File file = new File(filepath);
+ if (file.exists()) {
+ FileSet fileset = new FileSet();
+ if (file.isFile()) {
+ fileset.setFile(file);
+ } else {
+ fileset.setDir(file);
+ }
+ filesets.add(fileset);
+ }
+ }
+ }
+ mkdirAndCopyTo(destination, filesets);
+ }
+
+ String convertJavaToScriptNormalizingPaths(CommandlineJava commandLine) {
List statements = Lists.newArrayList();
String[] environment = env.getVariables();
if (environment != null) {
for (int i = 0; i < environment.length; i++) {
log("Setting environment variable: " + environment[i], Project.MSG_VERBOSE);
- statements.add(exec("{export} " + environment[i]));
+ String[] keyValue = environment[i].split("=");
+ statements.add(exec(String.format("{export} %s={vq}%s{vq}", keyValue[0], keyValue[1])));
}
}
statements.add(exec("{cd} " + remoteDirectory));
- statements.add(exec("jar -xf cwd.zip"));
-
StringBuilder commandBuilder = new StringBuilder(jvm);
- if (commandLine.getBootclasspath() != null
- && commandLine.getBootclasspath().list().length > 0) {
- commandBuilder.append(" -Xbootclasspath:boot-classpath.jar");
+ if (getCommandLine().getBootclasspath() != null) {
+ commandBuilder.append(" -Xbootclasspath:bootclasspath");
+ resetPathToUnderPrefixIfExistsAndIsFileIfNotExistsAddAsIs(commandLine.getBootclasspath(),
+ "bootclasspath", commandBuilder);
}
if (commandLine.getVmCommand().getArguments() != null
&& commandLine.getVmCommand().getArguments().length > 0) {
- commandBuilder.append(" ");
- String[] variables = commandLine.getVmCommand().getArguments();
- for (int i = 0; i < variables.length; i++) {
- commandBuilder.append(variables[i]);
- if (i + 1 < variables.length)
- commandBuilder.append(" ");
- }
- }
- if (commandLine.getClasspath() != null && commandLine.getClasspath().list().length > 0) {
- commandBuilder.append(" -cp classpath.jar");
+ commandBuilder.append(" ").append(
+ Joiner.on(' ').join(commandLine.getVmCommand().getArguments()));
}
+ commandBuilder.append(" -cp classpath");
+ resetPathToUnderPrefixIfExistsAndIsFileIfNotExistsAddAsIs(commandLine.getClasspath(),
+ "classpath", commandBuilder);
+
if (commandLine.getSystemProperties() != null
&& commandLine.getSystemProperties().getVariables() != null
&& commandLine.getSystemProperties().getVariables().length > 0) {
- commandBuilder.append(" ");
- String[] variables = commandLine.getSystemProperties().getVariables();
- for (int i = 0; i < variables.length; i++) {
- commandBuilder.append(variables[i]);
- if (i + 1 < variables.length)
- commandBuilder.append(" ");
- }
+ commandBuilder.append(" ").append(
+ Joiner.on(' ').join(commandLine.getSystemProperties().getVariables()));
}
commandBuilder.append(" ").append(commandLine.getClassname());
if (commandLine.getJavaCommand().getArguments() != null
&& commandLine.getJavaCommand().getArguments().length > 0) {
- commandBuilder.append(" ");
- String[] variables = commandLine.getJavaCommand().getArguments();
- for (int i = 0; i < variables.length; i++) {
- commandBuilder.append(variables[i]);
- if (i + 1 < variables.length)
- commandBuilder.append(" ");
- }
+ commandBuilder.append(" ").append(
+ Joiner.on(' ').join(commandLine.getJavaCommand().getArguments()));
}
statements.add(exec(commandBuilder.toString()));
@@ -351,6 +228,10 @@ public class JavaOverSsh extends Java {
env.addVariable(var);
}
+ /**
+ * Note that if the {@code dir} property is set, this will be copied recursively to the remote
+ * host.
+ */
@Override
public void setDir(File localDir) {
this.localDirectory = checkNotNull(localDir, "dir");
@@ -378,7 +259,8 @@ public class JavaOverSsh extends Java {
* The new host value
*/
public void setHost(String host) {
- this.host = host;
+ exec.setHost(host);
+ scp.setHost(host);
}
/**
@@ -387,7 +269,7 @@ public class JavaOverSsh extends Java {
* @return the host
*/
public String getHost() {
- return host;
+ return exec.getHost();
}
/**
@@ -397,6 +279,8 @@ public class JavaOverSsh extends Java {
* The new username value
*/
public void setUsername(String username) {
+ exec.setUsername(username);
+ scp.setUsername(username);
userInfo.setName(username);
}
@@ -407,6 +291,8 @@ public class JavaOverSsh extends Java {
* The new password value
*/
public void setPassword(String password) {
+ exec.setPassword(password);
+ scp.setPassword(password);
userInfo.setPassword(password);
}
@@ -417,7 +303,11 @@ public class JavaOverSsh extends Java {
* The new keyfile value
*/
public void setKeyfile(String keyfile) {
+ exec.setKeyfile(keyfile);
+ scp.setKeyfile(keyfile);
userInfo.setKeyfile(keyfile);
+ if (userInfo.getPassphrase() == null)
+ userInfo.setPassphrase("");
}
/**
@@ -427,6 +317,8 @@ public class JavaOverSsh extends Java {
* The new passphrase value
*/
public void setPassphrase(String passphrase) {
+ exec.setPassphrase(passphrase);
+ scp.setPassphrase(passphrase);
userInfo.setPassphrase(passphrase);
}
@@ -439,7 +331,8 @@ public class JavaOverSsh extends Java {
* a path to the known hosts file.
*/
public void setKnownhosts(String knownHosts) {
- this.knownHosts = knownHosts;
+ exec.setKnownhosts(knownHosts);
+ scp.setKnownhosts(knownHosts);
}
/**
@@ -449,6 +342,8 @@ public class JavaOverSsh extends Java {
* if true trust the identity of unknown hosts.
*/
public void setTrust(boolean yesOrNo) {
+ exec.setTrust(yesOrNo);
+ scp.setTrust(yesOrNo);
userInfo.setTrust(yesOrNo);
}
@@ -459,7 +354,8 @@ public class JavaOverSsh extends Java {
* port number of remote host.
*/
public void setPort(int port) {
- this.port = port;
+ exec.setPort(port);
+ scp.setPort(port);
}
/**
@@ -468,7 +364,7 @@ public class JavaOverSsh extends Java {
* @return the port
*/
public int getPort() {
- return port;
+ return exec.getPort();
}
/**
@@ -479,42 +375,8 @@ public class JavaOverSsh extends Java {
*/
public void init() throws BuildException {
super.init();
- this.knownHosts = System.getProperty("user.home") + "/.ssh/known_hosts";
- this.port = SSH_PORT;
- }
-
- /**
- * Open an ssh seession.
- *
- * @return the opened session
- * @throws JSchException
- * on error
- */
- protected Session openSession() throws JSchException {
- JSch jsch = new JSch();
- if (null != userInfo.getKeyfile()) {
- jsch.addIdentity(userInfo.getKeyfile());
- }
-
- if (!userInfo.getTrust() && knownHosts != null) {
- log("Using known hosts: " + knownHosts, Project.MSG_DEBUG);
- jsch.setKnownHosts(knownHosts);
- }
-
- Session session = jsch.getSession(userInfo.getName(), host, port);
- session.setUserInfo(userInfo);
- log("Connecting to " + host + ":" + port);
- session.connect();
- return session;
- }
-
- /**
- * Get the user information.
- *
- * @return the user information
- */
- protected SSHUserInfo getUserInfo() {
- return userInfo;
+ exec.init();
+ scp.init();
}
/**
@@ -525,36 +387,85 @@ public class JavaOverSsh extends Java {
* The new timeout value in seconds
*/
public void setTimeout(long timeout) {
- maxwait = timeout;
+ exec.setTimeout(timeout);
+ }
+
+ /**
+ * Set the verbose flag.
+ *
+ * @param verbose
+ * if true output more verbose logging
+ * @since Ant 1.6.2
+ */
+ public void setVerbose(boolean verbose) {
+ exec.setVerbose(verbose);
+ scp.setVerbose(verbose);
}
@Override
- public void setError(File out) {
- this.errorFile = out;
+ public void setError(File error) {
+ this.errorFile = error;
}
@Override
- public void setErrorProperty(String errorProp) {
- this.errorProperty = errorProp;
+ public void setErrorProperty(String property) {
+ errorProperty = property;
}
@Override
public void setOutput(File out) {
- this.outputFile = out;
+ outputFile = out;
}
@Override
public void setOutputproperty(String outputProp) {
- this.outputProperty = outputProp;
- }
-
- @Override
- public void setResultProperty(String resultProperty) {
- this.resultProperty = resultProperty;
+ outputProperty = outputProp;
}
@Override
public void setAppend(boolean append) {
this.append = append;
}
+
+ @Override
+ public void setProject(Project project) {
+ super.setProject(project);
+ exec.setProject(project);
+ scp.setProject(project);
+ }
+
+ @Override
+ public void setOwningTarget(Target target) {
+ super.setOwningTarget(target);
+ exec.setOwningTarget(target);
+ scp.setOwningTarget(target);
+ }
+
+ @Override
+ public void setTaskName(String taskName) {
+ super.setTaskName(taskName);
+ exec.setTaskName(taskName);
+ scp.setTaskName(taskName);
+ }
+
+ @Override
+ public void setDescription(String description) {
+ super.setDescription(description);
+ exec.setDescription(description);
+ scp.setDescription(description);
+ }
+
+ @Override
+ public void setLocation(Location location) {
+ super.setLocation(location);
+ exec.setLocation(location);
+ scp.setLocation(location);
+ }
+
+ @Override
+ public void setTaskType(String type) {
+ super.setTaskType(type);
+ exec.setTaskType(type);
+ scp.setTaskType(type);
+ }
}
diff --git a/tools/antcontrib/src/test/java/org/jclouds/tools/ant/JavaOverSshTest.java b/tools/antcontrib/src/test/java/org/jclouds/tools/ant/JavaOverSshTest.java
index 8e5bed33e9..539ebae90a 100644
--- a/tools/antcontrib/src/test/java/org/jclouds/tools/ant/JavaOverSshTest.java
+++ b/tools/antcontrib/src/test/java/org/jclouds/tools/ant/JavaOverSshTest.java
@@ -24,33 +24,39 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Map.Entry;
import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Java;
import org.apache.tools.ant.types.Environment;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Environment.Variable;
import org.testng.annotations.Test;
+import com.google.common.collect.Iterables;
+
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "jclouds.JavaOverSshTest")
public class JavaOverSshTest {
+ public static final Entry LAST_ENV = Iterables.getLast(System.getenv()
+ .entrySet());
+ // TODO, this test will break in windows
public void testFull() throws SecurityException, NoSuchMethodException {
- JavaOverSsh task = createTask();
- assertEquals(
- String
- .format(
- "cd /tmp/foo\njar -xf cwd.zip\n%s -Xms256 -cp classpath.jar -Dfooble=baz -Dfoo=bar org.jclouds.tools.ant.TestClass hello world\n",
- System.getProperty("java.home") + "/bin/java", System
- .getProperty("user.dir")), task.convertJavaToScript(task
- .getCommandLine()));
+ JavaOverSsh task = makeJavaOverSsh();
+ String expected = String
+ .format(
+ "export %s=\"%s\"%ncd /tmp/foo\n%s -Xms16m -Xmx32m -cp classpath -Dfooble=baz -Dfoo=bar org.jclouds.tools.ant.TestClass %s hello world\n",
+ LAST_ENV.getKey(), LAST_ENV.getValue(), System.getProperty("java.home")
+ + "/bin/java", LAST_ENV.getKey());
+ assertEquals(task.convertJavaToScriptNormalizingPaths(task.getCommandLine()), expected);
}
- private JavaOverSsh createTask() {
+ private Java populateTask(Java task) {
Project p = new Project();
- JavaOverSsh task = new JavaOverSsh();
task.setProject(p);
task.setClassname(TestClass.class.getName());
task.createClasspath().add(new Path(p, "target/test-classes"));
@@ -62,20 +68,43 @@ public class JavaOverSshTest {
Variable prop2 = new Environment.Variable();
prop2.setKey("foo");
prop2.setValue("bar");
-
task.addSysproperty(prop2);
- task.createJvmarg().setValue("-Xms256");
+ task.createJvmarg().setValue("-Xms16m");
+ task.createJvmarg().setValue("-Xmx32m");
+ Variable env = new Environment.Variable();
+ env.setKey(LAST_ENV.getKey());
+ env.setValue(LAST_ENV.getValue());
+ task.addEnv(env);
+ task.createArg().setValue(env.getKey());
task.createArg().setValue("hello");
task.createArg().setValue("world");
task.setDir(new File(System.getProperty("user.dir")));
- task.setRemotedir(new File("/tmp/foo"));
task.setFork(true);
task.setJvm(System.getProperty("java.home") + "/bin/java");
+ task.setOutputproperty("out");
+ task.setErrorProperty("err");
+ task.setResultProperty("result");
return task;
}
@Test(enabled = false, groups = { "live" })
public void testSsh() throws NumberFormatException, FileNotFoundException, IOException {
+ Java java = makeJava();
+ java.execute();
+
+ JavaOverSsh javaOverSsh = makeJavaOverSsh();
+ addDestinationTo(javaOverSsh);
+ javaOverSsh.execute();
+
+ assertEquals(javaOverSsh.getProject().getProperty("out"), javaOverSsh.getProject()
+ .getProperty("out"));
+ assertEquals(javaOverSsh.getProject().getProperty("err"), javaOverSsh.getProject()
+ .getProperty("err"));
+ assertEquals(javaOverSsh.getProject().getProperty("result"), javaOverSsh.getProject()
+ .getProperty("result"));
+ }
+
+ private void addDestinationTo(JavaOverSsh javaOverSsh) throws UnknownHostException {
String sshHost = System.getProperty("jclouds.test.ssh.host");
String sshPort = System.getProperty("jclouds.test.ssh.port");
String sshUser = System.getProperty("jclouds.test.ssh.username");
@@ -85,23 +114,26 @@ public class JavaOverSshTest {
int port = (sshPort != null) ? Integer.parseInt(sshPort) : 22;
InetAddress host = (sshHost != null) ? InetAddress.getByName(sshHost) : InetAddress
.getLocalHost();
-
- JavaOverSsh task = createTask();
- task.setHost(host.getHostAddress());
- task.setPort(port);
- task.setTrust(true);
- task.setUsername(sshUser);
+ javaOverSsh.setHost(host.getHostAddress());
+ javaOverSsh.setPort(port);
+ javaOverSsh.setUsername(sshUser);
if (sshKeyFile != null && !sshKeyFile.trim().equals("")) {
- task.setKeyfile(sshKeyFile);
+ javaOverSsh.setKeyfile(sshKeyFile);
} else {
- task.setPassword(sshPass);
+ javaOverSsh.setPassword(sshPass);
}
- task.setOutputproperty("out");
- task.setErrorProperty("err");
- task.setResultProperty("result");
- task.execute();
- assertEquals(task.getProject().getProperty("out"), "[hello, world]\n");
- assertEquals(task.getProject().getProperty("err"), "err\n");
- assertEquals(task.getProject().getProperty("result"), "3");
+ }
+
+ private JavaOverSsh makeJavaOverSsh() {
+ JavaOverSsh task = new JavaOverSsh();
+ populateTask(task);
+ task.setRemotedir(new File("/tmp/foo"));
+ task.setVerbose(true);
+ task.setTrust(true);
+ return task;
+ }
+
+ private Java makeJava() {
+ return populateTask(new Java());
}
}
diff --git a/tools/antcontrib/src/test/java/org/jclouds/tools/ant/TestClass.java b/tools/antcontrib/src/test/java/org/jclouds/tools/ant/TestClass.java
index 8cf6db3807..385be827f7 100644
--- a/tools/antcontrib/src/test/java/org/jclouds/tools/ant/TestClass.java
+++ b/tools/antcontrib/src/test/java/org/jclouds/tools/ant/TestClass.java
@@ -5,6 +5,8 @@ import java.util.Arrays;
public class TestClass {
public static void main(String... args) {
+ System.out.println("env:");
+ System.out.println(System.getenv(args[0]));
File cwd = new File(System.getProperty("user.dir"));
System.out.println("children:");
for (File child : cwd.listFiles())