blob: e4d93c93e86e571f6c8e4e33c8524f89c7494e81 [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.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.sling.feature.modelconverter.ProvisioningToFeature;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Converts the given list of Provisioning Models into
* Feature Models
*/
@Mojo(
name = "convert-pm",
requiresProject = true,
threadSafe = true
)
public final class ConvertPMMojo
extends AbstractBaseMojo
{
public static final String CFG_INPUT_FOLDER = "inputFolder";
public static final String CFG_OUTPUT_FOLDER = "outputFolder";
public static final String CFG_GROUP_ID = "groupId";
public static final String CFG_ARTIFACT_ID = "artifactId";
public static final String CFG_VERSION = "version";
public static final String CFG_FRAMEWORK_PROPERTIES = "frameworkProperties";
public static final String CFG_NO_PROVISIIONING_MODEL_NAME = "noProvisioningModelName";
public static final String CFG_EXCLUDE_BUNDLES = "excludeBundles";
public static final String CFG_RUN_MODES = "runModes";
public static final String DEFAULT_OUTPUT_FOLDER = "target/features";
/**
* The folder that contains the Provisioning Models
*/
@Parameter(property = CFG_INPUT_FOLDER, required = true)
private File inputFolder;
/**
* The folder that will contain the created Feature Models relative to the Maven Basedir Folder
*/
@Parameter(property = CFG_OUTPUT_FOLDER, defaultValue = DEFAULT_OUTPUT_FOLDER, required = true)
private String outputFolder;
/**
* If provided this becomes the Feature's Group Id
*/
@Parameter(property = CFG_GROUP_ID)
private String groupId;
/**
* If provided this becomes the Feature's Artifact Id. Tis will also
* make the original name to become the classifier
*/
@Parameter(property = CFG_ARTIFACT_ID)
private String artifactId;
/**
* If provided this becomes the Feature's Version
*/
@Parameter(property = CFG_VERSION)
private String version;
/**
* Franework Properties to be added to a given Feature Model.
* The format looks like this:
* 'launchpad:felix.systempackages.substitution=true' where
* launchpad is the name of the PM
*/
@Parameter(property = CFG_FRAMEWORK_PROPERTIES)
private List<String> frameworkProperties;
/**
* If set to {@code true} the converted Content Package will be installed in the local Maven Repository
*/
@Parameter(property = CFG_NO_PROVISIIONING_MODEL_NAME, defaultValue = "true")
private boolean noProvisioningModelName;
/**
* List of Bundles to be excluded from the Feature Model files
*/
@Parameter(property = CFG_EXCLUDE_BUNDLES)
private List<String> excludeBundles;
/**
* List of all Runmodes that are considered for this conversion
*
* The default and all parts of all runmodes listed are placed into
* the Feature Models, all others are excluded
*/
@Parameter(property = CFG_RUN_MODES)
private List<String> runModes;
private Pattern pattern = Pattern.compile("^(.*?):(.*?)=(.*?)$");
private String checkForPlaceholder(String text) {
String answer = text;
if(answer != null) {
answer = answer.replaceAll("\\$\\{\\{", "\\$\\{");
answer = answer.replaceAll("}}", "}");
getLog().info("Replaced Old Artifact Id Override: '" + text + "', with new one: '" + answer + "'");
}
return answer;
}
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
if (!inputFolder.isDirectory()) {
throw new MojoFailureException("Input Folder is not a directory: " + inputFolder);
}
if (!inputFolder.canRead()) {
throw new MojoFailureException("Input Folder is not readable:" + inputFolder);
}
String outputFolderPath = project.getBasedir() + "/" + outputFolder;
File output = new File(outputFolderPath);
if (!output.exists()) {
if(!output.mkdirs()) {
throw new MojoFailureException("Could not create Output Folder: " + outputFolder);
}
}
if (!output.isDirectory()) {
throw new MojoFailureException("Output Folder is not a directory: " + output);
}
if (!output.canWrite()) {
throw new MojoFailureException("Output Folder is not writable: " + output);
}
List<File> provisioningFiles = Arrays.asList(inputFolder.listFiles());
Map<String, Object> options = new HashMap<>();
if (groupId != null && !groupId.isEmpty()) {
groupId = checkForPlaceholder(groupId);
options.put("groupId", groupId);
}
if (version != null && !version.isEmpty()) {
version = checkForPlaceholder(version);
options.put("version", version);
}
// Todo: do we have a way to check the name?
if (artifactId != null && !artifactId.isEmpty()) {
artifactId = checkForPlaceholder(artifactId);
options.put("name", artifactId);
}
options.put("useProvidedVersion", version != null && !version.isEmpty());
options.put("noProvisioningModelName", noProvisioningModelName);
frameworkProperties = trimList(frameworkProperties);
Map<String, Map<String, String>> frameworkPropertiesMap = new HashMap<>();
for (String value : frameworkProperties) {
// Separate Model from Property Name Value pair. Create Sub Map if needed and then add
getLog().info("Check Add Framework Properties Line: " + value);
Matcher matcher = pattern.matcher(value);
if (matcher.matches() && matcher.groupCount() == 3) {
String modelName = matcher.group(1);
String propName = matcher.group(2);
String propValue = matcher.group(3);
getLog().info("Model Name: " + modelName + ", Prop Name: " + propName + ", Value: " + propValue);
Map<String, String> modelMap = frameworkPropertiesMap.get(modelName);
if (modelMap == null) {
modelMap = new HashMap<>();
frameworkPropertiesMap.put(modelName, modelMap);
}
modelMap.put(propName, propValue);
}
}
options.put("addFrameworkProperties", frameworkPropertiesMap);
excludeBundles = trimList(excludeBundles);
options.put("excludeBundles", excludeBundles);
getLog().info("Excluded Bundles: " + excludeBundles);
runModes = trimList(runModes);
options.put("runModes", runModes);
getLog().info("Runmodes: " + runModes);
// Start the Conversion
for (File file : provisioningFiles) {
getLog().info("Handle File: " + file.getAbsolutePath());
ProvisioningToFeature.convert(file, output, options);
}
}
// Because of the XML structure run modes can have leading, trailing spaces so we need to trim them here
public List<String> trimList(List<String> list) {
List<String> answer = new ArrayList<>();
if(list != null) {
for(String entry: list) {
if(entry != null) {
entry = entry.trim();
if(!entry.isEmpty()) {
answer.add(entry);
}
}
}
}
return answer;
}
}