Fixing caching of Model files, in case it's brought in via reactor and the current relativePath of a parent is wrong...it can still be found, as required by IT0103.

git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@497554 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
John Dennis Casey 2007-01-18 19:58:42 +00:00
parent 2faffb229f
commit 3e3b0fd239
4 changed files with 172 additions and 34 deletions

View File

@ -154,9 +154,9 @@ public class DefaultMavenProjectBuilder
private ModelValidator validator; private ModelValidator validator;
private Map rawProjectCache = new HashMap();
private Map processedProjectCache = new HashMap(); private Map processedProjectCache = new HashMap();
private Map cachedPomFilesByModelId = new HashMap();
// TODO: make it a component // TODO: make it a component
private MavenXpp3Reader modelReader; private MavenXpp3Reader modelReader;
@ -683,8 +683,6 @@ public class DefaultMavenProjectBuilder
} }
project.setOriginalModel( originalModel ); project.setOriginalModel( originalModel );
rawProjectCache.put( createCacheKey( project.getGroupId(), project.getArtifactId(), project.getVersion() ), new MavenProject( project ) );
// we don't have to force the collision exception for superModel here, it's already been done in getSuperModel() // we don't have to force the collision exception for superModel here, it's already been done in getSuperModel()
MavenProject previousProject = superProject; MavenProject previousProject = superProject;
@ -1023,7 +1021,7 @@ public class DefaultMavenProjectBuilder
ModelLineage modelLineage = new DefaultModelLineage(); ModelLineage modelLineage = new DefaultModelLineage();
modelLineage.setOrigin( model, new File( projectDir, "pom.xml" ), new ArrayList( aggregatedRemoteWagonRepositories ) ); modelLineage.setOrigin( model, new File( projectDir, "pom.xml" ), new ArrayList( aggregatedRemoteWagonRepositories ) );
modelLineageBuilder.resumeBuildingModelLineage( modelLineage, localRepository, externalProfileManager ); modelLineageBuilder.resumeBuildingModelLineage( modelLineage, localRepository, externalProfileManager, cachedPomFilesByModelId );
List explicitlyActive; List explicitlyActive;
List explicitlyInactive; List explicitlyInactive;

View File

