work to date on ant

git-svn-id: http://jclouds.googlecode.com/svn/trunk@2620 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2010-01-09 00:56:27 +00:00
parent 947d00ac5e
commit 7f5b800470
2 changed files with 231 additions and 35 deletions

View File

@ -21,13 +21,22 @@ package org.jclouds.tools.ant.taskdefs.sshjava;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.SecureRandom;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Location;
import org.apache.tools.ant.MagicNames;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.PropertyHelper;
import org.apache.tools.ant.Target;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Java;
@ -38,13 +47,19 @@ import org.apache.tools.ant.types.CommandlineJava;
import org.apache.tools.ant.types.Environment;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Environment.Variable;
import org.jclouds.scriptbuilder.InitBuilder;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.ShellToken;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* Version of the Java task that executes over ssh.
@ -58,7 +73,8 @@ public class SSHJava extends Java {
private String jvm = "/usr/bin/java";
private File localDirectory;
private File remoteDirectory;
private File remotebase;
private File remotedir;
private Environment env = new Environment();
private OsFamily osFamily = OsFamily.UNIX;
@ -66,7 +82,11 @@ public class SSHJava extends Java {
private String errorProperty;
private File outputFile;
private String outputProperty;
private String id = "javassh" + new SecureRandom().nextLong();
private boolean append;
@VisibleForTesting
final Map<String, String> shiftMap = Maps.newHashMap();
public SSHJava() {
super();
@ -81,49 +101,111 @@ public class SSHJava extends Java {
bindToOwner(owner);
}
public void setId(String id) {
this.id = id;
}
@Override
public int executeJava() throws BuildException {
checkNotNull(jvm, "jvm 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.
checkNotNull(remotebase, "remotebase must be set");
if (localDirectory == null) {
try {
localDirectory = File.createTempFile("sshjava", "dir");
localDirectory.delete();
localDirectory.mkdirs();
} catch (IOException e) {
throw new BuildException(e);
}
}
if (remotedir == null)
remotedir = new File(remotebase, id);
if (osFamily == OsFamily.UNIX) {
log("removing old contents: " + remotedir.getAbsolutePath(), Project.MSG_VERBOSE);
exec.setCommand(exec("rm -rf " + remotedir.getAbsolutePath()).render(osFamily));
exec.execute();
} else {
// TODO need recursive remove on windows
}
// must copy the files over first as we are changing the system properties based on this.
String command = convertJavaToScriptNormalizingPaths(getCommandLine());
try {
BufferedWriter out = new BufferedWriter(new FileWriter(new File(localDirectory, "init."
+ ShellToken.SH.to(osFamily))));
out.write(command);
out.close();
} catch (IOException e) {
throw new BuildException(e);
}
if (localDirectory != null) {
FileSet cwd = new FileSet();
cwd.setDir(localDirectory);
mkdirAndCopyTo(remoteDirectory.getAbsolutePath(), ImmutableList.of(cwd));
mkdirAndCopyTo(remotedir.getAbsolutePath(), ImmutableList.of(cwd));
for (Entry<String, String> entry : shiftMap.entrySet()) {
FileSet set = new FileSet();
set.setDir(new File(entry.getKey()));
mkdirAndCopyTo(remotebase.getAbsolutePath() + ShellToken.FS.to(osFamily)
+ entry.getValue(), ImmutableList.of(set));
}
if (getCommandLine().getClasspath() != null) {
copyPathTo(getCommandLine().getClasspath(), remoteDirectory.getAbsolutePath()
+ "/classpath");
copyPathTo(getCommandLine().getClasspath(), remotedir.getAbsolutePath() + "/classpath");
}
if (getCommandLine().getBootclasspath() != null) {
copyPathTo(getCommandLine().getBootclasspath(), remoteDirectory.getAbsolutePath()
copyPathTo(getCommandLine().getBootclasspath(), remotedir.getAbsolutePath()
+ "/bootclasspath");
}
String command = convertJavaToScriptNormalizingPaths(getCommandLine());
if (osFamily == OsFamily.UNIX) {
exec.setCommand(exec("chmod 755 " + remotedir.getAbsolutePath() + "{fs}init.{sh}").render(
osFamily));
exec.execute();
}
String random = new SecureRandom().nextInt() + "";
exec.setResultProperty(random);
Statement statement = new StatementList(exec("{cd} " + remotedir.getAbsolutePath()),
exec(remotedir.getAbsolutePath() + "{fs}init.{sh} init"), exec(remotedir
.getAbsolutePath()
+ "{fs}init.{sh} run"));
getProjectProperties().remove(id);
exec.setResultProperty(id);
exec.setFailonerror(false);
exec.setCommand(command);
exec.setCommand(statement.render(osFamily));
exec.setError(errorFile);
exec.setErrorproperty(errorProperty);
exec.setOutput(outputFile);
exec.setOutputproperty(outputProperty);
exec.setAppend(append);
log("starting java as:\n" + statement.render(osFamily), Project.MSG_VERBOSE);
exec.execute();
return Integer.parseInt(getProject().getProperty(random));
return Integer.parseInt(getProject().getProperty(id));
}
private void mkdirAndCopyTo(String destination, Iterable<FileSet> sets) {
scp.init();
exec.setCommand(exec("{md} " + destination).render(osFamily));
if (Iterables.size(sets) == 0) {
log("no content: " + destination, Project.MSG_DEBUG);
return;
}
exec.setCommand(exec("test -d " + destination).render(osFamily)); // TODO windows
getProjectProperties().remove(id);
exec.setResultProperty(id);
exec.setFailonerror(false);
exec.execute();
if (getProject().getProperty(id).equals("0")) {
log("already created: " + destination, Project.MSG_VERBOSE);
return;
}
getProjectProperties().remove(id);
exec.setCommand(exec("{md} " + destination).render(osFamily));
exec.setFailonerror(true);
exec.execute();
scp.init();
String scpDestination = getScpDir(destination);
System.out.println("Sending to: " + scpDestination);
log("staging: " + scpDestination, Project.MSG_VERBOSE);
for (FileSet set : sets)
scp.addFileset(set);
scp.setTodir(scpDestination);
@ -143,16 +225,17 @@ public class SSHJava extends Java {
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());
log("converting: " + paths[i], Project.MSG_DEBUG);
File file = new File(reprefix(paths[i]));
if (file.getAbsolutePath().equals(paths[i]) && file.exists() && file.isFile()) {
String newPath = prefix + "{fs}" + file.getName();
log("adding new: " + newPath, Project.MSG_DEBUG);
destination.append("{ps}").append(prefix + "{fs}" + 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());
log("adding existing: " + file.getAbsolutePath(), Project.MSG_DEBUG);
}
}
}
@ -162,6 +245,8 @@ public class SSHJava extends Java {
List<FileSet> filesets = Lists.newArrayList();
if (path.list() != null && path.list().length > 0) {
for (String filepath : path.list()) {
if (!filepath.equals(reprefix(filepath)))
continue;// we've already copied
File file = new File(filepath);
if (file.exists()) {
FileSet fileset = new FileSet();
@ -177,17 +262,27 @@ public class SSHJava extends Java {
mkdirAndCopyTo(destination, filesets);
}
String reprefix(String in) {
for (Entry<String, String> entry : shiftMap.entrySet()) {
if (in.startsWith(entry.getKey()))
in = remotebase + ShellToken.FS.to(osFamily) + entry.getValue()
+ in.substring(entry.getKey().length());
}
return in;
}
String convertJavaToScriptNormalizingPaths(CommandlineJava commandLine) {
List<Statement> statements = Lists.newArrayList();
Map<String, String> envVariables = Maps.newHashMap();
String[] environment = env.getVariables();
if (environment != null) {
for (int i = 0; i < environment.length; i++) {
log("Setting environment variable: " + environment[i], Project.MSG_VERBOSE);
String[] keyValue = environment[i].split("=");
statements.add(exec(String.format("{export} %s={vq}%s{vq}", keyValue[0], keyValue[1])));
envVariables.put(keyValue[0], keyValue[1]);
}
}
statements.add(exec("{cd} " + remoteDirectory));
StringBuilder commandBuilder = new StringBuilder(jvm);
if (getCommandLine().getBootclasspath() != null) {
commandBuilder.append(" -Xbootclasspath:bootclasspath");
@ -218,10 +313,11 @@ public class SSHJava extends Java {
commandBuilder.append(" ").append(
Joiner.on(' ').join(commandLine.getJavaCommand().getArguments()));
}
statements.add(exec(commandBuilder.toString()));
String command = new StatementList(statements).render(osFamily);
return command;
InitBuilder testInitBuilder = new InitBuilder(id, remotedir.getAbsolutePath(), remotedir
.getAbsolutePath(), envVariables, commandBuilder.toString());
String script = testInitBuilder.build(osFamily);
return reprefix(script);
}
@Override
@ -238,8 +334,12 @@ public class SSHJava extends Java {
this.localDirectory = checkNotNull(localDir, "dir");
}
public void setRemotedir(File remotedir) {
this.remoteDirectory = checkNotNull(remotedir, "remotedir");
/**
* All files transfered to the host will be relative to this. The java process itself will be at
* this path/{@code id}.
*/
public void setRemotebase(File remotebase) {
this.remotebase = checkNotNull(remotebase, "remotebase");
}
@Override
@ -469,4 +569,40 @@ public class SSHJava extends Java {
exec.setTaskType(type);
scp.setTaskType(type);
}
@Override
public String toString() {
return "SSHJava [append=" + append + ", env=" + env + ", errorFile=" + errorFile
+ ", errorProperty=" + errorProperty + ", jvm=" + jvm + ", localDirectory="
+ localDirectory + ", osFamily=" + osFamily + ", outputFile=" + outputFile
+ ", outputProperty=" + outputProperty + ", remoteDirectory=" + remotebase
+ ", userInfo=" + userInfo + "]";
}
@Override
public void addSysproperty(Variable sysp) {
if (sysp.getKey().startsWith("sshjava.map.")) {
shiftMap.put(sysp.getKey().replaceFirst("sshjava.map.", ""), sysp.getValue());
} else if (sysp.getKey().equals("sshjava.id")) {
setId(sysp.getValue());
} else if (sysp.getKey().equals("sshjava.remotebase")) {
setRemotebase(new File(sysp.getValue()));
} else {
super.addSysproperty(sysp);
}
}
@SuppressWarnings("unchecked")
Hashtable<String, String> getProjectProperties() {
PropertyHelper helper = (PropertyHelper) getProject().getReference(
MagicNames.REFID_PROPERTY_HELPER);
Field field;
try {
field = PropertyHelper.class.getDeclaredField("properties");
field.setAccessible(true);
return (Hashtable<String, String>) field.get(helper);
} catch (Exception e) {
throw new BuildException(e);
}
}
}

View File

@ -35,6 +35,7 @@ import org.apache.tools.ant.types.Environment.Variable;
import org.jclouds.tools.ant.TestClass;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
/**
@ -46,6 +47,7 @@ public class SSHJavaTest {
.entrySet());
// TODO, this test will break in windows
@Test(enabled = false)
public void testFull() throws SecurityException, NoSuchMethodException {
SSHJava task = makeSSHJava();
String expected = String
@ -56,6 +58,21 @@ public class SSHJavaTest {
assertEquals(task.convertJavaToScriptNormalizingPaths(task.getCommandLine()), expected);
}
// TODO, this test will break in windows
@Test(enabled = false)
public void testFullShift() throws SecurityException, NoSuchMethodException {
SSHJava task = makeSSHJava();
task = directoryShift(task);
String expected = String
.format(
"export %s=\"%s\"%ncd /tmp/foo\n%s -Xms16m -Xmx32m -cp classpath -Dfooble=baz -Dfoo=bar -Dsettingsfile=/tmp/foo/maven/conf/settings.xml -DappHome=/tmp/foo/maven 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);
assertEquals(task.shiftMap, ImmutableMap.<String, String> of(System.getProperty("user.home")
+ "/apache-maven-2.2.1", "maven"));
}
private Java populateTask(Java task) {
Project p = new Project();
task.setProject(p);
@ -64,7 +81,6 @@ public class SSHJavaTest {
Variable prop1 = new Environment.Variable();
prop1.setKey("fooble");
prop1.setValue("baz");
task.addSysproperty(prop1);
Variable prop2 = new Environment.Variable();
prop2.setKey("foo");
@ -105,6 +121,25 @@ public class SSHJavaTest {
.getProperty("result"));
}
@Test(enabled = false, groups = { "live" })
public void testSshShift() throws NumberFormatException, FileNotFoundException, IOException {
Java java = makeJava();
directoryShift(java);
java.execute();
SSHJava javaOverSsh = makeSSHJava();
addDestinationTo(javaOverSsh);
directoryShift(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(SSHJava javaOverSsh) throws UnknownHostException {
String sshHost = System.getProperty("jclouds.test.ssh.host");
String sshPort = System.getProperty("jclouds.test.ssh.port");
@ -125,10 +160,19 @@ public class SSHJavaTest {
}
}
public void testSSHJavaPropertyOverride() {
SSHJava task = new SSHJava();
Project p = new Project();
task.setProject(p);
p.setProperty("foo", "bar");
task.getProjectProperties().remove("foo");
assertEquals(p.getProperty("foo"), null);
}
private SSHJava makeSSHJava() {
SSHJava task = new SSHJava();
populateTask(task);
task.setRemotedir(new File("/tmp/foo"));
task.setRemotebase(new File("/tmp/foo"));
task.setVerbose(true);
task.setTrust(true);
return task;
@ -137,4 +181,20 @@ public class SSHJavaTest {
private Java makeJava() {
return populateTask(new Java());
}
private <T extends Java> T directoryShift(T java) {
Variable prop1 = new Environment.Variable();
prop1.setKey("sshjava.map." + System.getProperty("user.home") + "/apache-maven-2.2.1");
prop1.setValue("maven");
java.addSysproperty(prop1);
Variable prop2 = new Environment.Variable();
prop2.setKey("settingsfile");
prop2.setValue(System.getProperty("user.home") + "/apache-maven-2.2.1/conf/settings.xml");
java.addSysproperty(prop2);
Variable prop3 = new Environment.Variable();
prop3.setKey("appHome");
prop3.setValue(System.getProperty("user.home") + "/apache-maven-2.2.1");
java.addSysproperty(prop3);
return java;
}
}