blob: e5c361225cfe474061caf8aa70e24a99fea9ea45 [file] [log] [blame]
/*
* 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.sling.maven.projectsupport;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Properties;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.sling.maven.projectsupport.bundlelist.v1_0_0.BundleList;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.UnArchiver;
import org.codehaus.plexus.archiver.jar.JarArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
import org.codehaus.plexus.util.FileUtils;
/**
* Initialize a Sling application project by extracting bundles into the correct
* locations.
*
* @goal prepare-package
* @requiresDependencyResolution test
* @phase prepare-package
* @description initialize a Sling application project
*/
public class PreparePackageMojo extends AbstractLaunchpadFrameworkMojo {
/**
* The output directory for the default bundles in a WAR-packaged project,
* the base JAR (in the subdirectory named in the baseDestination
* parameter), and any additional bundles.
*
* @parameter default-value="${project.build.directory}/launchpad-bundles"
*/
private File warOutputDirectory;
/**
* The project's packaging type.
*
* @parameter expression="${project.packaging}"
*/
private String packaging;
/**
* The definition of the base JAR.
*
* @parameter
*/
private ArtifactDefinition base;
/**
* The definition of the package to be included to provide web support for
* JAR-packaged projects (i.e. pax-web).
*
* @parameter
*/
private ArtifactDefinition jarWebSupport;
/**
* The project's build output directory (i.e. target/classes).
*
* @parameter expression="${project.build.outputDirectory}"
* @readonly
*/
private File buildOutputDirectory;
/**
* The temp directory (i.e. target/maven-launchpad-plugintmp).
*
* @parameter expression="${project.build.directory}/maven-launchpad-plugintmp"
* @readonly
*/
private File tempDirectory;
/**
* To look up Archiver/UnArchiver implementations
*
* @component
*/
private ArchiverManager archiverManager;
/**
* The Jar archiver.
*
* @component role="org.codehaus.plexus.archiver.Archiver" roleHint="jar"
*/
private JarArchiver jarArchiver;
@Override
public void executeWithArtifacts() throws MojoExecutionException, MojoFailureException {
copyBaseArtifact();
copyBundles(getInitializedBundleList(), getOutputDirectory());
copyConfigurationFiles();
if (JAR.equals(packaging)) {
unpackBaseArtifact();
}
}
@Override
protected void initArtifactDefinitions(Properties dependencies) {
if (base == null) {
base = new ArtifactDefinition();
}
base.initDefaults(dependencies.getProperty("base"));
if (jarWebSupport == null) {
jarWebSupport = new ArtifactDefinition();
}
jarWebSupport.initDefaults(dependencies.getProperty("jarWebSupport"));
}
/**
* Add the JAR Web Support bundle to the bundle list.
*/
@Override
protected void initBundleList(BundleList bundleList) {
if (packaging.equals(JAR)) {
bundleList.add(jarWebSupport.toBundleList());
}
}
/**
* Patch the sling properties
*/
private void patchSlingProperties(final File dest, final Properties additionalProps)
throws MojoExecutionException {
final File origSlingProps = new File(dest, "sling.properties");
if ( !origSlingProps.exists() ) {
throw new MojoExecutionException("sling.properties not found at " + origSlingProps);
}
// read original properties
final Properties orig = new Properties();
FileInputStream fis = null;
try {
fis = new FileInputStream(origSlingProps);
orig.load(fis);
} catch (final IOException ioe) {
throw new MojoExecutionException("Unable to read " + origSlingProps, ioe);
} finally {
if ( fis != null ) {
try { fis.close(); } catch (final IOException ignore) {}
}
}
// patch
final Enumeration<Object> keys = additionalProps.keys();
if ( keys.hasMoreElements() ) {
getLog().info("Patching sling.properties");
}
while ( keys.hasMoreElements() ) {
final Object key = keys.nextElement();
orig.put(key, additionalProps.get(key));
}
/// and save
FileOutputStream fos = null;
try {
fos = new FileOutputStream(origSlingProps);
orig.store(fos, null);
} catch (final IOException ioe) {
throw new MojoExecutionException("Unable to save " + origSlingProps, ioe);
} finally {
if ( fis != null ) {
try { fis.close(); } catch (final IOException ignore) {}
}
}
}
/**
* Patch the sling bootstrap command file
*/
private void patchSlingBootstrap(final File dest, final String additionalCmd)
throws MojoExecutionException {
getLog().info("Patching sling_bootstrap.txt");
final File origSlingCmd = new File(dest, "sling_bootstrap.txt");
FileWriter writer = null;
/// and write
try {
writer = new FileWriter(origSlingCmd);
writer.write(additionalCmd);
} catch (final IOException ioe) {
throw new MojoExecutionException("Unable to save " + origSlingCmd, ioe);
} finally {
if ( writer != null ) {
try { writer.close(); } catch (final IOException ignore) {}
}
}
}
private void copyBaseArtifact() throws MojoExecutionException {
Artifact artifact = getBaseArtifact();
if (artifact == null) {
throw new MojoExecutionException(
String.format("Project doesn't have a base dependency of groupId %s and artifactId %s",
base.getGroupId(), base.getArtifactId()));
}
File destinationDir = new File(getOutputDirectory(), baseDestination);
File destinationFile = new File(destinationDir, artifact
.getArtifactId()
+ "." + artifact.getArtifactHandler().getExtension());
// check if custom sling.properties file or bootstrap command exists
final Properties additionalProps = this.getSlingProperties(JAR.equals(this.packaging));
final String bootstrapCmd = this.getSlingBootstrap(JAR.equals(this.packaging));
if ( additionalProps != null || bootstrapCmd != null ) {
// unpack to a temp destination
final File dest = new File(this.tempDirectory, "basejar");
try {
unpack(artifact.getFile(), dest);
// patch sling properties
if ( additionalProps != null ) {
this.patchSlingProperties(dest, additionalProps);
}
// patch bootstrap command
if ( bootstrapCmd != null ) {
this.patchSlingBootstrap(dest, bootstrapCmd);
}
// and repack again
pack(dest, destinationFile);
} finally {
this.tempDirectory.delete();
}
} else {
// we can just copy
if (shouldCopy(artifact.getFile(), destinationFile)) {
try {
getLog().info(
String.format("Copying base artifact from %s to %s.",
artifact.getFile(), destinationFile));
FileUtils.copyFile(artifact.getFile(), destinationFile);
} catch (IOException e) {
throw new MojoExecutionException(
"Unable to copy base artifact.", e);
}
} else {
getLog().debug(
String.format("Skipping copy of base artifact from %s.",
artifact.getFile()));
}
}
}
private Artifact getBaseArtifact() throws MojoExecutionException {
Artifact baseDependency = getBaseDependency();
if (baseDependency == null) {
return null;
}
return getArtifact(base.getGroupId(), base.getArtifactId(),
baseDependency.getVersion(), base.getType(), base
.getClassifier());
}
private Artifact getBaseDependency() {
return project.getArtifactMap().get(
base.getGroupId() + ":" + base.getArtifactId());
}
protected File getOutputDirectory() {
if (WAR.equals(packaging)) {
return warOutputDirectory;
}
return buildOutputDirectory;
}
protected void unpackBaseArtifact() throws MojoExecutionException {
Artifact artifact = getBaseDependency();
if (artifact == null) {
throw new MojoExecutionException(
String
.format(
"Project doesn't have a base dependency of groupId %s and artifactId %s",
base.getGroupId(), base.getArtifactId()));
}
unpack(artifact.getFile(), buildOutputDirectory);
}
private void copyConfigurationFiles() throws MojoExecutionException {
final File configDir = this.getConfigDirectory();
if (configDir.exists() ) {
try {
copyDirectory(configDir, new File(getOutputDirectory(), CONFIG_PATH_PREFIX), null, FileUtils.getDefaultExcludes());
} catch (IOException e) {
throw new MojoExecutionException("Unable to copy configuration files", e);
}
}
}
private void unpack(File source, File destination)
throws MojoExecutionException {
getLog().info("Unpacking " + source.getPath() + " to\n " + destination.getPath());
try {
destination.mkdirs();
UnArchiver unArchiver = archiverManager.getUnArchiver(source);
unArchiver.setSourceFile(source);
unArchiver.setDestDirectory(destination);
unArchiver.extract();
} catch (NoSuchArchiverException e) {
throw new MojoExecutionException("Unable to find archiver for " + source.getPath(), e);
} catch (ArchiverException e) {
throw new MojoExecutionException("Unable to unpack " + source.getPath(), e);
}
}
private void pack(File sourceDir, File destination)
throws MojoExecutionException {
getLog().info("Packing " + sourceDir.getPath() + " to\n " + destination.getPath());
try {
destination.getParentFile().mkdirs();
jarArchiver.setDestFile(destination);
jarArchiver.addDirectory(sourceDir);
jarArchiver.setManifest(new File(sourceDir, "META-INF/MANIFEST.MF".replace('/', File.separatorChar)));
jarArchiver.createArchive();
} catch (IOException e) {
throw new MojoExecutionException("Unable to pack " + sourceDir.getPath(), e);
} catch (ArchiverException e) {
throw new MojoExecutionException("Unable to pack " + sourceDir.getPath(), e);
}
}
}