summaryrefslogtreecommitdiffstats
path: root/branches/sca-java-1.1/tools/maven/maven-incremental-build/src/main
diff options
context:
space:
mode:
authordims <dims@13f79535-47bb-0310-9956-ffa450edef68>2008-06-17 00:23:01 +0000
committerdims <dims@13f79535-47bb-0310-9956-ffa450edef68>2008-06-17 00:23:01 +0000
commitbdd0a41aed7edf21ec2a65cfa17a86af2ef8c48a (patch)
tree38a92061c0793434c4be189f1d70c3458b6bc41d /branches/sca-java-1.1/tools/maven/maven-incremental-build/src/main
Move Tuscany from Incubator to top level.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@668359 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'branches/sca-java-1.1/tools/maven/maven-incremental-build/src/main')
-rw-r--r--branches/sca-java-1.1/tools/maven/maven-incremental-build/src/main/java/org/apache/tuscany/sca/tools/incremental/build/plugin/AbstractBuildMojo.java459
-rw-r--r--branches/sca-java-1.1/tools/maven/maven-incremental-build/src/main/java/org/apache/tuscany/sca/tools/incremental/build/plugin/IncrementalBuildMojo.java196
2 files changed, 655 insertions, 0 deletions
diff --git a/branches/sca-java-1.1/tools/maven/maven-incremental-build/src/main/java/org/apache/tuscany/sca/tools/incremental/build/plugin/AbstractBuildMojo.java b/branches/sca-java-1.1/tools/maven/maven-incremental-build/src/main/java/org/apache/tuscany/sca/tools/incremental/build/plugin/AbstractBuildMojo.java
new file mode 100644
index 0000000000..576fd47d96
--- /dev/null
+++ b/branches/sca-java-1.1/tools/maven/maven-incremental-build/src/main/java/org/apache/tuscany/sca/tools/incremental/build/plugin/AbstractBuildMojo.java
@@ -0,0 +1,459 @@
+package org.apache.tuscany.sca.tools.incremental.build.plugin;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.model.Resource;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.compiler.Compiler;
+import org.codehaus.plexus.compiler.CompilerConfiguration;
+import org.codehaus.plexus.compiler.CompilerException;
+import org.codehaus.plexus.compiler.CompilerOutputStyle;
+import org.codehaus.plexus.compiler.manager.CompilerManager;
+import org.codehaus.plexus.compiler.manager.NoSuchCompilerException;
+import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
+import org.codehaus.plexus.compiler.util.scan.SimpleSourceInclusionScanner;
+import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
+import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
+import org.codehaus.plexus.compiler.util.scan.mapping.SingleTargetSourceMapping;
+import org.codehaus.plexus.compiler.util.scan.mapping.SourceMapping;
+import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
+import org.codehaus.plexus.util.DirectoryScanner;
+
+/**
+ * @version $Id: StaleSourceScannerTest.java 2393 2005-08-08 22:32:59Z kenney $
+ */
+public abstract class AbstractBuildMojo extends AbstractMojo {
+ // ----------------------------------------------------------------------
+ // Configurables
+ // ----------------------------------------------------------------------
+
+ /**
+ * The -source argument for the Java compiler.
+ *
+ * @parameter expression="${maven.compiler.source}"
+ * @readonly
+ */
+ private String source;
+
+ /**
+ * The -target argument for the Java compiler.
+ *
+ * @parameter expression="${maven.compiler.target}"
+ * @readonly
+ */
+ private String target;
+
+ /**
+ * The -encoding argument for the Java compiler.
+ *
+ * @parameter expression="${maven.compiler.encoding}"
+ * @readonly
+ */
+ private String encoding;
+
+ /**
+ * Sets the granularity in milliseconds of the last modification
+ * date for testing whether a source needs recompilation.
+ *
+ * @parameter expression="${lastModGranularityMs}" default-value="0"
+ *
+ */
+ private int staleMillis;
+
+ /**
+ * The compiler id of the compiler to use. See this
+ * <a href="non-javac-compilers.html">guide</a> for more information.
+ *
+ * @parameter expression="${maven.compiler.compilerId}" default-value="javac"
+ * @readonly
+ */
+ private String compilerId;
+
+ /**
+ * Version of the compiler to use, ex. "1.3", "1.5", if fork is set to true.
+ *
+ * @parameter expression="${maven.compiler.compilerVersion}"
+ * @readonly
+ */
+ private String compilerVersion;
+
+ /**
+ * Sets the executable of the compiler to use when fork is true.
+ *
+ * @parameter expression="${maven.compiler.executable}"
+ * @readonly
+ */
+ private String executable;
+
+ /**
+ * The directory to run the compiler from if fork is true.
+ *
+ * @parameter expression="${basedir}"
+ * @required
+ * @readonly
+ */
+ protected File basedir;
+
+ /**
+ * The target directory of the compiler if fork is true.
+ *
+ * @parameter expression="${project.build.directory}"
+ * @required
+ * @readonly
+ */
+ private File buildDirectory;
+
+ /**
+ * Plexus compiler manager.
+ *
+ * @component
+ * @readonly
+ */
+ private CompilerManager compilerManager;
+
+ /**
+ * The project to create a build for.
+ *
+ * @parameter expression="${project}"
+ * @required
+ * @readonly
+ */
+ protected MavenProject project;
+
+ protected SourceInclusionScanner getSourceInclusionScanner(int staleMillis) {
+ return new StaleSourceScanner(staleMillis);
+ }
+
+ protected SourceInclusionScanner getSourceInclusionScanner(String inputFileEnding) {
+ Set includes = Collections.singleton("**/*." + inputFileEnding);
+ return new SimpleSourceInclusionScanner(includes, Collections.EMPTY_SET);
+ }
+
+ protected boolean isPOMChanged() {
+ File pom = project.getFile();
+ File out = getOutputFile();
+ return pom.lastModified() > out.lastModified();
+ }
+
+ protected File getOutputFile() {
+ File basedir = buildDirectory;
+ String finalName = project.getBuild().getFinalName();
+ String classifier = project.getArtifact().getClassifier();
+ if (classifier == null) {
+ classifier = "";
+ } else if (classifier.trim().length() > 0 && !classifier.startsWith("-")) {
+ classifier = "-" + classifier;
+ }
+
+ String pkg = project.getPackaging();
+ if ("maven-plugin".equals(pkg)) {
+ pkg = "jar";
+ }
+ return new File(basedir, finalName + classifier + "." + pkg);
+ }
+
+ /**
+ * Test if the resources have been changed
+ * @return
+ * @throws MojoExecutionException
+ */
+ protected boolean isResourceChanged() throws MojoExecutionException {
+ return isChanged(project.getResources(), project.getBuild().getOutputDirectory());
+ }
+
+ protected boolean isTestResourceChanged() throws MojoExecutionException {
+ return isChanged(project.getTestResources(), project.getBuild().getTestOutputDirectory());
+ }
+
+ private static final String[] EMPTY_STRING_ARRAY = {};
+
+ private static final String[] DEFAULT_INCLUDES = {"**/**"};
+
+ /**
+ * Test if any of the resources have been changed
+ * @param resources
+ * @param outputDirectory
+ * @return
+ * @throws MojoExecutionException
+ */
+ protected boolean isChanged(List resources, String outputDirectory) throws MojoExecutionException {
+
+ for (Iterator i = resources.iterator(); i.hasNext();) {
+ Resource resource = (Resource)i.next();
+
+ String targetPath = resource.getTargetPath();
+
+ File resourceDirectory = new File(resource.getDirectory());
+
+ if (!resourceDirectory.exists()) {
+ continue;
+ }
+
+ // this part is required in case the user specified "../something" as destination
+ // see MNG-1345
+ File outputDir = new File(outputDirectory);
+ if (!outputDir.exists()) {
+ return true;
+ }
+
+ DirectoryScanner scanner = new DirectoryScanner();
+
+ scanner.setBasedir(resource.getDirectory());
+ if (resource.getIncludes() != null && !resource.getIncludes().isEmpty()) {
+ scanner.setIncludes((String[])resource.getIncludes().toArray(EMPTY_STRING_ARRAY));
+ } else {
+ scanner.setIncludes(DEFAULT_INCLUDES);
+ }
+ if (resource.getExcludes() != null && !resource.getExcludes().isEmpty()) {
+ scanner.setExcludes((String[])resource.getExcludes().toArray(EMPTY_STRING_ARRAY));
+ }
+
+ scanner.addDefaultExcludes();
+ scanner.scan();
+
+ List includedFiles = Arrays.asList(scanner.getIncludedFiles());
+ for (Iterator j = includedFiles.iterator(); j.hasNext();) {
+ String name = (String)j.next();
+
+ String destination = name;
+
+ if (targetPath != null) {
+ destination = targetPath + "/" + name;
+ }
+
+ File source = new File(resource.getDirectory(), name);
+
+ File destinationFile = new File(outputDirectory, destination);
+
+ if (!destinationFile.exists()) {
+ return true;
+ } else {
+ if (source.lastModified() > destinationFile.lastModified()) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ protected boolean isSourceChanged(Compiler compiler) throws MojoExecutionException {
+ try {
+ List sourceRoots = project.getCompileSourceRoots();
+ File outputDir = new File(project.getBuild().getOutputDirectory());
+ List classPathEntries = project.getCompileClasspathElements();
+ return isChanged(compiler, sourceRoots, classPathEntries, outputDir);
+ } catch (Exception e) {
+ throw new MojoExecutionException(e.getMessage(), e);
+ }
+ }
+
+ protected boolean isTestSourceChanged(Compiler compiler) throws MojoExecutionException {
+ try {
+ List sourceRoots = project.getTestCompileSourceRoots();
+ File outputDir = new File(project.getBuild().getTestOutputDirectory());
+ List classPathEntries = project.getTestClasspathElements();
+ return isChanged(compiler, sourceRoots, classPathEntries, outputDir);
+ } catch (Exception e) {
+ throw new MojoExecutionException(e.getMessage(), e);
+ }
+ }
+
+ public boolean isChanged(Compiler compiler, List sourceRoots, List classPathEntries, File outputDir)
+ throws MojoExecutionException {
+ List compileSourceRoots = removeEmptyCompileSourceRoots(sourceRoots);
+
+ if (compileSourceRoots.isEmpty()) {
+ // getLog().info("No sources to compile");
+ return false;
+ }
+
+ // ----------------------------------------------------------------------
+ // Create the compiler configuration
+ // ----------------------------------------------------------------------
+
+ CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
+
+ compilerConfiguration.setOutputLocation(outputDir.getAbsolutePath());
+
+ compilerConfiguration.setClasspathEntries(classPathEntries);
+
+ compilerConfiguration.setSourceLocations(compileSourceRoots);
+
+ compilerConfiguration.setOptimize(false);
+
+ compilerConfiguration.setDebug(true);
+
+ compilerConfiguration.setVerbose(false);
+
+ compilerConfiguration.setShowWarnings(false);
+
+ compilerConfiguration.setShowDeprecation(true);
+
+ compilerConfiguration.setSourceVersion(source);
+
+ compilerConfiguration.setTargetVersion(target);
+
+ compilerConfiguration.setSourceEncoding(encoding);
+
+ compilerConfiguration.setExecutable(executable);
+
+ compilerConfiguration.setWorkingDirectory(basedir);
+
+ compilerConfiguration.setCompilerVersion(compilerVersion);
+
+ compilerConfiguration.setBuildDirectory(buildDirectory);
+
+ compilerConfiguration.setOutputFileName(project.getBuild().getFinalName());
+
+ // TODO: have an option to always compile (without need to clean)
+ Set staleSources;
+
+ boolean canUpdateTarget;
+
+ try {
+ staleSources =
+ computeStaleSources(compilerConfiguration,
+ compiler,
+ getSourceInclusionScanner(staleMillis),
+ sourceRoots,
+ outputDir);
+
+ canUpdateTarget = compiler.canUpdateTarget(compilerConfiguration);
+
+ if (compiler.getCompilerOutputStyle().equals(CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES) && !canUpdateTarget) {
+ getLog().info("RESCANNING!");
+ // TODO: This second scan for source files is sub-optimal
+ String inputFileEnding = compiler.getInputFileEnding(compilerConfiguration);
+
+ Set sources =
+ computeStaleSources(compilerConfiguration,
+ compiler,
+ getSourceInclusionScanner(inputFileEnding),
+ sourceRoots,
+ outputDir);
+
+ compilerConfiguration.setSourceFiles(sources);
+ } else {
+ compilerConfiguration.setSourceFiles(staleSources);
+ }
+ } catch (CompilerException e) {
+ throw new MojoExecutionException("Error while computing stale sources.", e);
+ }
+
+ return !staleSources.isEmpty();
+
+ }
+
+ protected Compiler getCompiler() throws MojoExecutionException {
+ Compiler compiler;
+
+ getLog().debug("Using compiler '" + compilerId + "'.");
+
+ try {
+ compiler = compilerManager.getCompiler(compilerId);
+ } catch (NoSuchCompilerException e) {
+ throw new MojoExecutionException("No such compiler '" + e.getCompilerId() + "'.");
+ }
+ return compiler;
+ }
+
+ protected Set computeStaleSources(CompilerConfiguration compilerConfiguration,
+ Compiler compiler,
+ SourceInclusionScanner scanner,
+ List sourceRoots,
+ File outputDir) throws MojoExecutionException, CompilerException {
+ CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
+
+ SourceMapping mapping;
+
+ File outputDirectory;
+
+ if (outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE) {
+ mapping =
+ new SuffixMapping(compiler.getInputFileEnding(compilerConfiguration), compiler
+ .getOutputFileEnding(compilerConfiguration));
+
+ outputDirectory = outputDir;
+ } else if (outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES) {
+ mapping =
+ new SingleTargetSourceMapping(compiler.getInputFileEnding(compilerConfiguration), compiler
+ .getOutputFile(compilerConfiguration));
+
+ outputDirectory = buildDirectory;
+ } else {
+ throw new MojoExecutionException("Unknown compiler output style: '" + outputStyle + "'.");
+ }
+
+ scanner.addSourceMapping(mapping);
+
+ Set staleSources = new HashSet();
+
+ for (Iterator it = sourceRoots.iterator(); it.hasNext();) {
+ String sourceRoot = (String)it.next();
+
+ File rootFile = new File(sourceRoot);
+
+ if (!rootFile.isDirectory()) {
+ continue;
+ }
+
+ try {
+ Set changed = scanner.getIncludedSources(rootFile, outputDirectory);
+ staleSources.addAll(changed);
+ } catch (InclusionScanException e) {
+ throw new MojoExecutionException("Error scanning source root: \'" + sourceRoot
+ + "\' "
+ + "for stale files to recompile.", e);
+ }
+ }
+
+ return staleSources;
+ }
+
+ /**
+ * @todo also in ant plugin. This should be resolved at some point so that it does not need to
+ * be calculated continuously - or should the plugins accept empty source roots as is?
+ */
+ private static List removeEmptyCompileSourceRoots(List compileSourceRootsList) {
+ List newCompileSourceRootsList = new ArrayList();
+ if (compileSourceRootsList != null) {
+ // copy as I may be modifying it
+ for (Iterator i = compileSourceRootsList.iterator(); i.hasNext();) {
+ String srcDir = (String)i.next();
+ if (!newCompileSourceRootsList.contains(srcDir) && new File(srcDir).exists()) {
+ newCompileSourceRootsList.add(srcDir);
+ }
+ }
+ }
+ return newCompileSourceRootsList;
+ }
+}
diff --git a/branches/sca-java-1.1/tools/maven/maven-incremental-build/src/main/java/org/apache/tuscany/sca/tools/incremental/build/plugin/IncrementalBuildMojo.java b/branches/sca-java-1.1/tools/maven/maven-incremental-build/src/main/java/org/apache/tuscany/sca/tools/incremental/build/plugin/IncrementalBuildMojo.java
new file mode 100644
index 0000000000..17fe2dfddb
--- /dev/null
+++ b/branches/sca-java-1.1/tools/maven/maven-incremental-build/src/main/java/org/apache/tuscany/sca/tools/incremental/build/plugin/IncrementalBuildMojo.java
@@ -0,0 +1,196 @@
+/*
+ * 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.tuscany.sca.tools.incremental.build.plugin;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.shared.invoker.DefaultInvocationRequest;
+import org.apache.maven.shared.invoker.InvocationResult;
+import org.apache.maven.shared.invoker.Invoker;
+import org.apache.maven.shared.invoker.MavenInvocationException;
+import org.codehaus.plexus.compiler.Compiler;
+import org.codehaus.plexus.util.cli.CommandLineException;
+
+/**
+ * @version $Rev$ $Date$
+ * @goal build
+ * @phase validate
+ * @requiresDependencyResolution test
+ * @description Incrementally build project modules that depend on modified modules.
+ */
+public class IncrementalBuildMojo extends AbstractBuildMojo {
+ /**
+ * Keep track of modified projects.
+ */
+ private static Set<String> modifiedProjectIDs = new HashSet<String>();
+
+ /**
+ * Returns the qualified id of an artifact .
+ * @param p a Maven artifact
+ * @return a qualified id
+ */
+ private static String id(Artifact a) {
+ return a.getGroupId() + ':' + a.getArtifactId();
+ }
+
+ /**
+ * Returns the qualified id of a project.
+ * @param p a Maven project
+ * @return a qualified id
+ */
+ private static String id(MavenProject p) {
+ return p.getGroupId() + ':' + p.getArtifactId();
+ }
+
+ /**
+ * The current user system settings for use in Maven.
+ *
+ * @parameter expression="${settings}"
+ * @required
+ * @readonly
+ */
+ // private Settings settings;
+ /**
+ * Used to invoke Maven builds.
+ *
+ * @component
+ */
+ private Invoker invoker;
+
+ /**
+ * The local repository where the artifacts are located
+ *
+ * @parameter expression="${localRepository}"
+ * @required
+ */
+ private ArtifactRepository localRepository;
+
+ /**
+ * @parameter expression="${settings}"
+ * @required
+ * @readonly
+ */
+ protected Settings settings;
+
+ public void execute() throws MojoExecutionException {
+ getLog().info("Building " + project.getName() + " [" + project.getId() + "]");
+ List<String> goals = new ArrayList<String>();
+ String type = project.getArtifact().getType();
+ if ("pom".equals(type)) {
+ goals.add("install");
+ } else {
+ String projectID = id(project);
+
+ Compiler compiler = getCompiler();
+ boolean changed = isSourceChanged(compiler) || isResourceChanged() || isPOMChanged();
+ boolean testChanged = false;
+ if (changed) {
+ modifiedProjectIDs.add(projectID);
+ } else {
+ testChanged = isTestSourceChanged(compiler) || isTestResourceChanged();
+ }
+
+ // Check if a project has compile dependencies on the modified projects
+ // and will need to be recompiled, or has runtime or test dependencies
+ // on the modified projects and needs to be retested
+
+ if (changed) {
+ goals.add("clean");
+ goals.add("install");
+ } else {
+ for (Artifact artifact : (List<Artifact>)project.getCompileArtifacts()) {
+ String artifactID = id(artifact);
+ if (modifiedProjectIDs.contains(artifactID)) {
+ getLog().info("Project " + projectID
+ + " depends on modified project "
+ + artifactID
+ + " and will be recompiled.");
+ goals.add("clean");
+ goals.add("install");
+ break;
+ }
+ }
+
+ if (goals.isEmpty()) {
+ List<Artifact> artifacts = new ArrayList<Artifact>();
+ artifacts.addAll(project.getRuntimeArtifacts());
+ artifacts.addAll(project.getTestArtifacts());
+ for (Artifact artifact : artifacts) {
+ String artifactID = id(artifact);
+ if (modifiedProjectIDs.contains(artifactID)) {
+ getLog().info("Project " + projectID
+ + " depends on modified project "
+ + artifactID
+ + " and will be retested.");
+ goals.add("test");
+ break;
+ }
+ }
+ }
+ }
+
+ if (testChanged && goals.isEmpty()) {
+ goals.add("test");
+ }
+ }
+
+ // Invoke Maven with the necessary goals
+ if (!goals.isEmpty()) {
+ DefaultInvocationRequest request = new DefaultInvocationRequest();
+ request.setGoals(goals);
+ // FIXME: The maven invoker doesn't handle the directory names with spaces
+ // request.setLocalRepositoryDirectory(new File(localRepository.getBasedir()));
+ request.setInteractive(false);
+ request.setShowErrors(true);
+ request.setRecursive(false);
+ // request.setDebug(true);
+ request.setOffline(settings.isOffline());
+ request.setBaseDirectory(project.getBasedir());
+ request.setPomFile(project.getFile());
+
+ try {
+ InvocationResult result = invoker.execute(request);
+
+ CommandLineException cle = result.getExecutionException();
+ if (cle != null) {
+ throw new MojoExecutionException(cle.getMessage(), cle);
+ }
+
+ int ec = result.getExitCode();
+ if (ec != 0) {
+ throw new MojoExecutionException("Maven invocation exit code: " + ec);
+ }
+ } catch (MavenInvocationException e) {
+ e.printStackTrace();
+ throw new MojoExecutionException(e.getMessage(), e);
+ }
+ } else {
+ getLog().info("The project is up-to-date. No build is required.");
+ }
+ }
+
+}