package org.antmod.buildplugin;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import org.antmod.util.AntUtil;
import org.apache.commons.io.FileUtils;
import org.apache.tools.ant.Project;
/**
* Represents an Antmod build plugin.
*
* @author Klaas Waslander
*/
public final class BuildPlugin {
public final static int BUILDLEVEL_MODULE = 1111;
public final static int BUILDLEVEL_RELEASE = 2222;
private File pluginDir;
private Project moduleAntProject;
private ArrayList moduleAntTargets;
private Project releaseAntProject;
private ArrayList releaseAntTargets;
/**
* Only to be instantiated by this package;
* this constructor uses reflection to get properties out of
* the given object, assuming the 'otherBuildPlugin' is a
* BuildPlugin loaded in another classloader instance.
*/
BuildPlugin(Project invokingAntProject, Object otherBuildPlugin) {
this.pluginDir = (File)invokeGetter(otherBuildPlugin, "getPluginHome");
this.moduleAntProject = (Project)invokeGetter(otherBuildPlugin, "getModuleAntProject");
this.moduleAntTargets = (ArrayList)invokeGetter(otherBuildPlugin, "getModuleAntTargets");
this.releaseAntProject = (Project)invokeGetter(otherBuildPlugin, "getReleaseAntProject");
this.releaseAntTargets = (ArrayList)invokeGetter(otherBuildPlugin, "getReleaseAntTargets");
/*
if (moduleAntProject != null) {
moduleAntProject.log("[ " + invokingAntProject.getProperty("ant.file") + "] CACHED BUILD PLUGIN: " + pluginDir, Project.MSG_WARN);
}
else if (releaseAntProject != null) {
releaseAntProject.log("[ " + invokingAntProject.getProperty("ant.file") + "] CACHED BUILD PLUGIN: " + pluginDir, Project.MSG_WARN);
}
*/
}
/** Only to be instantiated by this package */
BuildPlugin(Project antProject, File pluginDirectory) {
//antProject.log("[ " + antProject.getProperty("ant.file") + "] NEW BUILD PLUGIN: " + pluginDirectory, Project.MSG_WARN);
this.pluginDir = pluginDirectory;
// analyze buildfiles
//System.err.println("Scanning modulebuild.xml of " + getName() + "...");
File modulebuildFile = new File(pluginDirectory, "modulebuild.xml");
if (modulebuildFile.exists()) {
this.moduleAntProject = AntUtil.getAntProject(antProject, modulebuildFile, true);
if (this.moduleAntProject == null) {
throw new RuntimeException("modulebuild.xml for plugin " + getName() + " not found or initialized");
}
//AntUtil.inheritRefs(antProject, this.moduleAntProject);
this.moduleAntProject.setProperty("antmod.plugins." + getName() + ".home", pluginDirectory.getAbsolutePath());
this.moduleAntTargets = AntUtil.getAntTargets(this.moduleAntProject);
}
//System.err.println("Scanning releaseebuild.xml of " + getName() + "...");
File releasebuildFile = new File(pluginDirectory, "releasebuild.xml");
if (releasebuildFile.exists()) {
this.releaseAntProject = AntUtil.getAntProject(antProject, releasebuildFile, true);
if (this.releaseAntProject == null) {
throw new RuntimeException("releasebuild.xml for plugin " + getName() + " not found or initialized");
}
//AntUtil.inheritRefs(antProject, this.releaseAntProject);
this.releaseAntProject.setProperty("antmod.plugins." + getName() + ".home", pluginDirectory.getAbsolutePath());
this.releaseAntTargets = AntUtil.getAntTargets(this.releaseAntProject);
}
//System.err.println("Scanning done for " + getName() + "!");
}
private static Object invokeGetter(Object instance, String getMethod) {
Method m;
try {
m = instance.getClass().getMethod(getMethod, null);
return m.invoke(instance, null);
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* The plugin home directory.
*/
public File getPluginHome() {
return pluginDir;
}
/**
* The name of this build plugin.
*/
public String getName() {
return pluginDir.getName();
}
public Project getModuleAntProject() {
return moduleAntProject;
}
public ArrayList getModuleAntTargets() {
return moduleAntTargets;
}
public Project getReleaseAntProject() {
return releaseAntProject;
}
public ArrayList getReleaseAntTargets() {
return releaseAntTargets;
}
/**
* Check whether this plugin has the given Ant target in the given ant file.
* @param buildLevel Either BUILDLEVEL_MODULE or BUILDLEVEL_RELEASE
* @param antTarget The name of the Ant target that possibly exists for the given buildlevel
*/
public boolean hasAntTarget(int buildLevel, String antTarget) {
if (buildLevel == BUILDLEVEL_MODULE) {
return this.moduleAntTargets != null && this.moduleAntTargets.contains(antTarget);
} else if (buildLevel == BUILDLEVEL_RELEASE) {
return this.releaseAntTargets != null && this.releaseAntTargets.contains(antTarget);
}
throw new IllegalArgumentException("Invalid build level - should be either BUILDLEVEL_MODULE or BUILDLEVEL_RELEASE");
}
/**
* Invoke the given ant target of the plugin, properties created by the plugin are
* pushed back into the parentProject for reuse elsewhere in the Antmod builds.
* @param parentProject The project that receives the properties created by the plugin
* @param buildLevel Either BUILDLEVEL_MODULE or BUILDLEVEL_RELEASE
* @param antTarget The name of the Ant target to invoke for the given buildlevel
*/
public void invokeAntTarget(Project parentProject, int buildLevel, String antTarget) {
if (hasAntTarget(buildLevel, antTarget)) {
// execute target
if (buildLevel == BUILDLEVEL_MODULE) {
/*
this.moduleAntProject.setBaseDir(parentProject.getBaseDir());
this.moduleAntProject.setProperty("basedir",parentProject.getBaseDir().getAbsolutePath());
AntUtil.inheritRefs(parentProject, this.moduleAntProject);
passBackProperties("antmod.", parentProject, this.moduleAntProject);
this.moduleAntProject.executeTarget(antTarget);
passBackProperties("antmod." + getName(), this.moduleAntProject, parentProject);
*/
// REMIND: need to re-create Ant project every time, because basedir is not properly changeable it seems...
Project newModuleProject = AntUtil.getAntProject(parentProject, new File(this.pluginDir, "modulebuild.xml"), true);
AntUtil.inheritRefs(parentProject, newModuleProject);
newModuleProject.executeTarget(antTarget);
passBackProperties("antmod." + getName(), newModuleProject, parentProject);
}
else if (buildLevel == BUILDLEVEL_RELEASE) {
/*
this.releaseAntProject.setBaseDir(parentProject.getBaseDir());
this.releaseAntProject.setProperty("basedir",parentProject.getBaseDir().getAbsolutePath());
AntUtil.inheritRefs(parentProject, this.releaseAntProject);
passBackProperties("antmod.", parentProject, this.releaseAntProject);
this.releaseAntProject.executeTarget(antTarget);
passBackProperties("antmod." + getName(), this.releaseAntProject, parentProject);
*/
// REMIND: need to re-create Ant project every time, because basedir is not properly changeable it seems...
Project newReleaseProject = AntUtil.getAntProject(parentProject, new File(this.pluginDir, "releasebuild.xml"), true);
AntUtil.inheritRefs(parentProject, newReleaseProject);
newReleaseProject.executeTarget(antTarget);
passBackProperties("antmod." + getName(), newReleaseProject, parentProject);
}
else {
throw new IllegalArgumentException("Invalid build level - should be either BUILDLEVEL_MODULE or BUILDLEVEL_RELEASE");
}
}
}
/**
* Get the contents of the "injectrelease.xml" file of this plugin.
* @return Null if no injectrelease file existed
*/
public String getInjectReleaseContents() {
File injectRelease = new File(this.pluginDir, "injectrelease.xml");
if (injectRelease.exists()) {
try {
return FileUtils.readFileToString(injectRelease, System.getProperty("file.encoding"));
} catch (IOException ioe) {
throw new IllegalStateException("Cannot read contents of file \"" + injectRelease.getPath() + "\": " + ioe);
}
}
return null;
}
/**
* Get the contents of the "injectmodule.xml" file of this plugin.
* @return Null if no injectmodule file existed
*/
public String getInjectModuleContents() {
File injectModule = new File(this.pluginDir, "injectmodule.xml");
if (injectModule.exists()) {
try {
return FileUtils.readFileToString(injectModule, System.getProperty("file.encoding"));
} catch (IOException ioe) {
throw new IllegalStateException("Cannot read contents of file \"" + injectModule.getPath() + "\": " + ioe);
}
}
return null;
}
/** 'passes' only Antmod properties (starting with 'antmod.') from this Antmod plugin from 'fromProject' to 'toProject' */
private void passBackProperties(String propnameStart, Project fromProject, Project toProject) {
Hashtable props = fromProject.getProperties();
Enumeration propNames = props.keys();
String propName;
while (propNames.hasMoreElements()) {
propName = (String)propNames.nextElement();
if (propName.startsWith(propnameStart)) {
toProject.setProperty(propName, fromProject.getProperty(propName));
}
}
}
}
|