Remove weave mode building from the core

This commit is contained in:
Jason van Zyl 2014-02-06 16:27:15 -05:00
parent ccc7cb3abc
commit 0c5678fa89
8 changed files with 1 additions and 1457 deletions

View File

@ -1,221 +0,0 @@
package org.apache.maven.lifecycle.internal.builder.weave;
/*
* 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 org.apache.maven.lifecycle.internal.ExecutionPlanItem;
import org.apache.maven.project.MavenProject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @since 3.0
* @author Kristian Rosenvold
* NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
*/
public class BuildLogItem
{
private final ExecutionPlanItem executionPlanItem;
private final MavenProject project;
private final long startTime;
private long endTime;
private final List<DependencyLogEntry> dependencies =
Collections.synchronizedList( new ArrayList<DependencyLogEntry>() );
public BuildLogItem( MavenProject project, ExecutionPlanItem executionPlanItem )
{
this.executionPlanItem = executionPlanItem;
this.project = project;
startTime = System.currentTimeMillis();
}
public MavenProject getProject()
{
return project;
}
public void setComplete()
{
endTime = System.currentTimeMillis();
}
public void addWait( MavenProject upstreamProject, ExecutionPlanItem inSchedule, long startWait )
{
long now = System.currentTimeMillis();
dependencies.add( new DependencyLogEntry( upstreamProject, inSchedule, startWait, now, null ) );
}
public void addDependency( MavenProject upstreamProject, String message )
{
dependencies.add( new DependencyLogEntry( upstreamProject, message ) );
}
public String toString( long rootStart )
{
StringBuilder result = new StringBuilder();
result.append( String.format( "%1d %2d ", startTime - rootStart, endTime - rootStart ) );
result.append( project.getName() );
result.append( " " );
result.append( getMojoExecutionDescription( executionPlanItem ) );
if ( dependencies.size() > 0 )
{
result.append( "\n" );
for ( DependencyLogEntry waitLogEntry : dependencies )
{
result.append( " " );
result.append( waitLogEntry.toString() );
result.append( "\n" );
}
}
return result.toString();
}
public Object toGraph( long rootStart )
{
StringBuilder result = new StringBuilder();
if ( dependencies.size() > 0 )
{
for ( DependencyLogEntry waitLogEntry : dependencies )
{
result.append( " " );
result.append( nodeKey( project, executionPlanItem ) );
result.append( " -> " );
result.append( waitLogEntry.toNodeKey() );
result.append( waitLogEntry.toNodeDescription( rootStart ) );
result.append( "\n" );
}
}
else
{
result.append( " " );
result.append( nodeKey( project, executionPlanItem ) );
result.append( "\n" );
}
return result.toString();
}
private static String nodeKey( MavenProject mavenProject, ExecutionPlanItem executionPlanItem )
{
String key = mavenProject.getArtifactId();
if ( executionPlanItem != null )
{
key += "_" + getMojoExecutionDescription( executionPlanItem );
}
return key.replace( ".", "_" ).replace( ":", "_" );
}
private static String getMojoExecutionDescription( ExecutionPlanItem executionPlanItem )
{
if ( executionPlanItem.getMojoExecution() != null )
{
return executionPlanItem.getMojoExecution().getArtifactId() + getLifeCyclePhase( executionPlanItem );
}
else
{
return "";
}
}
private static String getLifeCyclePhase( ExecutionPlanItem executionPlanItem )
{
return executionPlanItem.getLifecyclePhase() != null ? "[" + executionPlanItem.getLifecyclePhase() + "]" : "";
}
class DependencyLogEntry
{
private final ExecutionPlanItem executionPlanItem;
private final MavenProject upstreamProject;
private final Long start;
private final Long stop;
private final String message;
DependencyLogEntry( MavenProject upstreamProject, ExecutionPlanItem executionPlanItem, Long start, Long stop,
String message )
{
this.upstreamProject = upstreamProject;
this.executionPlanItem = executionPlanItem;
this.start = start;
this.stop = stop;
this.message = message;
}
DependencyLogEntry( MavenProject upstreamProject, String message )
{
this( upstreamProject, null, null, null, message );
}
public String toString()
{
return upstreamProject.getName() + ":" + getExecutionPlanItem() + getElapsed() + getMessage();
}
public String toNodeKey()
{
return nodeKey( upstreamProject, executionPlanItem );
}
public String toNodeDescription( long rootStart )
{
return "";
}
private String getMessage()
{
return message != null ? message : "";
}
private String getExecutionPlanItem()
{
if ( executionPlanItem != null )
{
return getMojoExecutionDescription( executionPlanItem );
}
else
{
return "";
}
}
private String getElapsed()
{
if ( start != null && stop != null )
{
long elapsed = stop - start;
return elapsed > 0 ? ", wait=" + elapsed : "";
}
return "";
}
}
}

