View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.archetype.mojos;
20  
21  import javax.inject.Inject;
22  
23  import java.io.File;
24  import java.util.Map;
25  
26  import org.apache.maven.archetype.common.ArchetypeArtifactManager;
27  import org.apache.maven.archetype.exception.UnknownArchetype;
28  import org.apache.maven.archetype.metadata.ArchetypeDescriptor;
29  import org.apache.maven.archetype.metadata.RequiredProperty;
30  import org.apache.maven.archiver.MavenArchiveConfiguration;
31  import org.apache.maven.archiver.MavenArchiver;
32  import org.apache.maven.execution.MavenSession;
33  import org.apache.maven.plugin.AbstractMojo;
34  import org.apache.maven.plugin.MojoExecutionException;
35  import org.apache.maven.plugins.annotations.LifecyclePhase;
36  import org.apache.maven.plugins.annotations.Mojo;
37  import org.apache.maven.plugins.annotations.Parameter;
38  import org.apache.maven.project.MavenProject;
39  import org.codehaus.plexus.archiver.Archiver;
40  import org.codehaus.plexus.archiver.jar.JarArchiver;
41  import org.codehaus.plexus.archiver.util.DefaultFileSet;
42  
43  /**
44   * Build a JAR from the current Archetype project.
45   *
46   * @author rafale
47   */
48  @Mojo(name = "jar", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true)
49  public class JarMojo extends AbstractMojo {
50  
51      /**
52       * Directory containing the classes.
53       */
54      @Parameter(defaultValue = "${project.build.outputDirectory}", required = true)
55      private File archetypeDirectory;
56  
57      /**
58       * Name of the generated JAR.
59       */
60      @Parameter(defaultValue = "${project.build.finalName}", alias = "jarName", required = true)
61      private String finalName;
62  
63      /**
64       * Directory containing the generated JAR.
65       */
66      @Parameter(defaultValue = "${project.build.directory}", required = true)
67      private File outputDirectory;
68  
69      /**
70       * Exclude some files from the archetype like .gitignore.
71       */
72      @Parameter(defaultValue = "true")
73      private boolean useDefaultExcludes;
74  
75      /**
76       * The Maven project.
77       */
78      @Parameter(defaultValue = "${project}", readonly = true, required = true)
79      private MavenProject project;
80  
81      /**
82       * The {@link MavenSession}.
83       */
84      @Parameter(defaultValue = "${session}", readonly = true, required = true)
85      private MavenSession session;
86  
87      /**
88       * The archive configuration to use. See <a href="https://maven.apache.org/shared/maven-archiver/index.html">Maven
89       * Archiver Reference</a>.
90       *
91       * @since 3.2.0
92       */
93      @Parameter
94      private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
95  
96      /**
97       * Timestamp for reproducible output archive entries, either formatted as ISO 8601
98       * <code>yyyy-MM-dd'T'HH:mm:ssXXX</code> or as an int representing seconds since the epoch (like
99       * <a href="https://reproducible-builds.org/docs/source-date-epoch/">SOURCE_DATE_EPOCH</a>).
100      *
101      * @since 3.2.0
102      */
103     @Parameter(defaultValue = "${project.build.outputTimestamp}")
104     private String outputTimestamp;
105 
106     /**
107      * The Jar archiver.
108      */
109     private Map<String, Archiver> archivers;
110 
111     private ArchetypeArtifactManager archetypeArtifactManager;
112 
113     @Inject
114     public JarMojo(Map<String, Archiver> archivers, ArchetypeArtifactManager archetypeArtifactManager) {
115         this.archivers = archivers;
116         this.archetypeArtifactManager = archetypeArtifactManager;
117     }
118 
119     @Override
120     public void execute() throws MojoExecutionException {
121         File jarFile = new File(outputDirectory, finalName + ".jar");
122         getLog().info("Building archetype jar: " + jarFile);
123 
124         MavenArchiver archiver = new MavenArchiver();
125         archiver.setCreatedBy("Maven Archetype Plugin", "org.apache.maven.plugins", "maven-archetype-plugin");
126 
127         archiver.setOutputFile(jarFile);
128 
129         archiver.setArchiver((JarArchiver) archivers.get("jar"));
130 
131         // configure for Reproducible Builds based on outputTimestamp value
132         archiver.configureReproducibleBuild(outputTimestamp);
133 
134         try {
135             DefaultFileSet fs = DefaultFileSet.fileSet(archetypeDirectory)
136                     .prefixed("")
137                     .includeExclude(null, null)
138                     .includeEmptyDirs(true);
139             fs.setUsingDefaultExcludes(useDefaultExcludes);
140             archiver.getArchiver().addFileSet(fs);
141 
142             archiver.createArchive(session, project, archive);
143         } catch (Exception e) {
144             throw new MojoExecutionException("Error assembling archetype jar " + jarFile, e);
145         }
146 
147         checkArchetypeFile(jarFile);
148 
149         project.getArtifact().setFile(jarFile);
150     }
151 
152     private void checkArchetypeFile(File jarFile) throws MojoExecutionException {
153         try {
154             if (archetypeArtifactManager.isFileSetArchetype(jarFile)) {
155                 checkFileSetArchetypeFile(jarFile);
156             } else if (archetypeArtifactManager.isOldArchetype(jarFile)) {
157                 getLog().warn("Building an Old (1.x) Archetype: consider migrating it to current 2.x Archetype.");
158             } else {
159                 throw new MojoExecutionException("The current project does not build an archetype");
160             }
161         } catch (UnknownArchetype ua) {
162             throw new MojoExecutionException(ua.getMessage(), ua);
163         }
164     }
165 
166     private void checkFileSetArchetypeFile(File jarFile) throws UnknownArchetype {
167         ArchetypeDescriptor archetypeDescriptor = archetypeArtifactManager.getFileSetArchetypeDescriptor(jarFile);
168 
169         for (RequiredProperty rp : archetypeDescriptor.getRequiredProperties()) {
170             if (rp.getKey().contains(".")) {
171                 getLog().warn("Invalid required property name '" + rp.getKey()
172                         + "': dot character makes is unusable in Velocity template");
173             }
174         }
175     }
176 }