| /* |
| * 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.maven.plugins.resources; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.maven.execution.MavenSession; |
| import org.apache.maven.model.Resource; |
| import org.apache.maven.plugin.AbstractMojo; |
| import org.apache.maven.plugin.MojoExecutionException; |
| import org.apache.maven.plugins.annotations.Component; |
| import org.apache.maven.plugins.annotations.LifecyclePhase; |
| import org.apache.maven.plugins.annotations.Mojo; |
| import org.apache.maven.plugins.annotations.Parameter; |
| import org.apache.maven.project.MavenProject; |
| import org.apache.maven.shared.filtering.MavenFilteringException; |
| import org.apache.maven.shared.filtering.MavenResourcesExecution; |
| import org.apache.maven.shared.filtering.MavenResourcesFiltering; |
| |
| /** |
| * Copy resources for the main source code to the main output directory. Always uses the project.build.resources element |
| * to specify the resources to copy. |
| * |
| * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a> |
| * @author <a href="mailto:jason@maven.org">Jason van Zyl</a> |
| * @author Andreas Hoheneder |
| * @author William Ferguson |
| */ |
| @Mojo(name = "resources", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, requiresProject = true, threadSafe = true) |
| public class ResourcesMojo extends AbstractMojo { |
| |
| /** |
| * The character encoding to use when reading and writing filtered resources. |
| */ |
| @Parameter(defaultValue = "${project.build.sourceEncoding}") |
| protected String encoding; |
| |
| /** |
| * The character encoding to use when reading and writing filtered properties files. |
| * If not specified, it will default to the value of the "encoding" parameter. |
| * |
| * @since 3.2.0 |
| */ |
| @Parameter |
| protected String propertiesEncoding; |
| |
| /** |
| * The output directory into which to copy the resources. |
| */ |
| @Parameter(defaultValue = "${project.build.outputDirectory}", required = true) |
| private File outputDirectory; |
| |
| /** |
| * The list of resources we want to transfer. |
| */ |
| @Parameter(defaultValue = "${project.resources}", required = true, readonly = true) |
| private List<Resource> resources; |
| |
| /** |
| * |
| */ |
| @Parameter(defaultValue = "${project}", readonly = true, required = true) |
| protected MavenProject project; |
| |
| /** |
| * The list of additional filter properties files to be used along with System and project properties, which would |
| * be used for the filtering. |
| * |
| * @see ResourcesMojo#filters |
| * @since 2.4 |
| */ |
| @Parameter(defaultValue = "${project.build.filters}", readonly = true) |
| protected List<String> buildFilters; |
| |
| /** |
| * <p> |
| * The list of extra filter properties files to be used along with System properties, project properties, and filter |
| * properties files specified in the POM build/filters section, which should be used for the filtering during the |
| * current mojo execution.</p> |
| * <p> |
| * Normally, these will be configured from a plugin's execution section, to provide a different set of filters for a |
| * particular execution. For instance, starting in Maven 2.2.0, you have the option of configuring executions with |
| * the id's <code>default-resources</code> and <code>default-testResources</code> to supply different configurations |
| * for the two different types of resources. By supplying <code>extraFilters</code> configurations, you can separate |
| * which filters are used for which type of resource.</p> |
| */ |
| @Parameter |
| protected List<String> filters; |
| |
| /** |
| * If false, don't use the filters specified in the build/filters section of the POM when processing resources in |
| * this mojo execution. |
| * |
| * @see ResourcesMojo#buildFilters |
| * @see ResourcesMojo#filters |
| * @since 2.4 |
| */ |
| @Parameter(defaultValue = "true") |
| protected boolean useBuildFilters; |
| |
| /** |
| * |
| */ |
| @Component(role = MavenResourcesFiltering.class, hint = "default") |
| protected MavenResourcesFiltering mavenResourcesFiltering; |
| |
| /** |
| * |
| */ |
| @Component(role = MavenResourcesFiltering.class) |
| protected Map<String, MavenResourcesFiltering> mavenResourcesFilteringMap; |
| |
| /** |
| * |
| */ |
| @Parameter(defaultValue = "${session}", readonly = true, required = true) |
| protected MavenSession session; |
| |
| /** |
| * Expressions preceded with this string won't be interpolated. Anything else preceded with this string will be |
| * passed through unchanged. For example {@code \${foo}} will be replaced with {@code ${foo}} but {@code \\${foo}} |
| * will be replaced with {@code \\value of foo}, if this parameter has been set to the backslash. |
| * |
| * @since 2.3 |
| */ |
| @Parameter |
| protected String escapeString; |
| |
| /** |
| * Overwrite existing files even if the destination files are newer. |
| * |
| * @since 2.3 |
| */ |
| @Parameter(defaultValue = "false") |
| private boolean overwrite; |
| |
| /** |
| * Copy any empty directories included in the Resources. |
| * |
| * @since 2.3 |
| */ |
| @Parameter(defaultValue = "false") |
| protected boolean includeEmptyDirs; |
| |
| /** |
| * Additional file extensions to not apply filtering (already defined are : jpg, jpeg, gif, bmp, png) |
| * |
| * @since 2.3 |
| */ |
| @Parameter |
| protected List<String> nonFilteredFileExtensions; |
| |
| /** |
| * Whether to escape backslashes and colons in windows-style paths. |
| * |
| * @since 2.4 |
| */ |
| @Parameter(defaultValue = "true") |
| protected boolean escapeWindowsPaths; |
| |
| /** |
| * <p> |
| * Set of delimiters for expressions to filter within the resources. These delimiters are specified in the form |
| * {@code beginToken*endToken}. If no {@code *} is given, the delimiter is assumed to be the same for start and end. |
| * </p> |
| * <p> |
| * So, the default filtering delimiters might be specified as: |
| * </p> |
| * |
| * <pre> |
| * <delimiters> |
| * <delimiter>${*}</delimiter> |
| * <delimiter>@</delimiter> |
| * </delimiters> |
| * </pre> |
| * <p> |
| * Since the {@code @} delimiter is the same on both ends, we don't need to specify {@code @*@} (though we can). |
| * </p> |
| * |
| * @since 2.4 |
| */ |
| @Parameter |
| protected LinkedHashSet<String> delimiters; |
| |
| /** |
| * Use default delimiters in addition to custom delimiters, if any. |
| * |
| * @since 2.4 |
| */ |
| @Parameter(defaultValue = "true") |
| protected boolean useDefaultDelimiters; |
| |
| /** |
| * By default files like {@code .gitignore}, {@code .cvsignore} etc. are excluded which means they will not being |
| * copied. If you need them for a particular reason you can do that by settings this to {@code false}. This means |
| * all files like the following will be copied. |
| * <ul> |
| * <li>Misc: **/*~, **/#*#, **/.#*, **/%*%, **/._*</li> |
| * <li>CVS: **/CVS, **/CVS/**, **/.cvsignore</li> |
| * <li>RCS: **/RCS, **/RCS/**</li> |
| * <li>SCCS: **/SCCS, **/SCCS/**</li> |
| * <li>VSSercer: **/vssver.scc</li> |
| * <li>MKS: **/project.pj</li> |
| * <li>SVN: **/.svn, **/.svn/**</li> |
| * <li>GNU: **/.arch-ids, **/.arch-ids/**</li> |
| * <li>Bazaar: **/.bzr, **/.bzr/**</li> |
| * <li>SurroundSCM: **/.MySCMServerInfo</li> |
| * <li>Mac: **/.DS_Store</li> |
| * <li>Serena Dimension: **/.metadata, **/.metadata/**</li> |
| * <li>Mercurial: **/.hg, **/.hg/**</li> |
| * <li>Git: **/.git, **/.git/**</li> |
| * <li>Bitkeeper: **/BitKeeper, **/BitKeeper/**, **/ChangeSet, |
| * **/ChangeSet/**</li> |
| * <li>Darcs: **/_darcs, **/_darcs/**, **/.darcsrepo, |
| * **/.darcsrepo/****/-darcs-backup*, **/.darcs-temp-mail |
| * </ul> |
| * |
| * @since 3.0.0 |
| */ |
| @Parameter(defaultValue = "true") |
| protected boolean addDefaultExcludes; |
| |
| /** |
| * <p> |
| * List of plexus components hint which implements |
| * {@link MavenResourcesFiltering#filterResources(MavenResourcesExecution)}. They will be executed after the |
| * resources copying/filtering. |
| * </p> |
| * |
| * @since 2.4 |
| */ |
| @Parameter |
| private List<String> mavenFilteringHints; |
| |
| /** |
| * @since 2.4 |
| */ |
| private List<MavenResourcesFiltering> mavenFilteringComponents = new ArrayList<>(); |
| |
| /** |
| * stop searching endToken at the end of line |
| * |
| * @since 2.5 |
| */ |
| @Parameter(defaultValue = "false") |
| private boolean supportMultiLineFiltering; |
| |
| /** |
| * Support filtering of filenames folders etc. |
| * |
| * @since 3.0.0 |
| */ |
| @Parameter(defaultValue = "false") |
| private boolean fileNameFiltering; |
| |
| /** |
| * You can skip the execution of the plugin if you need to. Its use is NOT RECOMMENDED, but quite convenient on |
| * occasion. |
| * |
| * @since 3.0.0 |
| */ |
| @Parameter(property = "maven.resources.skip", defaultValue = "false") |
| private boolean skip; |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void execute() throws MojoExecutionException { |
| if (isSkip()) { |
| getLog().info("Skipping the execution."); |
| return; |
| } |
| |
| if (StringUtils.isBlank(encoding) && isFilteringEnabled(getResources())) { |
| getLog().warn("File encoding has not been set, using platform encoding " |
| + System.getProperty("file.encoding") |
| + ". Build is platform dependent!"); |
| getLog().warn("See https://maven.apache.org/general.html#encoding-warning"); |
| } |
| |
| try { |
| List<String> combinedFilters = getCombinedFiltersList(); |
| |
| MavenResourcesExecution mavenResourcesExecution = new MavenResourcesExecution( |
| getResources(), |
| getOutputDirectory(), |
| project, |
| encoding, |
| combinedFilters, |
| Collections.emptyList(), |
| session); |
| |
| mavenResourcesExecution.setEscapeWindowsPaths(escapeWindowsPaths); |
| |
| // never include project build filters in this call, since we've already accounted for the POM build filters |
| // above, in getCombinedFiltersList(). |
| mavenResourcesExecution.setInjectProjectBuildFilters(false); |
| |
| mavenResourcesExecution.setEscapeString(escapeString); |
| mavenResourcesExecution.setOverwrite(overwrite); |
| mavenResourcesExecution.setIncludeEmptyDirs(includeEmptyDirs); |
| mavenResourcesExecution.setSupportMultiLineFiltering(supportMultiLineFiltering); |
| mavenResourcesExecution.setFilterFilenames(fileNameFiltering); |
| mavenResourcesExecution.setAddDefaultExcludes(addDefaultExcludes); |
| |
| // Handle subject of MRESOURCES-99 |
| Properties additionalProperties = addSeveralSpecialProperties(); |
| mavenResourcesExecution.setAdditionalProperties(additionalProperties); |
| |
| // if these are NOT set, just use the defaults, which are '${*}' and '@'. |
| mavenResourcesExecution.setDelimiters(delimiters, useDefaultDelimiters); |
| |
| // Handle MRESOURCES-171 |
| mavenResourcesExecution.setPropertiesEncoding(propertiesEncoding); |
| |
| if (nonFilteredFileExtensions != null) { |
| mavenResourcesExecution.setNonFilteredFileExtensions(nonFilteredFileExtensions); |
| } |
| mavenResourcesFiltering.filterResources(mavenResourcesExecution); |
| |
| executeUserFilterComponents(mavenResourcesExecution); |
| } catch (MavenFilteringException e) { |
| throw new MojoExecutionException(e.getMessage(), e); |
| } |
| } |
| |
| /** |
| * This solves https://issues.apache.org/jira/browse/MRESOURCES-99.<br/> |
| * BUT:<br/> |
| * This should be done different than defining those properties a second time, cause they have already being defined |
| * in Maven Model Builder (package org.apache.maven.model.interpolation) via BuildTimestampValueSource. But those |
| * can't be found in the context which can be got from the maven core.<br/> |
| * A solution could be to put those values into the context by Maven core so they are accessible everywhere. (I'm |
| * not sure if this is a good idea). Better ideas are always welcome. |
| * <p> |
| * The problem at the moment is that maven core handles usage of properties and replacements in |
| * the model, but does not the resource filtering which needed some of the properties. |
| * |
| * @return the new instance with those properties. |
| */ |
| private Properties addSeveralSpecialProperties() { |
| String timeStamp = new MavenBuildTimestamp().formattedTimestamp(); |
| Properties additionalProperties = new Properties(); |
| additionalProperties.put("maven.build.timestamp", timeStamp); |
| if (project.getBasedir() != null) { |
| additionalProperties.put( |
| "project.baseUri", |
| project.getBasedir().getAbsoluteFile().toURI().toString()); |
| } |
| |
| return additionalProperties; |
| } |
| |
| /** |
| * @param mavenResourcesExecution {@link MavenResourcesExecution} |
| * @throws MojoExecutionException in case of wrong lookup. |
| * @throws MavenFilteringException in case of failure. |
| * @since 2.5 |
| */ |
| protected void executeUserFilterComponents(MavenResourcesExecution mavenResourcesExecution) |
| throws MojoExecutionException, MavenFilteringException { |
| |
| if (mavenFilteringHints != null) { |
| for (String hint : mavenFilteringHints) { |
| MavenResourcesFiltering userFilterComponent = mavenResourcesFilteringMap.get(hint); |
| if (userFilterComponent != null) { |
| getLog().debug("added user filter component with hint: " + hint); |
| mavenFilteringComponents.add(userFilterComponent); |
| } else { |
| throw new MojoExecutionException( |
| "User filter with hint `" + hint + "` requested, but not present. Discovered filters are: " |
| + mavenResourcesFilteringMap.keySet()); |
| } |
| } |
| } else { |
| getLog().debug("no user filter components"); |
| } |
| |
| if (mavenFilteringComponents != null && !mavenFilteringComponents.isEmpty()) { |
| getLog().debug("execute user filters"); |
| for (MavenResourcesFiltering filter : mavenFilteringComponents) { |
| filter.filterResources(mavenResourcesExecution); |
| } |
| } |
| } |
| |
| /** |
| * @return The combined filters. |
| */ |
| protected List<String> getCombinedFiltersList() { |
| if (filters == null || filters.isEmpty()) { |
| return useBuildFilters ? buildFilters : null; |
| } else { |
| List<String> result = new ArrayList<>(); |
| |
| if (useBuildFilters && buildFilters != null && !buildFilters.isEmpty()) { |
| result.addAll(buildFilters); |
| } |
| |
| result.addAll(filters); |
| |
| return result; |
| } |
| } |
| |
| /** |
| * Determines whether filtering has been enabled for any resource. |
| * |
| * @param theResources The set of resources to check for filtering, may be <code>null</code>. |
| * @return <code>true</code> if at least one resource uses filtering, <code>false</code> otherwise. |
| */ |
| private boolean isFilteringEnabled(Collection<Resource> theResources) { |
| if (theResources != null) { |
| for (Resource resource : theResources) { |
| if (resource.isFiltering()) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * @return {@link #resources} |
| */ |
| public List<Resource> getResources() { |
| return resources; |
| } |
| |
| /** |
| * @param resources set {@link #resources} |
| */ |
| public void setResources(List<Resource> resources) { |
| this.resources = resources; |
| } |
| |
| /** |
| * @return {@link #outputDirectory} |
| */ |
| public File getOutputDirectory() { |
| return outputDirectory; |
| } |
| |
| /** |
| * @param outputDirectory the output folder. |
| */ |
| public void setOutputDirectory(File outputDirectory) { |
| this.outputDirectory = outputDirectory; |
| } |
| |
| /** |
| * @return {@link #overwrite} |
| */ |
| public boolean isOverwrite() { |
| return overwrite; |
| } |
| |
| /** |
| * @param overwrite true to overwrite false otherwise. |
| */ |
| public void setOverwrite(boolean overwrite) { |
| this.overwrite = overwrite; |
| } |
| |
| /** |
| * @return {@link #includeEmptyDirs} |
| */ |
| public boolean isIncludeEmptyDirs() { |
| return includeEmptyDirs; |
| } |
| |
| /** |
| * @param includeEmptyDirs true/false. |
| */ |
| public void setIncludeEmptyDirs(boolean includeEmptyDirs) { |
| this.includeEmptyDirs = includeEmptyDirs; |
| } |
| |
| /** |
| * @return {@link #filters} |
| */ |
| public List<String> getFilters() { |
| return filters; |
| } |
| |
| /** |
| * @param filters The filters to use. |
| */ |
| public void setFilters(List<String> filters) { |
| this.filters = filters; |
| } |
| |
| /** |
| * @return {@link #delimiters} |
| */ |
| public LinkedHashSet<String> getDelimiters() { |
| return delimiters; |
| } |
| |
| /** |
| * @param delimiters The delimiters to use. |
| */ |
| public void setDelimiters(LinkedHashSet<String> delimiters) { |
| this.delimiters = delimiters; |
| } |
| |
| /** |
| * @return {@link #useDefaultDelimiters} |
| */ |
| public boolean isUseDefaultDelimiters() { |
| return useDefaultDelimiters; |
| } |
| |
| /** |
| * @param useDefaultDelimiters true to use {@code ${*}} |
| */ |
| public void setUseDefaultDelimiters(boolean useDefaultDelimiters) { |
| this.useDefaultDelimiters = useDefaultDelimiters; |
| } |
| |
| /** |
| * @return {@link #skip} |
| */ |
| public boolean isSkip() { |
| return skip; |
| } |
| } |