View File

@ -1,124 +0,0 @@
package org.apache.maven.lifecycle.internal.builder.weave;
/*
* 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 org.apache.maven.lifecycle.internal.ExecutionPlanItem;
import org.apache.maven.project.MavenProject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Handles all concurrency-related logging.
* <p/>
* The logging/diagnostic needs of a concurrent build are different from a linear build. This
* delta required to analyze a concurrent build is located here.
* <p/>
* NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
*
* @since 3.0
* @author Kristian Rosenvold
*/
public class ConcurrentBuildLogger
{
private final long startTime;
private final Map<MavenProject, Thread> threadMap = new ConcurrentHashMap<MavenProject, Thread>();
public ConcurrentBuildLogger()
{
startTime = System.currentTimeMillis();
}
List<BuildLogItem> items = Collections.synchronizedList( new ArrayList<BuildLogItem>() );
public BuildLogItem createBuildLogItem( MavenProject project, ExecutionPlanItem current )
{
threadMap.put( project, Thread.currentThread() );
BuildLogItem result = new BuildLogItem( project, current );
items.add( result );
return result;
}
public String toString()
{
StringBuilder result = new StringBuilder();
for ( Map.Entry<MavenProject, Thread> mavenProjectThreadEntry : threadMap.entrySet() )
{
result.append( mavenProjectThreadEntry.getKey().getName() );
result.append( " ran on " );
result.append( mavenProjectThreadEntry.getValue().getName() );
result.append( "\n" );
}
for ( BuildLogItem builtLogItem : items )
{
result.append( builtLogItem.toString( startTime ) );
result.append( "\n" );
}
return result.toString();
}
public String toGraph()
{
StringBuilder result = new StringBuilder();
Map<MavenProject, Collection<BuildLogItem>> multiMap = new HashMap<MavenProject, Collection<BuildLogItem>>();
for ( BuildLogItem builtLogItem : items )
{
MavenProject project = builtLogItem.getProject();
Collection<BuildLogItem> bag = multiMap.get( project );
if ( bag == null )
{
bag = new ArrayList<BuildLogItem>();
multiMap.put( project, bag );
}
bag.add( builtLogItem );
}
result.append( "digraph build" );
result.append( " {\n " );
for ( MavenProject mavenProject : multiMap.keySet() )
{
final Collection<BuildLogItem> builtLogItems = multiMap.get( mavenProject );
result.append( " subgraph " );
result.append( mavenProject.getArtifactId() );
result.append( " {\n" );
for ( BuildLogItem builtLogItem : builtLogItems )
{
result.append( builtLogItem.toGraph( startTime ) );
}
result.append( "\n }\n" );
}
result.append( "\n}\n " );
return result.toString();
}
}

View File

@ -1,44 +0,0 @@
package org.apache.maven.lifecycle.internal.builder.weave;
/*
* 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.
*/
/**
* Knows the phase the current thread is executing.
* <p/>
* This class is used in weave-mode only , there may be better ways of doing this once the dust settles.
*
* @since 3.0
* @author Kristian Rosenvold
*/
class CurrentPhaseForThread
{
private static final InheritableThreadLocal<String> THREAD_PHASE = new InheritableThreadLocal<String>();
public static void setPhase( String phase )
{
THREAD_PHASE.set( phase );
}
public static boolean isPhase( String phase )
{
return phase.equals( THREAD_PHASE.get() );
}
}

View File

