blob: 404d036e3b5a56161b1dc5780c62ece447e123a3 [file] [log] [blame]
package org.apache.maven.index.creator;
/*
* 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.Arrays;
import java.util.Collection;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.maven.index.ArtifactAvailablility;
import org.apache.maven.index.ArtifactContext;
import org.apache.maven.index.ArtifactInfo;
import org.apache.maven.index.IndexerField;
import org.apache.maven.index.IndexerFieldVersion;
import org.apache.maven.index.MAVEN;
import org.apache.maven.index.NEXUS;
import org.apache.maven.index.artifact.Gav;
import org.apache.maven.index.locator.JavadocLocator;
import org.apache.maven.index.locator.Locator;
import org.apache.maven.index.locator.Sha1Locator;
import org.apache.maven.index.locator.SignatureLocator;
import org.apache.maven.index.locator.SourcesLocator;
import org.apache.maven.model.Model;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.StringUtils;
/**
* A minimal index creator used to provide basic information about Maven artifact. This creator will create the index
* fast, will not open any file to be fastest as possible but it has some drawbacks: The information gathered by this
* creator are sometimes based on "best-effort" only, and does not reflect the reality (ie. maven archetype packaging @see
* {@link MavenArchetypeArtifactInfoIndexCreator}).
*
* @author cstamas
*/
@Singleton
@Named( MinimalArtifactInfoIndexCreator.ID )
public class MinimalArtifactInfoIndexCreator
extends AbstractIndexCreator
implements LegacyDocumentUpdater
{
public static final String ID = "min";
/**
* Info: packaging, lastModified, size, sourcesExists, javadocExists, signatureExists. Stored, not indexed.
*/
public static final IndexerField FLD_INFO = new IndexerField( NEXUS.INFO, IndexerFieldVersion.V1, "i",
"Artifact INFO (not indexed, stored)", Store.YES, Index.NO );
public static final IndexerField FLD_GROUP_ID_KW = new IndexerField( MAVEN.GROUP_ID, IndexerFieldVersion.V1, "g",
"Artifact GroupID (as keyword)", Store.NO, Index.NOT_ANALYZED );
public static final IndexerField FLD_GROUP_ID = new IndexerField( MAVEN.GROUP_ID, IndexerFieldVersion.V3,
"groupId", "Artifact GroupID (tokenized)", Store.NO, Index.ANALYZED );
public static final IndexerField FLD_ARTIFACT_ID_KW = new IndexerField( MAVEN.ARTIFACT_ID, IndexerFieldVersion.V1,
"a", "Artifact ArtifactID (as keyword)", Store.NO, Index.NOT_ANALYZED );
public static final IndexerField FLD_ARTIFACT_ID = new IndexerField( MAVEN.ARTIFACT_ID, IndexerFieldVersion.V3,
"artifactId", "Artifact ArtifactID (tokenized)", Store.NO, Index.ANALYZED );
public static final IndexerField FLD_VERSION_KW = new IndexerField( MAVEN.VERSION, IndexerFieldVersion.V1, "v",
"Artifact Version (as keyword)", Store.NO, Index.NOT_ANALYZED );
public static final IndexerField FLD_VERSION = new IndexerField( MAVEN.VERSION, IndexerFieldVersion.V3, "version",
"Artifact Version (tokenized)", Store.NO, Index.ANALYZED );
public static final IndexerField FLD_PACKAGING = new IndexerField( MAVEN.PACKAGING, IndexerFieldVersion.V1, "p",
"Artifact Packaging (as keyword)", Store.NO, Index.NOT_ANALYZED );
public static final IndexerField FLD_CLASSIFIER = new IndexerField( MAVEN.CLASSIFIER, IndexerFieldVersion.V1, "l",
"Artifact classifier (as keyword)", Store.NO, Index.NOT_ANALYZED );
public static final IndexerField FLD_NAME = new IndexerField( MAVEN.NAME, IndexerFieldVersion.V1, "n",
"Artifact name (tokenized, stored)", Store.YES, Index.ANALYZED );
public static final IndexerField FLD_DESCRIPTION = new IndexerField( MAVEN.DESCRIPTION, IndexerFieldVersion.V1,
"d", "Artifact description (tokenized, stored)", Store.YES, Index.ANALYZED );
public static final IndexerField FLD_LAST_MODIFIED = new IndexerField( MAVEN.LAST_MODIFIED, IndexerFieldVersion.V1,
"m", "Artifact last modified (not indexed, stored)", Store.YES, Index.NO );
public static final IndexerField FLD_SHA1 = new IndexerField( MAVEN.SHA1, IndexerFieldVersion.V1, "1",
"Artifact SHA1 checksum (as keyword, stored)", Store.YES, Index.NOT_ANALYZED );
private Locator jl = new JavadocLocator();
private Locator sl = new SourcesLocator();
private Locator sigl = new SignatureLocator();
private Locator sha1l = new Sha1Locator();
public MinimalArtifactInfoIndexCreator()
{
super( ID );
}
public void populateArtifactInfo( ArtifactContext ac )
{
File artifact = ac.getArtifact();
File pom = ac.getPom();
ArtifactInfo ai = ac.getArtifactInfo();
if ( pom != null )
{
ai.lastModified = pom.lastModified();
ai.fextension = "pom";
}
// TODO handle artifacts without poms
if ( pom != null )
{
if ( ai.classifier != null )
{
ai.sourcesExists = ArtifactAvailablility.NOT_AVAILABLE;
ai.javadocExists = ArtifactAvailablility.NOT_AVAILABLE;
}
else
{
File sources = sl.locate( pom );
if ( !sources.exists() )
{
ai.sourcesExists = ArtifactAvailablility.NOT_PRESENT;
}
else
{
ai.sourcesExists = ArtifactAvailablility.PRESENT;
}
File javadoc = jl.locate( pom );
if ( !javadoc.exists() )
{
ai.javadocExists = ArtifactAvailablility.NOT_PRESENT;
}
else
{
ai.javadocExists = ArtifactAvailablility.PRESENT;
}
}
}
Model model = ac.getPomModel();
if ( model != null )
{
ai.name = model.getName();
ai.description = model.getDescription();
// for main artifacts (without classifier) only:
if ( ai.classifier == null )
{
// only when this is not a classified artifact
if ( model.getPackaging() != null )
{
// set the read value that is coming from POM
ai.packaging = model.getPackaging();
}
else
{
// default it, since POM is present, is read, but does not contain explicit packaging
// TODO: this change breaks junit tests, but not sure why is "null" expected value?
// ai.packaging = "jar";
}
}
}
if ( "pom".equals( ai.packaging ) )
{
// special case, the POM _is_ the artifact
artifact = pom;
}
if ( artifact != null )
{
File signature = sigl.locate( artifact );
ai.signatureExists = signature.exists() ? ArtifactAvailablility.PRESENT : ArtifactAvailablility.NOT_PRESENT;
File sha1 = sha1l.locate( artifact );
if ( sha1.exists() )
{
try
{
ai.sha1 = StringUtils.chomp( FileUtils.fileRead( sha1 ) ).trim().split( " " )[0];
}
catch ( IOException e )
{
ac.addError( e );
}
}
ai.lastModified = artifact.lastModified();
ai.size = artifact.length();
ai.fextension = getExtension( artifact, ac.getGav() );
if ( ai.packaging == null )
{
ai.packaging = ai.fextension;
}
}
}
private String getExtension( File artifact, Gav gav )
{
if ( gav != null && StringUtils.isNotBlank( gav.getExtension() ) )
{
return gav.getExtension();
}
// last resort, the extension of the file
String artifactFileName = artifact.getName().toLowerCase();
// tar.gz? and other "special" combinations
if ( artifactFileName.endsWith( "tar.gz" ) )
{
return "tar.gz";
}
else if ( artifactFileName.equals( "tar.bz2" ) )
{
return "tar.bz2";
}
// get the part after the last dot
return FileUtils.getExtension( artifactFileName );
}
public void updateDocument( ArtifactInfo ai, Document doc )
{
String info =
new StringBuilder().append( ai.packaging ).append( ArtifactInfo.FS ).append(
Long.toString( ai.lastModified ) ).append( ArtifactInfo.FS ).append( Long.toString( ai.size ) ).append(
ArtifactInfo.FS ).append( ai.sourcesExists.toString() ).append( ArtifactInfo.FS ).append(
ai.javadocExists.toString() ).append( ArtifactInfo.FS ).append( ai.signatureExists.toString() ).append(
ArtifactInfo.FS ).append( ai.fextension ).toString();
doc.add( FLD_INFO.toField( info ) );
doc.add( FLD_GROUP_ID_KW.toField( ai.groupId ) );
doc.add( FLD_ARTIFACT_ID_KW.toField( ai.artifactId ) );
doc.add( FLD_VERSION_KW.toField( ai.version ) );
// V3
doc.add( FLD_GROUP_ID.toField( ai.groupId ) );
doc.add( FLD_ARTIFACT_ID.toField( ai.artifactId ) );
doc.add( FLD_VERSION.toField( ai.version ) );
if ( ai.name != null )
{
doc.add( FLD_NAME.toField( ai.name ) );
}
if ( ai.description != null )
{
doc.add( FLD_DESCRIPTION.toField( ai.description ) );
}
if ( ai.packaging != null )
{
doc.add( FLD_PACKAGING.toField( ai.packaging ) );
}
if ( ai.classifier != null )
{
doc.add( FLD_CLASSIFIER.toField( ai.classifier ) );
}
if ( ai.sha1 != null )
{
doc.add( FLD_SHA1.toField( ai.sha1 ) );
}
}
public void updateLegacyDocument( ArtifactInfo ai, Document doc )
{
updateDocument( ai, doc );
// legacy!
if ( ai.prefix != null )
{
doc.add( new Field( ArtifactInfo.PLUGIN_PREFIX, ai.prefix, Field.Store.YES, Field.Index.NOT_ANALYZED ) );
}
if ( ai.goals != null )
{
doc.add( new Field( ArtifactInfo.PLUGIN_GOALS, ArtifactInfo.lst2str( ai.goals ), Field.Store.YES,
Field.Index.NO ) );
}
doc.removeField( ArtifactInfo.GROUP_ID );
doc.add( new Field( ArtifactInfo.GROUP_ID, ai.groupId, Field.Store.NO, Field.Index.NOT_ANALYZED ) );
}
public boolean updateArtifactInfo( Document doc, ArtifactInfo ai )
{
boolean res = false;
String uinfo = doc.get( ArtifactInfo.UINFO );
if ( uinfo != null )
{
String[] r = ArtifactInfo.FS_PATTERN.split( uinfo );
ai.groupId = r[0];
ai.artifactId = r[1];
ai.version = r[2];
if ( r.length > 3 )
{
ai.classifier = ArtifactInfo.renvl( r[3] );
}
res = true;
}
String info = doc.get( ArtifactInfo.INFO );
if ( info != null )
{
String[] r = ArtifactInfo.FS_PATTERN.split( info );
ai.packaging = r[0];
ai.lastModified = Long.parseLong( r[1] );
ai.size = Long.parseLong( r[2] );
ai.sourcesExists = ArtifactAvailablility.fromString( r[3] );
ai.javadocExists = ArtifactAvailablility.fromString( r[4] );
ai.signatureExists = ArtifactAvailablility.fromString( r[5] );
if ( r.length > 6 )
{
ai.fextension = r[6];
}
else
{
if ( ai.classifier != null //
|| "pom".equals( ai.packaging ) //
|| "war".equals( ai.packaging ) //
|| "ear".equals( ai.packaging ) )
{
ai.fextension = ai.packaging;
}
else
{
ai.fextension = "jar"; // best guess
}
}
res = true;
}
String name = doc.get( ArtifactInfo.NAME );
if ( name != null )
{
ai.name = name;
res = true;
}
String description = doc.get( ArtifactInfo.DESCRIPTION );
if ( description != null )
{
ai.description = description;
res = true;
}
// sometimes there's a pom without packaging(default to jar), but no artifact, then the value will be a "null"
// String
if ( "null".equals( ai.packaging ) )
{
ai.packaging = null;
}
String sha1 = doc.get( ArtifactInfo.SHA1 );
if ( sha1 != null )
{
ai.sha1 = sha1;
}
return res;
// artifactInfo.fname = ???
}
// ==
@Override
public String toString()
{
return ID;
}
public Collection<IndexerField> getIndexerFields()
{
return Arrays.asList( FLD_INFO, FLD_GROUP_ID_KW, FLD_GROUP_ID, FLD_ARTIFACT_ID_KW, FLD_ARTIFACT_ID,
FLD_VERSION_KW, FLD_VERSION, FLD_PACKAGING, FLD_CLASSIFIER, FLD_NAME, FLD_DESCRIPTION, FLD_LAST_MODIFIED,
FLD_SHA1 );
}
}