blob: ef77035b69a01a99347af5c5177f823f6f351d03 [file] [log] [blame]
/**
* 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.
*/
package org.apache.maven.mercury.repository.local.m2;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.maven.mercury.artifact.Artifact;
import org.apache.maven.mercury.artifact.ArtifactBasicMetadata;
import org.apache.maven.mercury.artifact.DefaultArtifact;
import org.apache.maven.mercury.artifact.Quality;
import org.apache.maven.mercury.artifact.version.DefaultArtifactVersion;
import org.apache.maven.mercury.artifact.version.VersionComparator;
import org.apache.maven.mercury.artifact.version.VersionException;
import org.apache.maven.mercury.artifact.version.VersionRange;
import org.apache.maven.mercury.artifact.version.VersionRangeFactory;
import org.apache.maven.mercury.builder.api.DependencyProcessor;
import org.apache.maven.mercury.builder.api.MetadataReader;
import org.apache.maven.mercury.builder.api.MetadataReaderException;
import org.apache.maven.mercury.crypto.api.StreamObserverException;
import org.apache.maven.mercury.crypto.api.StreamVerifier;
import org.apache.maven.mercury.crypto.api.StreamVerifierException;
import org.apache.maven.mercury.crypto.api.StreamVerifierFactory;
import org.apache.maven.mercury.logging.IMercuryLogger;
import org.apache.maven.mercury.logging.MercuryLoggerManager;
import org.apache.maven.mercury.repository.api.AbstracRepositoryReader;
import org.apache.maven.mercury.repository.api.AbstractRepOpResult;
import org.apache.maven.mercury.repository.api.AbstractRepository;
import org.apache.maven.mercury.repository.api.ArtifactBasicResults;
import org.apache.maven.mercury.repository.api.ArtifactResults;
import org.apache.maven.mercury.repository.api.LocalRepository;
import org.apache.maven.mercury.repository.api.Repository;
import org.apache.maven.mercury.repository.api.RepositoryException;
import org.apache.maven.mercury.repository.api.RepositoryReader;
import org.apache.maven.mercury.util.FileUtil;
import org.apache.maven.mercury.util.Util;
import org.codehaus.plexus.lang.DefaultLanguage;
import org.codehaus.plexus.lang.Language;
public class LocalRepositoryReaderM2
extends AbstracRepositoryReader
implements RepositoryReader, MetadataReader
{
private static final IMercuryLogger LOG = MercuryLoggerManager.getLogger( LocalRepositoryReaderM2.class );
private static final Language LANG = new DefaultLanguage( LocalRepositoryReaderM2.class );
// ---------------------------------------------------------------------------------------------------------------
private static final String[] _protocols = new String[] { "file" };
LocalRepository _repo;
File _repoDir;
// ---------------------------------------------------------------------------------------------------------------
public LocalRepositoryReaderM2( LocalRepository repo, DependencyProcessor mdProcessor )
{
if ( repo == null )
throw new IllegalArgumentException( "localRepo cannot be null" );
_repoDir = repo.getDirectory();
if ( _repoDir == null )
throw new IllegalArgumentException( "localRepo directory cannot be null" );
if ( !_repoDir.exists() )
throw new IllegalArgumentException( "localRepo directory \"" + _repoDir.getAbsolutePath()
+ "\" should exist" );
_repo = repo;
if ( mdProcessor == null )
throw new IllegalArgumentException( "MetadataProcessor cannot be null " );
setDependencyProcessor( mdProcessor );
}
// ---------------------------------------------------------------------------------------------------------------
public Repository getRepository()
{
return _repo;
}
// ---------------------------------------------------------------------------------------------------------------
private static ArtifactLocation calculateLocation( String root, ArtifactBasicMetadata bmd, AbstractRepOpResult res )
{
ArtifactLocation loc = new ArtifactLocation( root, bmd );
File gaDir = new File( root, loc.getGaPath() );
if ( !gaDir.exists() )
{
if ( LOG.isWarnEnabled() )
LOG.warn( LANG.getMessage( "ga.not.found", bmd.toString(), loc.getGaPath() ) );
return null;
}
Quality vq = new Quality( loc.getVersion() );
// RELEASE = LATEST - SNAPSHOTs
if ( Artifact.RELEASE_VERSION.equals( loc.getVersion() ) || Artifact.LATEST_VERSION.equals( loc.getVersion() ) )
{
final boolean noSnapshots = Artifact.RELEASE_VERSION.equals( loc.getVersion() );
loc.setVersion( null );
final TreeSet<String> ts = new TreeSet<String>( new VersionComparator() );
gaDir.listFiles(
new FilenameFilter()
{
public boolean accept( File dir, String name )
{
if( new File(dir,name).isDirectory() )
{
if( noSnapshots && name.endsWith( Artifact.SNAPSHOT_VERSION ) )
return false;
ts.add( name );
return true;
}
return false;
}
}
);
if( !ts.isEmpty() )
loc.setVersion( ts.last() );
else
{
if( LOG.isErrorEnabled() )
LOG.error( LANG.getMessage( "gav.not.found", bmd.toString(), loc.getGaPath() ) );
return null;
}
// LATEST is a SNAPSHOT :(
if ( loc.getVersion().endsWith( Artifact.SNAPSHOT_VERSION ) )
{
loc.setVersionDir( loc.getVersion() );
if ( !findLatestSnapshot( bmd, loc, res ) )
return null;
}
else
// R or L found and actual captured in loc.version
loc.setVersionDir( loc.getVersion() );
}
// regular snapshot requested
else if ( loc.getVersion().endsWith( Artifact.SNAPSHOT_VERSION ) )
{
File gavDir = new File( gaDir, loc.getVersion() );
if ( !gavDir.exists() )
{
// res.addError( bmd, new RepositoryException( LANG.getMessage( "gavdir.not.found", bmd.toString(),
// gavDir.getAbsolutePath() ) ) );
if( LOG.isErrorEnabled() )
LOG.error( LANG.getMessage( "gavdir.not.found", bmd.toString(), gavDir.getAbsolutePath() ) );
return null;
}
if ( !findLatestSnapshot( bmd, loc, res ) )
return null;
}
// time stamped snapshot requested
else if ( vq.equals( Quality.SNAPSHOT_TS_QUALITY ) )
{
loc.setVersionDir( loc.getVersionWithoutTS() + FileUtil.DASH + Artifact.SNAPSHOT_VERSION );
}
return loc;
}
// ---------------------------------------------------------------------------------------------------------------
public ArtifactResults readArtifacts( Collection<ArtifactBasicMetadata> query )
throws RepositoryException, IllegalArgumentException
{
if ( query == null || query.isEmpty() )
throw new IllegalArgumentException( LANG.getMessage( "empty.query", query == null ? "null" : "empty" ) );
ArtifactResults res = new ArtifactResults();
Set<StreamVerifierFactory> vFacs = null;
if ( _repo.hasServer() && _repo.getServer().hasReaderStreamVerifierFactories() )
vFacs = _repo.getServer().getReaderStreamVerifierFactories();
for ( ArtifactBasicMetadata bmd : query )
{
DefaultArtifact da = bmd instanceof DefaultArtifact ? (DefaultArtifact) bmd : new DefaultArtifact( bmd );
ArtifactLocation loc = calculateLocation( _repoDir.getAbsolutePath(), bmd, res );
if ( loc == null )
continue;
File binary = new File( loc.getAbsPath() );
// binary calculated
if ( !binary.exists() )
{
// res.addError( bmd, new RepositoryException( LANG.getMessage( "binary.not.found", bmd.toString(),
// binary.getAbsolutePath() ) ) );
if( LOG.isErrorEnabled() )
LOG.error( LANG.getMessage( "binary.not.found", bmd.toString(), binary.getAbsolutePath() ) );
continue;
}
try // reading pom if one exists
{
if ( checkFile( binary, vFacs ) )
{
da.setFile( binary );
da.setTracker( this._repo );
}
if ( "pom".equals( bmd.getType() ) )
{
da.setPomBlob( FileUtil.readRawData( binary ) );
}
else
{
File pomFile = new File( loc.getAbsPomPath() );
if ( pomFile.exists() )
{
if ( checkFile( pomFile, vFacs ) )
da.setPomBlob( FileUtil.readRawData( pomFile ) );
}
else
LOG.warn( LANG.getMessage( "pom.not.found", bmd.toString() ) );
}
da.setVersion( loc.getVersion() );
res.add( bmd, da );
}
catch ( Exception e )
{
throw new RepositoryException( e );
}
}
return res;
}
// ---------------------------------------------------------------------------------------------------------------
private static boolean checkFile( File f, Set<StreamVerifierFactory> vFacs )
throws RepositoryException, StreamVerifierException
{
if ( vFacs != null )
{
String fileName = f.getAbsolutePath();
HashSet<StreamVerifier> vs = new HashSet<StreamVerifier>( vFacs.size() );
for ( StreamVerifierFactory svf : vFacs )
{
StreamVerifier sv = svf.newInstance();
String ext = sv.getAttributes().getExtension();
String sigFileName = fileName + ( ext.startsWith( "." ) ? "" : "." ) + ext;
File sigFile = new File( sigFileName );
if ( sigFile.exists() )
{
try
{
sv.initSignature( FileUtil.readRawDataAsString( sigFile ) );
}
catch ( IOException e )
{
throw new RepositoryException( LANG.getMessage( "cannot.read.signature.file", sigFileName,
e.getMessage() ) );
}
vs.add( sv );
}
else if ( !sv.getAttributes().isLenient() )
{
throw new RepositoryException( LANG.getMessage( "no.signature.file", ext, sigFileName ) );
}
// otherwise ignore absence of signature file, if verifier is lenient
}
FileInputStream fin = null;
try
{
fin = new FileInputStream( f );
byte[] buf = new byte[1024];
int n = -1;
while ( ( n = fin.read( buf ) ) != -1 )
{
for ( StreamVerifier sv : vs )
try
{
sv.bytesReady( buf, 0, n );
}
catch ( StreamObserverException e )
{
if ( !sv.getAttributes().isLenient() )
throw new RepositoryException( e );
}
}
for ( StreamVerifier sv : vs )
{
if ( sv.verifySignature() )
{
if ( sv.getAttributes().isSufficient() )
break;
}
else
{
if ( !sv.getAttributes().isLenient() )
throw new RepositoryException(
LANG.getMessage( "signature.failed",
sv.getAttributes().getExtension(), fileName ) );
}
}
}
catch ( IOException e )
{
throw new RepositoryException( e );
}
finally
{
if ( fin != null )
try
{
fin.close();
}
catch ( Exception any )
{
}
}
}
return true;
}
// ---------------------------------------------------------------------------------------------------------------
/**
*
*/
public ArtifactBasicResults readDependencies( Collection<ArtifactBasicMetadata> query )
throws RepositoryException, IllegalArgumentException
{
if ( query == null || query.size() < 1 )
return null;
ArtifactBasicResults ror = null;
File pomFile = null;
for ( ArtifactBasicMetadata bmd : query )
{
String pomPath =
bmd.getGroupId().replace( '.', '/' ) + "/" + bmd.getArtifactId() + "/" + ArtifactLocation.calculateVersionDir( bmd.getVersion() ) + "/"
+ bmd.getArtifactId() + '-' + bmd.getVersion() + ".pom";
pomFile = new File( _repoDir, pomPath );
if ( !pomFile.exists() )
{
LOG.warn( "file \"" + pomPath + "\" does not exist in local repo" );
continue;
}
// TODO HIGH og: delegate POM processing to maven-project
// for testing purpose - I plug in my test processor
try
{
List<ArtifactBasicMetadata> deps =
_mdProcessor.getDependencies( bmd, _mdReader == null ? this : _mdReader, System.getenv(),
System.getProperties() );
// for(ArtifactBasicMetadata d : deps )
// {
// System.out.println("======> "+d.getScope() );
// }
ror = ArtifactBasicResults.add( ror, bmd, deps );
}
catch ( Exception e )
{
LOG.warn( "error reading " + bmd.toString() + " dependencies", e );
continue;
}
}
return ror;
}
// ---------------------------------------------------------------------------------------------------------------
private static boolean findLatestSnapshot( final ArtifactBasicMetadata bmd, final ArtifactLocation loc, AbstractRepOpResult res )
{
File binary = new File( loc.getAbsPath() );
if ( binary.exists() )
return true;
// no real SNAPSHOT file, let's try to find one
File gavDir = new File( loc.getAbsGavPath() );
String classifier = Util.isEmpty( bmd.getClassifier() ) ? "" : '-'+bmd.getClassifier();
final String regEx = Artifact.SNAPSHOT_TS_REGEX + classifier + "\\."+bmd.getCheckedType();
final TreeSet<String> ts = new TreeSet<String>( new VersionComparator() );
final int pos = bmd.getArtifactId().length() + 1;
gavDir.listFiles( new FilenameFilter()
{
public boolean accept( File dir, String name )
{
if( name.matches( regEx ) )
{
String ver = name.substring( pos, name.lastIndexOf( '.' ) );
ts.add( ver );
return true;
}
return false;
}
}
);
if( ts.isEmpty() )
{
if( LOG.isErrorEnabled() )
LOG.error( LANG.getMessage( "snapshot.not.found", bmd.toString(), gavDir.getAbsolutePath() ) );
return false;
}
loc.setVersion( ts.last() );
return true;
}
// ---------------------------------------------------------------------------------------------------------------
/**
* direct disk search, no redirects - I cannot process pom files :(
*/
public ArtifactBasicResults readVersions( Collection<ArtifactBasicMetadata> query )
throws RepositoryException, IllegalArgumentException
{
if ( query == null || query.size() < 1 )
return null;
ArtifactBasicResults res = new ArtifactBasicResults( query.size() );
File gaDir = null;
for ( ArtifactBasicMetadata bmd : query )
{
gaDir = new File( _repoDir, bmd.getGroupId().replace( '.', '/' ) + "/" + bmd.getArtifactId() );
if ( !gaDir.exists() )
continue;
File[] versionFiles = gaDir.listFiles();
VersionRange versionQuery;
try
{
versionQuery = VersionRangeFactory.create( bmd.getVersion(), _repo.getVersionRangeQualityRange() );
}
catch ( VersionException e )
{
res = ArtifactBasicResults.add( res, bmd, new RepositoryException( e ) );
continue;
}
Quality vq = new Quality( bmd.getVersion() );
if ( vq.equals( Quality.FIXED_RELEASE_QUALITY ) || vq.equals( Quality.FIXED_LATEST_QUALITY )
|| vq.equals( Quality.SNAPSHOT_QUALITY ) )
{
ArtifactLocation loc = calculateLocation( _repoDir.getAbsolutePath(), bmd, res );
if ( loc == null )
continue;
ArtifactBasicMetadata vmd = new ArtifactBasicMetadata();
vmd.setGroupId( bmd.getGroupId() );
vmd.setArtifactId( bmd.getArtifactId() );
vmd.setClassifier( bmd.getClassifier() );
vmd.setType( bmd.getType() );
vmd.setVersion( loc.getVersion() );
res = ArtifactBasicResults.add( res, bmd, vmd );
continue;
}
for ( File vf : versionFiles )
{
if ( !vf.isDirectory() )
continue;
String version = vf.getName();
Quality q = new Quality( version );
if ( !_repo.isAcceptedQuality( q ) )
continue;
if ( !versionQuery.includes( vf.getName() ) )
continue;
ArtifactBasicMetadata vmd = new ArtifactBasicMetadata();
vmd.setGroupId( bmd.getGroupId() );
vmd.setArtifactId( bmd.getArtifactId() );
vmd.setClassifier( bmd.getClassifier() );
vmd.setType( bmd.getType() );
vmd.setVersion( vf.getName() );
res = ArtifactBasicResults.add( res, bmd, vmd );
}
}
return res;
}
// ---------------------------------------------------------------------------------------------------------------
public byte[] readRawData( ArtifactBasicMetadata bmd, String classifier, String type )
throws MetadataReaderException
{
return readRawData( bmd, classifier, type, false );
}
// ---------------------------------------------------------------------------------------------------------------
public byte[] readRawData( ArtifactBasicMetadata bmd, String classifier, String type, boolean exempt )
throws MetadataReaderException
{
return readRawData( relPathOf( bmd, classifier, type ), exempt );
}
// ---------------------------------------------------------------------------------------------------------------
private static String relPathOf( ArtifactBasicMetadata bmd, String classifier, String type )
{
String bmdPath =
bmd.getGroupId().replace( '.', '/' ) + '/' + bmd.getArtifactId() + '/' + ArtifactLocation.calculateVersionDir( bmd.getVersion() );
String path = bmdPath + '/' + bmd.getBaseName( classifier ) + '.' + ( type == null ? bmd.getType() : type );
if( LOG.isDebugEnabled() )
LOG.debug( bmd.toString()+" path is "+ path);
return path;
}
// ---------------------------------------------------------------------------------------------------------------
public byte[] readRawData( String path )
throws MetadataReaderException
{
return readRawData( path, false );
}
// ---------------------------------------------------------------------------------------------------------------
public byte[] readRawData( String path, boolean exempt )
throws MetadataReaderException
{
File file = new File( _repoDir, path );
if ( !file.exists() )
return null;
FileInputStream fis = null;
try
{
fis = new FileInputStream( file );
int len = (int) file.length();
byte[] pom = new byte[len];
fis.read( pom );
return pom;
}
catch ( IOException e )
{
throw new MetadataReaderException( e );
}
finally
{
if ( fis != null )
try
{
fis.close();
}
catch ( Exception any )
{
}
}
}
// ---------------------------------------------------------------------------------------------------------------
public String readStringData( String path )
throws MetadataReaderException
{
byte[] data = readRawData( path, false );
if ( data == null )
return null;
return new String( data );
}
// ---------------------------------------------------------------------------------------------------------------
public boolean canHandle( String protocol )
{
return AbstractRepository.DEFAULT_LOCAL_READ_PROTOCOL.equals( protocol );
}
// ---------------------------------------------------------------------------------------------------------------
public String[] getProtocols()
{
return _protocols;
}
// ---------------------------------------------------------------------------------------------------------------
public void close()
{
}
// ---------------------------------------------------------------------------------------------------------------
}