@ -1,320 +0,0 @@
package org.apache.maven.lifecycle.internal.builder.weave;
/*
* 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 org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.artifact.metadata.ArtifactMetadata;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
import org.apache.maven.artifact.versioning.VersionRange;
import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CountDownLatch;
/**
* An artifact that conditionally suspends on getFile for anything but the thread it is locked to.
*
* @since 3.0
*/
class ThreadLockedArtifact
implements Artifact
{
private final Artifact real;
private final CountDownLatch artifactLocked = new CountDownLatch( 1 );
ThreadLockedArtifact( Artifact real )
{
this.real = real;
}
public boolean hasReal()
{
return real != null
&& ( !( real instanceof ThreadLockedArtifact ) || ( (ThreadLockedArtifact) real ).hasReal() );
}
public String getGroupId()
{
return real.getGroupId();
}
public String getArtifactId()
{
return real.getArtifactId();
}
public String getVersion()
{
return real.getVersion();
}
public void setVersion( String version )
{
real.setVersion( version );
}
public String getScope()
{
return real.getScope();
}
public String getType()
{
return real.getType();
}
public String getClassifier()
{
return real.getClassifier();
}
public boolean hasClassifier()
{
return real.hasClassifier();
}
private static final InheritableThreadLocal<ThreadLockedArtifact> THREAD_ARTIFACT =
new InheritableThreadLocal<ThreadLockedArtifact>();
public void attachToThread()
{
THREAD_ARTIFACT.set( this );
}
public File getFile()
{
final ThreadLockedArtifact lockedArtifact = THREAD_ARTIFACT.get();
if ( lockedArtifact != null && this != lockedArtifact && mustLock() )
{
try
{
artifactLocked.await();
}
catch ( InterruptedException e )
{
// Ignore and go on to real.getFile();
}
}
return real.getFile();
}
private boolean mustLock()
{
boolean dontNeedLock = CurrentPhaseForThread.isPhase( "compile" ) || CurrentPhaseForThread.isPhase( "test" );
return !dontNeedLock;
}
public void setFile( File destination )
{
if ( destination != null && destination.exists() && destination.isFile() )
{
artifactLocked.countDown();
}
real.setFile( destination );
}
public String getBaseVersion()
{
return real.getBaseVersion();
}
public void setBaseVersion( String baseVersion )
{
real.setBaseVersion( baseVersion );
}
public String getId()
{
return real.getId();
}
public String getDependencyConflictId()
{
return real.getDependencyConflictId();
}
public void addMetadata( ArtifactMetadata metadata )
{
real.addMetadata( metadata );
}
public Collection<ArtifactMetadata> getMetadataList()
{
return real.getMetadataList();
}
public void setRepository( ArtifactRepository remoteRepository )
{
real.setRepository( remoteRepository );
}
public ArtifactRepository getRepository()
{
return real.getRepository();
}
public void updateVersion( String version, ArtifactRepository localRepository )
{
real.updateVersion( version, localRepository );
}
public String getDownloadUrl()
{
return real.getDownloadUrl();
}
public void setDownloadUrl( String downloadUrl )
{
real.setDownloadUrl( downloadUrl );
}
public ArtifactFilter getDependencyFilter()
{
return real.getDependencyFilter();
}
public void setDependencyFilter( ArtifactFilter artifactFilter )
{
real.setDependencyFilter( artifactFilter );
}
public ArtifactHandler getArtifactHandler()
{
return real.getArtifactHandler();
}
public List<String> getDependencyTrail()
{
return real.getDependencyTrail();
}
public void setDependencyTrail( List<String> dependencyTrail )
{
real.setDependencyTrail( dependencyTrail );
}
public void setScope( String scope )
{
real.setScope( scope );
}
public VersionRange getVersionRange()
{
return real.getVersionRange();
}
public void setVersionRange( VersionRange newRange )
{
real.setVersionRange( newRange );
}
public void selectVersion( String version )
{
real.selectVersion( version );
}
public void setGroupId( String groupId )
{
real.setGroupId( groupId );
}
public void setArtifactId( String artifactId )
{
real.setArtifactId( artifactId );
}
public boolean isSnapshot()
{
return real.isSnapshot();
}
public void setResolved( boolean resolved )
{
real.setResolved( resolved );
}
public boolean isResolved()
{
return real.isResolved();
}
public void setResolvedVersion( String version )
{
real.setResolvedVersion( version );
}
public void setArtifactHandler( ArtifactHandler handler )
{
real.setArtifactHandler( handler );
}
public boolean isRelease()
{
return real.isRelease();
}
public void setRelease( boolean release )
{
real.setRelease( release );
}
public List<ArtifactVersion> getAvailableVersions()
{
return real.getAvailableVersions();
}
public void setAvailableVersions( List<ArtifactVersion> versions )
{
real.setAvailableVersions( versions );
}
public boolean isOptional()
{
return real.isOptional();
}
public void setOptional( boolean optional )
{
real.setOptional( optional );
}
public ArtifactVersion getSelectedVersion()
throws OverConstrainedVersionException
{
return real.getSelectedVersion();
}
public boolean isSelectedVersionKnown()
throws OverConstrainedVersionException
{
return real.isSelectedVersionKnown();
}
public int compareTo( Artifact o )
{
return real.compareTo( o );
}
}

View File

