blob: 4638912619962919820f45e0a3df11559c2236c1 [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.cpconverter.maven.mojos;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.shared.transfer.artifact.install.ArtifactInstallerException;
import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
import org.apache.sling.feature.cpconverter.acl.DefaultAclManager;
import org.apache.sling.feature.cpconverter.artifacts.DefaultArtifactsDeployer;
import org.apache.sling.feature.cpconverter.features.DefaultFeaturesManager;
import org.apache.sling.feature.cpconverter.handlers.DefaultEntryHandlersManager;
import org.apache.sling.feature.cpconverter.vltpkg.DefaultPackagesEventsEmitter;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter.PACKAGE_CLASSIFIER;
import static org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter.ZIP_TYPE;
/**
* Converts the given Content Packages into Feature Models
* and places the converted Content Package into the local
* Maven Repository
*/
@Mojo(
name = "convert-cp",
requiresProject = true,
threadSafe = true
)
public final class ConvertCPMojo
extends AbstractBaseMojo
{
public static final String CFG_STRICT_VALIDATION = "strictValidation";
public static final String CFG_MERGE_CONFIGURATIONS = "mergeConfigurations";
public static final String CFG_BUNDLE_START_ORDER = "bundleStartOrder";
public static final String CFG_ARTIFACT_ID_OVERRIDE = "artifactIdOverride";
public static final String CFG_INSTALL_CONVERTED_PACKAGE = "installConvertedContentPackage";
public static final String CFG_FM_OUTPUT_DIRECTORY = "featureModelsOutputDirectory";
public static final String CFG_CONVERTED_CP_OUTPUT_DIRECTORY = "convertedContentPackageOutputDirectory";
public static final String CFG_CONVERTED_CP_FM_PREFIX = "fmPrefix";
public static final String CFG_SYSTEM_PROPERTIES = "cpSystemProperties";
public static final String CFG_CONTENT_PACKAGES = "packages";
public static final boolean DEFAULT_STRING_VALIDATION = false;
public static final boolean DEFAULT_MERGE_CONFIGURATIONS = false;
public static final int DEFAULT_BUNDLE_START_ORDER = 20;
public static final boolean DEFAULT_INSTALL_CONVERTED_PACKAGE = true;
public static final String DEFAULT_CONVERTED_CP_OUTPUT_DIRECTORY = "${project.build.directory}/cp-conversion";
public static final String DEFAULT_FM_OUTPUT_DIRECTORY = DEFAULT_CONVERTED_CP_OUTPUT_DIRECTORY + "/fm.out";
/**
* If set to {@code true} the Content Package is strictly validated.
*/
@Parameter(property = CFG_STRICT_VALIDATION, defaultValue = DEFAULT_STRING_VALIDATION + "")
private boolean strictValidation;
//AS TODO: Is that applicable to a single CP ?
/**
* If set to {@code true} the OSGi Configurations with same PID are merged.
*/
@Parameter(property = CFG_MERGE_CONFIGURATIONS, defaultValue = DEFAULT_MERGE_CONFIGURATIONS + "")
private boolean mergeConfigurations;
/**
* If set to {@code true} the Content Package is strictly validated.
*/
@Parameter(property = CFG_BUNDLE_START_ORDER, defaultValue = DEFAULT_BUNDLE_START_ORDER + "")
private int bundleStartOrder;
/**
* If set to {@code true} the Content Package is strictly validated.
*/
@Parameter(property = CFG_ARTIFACT_ID_OVERRIDE)
private String artifactIdOverride;
/**
* Target directory for the converted Content Package Feature Model file
*/
@Parameter(property = CFG_FM_OUTPUT_DIRECTORY, defaultValue = DEFAULT_FM_OUTPUT_DIRECTORY)
private File fmOutput;
/**
* Target directory for the Converted Content Package file
*/
@Parameter(property = CFG_CONVERTED_CP_OUTPUT_DIRECTORY, defaultValue = DEFAULT_CONVERTED_CP_OUTPUT_DIRECTORY)
private File convertedCPOutput;
/**
* If set to {@code true} the converted Content Package will be installed in the local Maven Repository
*/
@Parameter(property = CFG_INSTALL_CONVERTED_PACKAGE, defaultValue = DEFAULT_INSTALL_CONVERTED_PACKAGE + "")
private boolean installConvertedCP;
/**
* System Properties to hand over to the Content Package Converter
*/
@Parameter(property = CFG_CONVERTED_CP_FM_PREFIX)
private String fmPrefix;
/**
* System Properties to hand over to the Content Package Converter
*/
@Parameter(property = CFG_SYSTEM_PROPERTIES)
private List<String> systemProperties;
/**
* List of Content Packages to be converted
*/
@Parameter(property = CFG_CONTENT_PACKAGES)
private List<ContentPackage> contentPackages;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
// Un-encode a given Artifact Override Id
if(artifactIdOverride != null) {
String old = artifactIdOverride;
artifactIdOverride = artifactIdOverride.replaceAll("\\$\\{\\{", "\\$\\{");
artifactIdOverride = artifactIdOverride.replaceAll("}}", "}");
getLog().info("Replaced Old Artifact Id Override: '" + old + "', with new one: '" + artifactIdOverride + "'");
}
// Parse the System Properties if provided
Map<String,String> properties = new HashMap<>();
if(systemProperties != null) {
for(String systemProperty: systemProperties) {
if(systemProperty != null) {
int index = systemProperty.indexOf("=");
if(index > 0 && index < systemProperty.length() - 1) {
String key = systemProperty.substring(0, index);
String value = systemProperty.substring(index + 1);
properties.put(key, value);
}
}
}
}
try {
ContentPackage2FeatureModelConverter converter = new ContentPackage2FeatureModelConverter(strictValidation)
.setFeaturesManager(
new DefaultFeaturesManager(
mergeConfigurations,
bundleStartOrder,
fmOutput,
artifactIdOverride,
fmPrefix,
properties
)
)
.setBundlesDeployer(
new DefaultArtifactsDeployer(
convertedCPOutput
)
)
.setEntryHandlersManager(
new DefaultEntryHandlersManager()
)
.setAclManager(
new DefaultAclManager()
)
.setEmitter(DefaultPackagesEventsEmitter.open(fmOutput));
if(contentPackages == null || contentPackages.isEmpty()) {
getLog().info("Project Artifact File: " + project.getArtifact());
String targetPath = project.getModel().getBuild().getDirectory() + "/"
+ project.getModel().getBuild().getFinalName()
+ "." + ZIP_TYPE;
File targetFile = new File(targetPath);
if (targetFile.exists() && targetFile.isFile() && targetFile.canRead()) {
converter.convert(project.getArtifact().getFile());
// Artifact convertedPackage = new DefaultArtifact(
// project.getGroupId(), project.getArtifactId(), project.getVersion(),
// "compile", ZIP_TYPE, PACKAGE_CLASSIFIER, artifactHandlerManager.getArtifactHandler(ZIP_TYPE)
// );
// installConvertedCP(convertedPackage);
} else {
getLog().error("Artifact is not found: " + targetPath);
}
} else {
for(ContentPackage contentPackage: contentPackages) {
getLog().info("Content Package Artifact File: " + contentPackage.toString());
contentPackage.setExcludeTransitive(true);
final Collection<Artifact> artifacts = contentPackage.getMatchingArtifacts(project);
if (artifacts.isEmpty()) {
getLog().warn("No matching artifacts for " + contentPackage);
continue;
}
getLog().info("Target Convert CP of --- " + contentPackage + " ---");
for (final Artifact artifact : artifacts) {
final File source = artifact.getFile();
if (source.exists() && source.isFile() && source.canRead()) {
converter.convert(source);
Artifact convertedPackage = new DefaultArtifact(
artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(),
"compile", ZIP_TYPE, PACKAGE_CLASSIFIER, artifactHandlerManager.getArtifactHandler(ZIP_TYPE)
);
// installConvertedCP(convertedPackage);
} else {
getLog().error("Artifact is not found: " + artifact);
}
}
}
}
installGeneratedArtifacts();
} catch (Throwable t) {
throw new MojoExecutionException("Content Package Converter Exception", t);
}
}
/**
* For now this is a hack to update the local Maven Repo (.m2/repository) correctly
* bypassing the Maven Installer as this is giving us grief
*/
private void installGeneratedArtifacts() {
if(installConvertedCP) {
File userHome = new File(System.getProperty("user.home"));
if(userHome.isDirectory()) {
File destFolder = new File(userHome, ".m2/repository");
if(destFolder.isDirectory()) {
copyFiles(convertedCPOutput, destFolder);
}
}
}
}
/**
* Copies the local generated Maven Artifacts into the local Maven Repo
* recursively one folder at the time.
* Folder are created on the local Maven Repo if not found, missing files
* are copied over but only CP2FM Converted CP files are replaced on the
* target folders
*
* @param source Folder with the source files / folders
* @param destination Destination folder (inside the local Maven repo). This is the corresponding folder to the source
*/
private void copyFiles(File source, File destination) {
for(File file: source.listFiles()) {
String name = file.getName();
if(file.isDirectory()) {
File newDest = new File(destination, name);
if(!newDest.exists()) {
newDest.mkdirs();
}
if(newDest.isDirectory()) {
copyFiles(file, newDest);
} else {
getLog().warn("Source File: '" + file.getAbsolutePath() + "' is a folder but its counterpart is a file: " + newDest.getAbsolutePath());
}
} else {
File newDest = new File(destination, name);
if(!newDest.exists()) {
// Copy File over
try {
Files.copy(file.toPath(), newDest.toPath(), StandardCopyOption.COPY_ATTRIBUTES);
} catch (IOException e) {
getLog().warn("Failed to copy File: '" + file.getAbsolutePath() + "' to File: " + newDest.getAbsolutePath(), e);
}
} else {
// We only overwrite converted files
if(name.endsWith(PACKAGE_CLASSIFIER + "." + ZIP_TYPE)) {
// Copy File over
try {
Files.copy(file.toPath(), newDest.toPath(), StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
getLog().warn("Failed to copy generated File: '" + file.getAbsolutePath() + "' to File: " + newDest.getAbsolutePath(), e);
}
} else {
getLog().info("Ignore File: '" + file.getAbsolutePath());
}
}
}
}
}
private void installConvertedCP(Artifact artifact) throws MojoFailureException, MojoExecutionException {
if(installConvertedCP) {
Collection<Artifact> artifacts = Collections.synchronizedCollection(new ArrayList<>());
// Rebuild the converted package path
String convertedPackagePath = artifact.getGroupId().replaceAll("\\.", "/")
+ "/" + artifact.getArtifactId()
+ "/" + artifact.getVersion()
+ "/" + artifact.getArtifactId()
+ "-" + artifact.getVersion()
+ "-" + PACKAGE_CLASSIFIER
+ "." + ZIP_TYPE;
File convertedPackageFile = new File(convertedCPOutput, convertedPackagePath);
if(convertedPackageFile.exists() && convertedPackageFile.canRead()) {
artifact.setFile(convertedPackageFile);
artifacts.add(artifact);
installArtifact(mavenSession.getProjectBuildingRequest(), artifacts);
} else {
getLog().error("xCould not find Converted Package: " + convertedPackageFile);
}
}
}
private void installArtifact(ProjectBuildingRequest pbr, Collection<Artifact> artifacts )
throws MojoFailureException, MojoExecutionException
{
try
{
installer.install(pbr, artifacts);
}
catch ( ArtifactInstallerException e )
{
throw new MojoExecutionException( "ArtifactInstallerException", e );
}
}
}