/* * #%L * Native ARchive plugin for Maven * %% * Copyright (C) 2002 - 2014 NAR Maven Plugin developers. * %% * Licensed 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. * #L% */ package com.github.maven_nar; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.jar.JarFile; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.resolver.ArtifactNotFoundException; import org.apache.maven.artifact.resolver.ArtifactResolutionException; import org.apache.maven.artifact.resolver.ArtifactResolver; import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.logging.Log; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.archiver.manager.ArchiverManager; /** * @author Mark Donszelmann (Mark.Donszelmann@gmail.com) */ public class NarManager { private final Log log; private final MavenProject project; private final ArtifactRepository repository; private final AOL defaultAOL; private final String linkerName; private final String[] narTypes = { NarConstants.NAR_NO_ARCH, Library.STATIC, Library.SHARED, Library.JNI, Library.PLUGIN }; public NarManager(final Log log, final ArtifactRepository repository, final MavenProject project, final String architecture, final String os, final Linker linker) throws MojoFailureException, MojoExecutionException { this.log = log; this.repository = repository; this.project = project; this.defaultAOL = NarUtil.getAOL(project, architecture, os, linker, null, log); this.linkerName = NarUtil.getLinkerName(project, architecture, os, linker, log); } public final void downloadAttachedNars(final List/* <NarArtifacts> */narArtifacts, final List remoteRepositories, final ArtifactResolver resolver, final String classifier) throws MojoExecutionException, MojoFailureException { // FIXME this may not be the right way to do this.... -U ignored and // also SNAPSHOT not used final List dependencies = getAttachedNarDependencies(narArtifacts, classifier); this.log.debug("Download called with classifier: " + classifier + " for NarDependencies {"); for (final Object dependency2 : dependencies) { this.log.debug(" - " + dependency2); } this.log.debug("}"); for (final Object dependency1 : dependencies) { final Artifact dependency = (Artifact) dependency1; try { this.log.debug("Resolving " + dependency); resolver.resolve(dependency, remoteRepositories, this.repository); } catch (final ArtifactNotFoundException e) { final String message = "nar not found " + dependency.getId(); throw new MojoExecutionException(message, e); } catch (final ArtifactResolutionException e) { final String message = "nar cannot resolve " + dependency.getId(); throw new MojoExecutionException(message, e); } } } private List/* <AttachedNarArtifact> */getAttachedNarDependencies(final Artifact dependency, final AOL archOsLinker, final String type) throws MojoExecutionException, MojoFailureException { AOL aol = archOsLinker; this.log.debug("GetNarDependencies for " + dependency + ", aol: " + aol + ", type: " + type); final List artifactList = new ArrayList(); final NarInfo narInfo = getNarInfo(dependency); final String[] nars = narInfo.getAttachedNars(aol, type); // FIXME Move this to NarInfo.... if (nars != null) { for (final String nar2 : nars) { this.log.debug(" Checking: " + nar2); if (nar2.equals("")) { continue; } final String[] nar = nar2.split(":", 5); if (nar.length >= 4) { try { final String groupId = nar[0].trim(); final String artifactId = nar[1].trim(); final String ext = nar[2].trim(); String classifier = nar[3].trim(); // translate for instance g++ to gcc... aol = narInfo.getAOL(aol); if (aol != null) { classifier = NarUtil.replace("${aol}", aol.toString(), classifier); } final String version = nar.length >= 5 ? nar[4].trim() : dependency.getBaseVersion(); artifactList.add(new AttachedNarArtifact(groupId, artifactId, version, dependency.getScope(), ext, classifier, dependency.isOptional(), dependency.getFile())); } catch (final InvalidVersionSpecificationException e) { throw new MojoExecutionException("Error while reading nar file for dependency " + dependency, e); } } else { this.log.warn("nars property in " + dependency.getArtifactId() + " contains invalid field: '" + nar2 + "' for type: " + type); } } } return artifactList; } public final List/* <AttachedNarArtifact> */getAttachedNarDependencies(final List/* * < * NarArtifacts * > */narArtifacts) throws MojoExecutionException, MojoFailureException { return getAttachedNarDependencies(narArtifacts, (String) null); } /** * Returns a list of all attached nar dependencies for a specific binding and * "noarch", but not where "local" is * specified * * @param scope * compile, test, runtime, .... * @param aol * either a valid aol, noarch or null. In case of null both the * default getAOL() and noarch dependencies * are returned. * @param type * noarch, static, shared, jni, or null. In case of null the default * binding found in narInfo is used. * @return * @throws MojoExecutionException * @throws MojoFailureException */ public final List/* <AttachedNarArtifact> */getAttachedNarDependencies(final List/* * < * NarArtifacts * > */narArtifacts, final AOL archOsLinker, final String type) throws MojoExecutionException, MojoFailureException { boolean noarch = false; AOL aol = archOsLinker; if (aol == null) { noarch = true; aol = this.defaultAOL; } final List artifactList = new ArrayList(); for (final Object narArtifact : narArtifacts) { final Artifact dependency = (Artifact) narArtifact; final NarInfo narInfo = getNarInfo(dependency); if (noarch) { artifactList.addAll(getAttachedNarDependencies(dependency, null, NarConstants.NAR_NO_ARCH)); } // use preferred binding, unless non existing. final String binding = narInfo.getBinding(aol, type != null ? type : Library.STATIC); // FIXME kludge, but does not work anymore since AOL is now a class if (aol.equals(NarConstants.NAR_NO_ARCH)) { // FIXME no handling of local artifactList.addAll(getAttachedNarDependencies(dependency, null, NarConstants.NAR_NO_ARCH)); } else { artifactList.addAll(getAttachedNarDependencies(dependency, aol, binding)); } } return artifactList; } public final List/* <AttachedNarArtifact> */getAttachedNarDependencies(final List/* * < * NarArtifacts * > */narArtifacts, final String classifier) throws MojoExecutionException, MojoFailureException { AOL aol = null; String type = null; if (classifier != null) { final int dash = classifier.lastIndexOf('-'); if (dash < 0) { aol = new AOL(classifier); } else { aol = new AOL(classifier.substring(0, dash)); type = classifier.substring(dash + 1); } } return getAttachedNarDependencies(narArtifacts, aol, type); } public final List/* <AttachedNarArtifact> */getAttachedNarDependencies(final List/* * < * NarArtifacts * > */narArtifacts, final String[] classifiers) throws MojoExecutionException, MojoFailureException { final List artifactList = new ArrayList(); if (classifiers != null && classifiers.length > 0) { for (final String classifier : classifiers) { artifactList.addAll(getAttachedNarDependencies(narArtifacts, classifier)); } } else { artifactList.addAll(getAttachedNarDependencies(narArtifacts, (String) null)); } return artifactList; } public final File getNarFile(final Artifact dependency) throws MojoFailureException { // FIXME reported to maven developer list, isSnapshot changes behaviour // of getBaseVersion, called in pathOf. dependency.isSnapshot(); return new File(this.repository.getBasedir(), NarUtil.replace("${aol}", this.defaultAOL.toString(), this.repository.pathOf(dependency))); } public final NarInfo getNarInfo(final Artifact dependency) throws MojoExecutionException { // FIXME reported to maven developer list, isSnapshot changes behaviour // of getBaseVersion, called in pathOf. dependency.isSnapshot(); final File file = new File(this.repository.getBasedir(), this.repository.pathOf(dependency)); if (!file.exists()) { return null; } JarFile jar = null; try { jar = new JarFile(file); final NarInfo info = new NarInfo(dependency.getGroupId(), dependency.getArtifactId(), dependency.getBaseVersion(), this.log); if (!info.exists(jar)) { return null; } info.read(jar); return info; } catch (final IOException e) { throw new MojoExecutionException("Error while reading " + file, e); } finally { if (jar != null) { try { jar.close(); } catch (final IOException e) { // ignore } } } } public final void unpackAttachedNars(final List/* <NarArtifacts> */narArtifacts, final ArchiverManager archiverManager, final String classifier, final String os, final NarLayout layout, final File unpackDir) throws MojoExecutionException, MojoFailureException { this.log.debug("Unpack called for OS: " + os + ", classifier: " + classifier + " for NarArtifacts {"); for (final Object narArtifact : narArtifacts) { this.log.debug(" - " + narArtifact); } this.log.debug("}"); // FIXME, kludge to get to download the -noarch, based on classifier final List dependencies = getAttachedNarDependencies(narArtifacts, classifier); for (final Object dependency1 : dependencies) { final Artifact dependency = (Artifact) dependency1; this.log.debug("Unpack " + dependency + " to " + unpackDir); final File file = getNarFile(dependency); layout.unpackNar(unpackDir, archiverManager, file, os, this.linkerName, this.defaultAOL); } } }