@ -1,521 +0,0 @@
package org.apache.maven.lifecycle.internal.builder.weave;
/*
* 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 org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.execution.BuildSuccess;
import org.apache.maven.execution.ExecutionEvent;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.lifecycle.MavenExecutionPlan;
import org.apache.maven.lifecycle.Schedule;
import org.apache.maven.lifecycle.internal.BuildThreadFactory;
import org.apache.maven.lifecycle.internal.DependencyContext;
import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
import org.apache.maven.lifecycle.internal.ExecutionPlanItem;
import org.apache.maven.lifecycle.internal.LifecycleDebugLogger;
import org.apache.maven.lifecycle.internal.MojoExecutor;
import org.apache.maven.lifecycle.internal.PhaseRecorder;
import org.apache.maven.lifecycle.internal.ProjectBuildList;
import org.apache.maven.lifecycle.internal.ProjectSegment;
import org.apache.maven.lifecycle.internal.ReactorBuildStatus;
import org.apache.maven.lifecycle.internal.ReactorContext;
import org.apache.maven.lifecycle.internal.TaskSegment;
import org.apache.maven.lifecycle.internal.builder.Builder;
import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
* Builds the full lifecycle in weave-mode (phase by phase as opposed to project-by-project)
* <p/>
* NOTE: Weave mode is still experimental. It may be either promoted to first class citizen at some later point in time,
* and it may also be removed entirely. Weave mode has much more aggressive concurrency behaviour than regular threaded
* mode, and as such is still under test wrt cross platform stability.
* <p/>
* To remove weave mode from m3, the following should be removed: ExecutionPlanItem.schedule w/setters and getters
* DefaultLifeCycles.getScheduling() and all its use ReactorArtifactRepository has a reference to isWeave too. This
* class and its usage
*
* @since 3.0
* @author Kristian Rosenvold Builds one or more lifecycles for a full module
* <p/>
* NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
*/
@Component( role = Builder.class, hint = "weave" )
public class WeaveBuilder
implements Builder
{
@Requirement
private MojoExecutor mojoExecutor;
@Requirement
private BuilderCommon builderCommon;
@Requirement
private Logger logger;
@Requirement
private ExecutionEventCatapult eventCatapult;
@Requirement
private LifecycleDebugLogger lifecycleDebugLogger;
private Map<MavenProject, MavenExecutionPlan> executionPlans = new HashMap<MavenProject, MavenExecutionPlan>();
public WeaveBuilder()
{
}
public WeaveBuilder( MojoExecutor mojoExecutor, BuilderCommon builderCommon, Logger logger,
ExecutionEventCatapult eventCatapult, LifecycleDebugLogger lifecycleDebugLogger )
{
this.mojoExecutor = mojoExecutor;
this.builderCommon = builderCommon;
this.logger = logger;
this.eventCatapult = eventCatapult;
this.lifecycleDebugLogger = lifecycleDebugLogger;
}
public void build( MavenSession session, ReactorContext buildContext, ProjectBuildList projectBuilds,
List<TaskSegment> taskSegments, ReactorBuildStatus reactorBuildStatus )
throws ExecutionException, InterruptedException
{
lifecycleDebugLogger.logWeavePlan( session );
ExecutorService executor =
Executors.newFixedThreadPool( Math.min( session.getRequest().getDegreeOfConcurrency(),
session.getProjects().size() ), new BuildThreadFactory() );
try
{
ConcurrentBuildLogger concurrentBuildLogger = new ConcurrentBuildLogger();
CompletionService<ProjectSegment> service = new ExecutorCompletionService<ProjectSegment>( executor );
try
{
for ( MavenProject mavenProject : session.getProjects() )
{
Artifact mainArtifact = mavenProject.getArtifact();
if ( mainArtifact != null && !( mainArtifact instanceof ThreadLockedArtifact ) )
{
ThreadLockedArtifact threadLockedArtifact = new ThreadLockedArtifact( mainArtifact );
mavenProject.setArtifact( threadLockedArtifact );
}
}
final List<Future<ProjectSegment>> futures = new ArrayList<Future<ProjectSegment>>();
final Map<ProjectSegment, Future<MavenExecutionPlan>> plans =
new HashMap<ProjectSegment, Future<MavenExecutionPlan>>();
for ( TaskSegment taskSegment : taskSegments )
{
ProjectBuildList segmentChunks = projectBuilds.getByTaskSegment( taskSegment );
Set<Artifact> projectArtifacts = new HashSet<Artifact>();
for ( ProjectSegment segmentChunk : segmentChunks )
{
Artifact artifact = segmentChunk.getProject().getArtifact();
if ( artifact != null )
{
projectArtifacts.add( artifact );
}
}
for ( ProjectSegment projectBuild : segmentChunks )
{
plans.put( projectBuild, executor.submit( createEPFuture( projectBuild, projectArtifacts ) ) );
}
for ( ProjectSegment projectSegment : plans.keySet() )
{
executionPlans.put( projectSegment.getProject(), plans.get( projectSegment ).get() );
}
for ( ProjectSegment projectBuild : segmentChunks )
{
try
{
final MavenExecutionPlan executionPlan = plans.get( projectBuild ).get();
DependencyContext dependencyContext =
mojoExecutor.newDependencyContext( session, executionPlan.getMojoExecutions() );
final Callable<ProjectSegment> projectBuilder =
createCallableForBuildingOneFullModule( buildContext, session, reactorBuildStatus,
executionPlan, projectBuild, dependencyContext,
concurrentBuildLogger );
futures.add( service.submit( projectBuilder ) );
}
catch ( Exception e )
{
throw new ExecutionException( e );
}
}
for ( Future<ProjectSegment> buildFuture : futures )
{
buildFuture.get(); // At this point, this build *is* finished.
// Do not leak threads past here or evil gremlins will get you!
}
futures.clear();
}
}
finally
{
projectBuilds.closeAll();
}
logger.info( concurrentBuildLogger.toString() );
}
finally
{
executor.shutdown();
// If the builder has terminated with an exception we want to catch any stray threads before going
// to System.exit in the mavencli.
executor.awaitTermination( 5, TimeUnit.SECONDS );
}
}
private Callable<MavenExecutionPlan> createEPFuture( final ProjectSegment projectSegment,
final Set<Artifact> projectArtifacts )
{
return new Callable<MavenExecutionPlan>()
{
public MavenExecutionPlan call()
throws Exception
{
return builderCommon.resolveBuildPlan( projectSegment.getSession(), projectSegment.getProject(),
projectSegment.getTaskSegment(), projectArtifacts );
}
};
}
private Callable<ProjectSegment> createCallableForBuildingOneFullModule( final ReactorContext reactorContext,
final MavenSession rootSession,
final ReactorBuildStatus reactorBuildStatus,
final MavenExecutionPlan executionPlan,
final ProjectSegment projectBuild,
final DependencyContext dependencyContext,
final ConcurrentBuildLogger concurrentBuildLogger )
{
return new Callable<ProjectSegment>()
{
public ProjectSegment call()
throws Exception
{
Iterator<ExecutionPlanItem> planItems = executionPlan.iterator();
ExecutionPlanItem current = planItems.hasNext() ? planItems.next() : null;
ThreadLockedArtifact threadLockedArtifact =
(ThreadLockedArtifact) projectBuild.getProject().getArtifact();
if ( threadLockedArtifact != null )
{
threadLockedArtifact.attachToThread();
}
long buildStartTime = System.currentTimeMillis();
// muxer.associateThreadWithProjectSegment( projectBuild );
if ( reactorBuildStatus.isHaltedOrBlacklisted( projectBuild.getProject() ) )
{
eventCatapult.fire( ExecutionEvent.Type.ProjectSkipped, projectBuild.getSession(), null );
return null;
}
eventCatapult.fire( ExecutionEvent.Type.ProjectStarted, projectBuild.getSession(), null );
Collection<ArtifactLink> dependencyLinks = getUpstreamReactorDependencies( projectBuild );
try
{
PhaseRecorder phaseRecorder = new PhaseRecorder( projectBuild.getProject() );
long totalMojoTime = 0;
long mojoStart;
while ( current != null && !reactorBuildStatus.isHaltedOrBlacklisted( projectBuild.getProject() ) )
{
BuildLogItem builtLogItem =
concurrentBuildLogger.createBuildLogItem( projectBuild.getProject(), current );
final Schedule schedule = current.getSchedule();
mojoStart = System.currentTimeMillis();
buildExecutionPlanItem( current, phaseRecorder, schedule, reactorContext, projectBuild,
dependencyContext );
totalMojoTime += ( System.currentTimeMillis() - mojoStart );
current.setComplete();
builtLogItem.setComplete();
ExecutionPlanItem nextPlanItem = planItems.hasNext() ? planItems.next() : null;
if ( nextPlanItem != null && phaseRecorder.isDifferentPhase( nextPlanItem.getMojoExecution() ) )
{
final Schedule scheduleOfNext = nextPlanItem.getSchedule();
if ( scheduleOfNext == null || !scheduleOfNext.isParallel() )
{
waitForAppropriateUpstreamExecutionsToFinish( builtLogItem, nextPlanItem, projectBuild,
scheduleOfNext );
}
for ( ArtifactLink dependencyLink : dependencyLinks )
{
dependencyLink.resolveFromUpstream();
}
}
current = nextPlanItem;
}
final BuildSuccess summary = new BuildSuccess( projectBuild.getProject(), totalMojoTime ); // -
// waitingTime
reactorContext.getResult().addBuildSummary( summary );
eventCatapult.fire( ExecutionEvent.Type.ProjectSucceeded, projectBuild.getSession(), null );
}
catch ( Exception e )
{
builderCommon.handleBuildError( reactorContext, rootSession, projectBuild.getSession(),
projectBuild.getProject(), e, buildStartTime );
}
finally
{
if ( current != null )
{
executionPlan.forceAllComplete();
}
// muxer.setThisModuleComplete( projectBuild );
}
return null;
}
};
}
private void waitForAppropriateUpstreamExecutionsToFinish( BuildLogItem builtLogItem,
ExecutionPlanItem nextPlanItem,
ProjectSegment projectBuild, Schedule scheduleOfNext )
throws InterruptedException
{
for ( MavenProject upstreamProject : projectBuild.getImmediateUpstreamProjects() )
{
final MavenExecutionPlan upstreamPlan = executionPlans.get( upstreamProject );
final String nextPhase =
scheduleOfNext != null && scheduleOfNext.hasUpstreamPhaseDefined() ? scheduleOfNext.getUpstreamPhase()
: nextPlanItem.getLifecyclePhase();
final ExecutionPlanItem upstream = upstreamPlan.findLastInPhase( nextPhase );
if ( upstream != null )
{
long startWait = System.currentTimeMillis();
upstream.waitUntilDone();
builtLogItem.addWait( upstreamProject, upstream, startWait );
}
else if ( !upstreamPlan.containsPhase( nextPhase ) )
{
// Still a bit of a kludge; if we cannot connect in a sensible way to
// the upstream build plan we just revert to waiting for it all to
// complete. Real problem is per-mojo phase->lifecycle mapping
builtLogItem.addDependency( upstreamProject, "No phase tracking possible " );
upstreamPlan.waitUntilAllDone();
}
else
{
builtLogItem.addDependency( upstreamProject, "No schedule" );
}
}
}
private Collection<ArtifactLink> getUpstreamReactorDependencies( ProjectSegment projectBuild )
{
Collection<ArtifactLink> result = new ArrayList<ArtifactLink>();
for ( MavenProject upstreamProject : projectBuild.getTransitiveUpstreamProjects() )
{
Artifact upStreamArtifact = upstreamProject.getArtifact();
if ( upStreamArtifact != null )
{
Artifact dependencyArtifact = findDependency( projectBuild.getProject(), upStreamArtifact );
if ( dependencyArtifact != null )
{
result.add( new ArtifactLink( dependencyArtifact, upStreamArtifact ) );
}
}
Artifact upStreamTestScopedArtifact = findTestScopedArtifact( upstreamProject );
if ( upStreamTestScopedArtifact != null )
{
Artifact dependencyArtifact = findDependency( projectBuild.getProject(), upStreamArtifact );
if ( dependencyArtifact != null )
{
result.add( new ArtifactLink( dependencyArtifact, upStreamTestScopedArtifact ) );
}
}
}
return result;
}
private Artifact findTestScopedArtifact( MavenProject upstreamProject )
{
if ( upstreamProject == null )
{
return null;
}
List<Artifact> artifactList = upstreamProject.getAttachedArtifacts();
for ( Artifact artifact : artifactList )
{
if ( Artifact.SCOPE_TEST.equals( artifact.getScope() ) )
{
return artifact;
}
}
return null;
}
private static boolean isThreadLockedAndEmpty( Artifact artifact )
{
return artifact instanceof ThreadLockedArtifact && !( (ThreadLockedArtifact) artifact ).hasReal();
}
private static Artifact findDependency( MavenProject project, Artifact upStreamArtifact )
{
if ( upStreamArtifact == null || isThreadLockedAndEmpty( upStreamArtifact ) )
{
return null;
}
String key =
ArtifactUtils.key( upStreamArtifact.getGroupId(), upStreamArtifact.getArtifactId(),
upStreamArtifact.getVersion() );
final Set<Artifact> deps = project.getDependencyArtifacts();
for ( Artifact dep : deps )
{
String depKey = ArtifactUtils.key( dep.getGroupId(), dep.getArtifactId(), dep.getVersion() );
if ( key.equals( depKey ) )
{
return dep;
}
}
return null;
}
private void buildExecutionPlanItem( ExecutionPlanItem current, PhaseRecorder phaseRecorder, Schedule schedule,
ReactorContext reactorContext, ProjectSegment projectBuild,
DependencyContext dependencyContext )
throws LifecycleExecutionException
{
if ( schedule != null && schedule.isMojoSynchronized() )
{
synchronized ( current.getPlugin() )
{
buildExecutionPlanItem( reactorContext, current, projectBuild, dependencyContext, phaseRecorder );
}
}
else
{
buildExecutionPlanItem( reactorContext, current, projectBuild, dependencyContext, phaseRecorder );
}
}
private void buildExecutionPlanItem( ReactorContext reactorContext, ExecutionPlanItem node,
ProjectSegment projectBuild, DependencyContext dependencyContext,
PhaseRecorder phaseRecorder )
throws LifecycleExecutionException
{
MavenProject currentProject = projectBuild.getProject();
long buildStartTime = System.currentTimeMillis();
CurrentPhaseForThread.setPhase( node.getLifecyclePhase() );
MavenSession sessionForThisModule = projectBuild.getSession();
try
{
if ( reactorContext.getReactorBuildStatus().isHaltedOrBlacklisted( currentProject ) )
{
return;
}
BuilderCommon.attachToThread( currentProject );
mojoExecutor.execute( sessionForThisModule, node.getMojoExecution(), reactorContext.getProjectIndex(),
dependencyContext, phaseRecorder );
final BuildSuccess summary = new BuildSuccess( currentProject, System.currentTimeMillis() - buildStartTime );
reactorContext.getResult().addBuildSummary( summary );
}
finally
{
Thread.currentThread().setContextClassLoader( reactorContext.getOriginalContextClassLoader() );
}
}
public static boolean isWeaveMode( MavenExecutionRequest request )
{
return "true".equals( request.getUserProperties().getProperty( "maven3.weaveMode" ) );
}
public static void setWeaveMode( Properties properties )
{
properties.setProperty( "maven3.weaveMode", "true" );
}
static class ArtifactLink
{
private final Artifact artifactInThis;
private final Artifact upstream;
ArtifactLink( Artifact artifactInThis, Artifact upstream )
{
this.artifactInThis = artifactInThis;
this.upstream = upstream;
}
public void resolveFromUpstream()
{
artifactInThis.setFile( upstream.getFile() );
artifactInThis.setRepository( upstream.getRepository() );
artifactInThis.setResolved( true ); // Or maybe upstream.isResolved()....
}
}
}

