/* * Copyright 2002-2005 the original author or authors. * * Licensed 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 info.jtrac.maven; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeSet; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.resolver.ArtifactResolver; import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProjectBuilder; /** * base class for our mojos */ public abstract class AntPropsMojo extends AbstractMojo { //======================== MOJO =============================== /** * @parameter expression="${project}" */ protected MavenProject project; /** * @parameter expression="${localRepository}" */ private ArtifactRepository localRepository; /** * @component role="org.apache.maven.artifact.resolver.ArtifactResolver" */ private ArtifactResolver artifactResolver; /** * @parameter expression="${project.remoteArtifactRepositories}" */ private List remoteArtifactRepositories; /** * @component role="org.apache.maven.artifact.factory.ArtifactFactory" */ private ArtifactFactory artifactFactory; /** * @component role="org.apache.maven.project.MavenProjectBuilder" */ private MavenProjectBuilder mavenProjectBuilder; //======================== CONFIG ================================ /** * Things that will be added to the "test.jars" master classpath * @parameter */ private List testPaths; /** * Things that are not related to build / test and run but other * stuff like checkstyle, code coverage etc. * @parameter */ private List extraPaths; //======================== PRIVATE =============================== /** * properties initialized at the top e.g. "m2.repo" */ protected Map buildProperties = new LinkedHashMap(); /** * this collects paths resolved from the input "testPaths" parameter */ protected Map testClassPaths = new LinkedHashMap(); /** * this collects paths resolved from the input "extraPaths" parameter */ protected Map extraClassPaths = new LinkedHashMap(); /** * this collects the list of files that go into WEB-INF/lib */ protected Set runtimeFiles; /** * hack to hold paths flagged as filesets and that should be output as * (relativePath1,relativePath2) not classpaths like (absolutePath1:absolutePath2) * ideally we should have extended the Value Objects instead of using Maps above */ protected Set filesets = new HashSet(); //========================== MAIN ================================ public void execute() throws MojoExecutionException { if (testPaths == null) { testPaths = new ArrayList(); } if (extraPaths == null) { extraPaths = new ArrayList(); } String repoBaseDir = localRepository.getBasedir().replace('\\','/'); try { buildProperties.put("m2.repo", repoBaseDir); //======================================================== Collection runtimeArtifacts = project.getArtifacts(); runtimeFiles = getRelativePaths(getFiles(runtimeArtifacts), repoBaseDir); //======================================================== Set testArtifacts = project.getDependencyArtifacts(); testArtifacts.addAll(project.getTestArtifacts()); Collection testFiles = getFiles(testArtifacts); testClassPaths.put("m2.repo", getRelativePaths(testFiles, repoBaseDir)); //======================================================== Properties props = loadProperties(); for (Iterator i = testPaths.iterator(); i.hasNext(); ) { TestPath testPath = (TestPath) i.next(); String baseDirProperty = testPath.getBaseDirProperty(); String baseDirPath = props.getProperty(baseDirProperty); if (baseDirPath == null) { getLog().warn("baseDirProperty + '" + baseDirProperty + "' does not exist in build.properties"); break; } File baseDir = new File(baseDirPath); if (!baseDir.exists() || !baseDir.isDirectory()) { getLog().warn("path + '" + baseDirPath + "' is not valid directory"); break; } buildProperties.put(baseDirProperty, baseDirPath); Set filePaths = new TreeSet(); for (Iterator j = testPath.getPaths().iterator(); j.hasNext(); ) { String path = (String) j.next(); File file = new File(baseDirPath + "/" + path); if (!file.exists()) { getLog().warn("additional test path: '" + file.getPath() + "' does not exist"); continue; } if (file.isDirectory()) { File[] files = file.listFiles(); for (int x = 0; x < files.length; x++) { filePaths.add(getRelativePath(files[x], baseDir.getPath())); } } else { filePaths.add(getRelativePath(file, baseDir.getPath())); } } testClassPaths.put(baseDirProperty, filePaths); } //======================================================== for (Iterator i = extraPaths.iterator(); i.hasNext(); ) { ExtraPath ep = (ExtraPath) i.next(); Set paths = new TreeSet(); Collection files = new ArrayList(); for (Iterator j = ep.getDependencies().iterator(); j.hasNext(); ) { Dependency d = (Dependency) j.next(); if (d.isResolve()) { files.addAll(getFiles(d.getGroupId(), d.getArtifactId(), d.getVersion())); } else { Artifact a = getArtifact(d.getGroupId(), d.getArtifactId(), d.getVersion()); files.add(resolveArtifact(a)); } } paths.addAll(getRelativePaths(files, repoBaseDir)); extraClassPaths.put(ep.getName(), paths); if (ep.isFileset()) { filesets.add(ep.getName()); } } //======================================================== generate(); } catch (Exception e) { e.printStackTrace(); throw new MojoExecutionException(e.getLocalizedMessage()); } } //========================== HELPER METHODS ====================== /** * instantiate a single artifact using Maven, on the fly */ private Artifact getArtifact(String groupId, String artifactId, String version) { return artifactFactory.createArtifact(groupId, artifactId, version, "", "jar"); } /** * resolve dependencies for the given artifact details using Maven, on the fly */ private Collection resolveDependencies(String groupId, String artifactId, String version) throws Exception { Artifact pomArtifact = getArtifact(groupId, artifactId, version); MavenProject pomProject = mavenProjectBuilder.buildFromRepository(pomArtifact, remoteArtifactRepositories, localRepository); Collection artifacts = pomProject.createArtifacts(artifactFactory, Artifact.SCOPE_TEST, new ScopeArtifactFilter(Artifact.SCOPE_TEST)); Iterator i = artifacts.iterator(); while(i.hasNext()) { Artifact a = (Artifact) i.next(); resolveArtifact(a); } artifacts.add(pomArtifact); return artifacts; } /** * resolve single artifact to file, and resolve fully from repository if required */ private File resolveArtifact(Artifact artifact) throws Exception { File f = artifact.getFile(); if (f != null) { return f; } getLog().info("resolving artifact: " + artifact); artifactResolver.resolve(artifact, remoteArtifactRepositories, localRepository); return artifact.getFile(); } /** * convert a collection of maven artifacts into a collection of files */ private Collection getFiles(Collection artifacts) throws Exception { Collection files = new ArrayList(); Iterator i = artifacts.iterator(); while(i.hasNext()) { Artifact a = (Artifact) i.next(); files.add(resolveArtifact(a)); } return files; } /** * convenience combination of resolving and getting a bunch of files */ private Collection getFiles(String groupId, String artifactId, String version) throws Exception { return getFiles(resolveDependencies(groupId, artifactId, version)); } /** * function to return relative path given base path and the target file */ private String getRelativePath(File file, String basePath) { String p = basePath.replace('\\','/'); int len = p.length() + 1; if (p.endsWith("/")) { len--; } return file.getPath().substring(len).replace('\\','/'); } /** * add path entries for the given bunch of files */ private Set getRelativePaths(Collection files, String basePath) { Set paths = new TreeSet(); Iterator i = files.iterator(); while (i.hasNext()) { File f = (File) i.next(); String path = getRelativePath(f, basePath); paths.add(path); } return paths; } /** * load properties from file */ private Properties loadProperties() throws Exception { File file = new File("build.properties"); Properties props = new Properties(); if (!file.exists()) { getLog().warn("build.properties does not exist"); return props; } InputStream is = null; try { is = new FileInputStream("build.properties"); props.load(is); } finally { is.close(); } return props; } protected abstract void generate() throws Exception; protected void generateBuildXml() { String projectName = project.getArtifactId(); String projectNameTitleCase = Character.toUpperCase(projectName.charAt(0)) + projectName.substring(1); String buildSource = FileUtils.readFile(getClass(), "build.xml").toString(); String buildTarget = buildSource.replace("@@project.name@@", projectName); buildTarget = buildTarget.replace("@@project.name.titleCase@@", projectNameTitleCase); FileUtils.writeFile(buildTarget, "build.xml", false); getLog().info("created 'build.xml'"); } }