modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java |
12 -
modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/AbstractFileType.java |
9 +
modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java |
43 ++++++
modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/SystemServiceType.java |
57 +++++---
modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java |
65 ++++++++++
modules/common/ant-bundle/src/test/resources/test-bundle-subdir.xml |
25 +++
6 files changed, 181 insertions(+), 30 deletions(-)
New commits:
commit 9f1a09b854b0f21b66819f2906e7b6659347d2e7
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Thu Dec 23 11:09:49 2010 -0500
BZ 610879 - make sure the ant parser knows the true location of the local raw files
and archive files so the UI can ask for them when appropriate
diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java
b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java
index 86fd666..f5d32eb 100644
--- a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java
+++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java
@@ -238,13 +238,13 @@ public class AntLauncher {
"The bundle task must contain exactly one rhq:deploymentUnit child
element.");
}
DeploymentUnitType deployment = deployments.iterator().next();
- Map<File, File> files = deployment.getFiles();
- for (File file : files.keySet()) {
- project.getBundleFileNames().add(file.getName());
+ Map<File, String> files = deployment.getLocalFileNames();
+ for (String file : files.values()) {
+ project.getBundleFileNames().add(file);
}
- Set<File> archives = deployment.getArchives();
- for (File archive : archives) {
- project.getBundleFileNames().add(archive.getName());
+ Map<File, String> archives = deployment.getLocalArchiveNames();
+ for (String archive : archives.values()) {
+ project.getBundleFileNames().add(archive);
}
}
diff --git
a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/AbstractFileType.java
b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/AbstractFileType.java
index 29b9d92..f5bbe92 100644
---
a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/AbstractFileType.java
+++
b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/AbstractFileType.java
@@ -25,7 +25,6 @@ package org.rhq.bundle.ant.type;
import java.io.File;
import org.apache.tools.ant.BuildException;
-import org.apache.tools.ant.types.DataType;
/**
* A base class for the functionality shared by {@link FileType} and {@link
ArchiveType}.
@@ -33,6 +32,7 @@ import org.apache.tools.ant.types.DataType;
* @author Ian Springer
*/
public abstract class AbstractFileType extends AbstractBundleType {
+ private String name;
private File source;
// TODO: We currently do not call this method. Do we want to or should we just let
the Deployer utility handle
@@ -43,7 +43,7 @@ public abstract class AbstractFileType extends AbstractBundleType {
}
if (this.source.isDirectory()) {
throw new BuildException("File path specified by 'name'
attribute (" + this.source
- + ") is a directory - it must be a regular file.");
+ + ") is a directory - it must be a regular file.");
}
}
@@ -51,7 +51,12 @@ public abstract class AbstractFileType extends AbstractBundleType {
return this.source;
}
+ public String getName() {
+ return this.name;
+ }
+
public void setName(String name) {
+ this.name = name;
File file = new File(name);
if (file.isAbsolute()) {
throw new BuildException("Path specified by 'name' attribute
(" + name
diff --git
a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java
b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java
index 31a52bc..8d00a96 100644
---
a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java
+++
b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java
@@ -49,8 +49,10 @@ public class DeploymentUnitType extends AbstractBundleType {
private String name;
private String manageRootDir = Boolean.TRUE.toString();
private Map<File, File> files = new LinkedHashMap<File, File>();
+ private Map<File, String> localFileNames = new LinkedHashMap<File,
String>();
private Set<File> rawFilesToReplace = new LinkedHashSet<File>();
private Set<File> archives = new LinkedHashSet<File>();
+ private Map<File, String> localArchiveNames = new LinkedHashMap<File,
String>();
private Map<File, Boolean> archivesExploded = new HashMap<File,
Boolean>();
private Map<File, Pattern> archiveReplacePatterns = new HashMap<File,
Pattern>();
private SystemServiceType systemService;
@@ -175,15 +177,50 @@ public class DeploymentUnitType extends AbstractBundleType {
this.manageRootDir = booleanString;
}
+ /**
+ * Returns a map of all raw files. The key is the full absolute path
+ * to the file as it does or would appear on the file system. The value
+ * is a path that is either absolute or relative - it is the destination
+ * where the file is to be placed when being deployed on the destination file
system;
+ * if the value is relative, then it is relative to the root destination directory.
+ *
+ * @return map of raw files
+ */
public Map<File, File> getFiles() {
return files;
}
+ /**
+ * Returns a map of all raw files. The key is the full absolute path
+ * to the file as it does or would appear on the file system (the same key
+ * as the keys in map {@link #getFiles()}).
+ * The value is a path relative to the file as it is found in the bundle distro (this
+ * is the "name" attribute of the "file" type tag).
+ *
+ * @return map of local file names
+ */
+ public Map<File, String> getLocalFileNames() {
+ return localFileNames;
+ }
+
public Set<File> getArchives() {
return archives;
}
/**
+ * Returns a map of all archive files. The key is the full absolute path
+ * to the archive as it does or would appear on the file system (the same key
+ * as the keys in map {@link #getArchives()}).
+ * The value is a path relative to the file as it is found in the bundle distro (this
+ * is the "name" attribute of the "archive" type tag).
+ *
+ * @return map of local file names
+ */
+ public Map<File, String> getLocalArchiveNames() {
+ return localArchiveNames;
+ }
+
+ /**
* Returns a map keyed on {@link #getArchives() archive names} whose values
* are either true or false, where true means the archive is to be deployed exploded
* and false means the archive should be deployed in compressed form.
@@ -220,8 +257,10 @@ public class DeploymentUnitType extends AbstractBundleType {
// Add the init script and its config file to the list of bundle files.
this.files.put(this.systemService.getScriptFile(),
this.systemService.getScriptDestFile());
+ this.localFileNames.put(this.systemService.getScriptFile(),
this.systemService.getScriptFileName());
if (this.systemService.getConfigFile() != null) {
this.files.put(this.systemService.getConfigFile(),
this.systemService.getConfigDestFile());
+ this.localFileNames.put(this.systemService.getConfigFile(),
this.systemService.getConfigFileName());
this.rawFilesToReplace.add(this.systemService.getConfigFile());
}
}
@@ -232,7 +271,8 @@ public class DeploymentUnitType extends AbstractBundleType {
File destDir = file.getDestinationDir();
destFile = new File(destDir, file.getSource().getName());
}
- this.files.put(file.getSource(), destFile);
+ this.files.put(file.getSource(), destFile); // key=full absolute path,
value=could be relative or absolute
+ this.localFileNames.put(file.getSource(), file.getName());
if (file.isReplace()) {
this.rawFilesToReplace.add(file.getSource());
}
@@ -240,6 +280,7 @@ public class DeploymentUnitType extends AbstractBundleType {
public void addConfigured(ArchiveType archive) {
this.archives.add(archive.getSource());
+ this.localArchiveNames.put(archive.getSource(), archive.getName());
Pattern replacePattern = archive.getReplacePattern();
if (replacePattern != null) {
this.archiveReplacePatterns.put(archive.getSource(), replacePattern);
diff --git
a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/SystemServiceType.java
b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/SystemServiceType.java
index fd1fd93..6521d2e 100644
---
a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/SystemServiceType.java
+++
b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/SystemServiceType.java
@@ -18,12 +18,6 @@
*/
package org.rhq.bundle.ant.type;
-import org.apache.tools.ant.BuildException;
-import org.apache.tools.ant.taskdefs.Chmod;
-import org.apache.tools.ant.taskdefs.Copy;
-import org.apache.tools.ant.taskdefs.Execute;
-import org.apache.tools.ant.taskdefs.optional.unix.Symlink;
-
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
@@ -31,6 +25,12 @@ import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Chmod;
+import org.apache.tools.ant.taskdefs.Copy;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.optional.unix.Symlink;
+
/**
* An Ant task that installs a system startup/shutdown service. Currently only Red Hat
Linux versions are supported.
*
@@ -53,6 +53,8 @@ public class SystemServiceType extends AbstractBundleType {
private String name;
private File scriptFile;
private File configFile;
+ private String scriptFileName;
+ private String configFileName;
private boolean overwriteScript;
private boolean overwriteConfig;
private boolean overwriteLinks = true;
@@ -64,7 +66,7 @@ public class SystemServiceType extends AbstractBundleType {
* before services with a higher priority number.
*/
private Byte startPriority;
-
+
/**
* An integer from 0-99 indicating the service's stop order - services with a
lower priority number are stopped
* before services with a higher priority number.
@@ -79,13 +81,13 @@ public class SystemServiceType extends AbstractBundleType {
public void validate() throws BuildException {
validateAttributes();
-
+
this.scriptDestFile = new File(getInitDir(), this.name);
this.configDestFile = new File(getSysConfigDir(), this.name);
}
public void init() throws BuildException {
- if (!OS_NAME.equals("Linux") || !REDHAT_RELEASE_FILE.exists() ) {
+ if (!OS_NAME.equals("Linux") || !REDHAT_RELEASE_FILE.exists()) {
throw new BuildException("The system-service element is only supported
on Red Hat Linux systems.");
}
@@ -116,7 +118,7 @@ public class SystemServiceType extends AbstractBundleType {
// Install the script itself (e.g. /etc/init.d/named).
File initDir = getInitDir();
if (!initDir.exists()) {
- initDir.mkdirs();
+ initDir.mkdirs();
}
if (!initDir.canWrite()) {
throw new BuildException(initDir + " directory is not
writeable.");
@@ -150,23 +152,23 @@ public class SystemServiceType extends AbstractBundleType {
public void start() throws BuildException {
File scriptFile = getScriptDestFile();
- String[] commandLine = {scriptFile.getAbsolutePath(), "start"};
+ String[] commandLine = { scriptFile.getAbsolutePath(), "start" };
try {
executeCommand(commandLine);
} catch (IOException e) {
- throw new BuildException("Failed to start " + this.name + "
system service via command [" + Arrays.toString(commandLine)
- + "].", e);
+ throw new BuildException("Failed to start " + this.name + "
system service via command ["
+ + Arrays.toString(commandLine) + "].", e);
}
}
public void stop() throws BuildException {
File scriptFile = getScriptDestFile();
- String[] commandLine = {scriptFile.getAbsolutePath(), "stop"};
+ String[] commandLine = { scriptFile.getAbsolutePath(), "stop" };
try {
executeCommand(commandLine);
} catch (IOException e) {
- throw new BuildException("Failed to stop " + this.name + "
system service via command [" + Arrays.toString(commandLine)
- + "].", e);
+ throw new BuildException("Failed to stop " + this.name + "
system service via command ["
+ + Arrays.toString(commandLine) + "].", e);
}
}
@@ -182,6 +184,10 @@ public class SystemServiceType extends AbstractBundleType {
this.name = name;
}
+ public String getScriptFileName() {
+ return scriptFileName;
+ }
+
public File getScriptFile() {
return scriptFile;
}
@@ -192,9 +198,14 @@ public class SystemServiceType extends AbstractBundleType {
throw new BuildException("Path specified by 'scriptFile'
attribute (" + scriptFile
+ ") is not relative - it must be a relative path, relative to the
Ant basedir.");
}
+ this.scriptFileName = scriptFile;
this.scriptFile = getProject().resolveFile(scriptFile);
}
+ public String getConfigFileName() {
+ return configFileName;
+ }
+
public File getConfigFile() {
return configFile;
}
@@ -205,6 +216,7 @@ public class SystemServiceType extends AbstractBundleType {
throw new BuildException("Path specified by 'configFile'
attribute (" + configFile
+ ") is not relative - it must be a relative path, relative to the
Ant basedir.");
}
+ this.configFileName = configFile;
this.configFile = getProject().resolveFile(configFile);
}
@@ -290,7 +302,7 @@ public class SystemServiceType extends AbstractBundleType {
throw new BuildException("The 'startLevels' attribute must have
a non-empty value.");
}
this.startLevelChars = parseLevels(this.startLevels);
- this.stopLevelChars = new TreeSet<Character>();
+ this.stopLevelChars = new TreeSet<Character>();
for (char level : REDHAT_RUN_LEVELS) {
if (!this.startLevelChars.contains(level)) {
this.stopLevelChars.add(level);
@@ -314,7 +326,7 @@ public class SystemServiceType extends AbstractBundleType {
this.root.mkdirs();
if (!this.root.exists()) {
throw new BuildException("Failed to create root directory " +
this.root
- + " as specified by 'root' attribute.");
+ + " as specified by 'root' attribute.");
}
}
if (!this.root.isDirectory()) {
@@ -341,12 +353,15 @@ public class SystemServiceType extends AbstractBundleType {
}
} catch (Exception e) {
- throw new BuildException("Invalid run level: " + token
+ throw new BuildException(
+ "Invalid run level: "
+ + token
+ " - the 'startLevels' attribute must be a
comma-separated list of run levels - the valid levels are "
+ REDHAT_RUN_LEVELS + ".");
}
if (levelChars.contains(level)) {
- throw new BuildException("The 'startLevels' attribute
defines run level " + level + " more than once.");
+ throw new BuildException("The 'startLevels' attribute
defines run level " + level
+ + " more than once.");
}
levelChars.add(level);
}
@@ -399,7 +414,7 @@ public class SystemServiceType extends AbstractBundleType {
private int executeCommand(String[] commandLine) throws IOException {
Execute executeTask = new Execute();
- executeTask.setCommandline(commandLine);
+ executeTask.setCommandline(commandLine);
return executeTask.execute();
}
diff --git
a/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java
b/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java
index 772c3e5..956ea93 100644
--- a/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java
+++ b/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java
@@ -476,6 +476,71 @@ public class AntLauncherTest {
"777");
}
+ public void testSubdirectoriesInRecipe() throws Exception {
+ // We want to test a fresh install, so make sure the deploy dir doesn't
pre-exist.
+ FileUtil.purge(DEPLOY_DIR, true);
+
+ // we need to create our own directory structure - let's build a temporary
ant basedir
+ // and put our recipe in there as well as a subdirectory with a test raw file and
test zip file
+ File antBasedir = FileUtil.createTempDirectory("anttest",
".test", null);
+ try {
+ File subdir = new File(antBasedir, "subdir"); // must match the
name in the recipe
+ subdir.mkdirs();
+ writeFile("file1", subdir, "test1.txt"); // filename must
match recipe
+ writeFile("file2", subdir, "test2.txt"); // filename must
match recipe
+ createZip(new String[] { "one", "two" }, subdir,
"test.zip", new String[] { "one.txt", "two.txt" });
+ createZip(new String[] { "3", "4" }, subdir,
"test-explode.zip", new String[] { "three.txt", "four.txt"
});
+ createZip(new String[] { "X=@@X@@\n" }, subdir,
"test-replace.zip", new String[] { "template.txt" }); // will be
exploded then recompressed
+ File recipeFile = new File(antBasedir, "deploy.xml");
+ FileUtil.copyFile(new File(ANT_BASEDIR, "test-bundle-subdir.xml"),
recipeFile);
+
+ AntLauncher ant = new AntLauncher();
+ Properties inputProps = new Properties();
+ inputProps.setProperty(DeployPropertyNames.DEPLOY_DIR,
DEPLOY_DIR.getPath());
+ inputProps.setProperty(DeployPropertyNames.DEPLOY_ID,
String.valueOf(++this.deploymentId));
+ inputProps.setProperty(DeployPropertyNames.DEPLOY_PHASE,
DeploymentPhase.INSTALL.name());
+ inputProps.setProperty("X", "alpha-omega");
+ List<BuildListener> buildListeners = createBuildListeners();
+
+ BundleAntProject project = ant.executeBundleDeployFile(recipeFile,
inputProps, buildListeners);
+ assert project != null;
+ Set<String> bundleFiles = project.getBundleFileNames();
+ assert bundleFiles != null;
+ assert bundleFiles.size() == 5 : bundleFiles;
+ assert bundleFiles.contains("subdir/test1.txt") : bundleFiles;
+ assert bundleFiles.contains("subdir/test2.txt") : bundleFiles;
+ assert bundleFiles.contains("subdir/test.zip") : bundleFiles;
+ assert bundleFiles.contains("subdir/test-explode.zip") :
bundleFiles;
+ assert bundleFiles.contains("subdir/test-replace.zip") :
bundleFiles;
+
+ assert new File(DEPLOY_DIR, "another/foo.txt").exists() :
"missing raw file from the destinationFile";
+ assert new File(DEPLOY_DIR, "second.dir/test2.txt").exists() :
"missing raw file from the destinationDir";
+ assert !new File(DEPLOY_DIR, "subdir/test1.zip").exists() :
"should not be here because destinationFile was specified";
+ assert !new File(DEPLOY_DIR, "subdir/test2.zip").exists() :
"should not be here because destinationFile was specified";
+ assert new File(DEPLOY_DIR, "subdir/test.zip").exists() :
"missing unexploded zip file";
+ assert new File(DEPLOY_DIR, "subdir/test-replace.zip").exists() :
"missing unexploded zip file";
+ assert !new File(DEPLOY_DIR, "subdir/test-explode.zip").exists() :
"should have been exploded";
+
+ // test that the file in the zip is realized
+ final String[] templateVarValue = new String[] { null };
+ ZipUtil.walkZipFile(new File(DEPLOY_DIR,
"subdir/test-replace.zip"), new ZipUtil.ZipEntryVisitor() {
+ @Override
+ public boolean visit(ZipEntry entry, ZipInputStream stream) throws
Exception {
+ if (entry.getName().equals("template.txt")) {
+ Properties props = new Properties();
+ props.load(stream);
+ templateVarValue[0] = props.getProperty("X");
+ }
+ return true;
+ }
+ });
+ assert templateVarValue[0] != null &&
templateVarValue[0].equals("alpha-omega") : templateVarValue[0];
+
+ } finally {
+ FileUtil.purge(antBasedir, true);
+ }
+ }
+
private List<BuildListener> createBuildListeners() {
List<BuildListener> buildListeners = new ArrayList<BuildListener>();
DefaultLogger logger = new DefaultLogger();
diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-subdir.xml
b/modules/common/ant-bundle/src/test/resources/test-bundle-subdir.xml
new file mode 100644
index 0000000..940ecf1
--- /dev/null
+++ b/modules/common/ant-bundle/src/test/resources/test-bundle-subdir.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+
+<project name="test-bundle" default="main"
xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="test" version="1">
+
+ <rhq:input-property name="X" />
+
+ <rhq:deployment-unit name="appserver">
+ <rhq:file name="subdir/test1.txt"
destinationFile="another/foo.txt" replace="false"/>
+ <rhq:file name="subdir/test2.txt"
destinationDir="second.dir" replace="false"/>
+ <rhq:archive name="subdir/test.zip" exploded="false"
/>
+ <rhq:archive name="subdir/test-explode.zip"
exploded="true" />
+ <rhq:archive name="subdir/test-replace.zip"
exploded="false">
+ <rhq:replace>
+ <rhq:fileset includes="template.txt"/>
+ </rhq:replace>
+ </rhq:archive>
+ </rhq:deployment-unit>
+
+ </rhq:bundle>
+
+ <target name="main"/>
+
+</project>
\ No newline at end of file