View File

@ -1,77 +0,0 @@
package org.apache.maven.lifecycle.internal;
/*
* 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.util.Iterator;
import junit.framework.TestCase;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.lifecycle.MavenExecutionPlan;
import org.apache.maven.lifecycle.internal.builder.weave.BuildLogItem;
import org.apache.maven.lifecycle.internal.builder.weave.ConcurrentBuildLogger;
import org.apache.maven.lifecycle.internal.stub.ProjectDependencyGraphStub;
import org.apache.maven.project.MavenProject;
/**
* @author Kristian Rosenvold
*/
public class ConcurrentBuildLoggerTest
extends TestCase
{
@SuppressWarnings( "unused" )
public void testToGraph()
throws Exception
{
ConcurrentBuildLogger concurrentBuildLogger = new ConcurrentBuildLogger();
MojoDescriptorCreator mojoDescriptorCreator =
LifecycleExecutionPlanCalculatorTest.createMojoDescriptorCreator();
LifecycleExecutionPlanCalculator lifecycleExecutionPlanCalculator =
LifecycleExecutionPlanCalculatorTest.createExecutionPlaceCalculator( mojoDescriptorCreator );
MavenProject A = ProjectDependencyGraphStub.B;
MavenProject B = ProjectDependencyGraphStub.C;
final MavenSession session1 = ProjectDependencyGraphStub.getMavenSession( A );
final GoalTask goalTask1 = new GoalTask( "compiler:compile" );
final GoalTask goalTask2 = new GoalTask( "surefire:test" );
final TaskSegment taskSegment1 = new TaskSegment( false, goalTask1, goalTask2 );
MavenExecutionPlan executionPlan =
lifecycleExecutionPlanCalculator.calculateExecutionPlan( session1, A, taskSegment1.getTasks() );
MavenExecutionPlan executionPlan2 =
lifecycleExecutionPlanCalculator.calculateExecutionPlan( session1, B, taskSegment1.getTasks() );
final Iterator<ExecutionPlanItem> planItemIterator = executionPlan.iterator();
final BuildLogItem a1 = concurrentBuildLogger.createBuildLogItem( A, planItemIterator.next() );
final BuildLogItem a2 = concurrentBuildLogger.createBuildLogItem( A, planItemIterator.next() );
final Iterator<ExecutionPlanItem> plan2ItemIterator = executionPlan.iterator();
final BuildLogItem b1 = concurrentBuildLogger.createBuildLogItem( B, plan2ItemIterator.next() );
final BuildLogItem b2 = concurrentBuildLogger.createBuildLogItem( B, plan2ItemIterator.next() );
b1.addDependency( A, "Project dependency" );
final Iterator<ExecutionPlanItem> aPlan = executionPlan.iterator();
b1.addWait( A, aPlan.next(), System.currentTimeMillis() );
b2.addWait( A, aPlan.next(), System.currentTimeMillis() );
final String response = concurrentBuildLogger.toGraph();
assertTrue( response.contains( "digraph" ) );
}
}

