1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.apache.maven.plugins.install;
20  
21  import java.io.File;
22  import java.io.FileNotFoundException;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.Writer;
26  import java.nio.file.Files;
27  import java.nio.file.Path;
28  import java.nio.file.StandardCopyOption;
29  import java.util.ArrayList;
30  import java.util.List;
31  import java.util.jar.JarEntry;
32  import java.util.jar.JarFile;
33  import java.util.regex.Pattern;
34  
35  import org.apache.maven.api.Artifact;
36  import org.apache.maven.api.ProducedArtifact;
37  import org.apache.maven.api.Session;
38  import org.apache.maven.api.di.Inject;
39  import org.apache.maven.api.model.Model;
40  import org.apache.maven.api.model.Parent;
41  import org.apache.maven.api.plugin.Log;
42  import org.apache.maven.api.plugin.MojoException;
43  import org.apache.maven.api.plugin.annotations.Mojo;
44  import org.apache.maven.api.plugin.annotations.Parameter;
45  import org.apache.maven.api.services.ArtifactInstaller;
46  import org.apache.maven.api.services.ArtifactInstallerException;
47  import org.apache.maven.api.services.ArtifactManager;
48  import org.apache.maven.api.services.xml.ModelXmlFactory;
49  import org.apache.maven.api.services.xml.XmlReaderException;
50  
51  
52  
53  
54  @Mojo(name = "install-file", projectRequired = false, aggregator = true)
55  @SuppressWarnings("unused")
56  public class InstallFileMojo implements org.apache.maven.api.plugin.Mojo {
57      private static final String TAR = "tar.";
58      private static final String ILLEGAL_VERSION_CHARS = "\\/:\"<>|?*[](){},";
59  
60      @Inject
61      private Log log;
62  
63      @Inject
64      private Session session;
65  
66      
67  
68  
69  
70      @Parameter(property = "groupId")
71      private String groupId;
72  
73      
74  
75  
76  
77      @Parameter(property = "artifactId")
78      private String artifactId;
79  
80      
81  
82  
83  
84      @Parameter(property = "version")
85      private String version;
86  
87      
88  
89  
90  
91      @Parameter(property = "packaging")
92      private String packaging;
93  
94      
95  
96  
97  
98  
99  
100     @Parameter(property = "classifier")
101     private String classifier;
102 
103     
104 
105 
106     @Parameter(property = "file", required = true)
107     private Path file;
108 
109     
110 
111 
112 
113 
114     @Parameter(property = "javadoc")
115     private Path javadoc;
116 
117     
118 
119 
120 
121 
122     @Parameter(property = "sources")
123     private Path sources;
124 
125     
126 
127 
128 
129 
130 
131     @Parameter(property = "pomFile")
132     private Path pomFile;
133 
134     
135 
136 
137 
138 
139 
140     @Parameter(property = "generatePom")
141     private Boolean generatePom;
142 
143     
144 
145 
146 
147 
148 
149     @Parameter(property = "localRepositoryPath")
150     private Path localRepositoryPath;
151 
152     @Override
153     public void execute() {
154         if (!Files.exists(file)) {
155             String message = "The specified file '" + file + "' does not exist";
156             log.error(message);
157             throw new MojoException(message);
158         }
159 
160         Session session = this.session;
161 
162         List<ProducedArtifact> installableArtifacts = new ArrayList<>();
163 
164         
165         if (localRepositoryPath != null) {
166             session = session.withLocalRepository(session.createLocalRepository(localRepositoryPath));
167 
168             log.debug("localRepoPath: " + localRepositoryPath);
169         }
170 
171         Path deployedPom;
172         Path temporaryPom = null;
173         if (pomFile != null) {
174             deployedPom = pomFile;
175             processModel(readModel(deployedPom));
176         } else {
177             if (!Boolean.TRUE.equals(generatePom)) {
178                 temporaryPom = readingPomFromJarFile();
179                 deployedPom = temporaryPom;
180                 if (deployedPom != null) {
181                     log.debug("Using JAR embedded POM as pomFile");
182                 }
183             } else {
184                 deployedPom = null;
185             }
186         }
187 
188         if (groupId == null || artifactId == null || version == null || packaging == null) {
189             throw new MojoException("The artifact information is incomplete: 'groupId', 'artifactId', "
190                     + "'version' and 'packaging' are required.");
191         }
192 
193         if (!isValidId(groupId) || !isValidId(artifactId) || !isValidVersion(version)) {
194             throw new MojoException("The artifact information is not valid: uses invalid characters.");
195         }
196 
197         boolean isFilePom = classifier == null && "pom".equals(packaging);
198         ProducedArtifact artifact = session.createProducedArtifact(
199                 groupId, artifactId, version, classifier, isFilePom ? "pom" : getExtension(file), packaging);
200 
201         if (file.equals(getLocalRepositoryFile(artifact))) {
202             throw new MojoException("Cannot install artifact. "
203                     + "Artifact is already in the local repository.\n\nFile in question is: " + file + "\n");
204         }
205 
206         ArtifactManager artifactManager = session.getService(ArtifactManager.class);
207         artifactManager.setPath(artifact, file);
208         installableArtifacts.add(artifact);
209 
210         ProducedArtifact pomArtifact = null;
211         if (!isFilePom) {
212             pomArtifact = session.createProducedArtifact(groupId, artifactId, version, null, "pom", null);
213             if (deployedPom != null) {
214                 artifactManager.setPath(pomArtifact, deployedPom);
215                 installableArtifacts.add(pomArtifact);
216             } else {
217                 temporaryPom = generatePomFile();
218                 deployedPom = temporaryPom;
219                 artifactManager.setPath(pomArtifact, deployedPom);
220                 if (Boolean.TRUE.equals(generatePom)
221                         || (generatePom == null && !Files.exists(getLocalRepositoryFile(pomArtifact)))) {
222                     log.debug("Installing generated POM");
223                     installableArtifacts.add(pomArtifact);
224                 } else if (generatePom == null) {
225                     log.debug("Skipping installation of generated POM, already present in local repository");
226                 }
227             }
228         }
229 
230         if (sources != null) {
231             ProducedArtifact sourcesArtifact =
232                     session.createProducedArtifact(groupId, artifactId, version, "sources", "jar", null);
233             artifactManager.setPath(sourcesArtifact, sources);
234             installableArtifacts.add(sourcesArtifact);
235         }
236 
237         if (javadoc != null) {
238             ProducedArtifact javadocArtifact =
239                     session.createProducedArtifact(groupId, artifactId, version, "javadoc", "jar", null);
240             artifactManager.setPath(javadocArtifact, javadoc);
241             installableArtifacts.add(javadocArtifact);
242         }
243 
244         try {
245             ArtifactInstaller artifactInstaller = session.getService(ArtifactInstaller.class);
246             artifactInstaller.install(session, installableArtifacts);
247         } catch (ArtifactInstallerException e) {
248             throw new MojoException(e.getMessage(), e);
249         } finally {
250             if (temporaryPom != null) {
251                 try {
252                     Files.deleteIfExists(temporaryPom);
253                 } catch (IOException e) {
254                     
255                 }
256                 if (pomArtifact != null) {
257                     artifactManager.setPath(pomArtifact, null);
258                 }
259             }
260         }
261     }
262 
263     private Path readingPomFromJarFile() {
264         Pattern pomEntry = Pattern.compile("META-INF/maven/.*/pom\\.xml");
265         try {
266             try (JarFile jarFile = new JarFile(file.toFile())) {
267                 JarEntry entry = jarFile.stream()
268                         .filter(e -> pomEntry.matcher(e.getName()).matches())
269                         .findFirst()
270                         .orElse(null);
271                 if (entry != null) {
272                     log.debug("Loading " + entry.getName());
273 
274                     try (InputStream pomInputStream = jarFile.getInputStream(entry)) {
275                         String base = file.getFileName().toString();
276                         if (base.indexOf('.') > 0) {
277                             base = base.substring(0, base.lastIndexOf('.'));
278                         }
279                         Path pomFile = File.createTempFile(base, ".pom").toPath();
280 
281                         Files.copy(pomInputStream, pomFile, StandardCopyOption.REPLACE_EXISTING);
282 
283                         processModel(readModel(pomFile));
284 
285                         return pomFile;
286                     }
287                 } else {
288                     log.info("pom.xml not found in " + file.getFileName());
289                 }
290             }
291         } catch (IOException e) {
292             
293         }
294         return null;
295     }
296 
297     
298 
299 
300 
301 
302 
303 
304     private Model readModel(Path pomFile) throws MojoException {
305         try {
306             try (InputStream is = Files.newInputStream(pomFile)) {
307                 return session.getService(ModelXmlFactory.class).read(is);
308             }
309         } catch (FileNotFoundException e) {
310             throw new MojoException("File not found " + pomFile, e);
311         } catch (IOException e) {
312             throw new MojoException("Error reading POM " + pomFile, e);
313         } catch (XmlReaderException e) {
314             throw new MojoException("Error parsing POM " + pomFile, e);
315         }
316     }
317 
318     
319 
320 
321 
322 
323     private void processModel(Model model) {
324         Parent parent = model.getParent();
325 
326         if (this.groupId == null) {
327             this.groupId = model.getGroupId();
328             if (this.groupId == null && parent != null) {
329                 this.groupId = parent.getGroupId();
330             }
331         }
332         if (this.artifactId == null) {
333             this.artifactId = model.getArtifactId();
334         }
335         if (this.version == null) {
336             this.version = model.getVersion();
337             if (this.version == null && parent != null) {
338                 this.version = parent.getVersion();
339             }
340         }
341         if (this.packaging == null) {
342             this.packaging = model.getPackaging();
343         }
344     }
345 
346     
347 
348 
349 
350 
351     private Model generateModel() {
352         return Model.newBuilder()
353                 .modelVersion("4.0.0")
354                 .groupId(groupId)
355                 .artifactId(artifactId)
356                 .version(version)
357                 .packaging(packaging)
358                 .description("POM was created from install:install-file")
359                 .build();
360     }
361 
362     
363 
364 
365 
366 
367 
368 
369     private Path generatePomFile() throws MojoException {
370         Model model = generateModel();
371         try {
372             Path pomFile = File.createTempFile("mvninstall", ".pom").toPath();
373             try (Writer writer = Files.newBufferedWriter(pomFile)) {
374                 session.getService(ModelXmlFactory.class).write(model, writer);
375             }
376             return pomFile;
377         } catch (IOException e) {
378             throw new MojoException("Error writing temporary POM file: " + e.getMessage(), e);
379         }
380     }
381 
382     
383 
384 
385 
386     private Path getLocalRepositoryFile(Artifact artifact) {
387         return session.getPathForLocalArtifact(artifact);
388     }
389 
390     
391 
392 
393     private String getExtension(final Path file) {
394         String filename = file.getFileName().toString();
395         int lastDot = filename.lastIndexOf('.');
396         if (lastDot > 0 && lastDot < filename.length() - 1) {
397             String ext = filename.substring(lastDot + 1);
398             return filename.regionMatches(lastDot + 1 - TAR.length(), TAR, 0, TAR.length()) ? TAR + ext : ext;
399         }
400         return "";
401     }
402 
403     
404 
405 
406     private boolean isValidId(String id) {
407         if (id == null) {
408             return false;
409         }
410         for (int i = 0; i < id.length(); i++) {
411             char c = id.charAt(i);
412             if (!(c >= 'a' && c <= 'z'
413                     || c >= 'A' && c <= 'Z'
414                     || c >= '0' && c <= '9'
415                     || c == '-'
416                     || c == '_'
417                     || c == '.')) {
418                 return false;
419             }
420         }
421         return true;
422     }
423 
424     
425 
426 
427     private boolean isValidVersion(String version) {
428         if (version == null) {
429             return false;
430         }
431         for (int i = version.length() - 1; i >= 0; i--) {
432             if (ILLEGAL_VERSION_CHARS.indexOf(version.charAt(i)) >= 0) {
433                 return false;
434             }
435         }
436         return true;
437     }
438 }