org.jerkar.tool.JkRun Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core Show documentation
Show all versions of core Show documentation
Build simpler, stronger, faster
The newest version!
package org.jerkar.tool;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.jerkar.api.depmanagement.JkDependencySet;
import org.jerkar.api.depmanagement.JkDependencyResolver;
import org.jerkar.api.file.JkPathTree;
import org.jerkar.api.system.JkLog;
import org.jerkar.api.utils.*;
/**
* Base class for defining runs. All run classes must extend this class in order to be run with Jerkar.
*
* @author Jerome Angibaud
*/
public class JkRun {
private static final ThreadLocal BASE_DIR_CONTEXT = new ThreadLocal<>();
static void baseDirContext(Path baseDir) {
if (baseDir == null) {
BASE_DIR_CONTEXT.set(null);
} else {
JkUtilsAssert.isTrue(baseDir.isAbsolute(), baseDir + " is not absolute");
JkUtilsAssert.isTrue(Files.isDirectory(baseDir), baseDir + " is not a directory.");
BASE_DIR_CONTEXT.set(baseDir.toAbsolutePath().normalize());
}
}
private final Path baseDir;
private JkRunPlugins plugins;
private JkDependencyResolver runDefDependencyResolver;
private JkDependencySet runDependencies;
private final JkImportedRuns importedRuns;
// ------------------ options --------------------------------------------------------
@JkDoc("Help options")
private final JkHelpOptions help = new JkHelpOptions();
// ------------------ Instantiation cycle --------------------------------------
/**
* Constructs a {@link JkRun}. Using constructor alone won't give you an instance populated with runtime options
* neither decorated with plugins.
* Use {@link JkRun#of(Class)} to get instances populated with options and decorated with plugins.
*/
protected JkRun() {
final Path baseDirContext = BASE_DIR_CONTEXT.get();
JkLog.trace("Initializing " + this.getClass().getName() + " instance with base dir context : " + baseDirContext);
this.baseDir = JkUtilsObject.firstNonNull(baseDirContext, Paths.get("").toAbsolutePath());
JkLog.trace("Initializing " + this.getClass().getName() + " instance with base dir : " + this.baseDir);
// Instantiating imported runs
this.importedRuns = JkImportedRuns.of(this.getBaseTree().getRoot(), this);
this.plugins = new JkRunPlugins(this, Environment.commandLine.getPluginOptions());
}
/**
* Creates a instance of the specified run class (extending JkRun), including option injection, plugin loading
* and plugin activation.
*/
public static T of(Class runClass) {
if (BASE_DIR_CONTEXT.get() == null) {
baseDirContext(Paths.get("").toAbsolutePath());
}
JkLog.startTask("Initializing class " + runClass.getName() + " at " + BASE_DIR_CONTEXT.get());
final T run = JkUtilsReflect.newInstance(runClass);
final JkRun jkRun = run;
// Inject options & environment variables
JkOptions.populateFields(run, JkOptions.readSystemAndUserOptions());
FieldInjector.injectEnv(run);
JkOptions.populateFields(run, Environment.commandLine.getOptions());
// Load plugins declared in command line and inject options
jkRun.plugins.loadCommandLinePlugins();
List plugins = jkRun.getPlugins().getAll();
for (JkPlugin plugin : plugins) {
jkRun.plugins.injectOptions(plugin);
}
run.setup();
for (JkPlugin plugin : new LinkedList<>(plugins)) {
List defs = ProjectDef.RunClassDef.of(plugin).optionDefs();
try {
plugin.activate();
} catch (RuntimeException e) {
JkLog.setVerbosity(JkLog.Verbosity.NORMAL);
JkLog.error("Plugin " + plugin.name() + " has caused build instantiation failure.");
throw e;
}
String pluginInfo = "Instance decorated with plugin " + plugin.getClass()
+ HelpDisplayer.optionValues(defs);
JkLog.info(pluginInfo);
}
// Extra run configuration
run.setupAfterPluginActivations();
List defs = ProjectDef.RunClassDef.of(run).optionDefs();
JkLog.info("Run instance initialized with options " + HelpDisplayer.optionValues(defs));
JkLog.endTask();
baseDirContext(null);
return run;
}
/**
* This method is invoked right after options has been injected into this instance. Here, You will typically
* configure plugins before they are activated.
*/
protected void setup() {
// Do nothing by default
}
/**
* This method is called once all plugin has been activated. This method is intended to overwrite what plugin
* activation has setup.
*/
protected void setupAfterPluginActivations() {
// Do nothing by default
}
// -------------------------------- accessors ---------------------------------------
/**
* Returns the base directory tree for this project. All file/directory path are
* resolved to this directory. Short-hand for JkPathTree.of(baseDir)
.
*/
public final JkPathTree getBaseTree() {
return JkPathTree.of(baseDir);
}
/**
* Returns the base directory for this project.
*/
public final Path getBaseDir() {
return baseDir;
}
/**
* Returns the output directory where all the final and intermediate artifacts are generated.
*/
public Path getOutputDir() {
return baseDir.resolve(JkConstants.OUTPUT_PATH);
}
/**
* Returns the container of loaded plugins for this instance.
*/
public JkRunPlugins getPlugins() {
return this.plugins;
}
/**
* Shorthand to getPlugins().get()
.
* Returns the plugin instance of the specified class loaded in the holding JkRun instance. If it does not hold
* a plugin of the specified class at call time, the plugin is loaded then returned.
*/
public T getPlugin(Class pluginClass) {
return getPlugins().get(pluginClass);
}
// ------------------------------ run dependencies --------------------------------
void setRunDependencyResolver(JkDependencySet runDependencies, JkDependencyResolver scriptDependencyResolver) {
this.runDependencies = runDependencies;
this.runDefDependencyResolver = scriptDependencyResolver;
}
/**
* Returns the dependency resolver used to compile/run scripts of this project.
*/
public final JkDependencyResolver getRunDependencyResolver() {
return this.runDefDependencyResolver;
}
/**
* Dependencies necessary to compile the this run class. It is not the dependencies for building the project.
*/
public final JkDependencySet getRunDependencies() {
return runDependencies;
}
/**
* Returns imported runs with plugins applied on.
*/
public final JkImportedRuns getImportedRuns() {
return importedRuns;
}
// ------------------------------ Command line methods ------------------------------
/**
* Cleans the output directory.
*/
@JkDoc("Cleans the output directory except the compiled run classes.")
public void clean() {
JkLog.info("Clean output directory " + getOutputDir());
if (Files.exists(getOutputDir())) {
JkPathTree.of(getOutputDir()).andMatching(false, JkConstants.DEF_BIN_DIR_NAME + "/**")
.deleteContent();
}
}
/**
* Displays all available methods defined in this run.
*/
@JkDoc("Displays all available methods and options defined for this run class.")
public void help() {
if (help.xml || help.xmlFile != null) {
HelpDisplayer.help(this, help.xmlFile);
} else {
HelpDisplayer.help(this);
}
}
// ----------------------------------------------------------------------------------
@Override
public String toString() {
return this.getClass().getName() + " at " + this.baseDir.toString();
}
}