View File

@ -1,142 +0,0 @@
package org.apache.maven.lifecycle.internal;
/*
* 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 junit.framework.TestCase;
import org.apache.maven.execution.DefaultMavenExecutionResult;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.lifecycle.LifecycleNotFoundException;
import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
import org.apache.maven.lifecycle.internal.builder.weave.WeaveBuilder;
import org.apache.maven.lifecycle.internal.stub.ExecutionEventCatapultStub;
import org.apache.maven.lifecycle.internal.stub.LifecycleExecutionPlanCalculatorStub;
import org.apache.maven.lifecycle.internal.stub.LifecycleTaskSegmentCalculatorStub;
import org.apache.maven.lifecycle.internal.stub.LoggerStub;
import org.apache.maven.lifecycle.internal.stub.MojoExecutorStub;
import org.apache.maven.lifecycle.internal.stub.ProjectDependencyGraphStub;
import org.apache.maven.plugin.InvalidPluginDescriptorException;
import org.apache.maven.plugin.MojoNotFoundException;
import org.apache.maven.plugin.PluginDescriptorParsingException;
import org.apache.maven.plugin.PluginNotFoundException;
import org.apache.maven.plugin.PluginResolutionException;
import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
import org.apache.maven.plugin.version.PluginVersionResolutionException;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author Kristian Rosenvold
*/
public class LifecycleWeaveBuilderTest
extends TestCase
{
/* public void testBuildProjectSynchronously()
throws Exception
{
final CompletionService<ProjectSegment> service = new CompletionServiceStub( true );
final ProjectBuildList projectBuildList = runWithCompletionService( service );
assertEquals( "Expect all tasks to be scheduled", projectBuildList.size(),
( (CompletionServiceStub) service ).size() );
}
*/
@SuppressWarnings( "unused" )
public void testBuildProjectThreaded()
throws Exception
{
ExecutorService executor = Executors.newFixedThreadPool( 10 );
ExecutorCompletionService<ProjectSegment> service = new ExecutorCompletionService<ProjectSegment>( executor );
runWithCompletionService( executor );
executor.shutdown();
}
@SuppressWarnings( "unused" )
public void testBuildProjectThreadedAggressive()
throws Exception
{
ExecutorService executor = Executors.newFixedThreadPool( 10 );
ExecutorCompletionService<ProjectSegment> service = new ExecutorCompletionService<ProjectSegment>( executor );
runWithCompletionService( executor );
executor.shutdown();
}
private ProjectBuildList runWithCompletionService( ExecutorService service )
throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
PluginVersionResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException,
ExecutionException, InterruptedException
{
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
try
{
BuildListCalculator buildListCalculator = new BuildListCalculator();
final MavenSession session = ProjectDependencyGraphStub.getMavenSession();
List<TaskSegment> taskSegments = getTaskSegmentCalculator().calculateTaskSegments( session );
ProjectBuildList projectBuildList = buildListCalculator.calculateProjectBuilds( session, taskSegments );
final MojoExecutorStub mojoExecutorStub = new MojoExecutorStub();
final WeaveBuilder builder = getWeaveBuilder( mojoExecutorStub );
final ReactorContext buildContext = createBuildContext( session );
ReactorBuildStatus reactorBuildStatus = new ReactorBuildStatus( session.getProjectDependencyGraph() );
builder.build( session, buildContext, projectBuildList, taskSegments, reactorBuildStatus );
LifecycleExecutionPlanCalculatorStub lifecycleExecutionPlanCalculatorStub =
new LifecycleExecutionPlanCalculatorStub();
final int expected = lifecycleExecutionPlanCalculatorStub.getNumberOfExceutions( projectBuildList );
assertEquals( "All executions should be scheduled", expected, mojoExecutorStub.executions.size() );
return projectBuildList;
}
finally
{
Thread.currentThread().setContextClassLoader( loader );
}
}
private static LifecycleTaskSegmentCalculator getTaskSegmentCalculator()
{
return new LifecycleTaskSegmentCalculatorStub();
}
private ReactorContext createBuildContext( MavenSession session )
{
MavenExecutionResult mavenExecutionResult = new DefaultMavenExecutionResult();
ReactorBuildStatus reactorBuildStatus = new ReactorBuildStatus( session.getProjectDependencyGraph() );
return new ReactorContext( mavenExecutionResult, null, null, reactorBuildStatus );
}
private WeaveBuilder getWeaveBuilder( MojoExecutor mojoExecutor )
{
final BuilderCommon builderCommon = getBuilderCommon();
final LoggerStub loggerStub = new LoggerStub();
return new WeaveBuilder( mojoExecutor, builderCommon, loggerStub, new ExecutionEventCatapultStub(), new LifecycleDebugLogger( loggerStub ) );
}
private BuilderCommon getBuilderCommon()
{
final LifecycleDebugLogger logger = new LifecycleDebugLogger( new LoggerStub() );
return new BuilderCommon( logger, new LifecycleExecutionPlanCalculatorStub(),
new LoggerStub() );
}
}

View File

@ -1087,14 +1087,7 @@ public class MavenCli
if ( threadConfiguration != null )
{
if ( threadConfiguration.contains( "W" ) )
{
request.setBuilderId( "weave" );
}
else
{
request.setBuilderId( "multithreaded" );
}
request.setBuilderId( "multithreaded" );
int threads =
threadConfiguration.contains( "C" ) ? Integer.valueOf( threadConfiguration.replace( "C", "" ) )