package org.apache.maven.plugin.nar; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; 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 Log log; private MavenProject project; private ArtifactRepository repository; private AOL defaultAOL; private String linkerName; private String[] narTypes = { NarConstants.NAR_NO_ARCH, Library.STATIC, Library.SHARED, Library.JNI, Library.PLUGIN }; public NarManager( Log log, ArtifactRepository repository, MavenProject project, String architecture, String os, Linker linker ) throws MojoFailureException, MojoExecutionException { this.log = log; this.repository = repository; this.project = project; this.defaultAOL = NarUtil.getAOL( architecture, os, linker, null ); this.linkerName = NarUtil.getLinkerName( architecture, os, linker ); } /** * Returns dependencies which are dependent on NAR files (i.e. contain NarInfo) */ public final List/* */getNarDependencies( String scope ) throws MojoExecutionException { List narDependencies = new LinkedList(); for ( Iterator i = getDependencies( scope ).iterator(); i.hasNext(); ) { Artifact dependency = (Artifact) i.next(); log.debug( "Examining artifact for NarInfo: " + dependency ); NarInfo narInfo = getNarInfo( dependency ); if ( narInfo != null ) { log.debug( " - added as NarDependency" ); narDependencies.add( new NarArtifact( dependency, narInfo ) ); } } return narDependencies; } /** * Returns all NAR dependencies by type: noarch, static, dynamic, jni, plugin. * * @throws MojoFailureException */ public final Map/* > */getAttachedNarDependencyMap( String scope ) throws MojoExecutionException, MojoFailureException { Map attachedNarDependencies = new HashMap(); for ( Iterator i = getNarDependencies( scope ).iterator(); i.hasNext(); ) { Artifact dependency = (Artifact) i.next(); for ( int j = 0; j < narTypes.length; j++ ) { List artifactList = getAttachedNarDependencies( dependency, defaultAOL, narTypes[j] ); if ( artifactList != null ) { attachedNarDependencies.put( narTypes[j], artifactList ); } } } return attachedNarDependencies; } public final List/* */getAttachedNarDependencies( List/* */narArtifacts ) throws MojoExecutionException, MojoFailureException { return getAttachedNarDependencies( narArtifacts, ( String )null ); } public final List/* */getAttachedNarDependencies( List/* */narArtifacts, String classifier ) throws MojoExecutionException, MojoFailureException { AOL aol = null; String type = null; if ( classifier != null ) { int dash = classifier.lastIndexOf( '-' ); if ( dash < 0 ) { aol = new AOL( classifier ); type = null; } else { aol = new AOL( classifier.substring( 0, dash ) ); type = classifier.substring( dash + 1 ); } } return getAttachedNarDependencies( narArtifacts, aol, type ); } public final List/* */getAttachedNarDependencies( List/* */narArtifacts, List classifiers) throws MojoExecutionException, MojoFailureException { String[] types; List artifactList = new ArrayList(); if( classifiers != null && !classifiers.isEmpty() ) { types = (String[]) classifiers.toArray(); for ( int j = 0; j < types.length; j++ ) { if ( artifactList != null ) { artifactList.addAll( getAttachedNarDependencies( narArtifacts, types[j] )); } } } else { artifactList.addAll( getAttachedNarDependencies( narArtifacts, ( String )null )); } return artifactList; } /** * 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/* */getAttachedNarDependencies( List/* */narArtifacts, AOL archOsLinker, String type ) throws MojoExecutionException, MojoFailureException { boolean noarch = false; AOL aol = archOsLinker; if ( aol == null ) { noarch = true; aol = defaultAOL; } List artifactList = new ArrayList(); for ( Iterator i = narArtifacts.iterator(); i.hasNext(); ) { Artifact dependency = (Artifact) i.next(); NarInfo narInfo = getNarInfo( dependency ); if ( noarch ) { artifactList.addAll( getAttachedNarDependencies( dependency, null, NarConstants.NAR_NO_ARCH ) ); } // use preferred binding, unless non existing. 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; } private List/* */getAttachedNarDependencies( Artifact dependency, AOL archOsLinker, String type ) throws MojoExecutionException, MojoFailureException { AOL aol = archOsLinker; log.debug( "GetNarDependencies for " + dependency + ", aol: " + aol + ", type: " + type ); List artifactList = new ArrayList(); NarInfo narInfo = getNarInfo( dependency ); String[] nars = narInfo.getAttachedNars( aol, type ); // FIXME Move this to NarInfo.... if ( nars != null ) { for ( int j = 0; j < nars.length; j++ ) { log.debug( " Checking: " + nars[j] ); if ( nars[j].equals( "" ) ) { continue; } String[] nar = nars[j].split( ":", 5 ); if ( nar.length >= 4 ) { try { String groupId = nar[0].trim(); String artifactId = nar[1].trim(); 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 ); } String version = nar.length >= 5 ? nar[4].trim() : dependency.getVersion(); artifactList.add( new AttachedNarArtifact( groupId, artifactId, version, dependency.getScope(), ext, classifier, dependency.isOptional(), dependency.getFile() )); } catch ( InvalidVersionSpecificationException e ) { throw new MojoExecutionException( "Error while reading nar file for dependency " + dependency, e ); } } else { log.warn( "nars property in " + dependency.getArtifactId() + " contains invalid field: '" + nars[j] + "' for type: " + type ); } } } return artifactList; } public final NarInfo getNarInfo( Artifact dependency ) throws MojoExecutionException { // FIXME reported to maven developer list, isSnapshot changes behaviour // of getBaseVersion, called in pathOf. dependency.isSnapshot(); File file = new File( repository.getBasedir(), repository.pathOf( dependency ) ); if ( !file.exists() ) { return null; } JarFile jar = null; try { jar = new JarFile( file ); NarInfo info = new NarInfo( dependency.getGroupId(), dependency.getArtifactId(), dependency.getBaseVersion(), log ); if ( !info.exists( jar ) ) { return null; } info.read( jar ); return info; } catch ( IOException e ) { throw new MojoExecutionException( "Error while reading " + file, e ); } finally { if ( jar != null ) { try { jar.close(); } catch ( IOException e ) { // ignore } } } } public final File getNarFile( Artifact dependency ) throws MojoFailureException { // FIXME reported to maven developer list, isSnapshot changes behaviour // of getBaseVersion, called in pathOf. dependency.isSnapshot(); return new File( repository.getBasedir(), NarUtil.replace( "${aol}", defaultAOL.toString(), repository.pathOf( dependency ) ) ); } private List getDependencies( String scope ) { if ( scope.equals( Artifact.SCOPE_TEST ) ) { return project.getTestArtifacts(); } else if ( scope.equals( Artifact.SCOPE_RUNTIME ) ) { return project.getRuntimeArtifacts(); } return project.getCompileArtifacts(); } public final void downloadAttachedNars( List/* */narArtifacts, List remoteRepositories, ArtifactResolver resolver, String classifier ) throws MojoExecutionException, MojoFailureException { // FIXME this may not be the right way to do this.... -U ignored and // also SNAPSHOT not used List dependencies = getAttachedNarDependencies( narArtifacts, classifier ); log.debug( "Download called with classifier: " + classifier + " for NarDependencies {" ); for ( Iterator i = dependencies.iterator(); i.hasNext(); ) { log.debug( " - " + ( i.next() ) ); } log.debug( "}" ); for ( Iterator i = dependencies.iterator(); i.hasNext(); ) { Artifact dependency = (Artifact) i.next(); try { log.debug( "Resolving " + dependency ); resolver.resolve( dependency, remoteRepositories, repository ); } catch ( ArtifactNotFoundException e ) { String message = "nar not found " + dependency.getId(); throw new MojoExecutionException( message, e ); } catch ( ArtifactResolutionException e ) { String message = "nar cannot resolve " + dependency.getId(); throw new MojoExecutionException( message, e ); } } } public final void unpackAttachedNars( List/* */narArtifacts, ArchiverManager archiverManager, String classifier, String os, NarLayout layout, File unpackDir ) throws MojoExecutionException, MojoFailureException { log.debug( "Unpack called for OS: " + os + ", classifier: " + classifier + " for NarArtifacts {" ); for ( Iterator i = narArtifacts.iterator(); i.hasNext(); ) { log.debug( " - " + ( i.next() ) ); } log.debug( "}" ); // FIXME, kludge to get to download the -noarch, based on classifier List dependencies = getAttachedNarDependencies( narArtifacts, classifier ); for ( Iterator i = dependencies.iterator(); i.hasNext(); ) { Artifact dependency = (Artifact) i.next(); log.debug( "Unpack " + dependency ); File file = getNarFile( dependency ); layout.unpackNar(unpackDir, archiverManager, file, os, linkerName, defaultAOL); } } }