View Javadoc

1   /*
2    * #%L
3    * Native ARchive plugin for Maven
4    * %%
5    * Copyright (C) 2002 - 2014 NAR Maven Plugin developers.
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   * 
11   * http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package com.github.maven_nar;
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.jar.JarFile;
27  
28  import org.apache.maven.artifact.Artifact;
29  import org.apache.maven.artifact.repository.ArtifactRepository;
30  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
31  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
32  import org.apache.maven.artifact.resolver.ArtifactResolver;
33  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
34  import org.apache.maven.plugin.MojoExecutionException;
35  import org.apache.maven.plugin.MojoFailureException;
36  import org.apache.maven.plugin.logging.Log;
37  import org.apache.maven.project.MavenProject;
38  import org.codehaus.plexus.archiver.manager.ArchiverManager;
39  
40  /**
41   * @author Mark Donszelmann (Mark.Donszelmann@gmail.com)
42   */
43  public class NarManager {
44  
45    private final Log log;
46  
47    private final MavenProject project;
48  
49    private final ArtifactRepository repository;
50  
51    private final AOL defaultAOL;
52  
53    private final String linkerName;
54  
55    private final String[] narTypes = {
56        NarConstants.NAR_NO_ARCH, Library.STATIC, Library.SHARED, Library.JNI, Library.PLUGIN
57    };
58  
59    public NarManager(final Log log, final ArtifactRepository repository, final MavenProject project,
60        final String architecture, final String os, final Linker linker)
61        throws MojoFailureException, MojoExecutionException {
62      this.log = log;
63      this.repository = repository;
64      this.project = project;
65      this.defaultAOL = NarUtil.getAOL(project, architecture, os, linker, null, log);
66      this.linkerName = NarUtil.getLinkerName(project, architecture, os, linker, log);
67    }
68  
69    public final void downloadAttachedNars(final List/* <NarArtifacts> */narArtifacts, final List remoteRepositories,
70        final ArtifactResolver resolver, final String classifier) throws MojoExecutionException, MojoFailureException {
71      // FIXME this may not be the right way to do this.... -U ignored and
72      // also SNAPSHOT not used
73      final List dependencies = getAttachedNarDependencies(narArtifacts, classifier);
74  
75      this.log.debug("Download called with classifier: " + classifier + " for NarDependencies {");
76      for (final Object dependency2 : dependencies) {
77        this.log.debug("  - " + dependency2);
78      }
79      this.log.debug("}");
80  
81      for (final Object dependency1 : dependencies) {
82        final Artifact dependency = (Artifact) dependency1;
83        try {
84          this.log.debug("Resolving " + dependency);
85          resolver.resolve(dependency, remoteRepositories, this.repository);
86        } catch (final ArtifactNotFoundException e) {
87          final String message = "nar not found " + dependency.getId();
88          throw new MojoExecutionException(message, e);
89        } catch (final ArtifactResolutionException e) {
90          final String message = "nar cannot resolve " + dependency.getId();
91          throw new MojoExecutionException(message, e);
92        }
93      }
94    }
95  
96    private List/* <AttachedNarArtifact> */getAttachedNarDependencies(final Artifact dependency, final AOL archOsLinker,
97        final String type) throws MojoExecutionException, MojoFailureException {
98      AOL aol = archOsLinker;
99      this.log.debug("GetNarDependencies for " + dependency + ", aol: " + aol + ", type: " + type);
100     final List artifactList = new ArrayList();
101     final NarInfo narInfo = getNarInfo(dependency);
102     final String[] nars = narInfo.getAttachedNars(aol, type);
103     // FIXME Move this to NarInfo....
104     if (nars != null) {
105       for (final String nar2 : nars) {
106         this.log.debug("    Checking: " + nar2);
107         if (nar2.equals("")) {
108           continue;
109         }
110         final String[] nar = nar2.split(":", 5);
111         if (nar.length >= 4) {
112           try {
113             final String groupId = nar[0].trim();
114             final String artifactId = nar[1].trim();
115             final String ext = nar[2].trim();
116             String classifier = nar[3].trim();
117             // translate for instance g++ to gcc...
118             aol = narInfo.getAOL(aol);
119             if (aol != null) {
120               classifier = NarUtil.replace("${aol}", aol.toString(), classifier);
121             }
122             final String version = nar.length >= 5 ? nar[4].trim() : dependency.getBaseVersion();
123             artifactList.add(new AttachedNarArtifact(groupId, artifactId, version, dependency.getScope(), ext,
124                 classifier, dependency.isOptional(), dependency.getFile()));
125           } catch (final InvalidVersionSpecificationException e) {
126             throw new MojoExecutionException("Error while reading nar file for dependency " + dependency, e);
127           }
128         } else {
129           this.log.warn("nars property in " + dependency.getArtifactId() + " contains invalid field: '" + nar2
130               + "' for type: " + type);
131         }
132       }
133     }
134     return artifactList;
135   }
136 
137   public final List/* <AttachedNarArtifact> */getAttachedNarDependencies(final List/*
138                                                                                     * <
139                                                                                     * NarArtifacts
140                                                                                     * >
141                                                                                     */narArtifacts)
142       throws MojoExecutionException, MojoFailureException {
143     return getAttachedNarDependencies(narArtifacts, (String) null);
144   }
145 
146   /**
147    * Returns a list of all attached nar dependencies for a specific binding and
148    * "noarch", but not where "local" is
149    * specified
150    * 
151    * @param scope
152    *          compile, test, runtime, ....
153    * @param aol
154    *          either a valid aol, noarch or null. In case of null both the
155    *          default getAOL() and noarch dependencies
156    *          are returned.
157    * @param type
158    *          noarch, static, shared, jni, or null. In case of null the default
159    *          binding found in narInfo is used.
160    * @return
161    * @throws MojoExecutionException
162    * @throws MojoFailureException
163    */
164   public final List/* <AttachedNarArtifact> */getAttachedNarDependencies(final List/*
165                                                                                     * <
166                                                                                     * NarArtifacts
167                                                                                     * >
168                                                                                     */narArtifacts,
169       final AOL archOsLinker, final String type) throws MojoExecutionException, MojoFailureException {
170     boolean noarch = false;
171     AOL aol = archOsLinker;
172     if (aol == null) {
173       noarch = true;
174       aol = this.defaultAOL;
175     }
176 
177     final List artifactList = new ArrayList();
178     for (final Object narArtifact : narArtifacts) {
179       final Artifact dependency = (Artifact) narArtifact;
180       final NarInfo narInfo = getNarInfo(dependency);
181       if (noarch) {
182         artifactList.addAll(getAttachedNarDependencies(dependency, null, NarConstants.NAR_NO_ARCH));
183       }
184 
185       // use preferred binding, unless non existing.
186       final String binding = narInfo.getBinding(aol, type != null ? type : Library.STATIC);
187 
188       // FIXME kludge, but does not work anymore since AOL is now a class
189       if (aol.equals(NarConstants.NAR_NO_ARCH)) {
190         // FIXME no handling of local
191         artifactList.addAll(getAttachedNarDependencies(dependency, null, NarConstants.NAR_NO_ARCH));
192       } else {
193         artifactList.addAll(getAttachedNarDependencies(dependency, aol, binding));
194       }
195     }
196     return artifactList;
197   }
198 
199   public final List/* <AttachedNarArtifact> */getAttachedNarDependencies(final List/*
200                                                                                     * <
201                                                                                     * NarArtifacts
202                                                                                     * >
203                                                                                     */narArtifacts,
204       final String classifier) throws MojoExecutionException, MojoFailureException {
205     AOL aol = null;
206     String type = null;
207     if (classifier != null) {
208       final int dash = classifier.lastIndexOf('-');
209       if (dash < 0) {
210         aol = new AOL(classifier);
211       } else {
212         aol = new AOL(classifier.substring(0, dash));
213         type = classifier.substring(dash + 1);
214       }
215     }
216     return getAttachedNarDependencies(narArtifacts, aol, type);
217   }
218 
219   public final List/* <AttachedNarArtifact> */getAttachedNarDependencies(final List/*
220                                                                                     * <
221                                                                                     * NarArtifacts
222                                                                                     * >
223                                                                                     */narArtifacts,
224       final String[] classifiers) throws MojoExecutionException, MojoFailureException {
225 
226     final List artifactList = new ArrayList();
227 
228     if (classifiers != null && classifiers.length > 0) {
229 
230       for (final String classifier : classifiers) {
231         artifactList.addAll(getAttachedNarDependencies(narArtifacts, classifier));
232       }
233     } else {
234       artifactList.addAll(getAttachedNarDependencies(narArtifacts, (String) null));
235     }
236 
237     return artifactList;
238   }
239 
240   public final File getNarFile(final Artifact dependency) throws MojoFailureException {
241     // FIXME reported to maven developer list, isSnapshot changes behaviour
242     // of getBaseVersion, called in pathOf.
243     dependency.isSnapshot();
244     return new File(this.repository.getBasedir(), NarUtil.replace("${aol}", this.defaultAOL.toString(),
245         this.repository.pathOf(dependency)));
246   }
247 
248   public final NarInfo getNarInfo(final Artifact dependency) throws MojoExecutionException {
249     // FIXME reported to maven developer list, isSnapshot changes behaviour
250     // of getBaseVersion, called in pathOf.
251     dependency.isSnapshot();
252 
253     final File file = new File(this.repository.getBasedir(), this.repository.pathOf(dependency));
254     if (!file.exists()) {
255       return null;
256     }
257 
258     JarFile jar = null;
259     try {
260       jar = new JarFile(file);
261       final NarInfo info = new NarInfo(dependency.getGroupId(), dependency.getArtifactId(),
262           dependency.getBaseVersion(), this.log);
263       if (!info.exists(jar)) {
264         return null;
265       }
266       info.read(jar);
267       return info;
268     } catch (final IOException e) {
269       throw new MojoExecutionException("Error while reading " + file, e);
270     } finally {
271       if (jar != null) {
272         try {
273           jar.close();
274         } catch (final IOException e) {
275           // ignore
276         }
277       }
278     }
279   }
280 
281   public final void unpackAttachedNars(final List/* <NarArtifacts> */narArtifacts,
282       final ArchiverManager archiverManager, final String classifier, final String os, final NarLayout layout,
283       final File unpackDir) throws MojoExecutionException, MojoFailureException {
284     this.log.debug("Unpack called for OS: " + os + ", classifier: " + classifier + " for NarArtifacts {");
285     for (final Object narArtifact : narArtifacts) {
286       this.log.debug("  - " + narArtifact);
287     }
288     this.log.debug("}");
289     // FIXME, kludge to get to download the -noarch, based on classifier
290     final List dependencies = getAttachedNarDependencies(narArtifacts, classifier);
291     for (final Object dependency1 : dependencies) {
292       final Artifact dependency = (Artifact) dependency1;
293       this.log.debug("Unpack " + dependency + " to " + unpackDir);
294       final File file = getNarFile(dependency);
295 
296       layout.unpackNar(unpackDir, archiverManager, file, os, this.linkerName, this.defaultAOL);
297     }
298   }
299 }