View Javadoc
1   package com.soebes.maven.extensions.incremental;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.nio.file.Path;
23  import java.util.List;
24  import java.util.concurrent.ExecutionException;
25  
26  import javax.inject.Inject;
27  import javax.inject.Named;
28  import javax.inject.Singleton;
29  
30  import org.apache.commons.lang.StringUtils;
31  import org.apache.maven.execution.MavenSession;
32  import org.apache.maven.lifecycle.internal.LifecycleModuleBuilder;
33  import org.apache.maven.lifecycle.internal.ProjectBuildList;
34  import org.apache.maven.lifecycle.internal.ReactorBuildStatus;
35  import org.apache.maven.lifecycle.internal.ReactorContext;
36  import org.apache.maven.lifecycle.internal.TaskSegment;
37  import org.apache.maven.lifecycle.internal.builder.Builder;
38  import org.apache.maven.project.MavenProject;
39  import org.apache.maven.scm.ScmException;
40  import org.apache.maven.scm.ScmFile;
41  import org.apache.maven.scm.ScmFileSet;
42  import org.apache.maven.scm.command.status.StatusScmResult;
43  import org.apache.maven.scm.manager.NoSuchScmProviderException;
44  import org.apache.maven.scm.manager.ScmManager;
45  import org.apache.maven.scm.repository.ScmRepository;
46  import org.apache.maven.scm.repository.ScmRepositoryException;
47  import org.slf4j.Logger;
48  import org.slf4j.LoggerFactory;
49  
50  /**
51   * Incremental Module Builder behaviour.
52   * 
53   * @author Karl Heinz Marbaise <khmarbaise@apache.org>
54   */
55  @Singleton
56  @Named( "incremental" )
57  public class IncrementalModuleBuilder
58      implements Builder
59  {
60      private final Logger LOGGER = LoggerFactory.getLogger( getClass() );
61  
62      private final LifecycleModuleBuilder lifecycleModuleBuilder;
63  
64      @Inject
65      private ScmManager scmManager;
66  
67      @Inject
68      public IncrementalModuleBuilder( LifecycleModuleBuilder lifecycleModuleBuilder )
69      {
70          LOGGER.info( " ------------------------------------" );
71          LOGGER.info( " Maven Incremental Module Builder" );
72          LOGGER.info( " Version: {}", IncrementalModuleBuilderVersion.getVersion() );
73          LOGGER.debug( "     SHA: {}", IncrementalModuleBuilderVersion.getRevision() );
74          LOGGER.info( " ------------------------------------" );
75          this.lifecycleModuleBuilder = lifecycleModuleBuilder;
76      }
77  
78      private boolean havingScmDeveloperConnection( MavenSession session )
79      {
80          if ( session.getTopLevelProject().getScm() == null )
81          {
82              LOGGER.error( "The incremental module builder needs a correct scm configuration." );
83              return false;
84          }
85  
86          if ( StringUtils.isEmpty( session.getTopLevelProject().getScm().getDeveloperConnection() ) )
87          {
88              LOGGER.error( "The incremental module builder needs the scm developerConnection to work properly." );
89              return false;
90          }
91  
92          return true;
93      }
94  
95      @Override
96      public void build( final MavenSession session, final ReactorContext reactorContext, ProjectBuildList projectBuilds,
97                         final List<TaskSegment> taskSegments, ReactorBuildStatus reactorBuildStatus )
98          throws ExecutionException, InterruptedException
99      {
100 
101         // Think about this?
102         if ( !session.getCurrentProject().isExecutionRoot() )
103         {
104             LOGGER.info( "Not executing in root." );
105         }
106 
107         Path projectRootpath = session.getTopLevelProject().getBasedir().toPath();
108 
109         if ( !havingScmDeveloperConnection( session ) )
110         {
111             LOGGER.warn( "There is no scm developer connection configured." );
112             LOGGER.warn( "So we can't estimate which modules have changed." );
113             return;
114         }
115 
116         // TODO: Make more separation of concerns..(Extract the SCM Code from
117         // here?
118         ScmRepository repository = null;
119         try
120         {
121             // Assumption: top level project contains the SCM entry.
122             repository = scmManager.makeScmRepository( session.getTopLevelProject().getScm().getDeveloperConnection() );
123         }
124         catch ( ScmRepositoryException | NoSuchScmProviderException e )
125         {
126             LOGGER.error( "Failure during makeScmRepository", e );
127             return;
128         }
129 
130         StatusScmResult result = null;
131         try
132         {
133             result = scmManager.status( repository, new ScmFileSet( session.getTopLevelProject().getBasedir() ) );
134         }
135         catch ( ScmException e )
136         {
137             LOGGER.error( "Failure during status", e );
138             return;
139         }
140 
141         List<ScmFile> changedFiles = result.getChangedFiles();
142         if ( changedFiles.isEmpty() )
143         {
144             LOGGER.info( " Nothing has been changed." );
145         }
146         else
147         {
148 
149             for ( ScmFile scmFile : changedFiles )
150             {
151                 LOGGER.info( " Changed file: " + scmFile.getPath() + " " + scmFile.getStatus() );
152             }
153 
154             ModuleCalculator mc =
155                 new ModuleCalculator( session.getProjectDependencyGraph().getSortedProjects(), changedFiles );
156             List<MavenProject> calculateChangedModules = mc.calculateChangedModules( projectRootpath );
157 
158             for ( MavenProject mavenProject : calculateChangedModules )
159             {
160                 LOGGER.info( "Changed Project: " + mavenProject.getId() );
161             }
162 
163             IncrementalModuleBuilderImpl incrementalModuleBuilderImpl =
164                 new IncrementalModuleBuilderImpl( calculateChangedModules, lifecycleModuleBuilder, session,
165                                                   reactorContext, taskSegments );
166 
167             // Really build only changed modules.
168             incrementalModuleBuilderImpl.build();
169         }
170     }
171 
172 }