blob: c35764049ceaf072bc358f417ac1f0503fa156da [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.FileInputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
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.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.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() )
{
res.addError( bmd, new RepositoryException( _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() )
)
{
boolean noSnapshots = Artifact.RELEASE_VERSION.equals( loc.getVersion() );
loc.setVersion( null );
DefaultArtifactVersion tempDav = null;
DefaultArtifactVersion tempDav2 = null;
File [] files = gaDir.listFiles();
// find latest
for( File vf : files )
{
if( vf.isFile() )
continue;
String vn = vf.getName();
// RELEASE?
if( noSnapshots && vn.endsWith( Artifact.SNAPSHOT_VERSION ))
continue;
if( loc.getVersion() == null )
{
loc.setVersion( vn );
tempDav = new DefaultArtifactVersion( vn );
continue;
}
tempDav2 = new DefaultArtifactVersion( vn );
if( tempDav2.compareTo( tempDav ) > 0 )
{
loc.setVersion( vn );
tempDav = tempDav2;
}
}
if( loc.getVersion() == null )
{
res.addError( bmd, new RepositoryException( _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() ) ) );
return null;
}
if( !findLatestSnapshot( bmd, loc, res ) )
return null;
}
// time stamped snapshot requested
else if( vq.equals( Quality.SNAPSHOT_TS_QUALITY ))
{
loc.setVersionDir( loc.getBaseVersion()+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() ) ) );
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()
+ "/" + 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( ArtifactBasicMetadata bmd, 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.getGavPath() );
File [] files = gavDir.listFiles();
loc.setVersion( null );
DefaultArtifactVersion tempDav = null;
DefaultArtifactVersion tempDav2 = null;
int aLen = loc.getBaseName().length();
// find latest
for( File vf : files )
{
if( vf.isFile() )
continue;
String vn = vf.getName().substring( aLen+1 );
// no snapshots
if( vn.endsWith( Artifact.SNAPSHOT_VERSION ))
continue;
if( loc.getVersion() == null )
{
loc.setVersion( vn );
tempDav = new DefaultArtifactVersion( vn );
continue;
}
tempDav2 = new DefaultArtifactVersion( vn );
if( tempDav2.compareTo( tempDav ) > 0 )
{
loc.setVersion( vn );
tempDav = tempDav2;
}
}
if( loc.getVersion() == null )
{
res.addError( bmd, new RepositoryException( _lang.getMessage( "snapshot.not.found", bmd.toString(), gavDir.getAbsolutePath() ) ) );
return false;
}
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( relPathOf(bmd, classifier, type, null ) );
}
//---------------------------------------------------------------------------------------------------------------
private static String relPathOf( ArtifactBasicMetadata bmd, String classifier, String type, DefaultArtifactVersion inDav )
{
DefaultArtifactVersion dav = inDav;
if( inDav == null )
dav = new DefaultArtifactVersion( bmd.getVersion() );
Quality aq = dav.getQuality();
boolean isSnapshot = aq.equals( Quality.SNAPSHOT_QUALITY ) || aq.equals( Quality.SNAPSHOT_TS_QUALITY );
String bmdPath = bmd.getGroupId().replace( '.', '/' )+'/'+bmd.getArtifactId()
+'/' + ( isSnapshot ? dav.getBase()+'-'+Artifact.SNAPSHOT_VERSION : bmd.getVersion() );
String path = bmdPath+'/'+bmd.getBaseName(classifier)+'.' + (type == null ? bmd.getType() : type );
return path ;
}
//---------------------------------------------------------------------------------------------------------------
public byte[] readRawData( String path )
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 );
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()
{
}
//---------------------------------------------------------------------------------------------------------------
}