Add .tox/ to .gitignore
[odlparent.git] / karaf / karaf-maven-plugin / src / main / java / org / apache / karaf / tooling / utils / MojoSupport.java
1 /**
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one or more
4  * contributor license agreements.  See the NOTICE file distributed with
5  * this work for additional information regarding copyright ownership.
6  * The ASF licenses this file to You under the Apache License, Version 2.0
7  * (the "License"); you may not use this file except in compliance with
8  * 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, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 package org.apache.karaf.tooling.utils;
19
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.net.MalformedURLException;
25 import java.net.URL;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31
32 import org.apache.karaf.util.StreamUtils;
33 import org.apache.maven.artifact.Artifact;
34 import org.apache.maven.artifact.factory.ArtifactFactory;
35 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
36 import org.apache.maven.artifact.repository.ArtifactRepository;
37 import org.apache.maven.artifact.repository.DefaultArtifactRepository;
38 import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
39 import org.apache.maven.artifact.resolver.ArtifactResolver;
40 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
41 import org.apache.maven.artifact.versioning.VersionRange;
42 import org.apache.maven.execution.MavenSession;
43 import org.apache.maven.model.Dependency;
44 import org.apache.maven.model.DependencyManagement;
45 import org.apache.maven.plugin.AbstractMojo;
46 import org.apache.maven.plugin.MojoExecutionException;
47 import org.apache.maven.plugins.annotations.Component;
48 import org.apache.maven.plugins.annotations.Parameter;
49 import org.apache.maven.project.MavenProject;
50 import org.apache.maven.project.MavenProjectBuilder;
51 import org.apache.maven.project.MavenProjectHelper;
52 import org.apache.maven.project.ProjectBuildingException;
53 import org.apache.maven.settings.Proxy;
54 import org.codehaus.plexus.PlexusContainer;
55
56 @SuppressWarnings({"deprecation", "rawtypes", "unchecked"})
57 public abstract class MojoSupport extends AbstractMojo {
58
59     /**
60      * Maven ProjectHelper
61      */
62     @Component
63     protected MavenProjectHelper projectHelper;
64
65     /**
66      * The Maven project.
67      */
68     @Parameter(defaultValue = "${project}", readonly = true)
69     protected MavenProject project;
70
71     /**
72      * Directory that resources are copied to during the build.
73      */
74     @Parameter(defaultValue = "${project.build.directory}/${project.artifactId}-${project.version}-installer")
75     protected File workDirectory;
76
77     @Component
78     protected MavenProjectBuilder projectBuilder;
79
80     @Parameter(defaultValue = "${localRepository}")
81     protected ArtifactRepository localRepo;
82
83     @Parameter(defaultValue = "${project.remoteArtifactRepositories}")
84     protected List<ArtifactRepository> remoteRepos;
85
86     @Component
87     protected ArtifactMetadataSource artifactMetadataSource;
88
89     @Component
90     protected ArtifactResolver artifactResolver;
91
92     @Component
93     protected ArtifactFactory factory;
94     
95     /**
96      * The artifact type of a feature.
97      */
98     @Parameter(defaultValue = "xml")
99     private String featureArtifactType = "xml";
100     
101     /**
102      * The Maven session.
103      */
104     @Parameter(defaultValue = "${session}", readonly = true)
105     protected MavenSession mavenSession;
106
107     /**
108      * <p>We can't autowire strongly typed RepositorySystem from Aether because it may be Sonatype (Maven 3.0.x)
109      * or Eclipse (Maven 3.1.x/3.2.x) version, so we switch to service locator by autowiring entire {@link PlexusContainer}</p>
110      *
111      * <p>It's a bit of a hack but we have not choice when we want to be usable both in Maven 3.0.x and 3.1.x/3.2.x</p>
112      */
113     @Component
114     protected PlexusContainer container;
115
116     protected MavenProject getProject() {
117         return project;
118     }
119
120     protected File getWorkDirectory() {
121         return workDirectory;
122     }
123
124     public MavenProjectHelper getProjectHelper() {
125         return projectHelper;
126     }
127
128     // called by Plexus when injecting the mojo's session
129     public void setMavenSession(MavenSession mavenSession) {
130         this.mavenSession = mavenSession;
131
132         if (mavenSession != null) {
133             // check for custom settings.xml and pass it onto pax-url-aether
134             File settingsFile = mavenSession.getRequest().getUserSettingsFile();
135             if (settingsFile != null && settingsFile.isFile()) {
136                 System.setProperty("org.ops4j.pax.url.mvn.settings", settingsFile.getPath());
137             }
138         }
139     }
140
141     protected Map createManagedVersionMap(String projectId,
142             DependencyManagement dependencyManagement) throws ProjectBuildingException {
143         Map map;
144         if (dependencyManagement != null
145                 && dependencyManagement.getDependencies() != null) {
146             map = new HashMap();
147             for (Iterator i = dependencyManagement.getDependencies().iterator(); i
148                     .hasNext();) {
149                 Dependency d = (Dependency) i.next();
150
151                 try {
152                     VersionRange versionRange = VersionRange
153                             .createFromVersionSpec(d.getVersion());
154                     Artifact artifact = factory.createDependencyArtifact(d
155                             .getGroupId(), d.getArtifactId(), versionRange, d
156                             .getType(), d.getClassifier(), d.getScope());
157                     map.put(d.getManagementKey(), artifact);
158                 } catch (InvalidVersionSpecificationException e) {
159                     throw new ProjectBuildingException(projectId,
160                             "Unable to parse version '" + d.getVersion()
161                                     + "' for dependency '"
162                                     + d.getManagementKey() + "': "
163                                     + e.getMessage(), e);
164                 }
165             }
166         } else {
167             map = Collections.EMPTY_MAP;
168         }
169         return map;
170     }
171     
172     protected String translateFromMaven(String uri) {
173         if (uri.startsWith("mvn:")) {
174             String[] parts = uri.substring("mvn:".length()).split("/");
175             String groupId = parts[0];
176             String artifactId = parts[1];
177             String version = null;
178             String classifier = null;
179             String type = "jar";
180             if (parts.length > 2) {
181                 version = parts[2];
182                 if (parts.length > 3) {
183                     type = parts[3];
184                     if (parts.length > 4) {
185                         classifier = parts[4];
186                     }
187                 }
188             }
189             String dir = groupId.replace('.', '/') + "/" + artifactId + "/" + version + "/";
190             String name = artifactId + "-" + version + (classifier != null ? "-" + classifier : "") + "." + type;
191
192             return getLocalRepoUrl() + "/" + dir + name;
193         }
194         if (System.getProperty("os.name").startsWith("Windows") && uri.startsWith("file:")) {
195                 String baseDir = uri.substring(5).replace('\\', '/').replaceAll(" ", "%20");
196                 String result = baseDir;
197                 if (baseDir.indexOf(":") > 0) {
198                         result = "file:///" + baseDir;
199                 }
200                 return result;
201         }
202         return uri;
203     }
204
205     protected String getLocalRepoUrl() {
206          if (System.getProperty("os.name").startsWith("Windows")) {
207              String baseDir = localRepo.getBasedir().replace('\\', '/').replaceAll(" ", "%20");
208              return extractProtocolFromLocalMavenRepo()  + ":///" + baseDir;
209          } else {
210              return localRepo.getUrl();
211          }
212     }
213
214     /**
215      * Required because Maven 3 returns null in {@link ArtifactRepository#getProtocol()} (see KARAF-244)
216      */
217     private String extractProtocolFromLocalMavenRepo() {
218         try {
219             return new URL(localRepo.getUrl()).getProtocol();
220         } catch (MalformedURLException e) {
221             // Basically this should not happen; if it does though cancel the process
222             throw new RuntimeException("Repository URL is not valid", e);
223         }
224     }
225     
226     private Dependency findDependency(List<Dependency> dependencies, String artifactId, String groupId) {
227         for(Dependency dep : dependencies) {
228             if (artifactId.equals(dep.getArtifactId()) && groupId.equals(dep.getGroupId()) &&
229                     featureArtifactType.equals(dep.getType())) {
230                 if (dep.getVersion() != null) 
231                     return dep;
232             }
233         }
234         return null;
235     }
236
237     /**
238      * Convert a feature resourceLocation (bundle or configuration file) into an artifact.
239      *
240      * @param resourceLocation the feature resource location (bundle or configuration file).
241      * @param skipNonMavenProtocols flag to skip protocol different than mvn:
242      * @return the artifact corresponding to the resource.
243      * @throws MojoExecutionException
244      */
245     protected Artifact resourceToArtifact(String resourceLocation, boolean skipNonMavenProtocols) throws MojoExecutionException {
246         resourceLocation = resourceLocation.replace("\r\n", "").replace("\n", "").replace(" ", "").replace("\t", "");
247         final int index = resourceLocation.indexOf("mvn:");
248         if (index < 0) {
249             if (skipNonMavenProtocols) {
250                 return null;
251             }
252             throw new MojoExecutionException("Resource URL is not a Maven URL: " + resourceLocation);
253         } else {
254             resourceLocation = resourceLocation.substring(index + "mvn:".length());
255         }
256         // Truncate the URL when a '#', a '?' or a '$' is encountered
257         final int index1 = resourceLocation.indexOf('?');
258         final int index2 = resourceLocation.indexOf('#');
259         int endIndex = -1;
260         if (index1 > 0) {
261             if (index2 > 0) {
262                 endIndex = Math.min(index1, index2);
263             } else {
264                 endIndex = index1;
265             }
266         } else if (index2 > 0) {
267             endIndex = index2;
268         }
269         if (endIndex >= 0) {
270             resourceLocation = resourceLocation.substring(0, endIndex);
271         }
272         final int index3 = resourceLocation.indexOf('$');
273         if (index3 > 0) {
274             resourceLocation = resourceLocation.substring(0, index3);
275         }
276
277         //check if the resourceLocation descriptor contains also remote repository information.
278         ArtifactRepository repo = null;
279         if (resourceLocation.startsWith("http://")) {
280             final int repoDelimIntex = resourceLocation.indexOf('!');
281             String repoUrl = resourceLocation.substring(0, repoDelimIntex);
282
283             repo = new DefaultArtifactRepository(
284                     repoUrl,
285                     repoUrl,
286                     new DefaultRepositoryLayout());
287             org.apache.maven.repository.Proxy mavenProxy = configureProxyToInlineRepo();
288             if (mavenProxy != null) {
289                 repo.setProxy(mavenProxy);
290             }
291             resourceLocation = resourceLocation.substring(repoDelimIntex + 1);
292
293         }
294         String[] parts = resourceLocation.split("/");
295         String groupId = parts[0];
296         String artifactId = parts[1];
297         String version = null;
298         String classifier = null;
299         String type = "jar";
300         if (parts.length > 2) {
301             version = parts[2];
302             if (parts.length > 3) {
303                 type = parts[3];
304                 if (parts.length > 4) {
305                     classifier = parts[4];
306                 }
307             }
308         } else {
309             Dependency dep = findDependency(project.getDependencies(), artifactId, groupId);
310             if (dep == null && project.getDependencyManagement() != null) {
311                 dep = findDependency(project.getDependencyManagement().getDependencies(), artifactId, groupId);
312             }
313             if (dep != null) {
314                 version = dep.getVersion();
315                 classifier = dep.getClassifier();
316                 type = dep.getType();
317             }
318         }
319         if (version == null || version.isEmpty()) {
320             throw new MojoExecutionException("Cannot find version for: " + resourceLocation);
321         }
322         Artifact artifact = factory.createArtifactWithClassifier(groupId, artifactId, version, type, classifier);
323         artifact.setRepository(repo);
324         return artifact;
325     }
326     
327     private org.apache.maven.repository.Proxy configureProxyToInlineRepo() {
328         if (mavenSession != null && mavenSession.getSettings() != null) {
329             Proxy proxy = mavenSession.getSettings().getActiveProxy();
330             org.apache.maven.repository.Proxy mavenProxy = new org.apache.maven.repository.Proxy();
331             if (proxy != null) {
332                 mavenProxy.setProtocol(proxy.getProtocol());
333                 mavenProxy.setHost(proxy.getHost());
334                 mavenProxy.setPort(proxy.getPort());
335                 mavenProxy.setNonProxyHosts(proxy.getNonProxyHosts());
336                 mavenProxy.setUserName(proxy.getUsername());
337                 mavenProxy.setPassword(proxy.getPassword());
338                 return mavenProxy;
339             } else {
340                 return null;
341             }
342             
343         } else {
344             return null;
345         }
346     }
347
348     protected void copy(File sourceFile, File destFile) {
349         File targetDir = destFile.getParentFile();
350         ensureDirExists(targetDir);
351
352         try {
353             try (
354                 FileInputStream is = new FileInputStream(sourceFile);
355                 FileOutputStream bos = new FileOutputStream(destFile)
356             ) {
357                 StreamUtils.copy(is, bos);
358             }
359         } catch (IOException e) {
360             throw new RuntimeException(e.getMessage(), e);
361         }
362     }
363     
364
365     /**
366      * Make sure the target directory exists and
367      * that is actually a directory
368      * @param targetDir
369      * @throws IOException
370      */
371     private static void ensureDirExists(File targetDir) {
372         if (!targetDir.exists()) {
373             if (!targetDir.mkdirs()) {
374                 throw new RuntimeException("Unable to create target directory: " + targetDir);
375             }
376         } else if (!targetDir.isDirectory()) {
377             throw new RuntimeException("Target is not a directory: " + targetDir);
378         }
379     }
380 }