@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
@ -63,7 +64,7 @@ public class DefaultModelLineageBuilder
* @see org.apache.maven.project.build.model.ModelLineageBuilder#buildModelLineage(java.io.File, org.apache.maven.artifact.repository.ArtifactRepository, java.util.List) * @see org.apache.maven.project.build.model.ModelLineageBuilder#buildModelLineage(java.io.File, org.apache.maven.artifact.repository.ArtifactRepository, java.util.List)
*/ */
public ModelLineage buildModelLineage( File pom, ArtifactRepository localRepository, List remoteRepositories, public ModelLineage buildModelLineage( File pom, ArtifactRepository localRepository, List remoteRepositories,
ProfileManager profileManager ) ProfileManager profileManager, Map cachedPomFilesByModelId )
throws ProjectBuildingException throws ProjectBuildingException
{ {
ModelLineage lineage = new DefaultModelLineage(); ModelLineage lineage = new DefaultModelLineage();
@ -74,7 +75,7 @@ public class DefaultModelLineageBuilder
while ( pomFile != null ) while ( pomFile != null )
{ {
Model model = readModel( pomFile ); Model model = readModel( pomFile, cachedPomFilesByModelId );
if ( lineage.size() == 0 ) if ( lineage.size() == 0 )
{ {
@ -87,14 +88,15 @@ public class DefaultModelLineageBuilder
currentRemoteRepositories = updateRepositorySet( model, currentRemoteRepositories, pomFile, profileManager ); currentRemoteRepositories = updateRepositorySet( model, currentRemoteRepositories, pomFile, profileManager );
pomFile = resolveParentPom( model, currentRemoteRepositories, localRepository, pomFile ); pomFile = resolveParentPom( model, currentRemoteRepositories, localRepository, pomFile,
cachedPomFilesByModelId );
} }
return lineage; return lineage;
} }
public void resumeBuildingModelLineage( ModelLineage lineage, ArtifactRepository localRepository, public void resumeBuildingModelLineage( ModelLineage lineage, ArtifactRepository localRepository,
ProfileManager profileManager ) ProfileManager profileManager, Map cachedPomFilesByModelId )
throws ProjectBuildingException throws ProjectBuildingException
{ {
File pomFile = lineage.getDeepestFile(); File pomFile = lineage.getDeepestFile();
@ -108,11 +110,11 @@ public class DefaultModelLineageBuilder
Model model = lineage.getDeepestModel(); Model model = lineage.getDeepestModel();
// use the above information to re-bootstrap the resolution chain... // use the above information to re-bootstrap the resolution chain...
pomFile = resolveParentPom( model, currentRemoteRepositories, localRepository, pomFile ); pomFile = resolveParentPom( model, currentRemoteRepositories, localRepository, pomFile, cachedPomFilesByModelId );
while ( pomFile != null ) while ( pomFile != null )
{ {
model = readModel( pomFile ); model = readModel( pomFile, cachedPomFilesByModelId );
if ( lineage.size() == 0 ) if ( lineage.size() == 0 )
{ {
@ -125,15 +127,38 @@ public class DefaultModelLineageBuilder
currentRemoteRepositories = updateRepositorySet( model, currentRemoteRepositories, pomFile, profileManager ); currentRemoteRepositories = updateRepositorySet( model, currentRemoteRepositories, pomFile, profileManager );
pomFile = resolveParentPom( model, currentRemoteRepositories, localRepository, pomFile ); pomFile = resolveParentPom( model, currentRemoteRepositories, localRepository, pomFile,
cachedPomFilesByModelId );
} }
} }
/** /**
* Read the Model instance from the given POM file. * Read the Model instance from the given POM file. Skip caching the Model on this call, since
* it's meant for diagnostic purposes (to determine a parent match).
*/ */
private Model readModel( File pomFile ) private Model readModel( File pomFile )
throws ProjectBuildingException throws ProjectBuildingException
{
return readModel( pomFile, null, true );
}
/**
* Read the Model instance from the given POM file, and cache it in the given Map before
* returning it.
*/
private Model readModel( File pomFile, Map cachedPomFilesByModelId )
throws ProjectBuildingException
{
return readModel( pomFile, cachedPomFilesByModelId, false );
}
/**
* Read the Model instance from the given POM file. Optionally (in normal cases) cache the
* Model instance in the given Map before returning it. The skipCache flag controls whether the
* Model instance is actually cached.
*/
private Model readModel( File pomFile, Map cachedPomFilesByModelId, boolean skipCache )
throws ProjectBuildingException
{ {
Model model; Model model;
FileReader reader = null; FileReader reader = null;
@ -156,6 +181,11 @@ public class DefaultModelLineageBuilder
IOUtil.close( reader ); IOUtil.close( reader );
} }
if ( !skipCache )
{
cachedPomFilesByModelId.put( createCacheKey( model, pomFile ), pomFile );
}
return model; return model;
} }
@ -203,7 +233,7 @@ public class DefaultModelLineageBuilder
{ {
List explicitlyActive; List explicitlyActive;
List explicitlyInactive; List explicitlyInactive;
if ( profileManager != null ) if ( profileManager != null )
{ {
explicitlyActive = profileManager.getExplicitlyActivatedIds(); explicitlyActive = profileManager.getExplicitlyActivatedIds();
@ -214,8 +244,10 @@ public class DefaultModelLineageBuilder
explicitlyActive = Collections.EMPTY_LIST; explicitlyActive = Collections.EMPTY_LIST;
explicitlyInactive = Collections.EMPTY_LIST; explicitlyInactive = Collections.EMPTY_LIST;
} }
LinkedHashSet profileRepos = profileAdvisor.getArtifactRepositoriesFromActiveProfiles( model, projectDir, explicitlyActive, explicitlyInactive ); LinkedHashSet profileRepos = profileAdvisor.getArtifactRepositoriesFromActiveProfiles( model, projectDir,
explicitlyActive,
explicitlyInactive );
if ( !profileRepos.isEmpty() ) if ( !profileRepos.isEmpty() )
{ {
@ -226,9 +258,10 @@ public class DefaultModelLineageBuilder
/** /**
* Pull the parent specification out of the given model, construct an Artifact instance, and * Pull the parent specification out of the given model, construct an Artifact instance, and
* resolve that artifact...then, return the resolved POM file for the parent. * resolve that artifact...then, return the resolved POM file for the parent.
* @param cachedModelsById
*/ */
private File resolveParentPom( Model model, List remoteRepositories, ArtifactRepository localRepository, private File resolveParentPom( Model model, List remoteRepositories, ArtifactRepository localRepository,
File modelPomFile ) File modelPomFile, Map cachedModelsById )
throws ProjectBuildingException throws ProjectBuildingException
{ {
Parent modelParent = model.getParent(); Parent modelParent = model.getParent();
@ -239,7 +272,16 @@ public class DefaultModelLineageBuilder
{ {
validateParentDeclaration( modelParent, model ); validateParentDeclaration( modelParent, model );
pomFile = resolveParentWithRelativePath( modelParent, modelPomFile ); String cacheKey = createCacheKey( modelParent );
getLogger().debug( "Looking for cached parent POM under: " + cacheKey );
pomFile = (File) cachedModelsById.get( cacheKey );
if ( pomFile == null )
{
pomFile = resolveParentWithRelativePath( modelParent, modelPomFile );
}
if ( pomFile == null ) if ( pomFile == null )
{ {
@ -250,6 +292,42 @@ public class DefaultModelLineageBuilder
return pomFile; return pomFile;
} }
private String createCacheKey( Parent modelParent )
{
return modelParent.getGroupId() + ":" + modelParent.getArtifactId() + ":" + modelParent.getVersion();
}
private String createCacheKey( Model model, File pomFile )
throws ProjectBuildingException
{
Parent modelParent = model.getParent();
String groupId = model.getGroupId();
if ( groupId == null && modelParent != null )
{
groupId = modelParent.getGroupId();
}
String artifactId = model.getArtifactId();
String version = model.getVersion();
if ( version == null && modelParent != null )
{
version = modelParent.getVersion();
}
if ( groupId == null || version == null )
{
throw new ProjectBuildingException( model.getId(),
"Invalid model. Must either specify groupId and version directly, or specify a parent groupId and version.\nIn POM: "
+ pomFile );
}
return groupId + ":" + artifactId + ":" + version;
}
private void validateParentDeclaration( Parent modelParent, Model model ) private void validateParentDeclaration( Parent modelParent, Model model )
throws ProjectBuildingException throws ProjectBuildingException
{ {
@ -283,7 +361,7 @@ public class DefaultModelLineageBuilder
getLogger().debug( "Looking for parent: " + modelParent.getId() + " using artifact: " + parentPomArtifact ); getLogger().debug( "Looking for parent: " + modelParent.getId() + " using artifact: " + parentPomArtifact );
getLogger().debug( "\tLocal repository: " + localRepository.getBasedir() + "\n" ); getLogger().debug( "\tLocal repository: " + localRepository.getBasedir() + "\n" );
getLogger().debug( "\tRemote repositories:\n" + remoteRepositories.toString().replace( ',', '\n' ) + "\n" ); getLogger().debug( "\tRemote repositories:\n" + remoteRepositories.toString().replace( ',', '\n' ) + "\n" );
try try
{ {
artifactResolver.resolve( parentPomArtifact, remoteRepositories, localRepository ); artifactResolver.resolve( parentPomArtifact, remoteRepositories, localRepository );
@ -295,8 +373,8 @@ public class DefaultModelLineageBuilder
} }
catch ( ArtifactNotFoundException e ) catch ( ArtifactNotFoundException e )
{ {
throw new ProjectBuildingException( "Parent: " + modelParent.getId(), "Cannot find parent: " + parentPomArtifact.getId() + " of: " throw new ProjectBuildingException( "Parent: " + modelParent.getId(), "Cannot find parent: "
+ pomFile, e ); + parentPomArtifact.getId() + " of: " + pomFile, e );
} }
if ( parentPomArtifact.isResolved() ) if ( parentPomArtifact.isResolved() )
@ -316,13 +394,13 @@ public class DefaultModelLineageBuilder
File modelDir = modelPomFile.getParentFile(); File modelDir = modelPomFile.getParentFile();
File parentPomFile = new File( modelDir, relativePath ); File parentPomFile = new File( modelDir, relativePath );
if ( parentPomFile.isDirectory() ) if ( parentPomFile.isDirectory() )
{ {
getLogger().debug( "Parent relative-path is a directory; assuming \'pom.xml\' file exists within." ); getLogger().debug( "Parent relative-path is a directory; assuming \'pom.xml\' file exists within." );
parentPomFile = new File( parentPomFile, "pom.xml" ); parentPomFile = new File( parentPomFile, "pom.xml" );
} }
getLogger().debug( "Looking for parent: " + modelParent.getId() + " in: " + parentPomFile ); getLogger().debug( "Looking for parent: " + modelParent.getId() + " in: " + parentPomFile );
if ( parentPomFile.exists() ) if ( parentPomFile.exists() )
@ -349,7 +427,7 @@ public class DefaultModelLineageBuilder
{ {
logger = new ConsoleLogger( Logger.LEVEL_DEBUG, "DefaultModelLineageBuilder:internal" ); logger = new ConsoleLogger( Logger.LEVEL_DEBUG, "DefaultModelLineageBuilder:internal" );
} }
return logger; return logger;
} }

View File

@ -6,6 +6,7 @@ import org.apache.maven.project.ProjectBuildingException;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Builds the lineage of Model instances, starting from a given POM file, and stretching back through * Builds the lineage of Model instances, starting from a given POM file, and stretching back through
@ -29,16 +30,30 @@ public interface ModelLineageBuilder
* @param localRepository The local repository against which parent POMs should be resolved * @param localRepository The local repository against which parent POMs should be resolved
* @param remoteRepositories List of ArtifactRepository instances against which parent POMs * @param remoteRepositories List of ArtifactRepository instances against which parent POMs
* should be resolved * should be resolved
* @param profileManager The profile manager containing information about global profiles to be
* applied (from settings.xml, for instance)
* @param cachedPomFilesByModelId A "global" cache of Model source files, partially for
* optimization, and partially for loading Models that are unavailable in the repository and
* have an incorrect relativePath
*/ */
ModelLineage buildModelLineage( File pom, ArtifactRepository localRepository, List remoteRepositories, ProfileManager profileManager ) ModelLineage buildModelLineage( File pom, ArtifactRepository localRepository, List remoteRepositories,
ProfileManager profileManager, Map cachedPomFilesByModelId )
throws ProjectBuildingException; throws ProjectBuildingException;
/** /**
* Resume the process of constructing a lineage of inherited models, picking up using the deepest * Resume the process of constructing a lineage of inherited models, picking up using the deepest
* parent already in the lineage. * parent already in the lineage.
* *
* @param lineage The ModelLineage instance in progress, which should be completed.
* @param localRepository The local repository against which parent POMs should be resolved
* @param profileManager The profile manager containing information about global profiles to be
* applied (from settings.xml, for instance)
* @param cachedPomFilesByModelId A "global" cache of Model source files, partially for
* optimization, and partially for loading Models that are unavailable in the repository and
* have an incorrect relativePath
*/ */
void resumeBuildingModelLineage( ModelLineage lineage, ArtifactRepository localRepository, ProfileManager profileManager ) void resumeBuildingModelLineage( ModelLineage lineage, ArtifactRepository localRepository,
ProfileManager profileManager, Map cachedPomFilesByModelId )
throws ProjectBuildingException; throws ProjectBuildingException;
} }

View File

@ -16,7 +16,9 @@ import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map;
public class DefaultModelLineageBuilderTest public class DefaultModelLineageBuilderTest
extends PlexusTestCase extends PlexusTestCase
@ -66,7 +68,7 @@ public class DefaultModelLineageBuilderTest
IOUtil.close( writer ); IOUtil.close( writer );
} }
ModelLineage lineage = modelLineageBuilder.buildModelLineage( pomFile, null, null, null ); ModelLineage lineage = modelLineageBuilder.buildModelLineage( pomFile, null, null, null, new HashMap() );
assertEquals( 1, lineage.size() ); assertEquals( 1, lineage.size() );
@ -124,7 +126,7 @@ public class DefaultModelLineageBuilderTest
.toExternalForm(), defaultLayout ); .toExternalForm(), defaultLayout );
ModelLineage lineage = modelLineageBuilder.buildModelLineage( currentPOM, localRepository, ModelLineage lineage = modelLineageBuilder.buildModelLineage( currentPOM, localRepository,
Collections.EMPTY_LIST, null ); Collections.EMPTY_LIST, null, new HashMap() );
assertEquals( 3, lineage.size() ); assertEquals( 3, lineage.size() );
@ -196,7 +198,7 @@ public class DefaultModelLineageBuilderTest
.toExternalForm(), defaultLayout ); .toExternalForm(), defaultLayout );
ModelLineage lineage = modelLineageBuilder.buildModelLineage( currentPOM, localRepository, Collections ModelLineage lineage = modelLineageBuilder.buildModelLineage( currentPOM, localRepository, Collections
.singletonList( remoteRepository ), null ); .singletonList( remoteRepository ), null, new HashMap() );
assertEquals( 3, lineage.size() ); assertEquals( 3, lineage.size() );
@ -217,11 +219,11 @@ public class DefaultModelLineageBuilderTest
projectRootDirectory.mkdirs(); projectRootDirectory.mkdirs();
deleteDirOnExit( projectRootDirectory ); deleteDirOnExit( projectRootDirectory );
// 2. create dir for parent POM within project root directory. // 2. create dir for parent POM within project root directory.
File parentDir = new File( projectRootDirectory, "parent" ); File parentDir = new File( projectRootDirectory, "parent" );
parentDir.mkdirs(); parentDir.mkdirs();
// 2. create dir for child project within project root directory. // 2. create dir for child project within project root directory.
File childDir = new File( projectRootDirectory, "child" ); File childDir = new File( projectRootDirectory, "child" );
childDir.mkdirs(); childDir.mkdirs();
@ -250,8 +252,8 @@ public class DefaultModelLineageBuilderTest
ArtifactRepository localRepository = new DefaultArtifactRepository( "local", projectRootDirectory.toURL() ArtifactRepository localRepository = new DefaultArtifactRepository( "local", projectRootDirectory.toURL()
.toExternalForm(), defaultLayout ); .toExternalForm(), defaultLayout );
ModelLineage lineage = modelLineageBuilder.buildModelLineage( currentPOM, localRepository, Collections ModelLineage lineage = modelLineageBuilder.buildModelLineage( currentPOM, localRepository,
.EMPTY_LIST, null ); Collections.EMPTY_LIST, null, new HashMap() );
assertEquals( 2, lineage.size() ); assertEquals( 2, lineage.size() );
@ -300,6 +302,51 @@ public class DefaultModelLineageBuilderTest
System.out.println( "Verifying that: " + file.getAbsolutePath() + " exists: " + file.exists() ); System.out.println( "Verifying that: " + file.getAbsolutePath() + " exists: " + file.exists() );
} }
public void testReadPOMWithParentInOtherLocalFileWithBadRelativePath()
throws IOException, ProjectBuildingException
{
// 1. create the parent model in a "local" POM file.
File parentPOM = File.createTempFile( "DefaultModelLineageBuilder.test.", ".pom" );
parentPOM.deleteOnExit();
Model parent = createModel( "group", "parent", "1" );
// 4. write the parent model to the local repo directory
writeModel( parent, parentPOM );
Map cache = new HashMap();
cache.put( "group:parent:1", parentPOM );
// 5. create the current pom with a parent-ref on the parent model
Model current = createModel( "group", "current", "1" );
Parent currentParent = new Parent();
currentParent.setGroupId( "group" );
currentParent.setArtifactId( "parent" );
currentParent.setVersion( "1" );
currentParent.setRelativePath( "../parent/pom.xml" );
current.setParent( currentParent );
// 6. write the current pom somewhere
File currentPOM = File.createTempFile( "DefaultModelLineageBuilder.test.", ".pom" );
currentPOM.deleteOnExit();
writeModel( current, currentPOM );
// 7. build the lineage.
ModelLineage lineage = modelLineageBuilder.buildModelLineage( currentPOM, null, Collections
.EMPTY_LIST, null, cache );
assertEquals( 2, lineage.size() );
Iterator modelIterator = lineage.modelIterator();
assertEquals( 2, cache.size() );
assertEquals( current.getId(), ( (Model) modelIterator.next() ).getId() );
assertEquals( parent.getId(), ( (Model) modelIterator.next() ).getId() );
}
private Model createModel( String groupId, String artifactId, String version ) private Model createModel( String groupId, String artifactId, String version )
{ {
Model model = new Model(); Model model = new Model();