View Javadoc

1   package org.apache.maven.continuum.project.builder.maven;
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.io.File;
23  import java.net.MalformedURLException;
24  import java.net.URL;
25  import java.util.ArrayList;
26  import java.util.List;
27  
28  import org.apache.continuum.dao.LocalRepositoryDao;
29  import org.apache.continuum.dao.ScheduleDao;
30  import org.apache.continuum.model.repository.LocalRepository;
31  import org.apache.maven.continuum.builddefinition.BuildDefinitionService;
32  import org.apache.maven.continuum.builddefinition.BuildDefinitionServiceException;
33  import org.apache.maven.continuum.configuration.ConfigurationService;
34  import org.apache.maven.continuum.execution.maven.m2.MavenBuilderHelper;
35  import org.apache.maven.continuum.execution.maven.m2.MavenTwoBuildExecutor;
36  import org.apache.maven.continuum.model.project.BuildDefinition;
37  import org.apache.maven.continuum.model.project.BuildDefinitionTemplate;
38  import org.apache.maven.continuum.model.project.Project;
39  import org.apache.maven.continuum.model.project.ProjectGroup;
40  import org.apache.maven.continuum.model.project.Schedule;
41  import org.apache.maven.continuum.project.builder.AbstractContinuumProjectBuilder;
42  import org.apache.maven.continuum.project.builder.ContinuumProjectBuilder;
43  import org.apache.maven.continuum.project.builder.ContinuumProjectBuilderException;
44  import org.apache.maven.continuum.project.builder.ContinuumProjectBuildingResult;
45  import org.apache.maven.continuum.store.ContinuumStoreException;
46  import org.apache.maven.project.MavenProject;
47  import org.codehaus.plexus.util.StringUtils;
48  
49  /**
50   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
51   * @version $Id: MavenTwoContinuumProjectBuilder.java 760328 2009-03-31 04:55:00Z evenisse $
52   * @plexus.component role="org.apache.maven.continuum.project.builder.ContinuumProjectBuilder" role-hint="maven-two-builder"
53   */
54  public class MavenTwoContinuumProjectBuilder
55      extends AbstractContinuumProjectBuilder
56      implements ContinuumProjectBuilder
57  {
58      public static final String ID = "maven-two-builder";
59  
60      private static final String POM_PART = "/pom.xml";
61  
62      /**
63       * @plexus.requirement
64       */
65      private LocalRepositoryDao localRepositoryDao;
66  
67      /**
68       * @plexus.requirement
69       */
70      private MavenBuilderHelper builderHelper;
71  
72      /**
73       * @plexus.requirement
74       */
75      private ScheduleDao scheduleDao;
76  
77      /**
78       * @plexus.requirement
79       */
80      private BuildDefinitionService buildDefinitionService;
81  
82      /**
83       * @plexus.configuration
84       */
85      private List<String> excludedPackagingTypes = new ArrayList<String>();
86  
87      // ----------------------------------------------------------------------
88      // AbstractContinuumProjectBuilder Implementation
89      // ----------------------------------------------------------------------
90      public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password )
91          throws ContinuumProjectBuilderException
92      {
93          return buildProjectsFromMetadata( url, username, password, true );
94      }
95  
96      public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password,
97                                                                       boolean loadRecursiveProjects )
98          throws ContinuumProjectBuilderException
99      {
100         try
101         {
102             return buildProjectsFromMetadata( url, username, password, loadRecursiveProjects,
103                                               buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate() );
104         }
105         catch ( BuildDefinitionServiceException e )
106         {
107             throw new ContinuumProjectBuilderException( e.getMessage(), e );
108         }
109     }
110 
111     public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password,
112                                                                      boolean loadRecursiveProjects,
113                                                                      BuildDefinitionTemplate buildDefinitionTemplate )
114         throws ContinuumProjectBuilderException
115     {
116         // ----------------------------------------------------------------------
117         // We need to roll the project data into a file so that we can use it
118         // ----------------------------------------------------------------------
119 
120         ContinuumProjectBuildingResult result = new ContinuumProjectBuildingResult();
121 
122         try
123         {
124             readModules( url, result, true, username, password, null, loadRecursiveProjects, buildDefinitionTemplate );
125         }
126         catch ( BuildDefinitionServiceException e )
127         {
128             throw new ContinuumProjectBuilderException( e.getMessage(), e );
129         }
130         return result;
131     }
132 
133     // ----------------------------------------------------------------------
134     //
135     // ----------------------------------------------------------------------
136 
137     private void readModules( URL url, ContinuumProjectBuildingResult result, boolean groupPom, String username,
138                               String password, String scmUrl, boolean loadRecursiveProjects,
139                               BuildDefinitionTemplate buildDefinitionTemplate )
140         throws ContinuumProjectBuilderException, BuildDefinitionServiceException
141     {
142 
143         MavenProject mavenProject;
144 
145         File pomFile = null;
146 
147         try
148         {
149             pomFile = createMetadataFile( result, url, username, password );
150 
151             if ( result.hasErrors() )
152             {
153                 return;
154             }
155 
156             mavenProject = builderHelper.getMavenProject( result, pomFile );
157 
158             if ( result.hasErrors() )
159             {
160                 return;
161             }
162         }
163         finally
164         {
165             if ( pomFile != null && pomFile.exists() )
166             {
167                 pomFile.delete();
168             }
169         }
170         log.debug( "groupPom " + groupPom );
171         if ( groupPom )
172         {
173             ProjectGroup projectGroup = buildProjectGroup( mavenProject, result );
174 
175             // project groups have the top lvl build definition which is the default build defintion for the sub
176             // projects
177             log.debug( "projectGroup != null" + ( projectGroup != null ) );
178             if ( projectGroup != null )
179             {
180                 List<BuildDefinition> buildDefinitions =
181                     getBuildDefinitions( buildDefinitionTemplate, loadRecursiveProjects );
182                 boolean defaultSetted = false;
183                 for ( BuildDefinition buildDefinition : buildDefinitions )
184                 {
185                     if ( !defaultSetted && buildDefinition.isDefaultForProject() )
186                     {
187                         buildDefinition.setDefaultForProject( true );
188                         defaultSetted = true;
189                     }
190                     buildDefinition = buildDefinitionService.addBuildDefinition(
191                         buildDefinitionService.cloneBuildDefinition( buildDefinition ) );
192                     //CONTINUUM-1296
193                     String defaultGoal = mavenProject.getBuild().getDefaultGoal();
194                     if ( StringUtils.isNotEmpty( defaultGoal ) )
195                     {
196                         buildDefinition.setGoals( defaultGoal );
197                     }
198                     if ( buildDefinition.getSchedule() == null )
199                     {
200                         try
201                         {
202                             Schedule schedule =
203                                 scheduleDao.getScheduleByName( ConfigurationService.DEFAULT_SCHEDULE_NAME );
204 
205                             buildDefinition.setSchedule( schedule );
206                         }
207                         catch ( ContinuumStoreException e )
208                         {
209                             log.warn( "Can't get default schedule.", e );
210                         }
211                     }
212                     // jdo complains that Collections.singletonList(bd) is a second class object and fails.
213                     //ArrayList arrayList = new ArrayList();
214 
215                     //arrayList.add( buildDefinition );
216 
217                     projectGroup.addBuildDefinition( buildDefinition );
218                     // .setBuildDefinitions( arrayList );
219                 }
220                 result.addProjectGroup( projectGroup );
221             }
222         }
223 
224         if ( !excludedPackagingTypes.contains( mavenProject.getPackaging() ) )
225         {
226             Project continuumProject = new Project();
227 
228             /*
229             We are interested in having the scm username and password being passed into this method be taken into
230             account during project mapping so make sure we set it to the continuum project instance.
231              */
232             if ( username != null && StringUtils.isNotEmpty( username ) )
233             {
234                 continuumProject.setScmUsername( username );
235 
236                 if ( password != null && StringUtils.isNotEmpty( password ) )
237                 {
238                     continuumProject.setScmPassword( password );
239                 }
240             }
241 
242             builderHelper.mapMavenProjectToContinuumProject( result, mavenProject, continuumProject, groupPom );
243 
244             if ( result.hasErrors() )
245             {
246                 log.info(
247                     "Error adding project: Unknown error mapping project " + url + ": " + result.getErrorsAsString() );
248                 return;
249             }
250 
251             // Rewrite scmurl from the one found in added project due to a bug in scm url resolution
252             // for projects that doesn't have module name != artifactId
253             if ( StringUtils.isNotEmpty( scmUrl ) )
254             {
255                 continuumProject.setScmUrl( scmUrl );
256             }
257             else
258             {
259                 scmUrl = continuumProject.getScmUrl();
260             }
261 
262             if ( !"HEAD".equals( mavenProject.getScm().getTag() ) )
263             {
264                 continuumProject.setScmTag( mavenProject.getScm().getTag() );
265             }
266             result.addProject( continuumProject, MavenTwoBuildExecutor.ID );
267         }
268 
269         List<String> modules = mavenProject.getModules();
270 
271         String prefix = url.toExternalForm();
272 
273         String suffix = "";
274 
275         int i = prefix.indexOf( '?' );
276 
277         int lastSlash;
278 
279         if ( i != -1 )
280         {
281             suffix = prefix.substring( i );
282 
283             lastSlash = prefix.lastIndexOf( "/", i );
284         }
285         else
286         {
287             lastSlash = prefix.lastIndexOf( "/" );
288         }
289 
290         prefix = prefix.substring( 0, lastSlash );
291         if ( loadRecursiveProjects )
292         {
293             for ( String module : modules )
294             {
295                 if ( StringUtils.isNotEmpty( module ) )
296                 {
297                     String urlString = prefix + "/" + module + POM_PART + suffix;
298 
299                     URL moduleUrl;
300 
301                     try
302                     {
303                         moduleUrl = new URL( urlString );
304                     }
305                     catch ( MalformedURLException e )
306                     {
307                         log.debug( "Error adding project module: Malformed URL " + urlString, e );
308                         result.addError( ContinuumProjectBuildingResult.ERROR_MALFORMED_URL, urlString );
309                         continue;
310                     }
311 
312                     String moduleScmUrl;
313                     if ( scmUrl.endsWith( "/" ) )
314                     {
315                         moduleScmUrl = scmUrl + module;
316                     }
317                     else
318                     {
319                         moduleScmUrl = scmUrl + "/" + module;
320                     }
321                     // we are in recursive loading mode
322                     readModules( moduleUrl, result, false, username, password, moduleScmUrl, true,
323                                  buildDefinitionTemplate );
324                 }
325             }
326         }
327     }
328 
329     private List<BuildDefinition> getBuildDefinitions( BuildDefinitionTemplate template, boolean loadRecursiveProjects )
330         throws ContinuumProjectBuilderException, BuildDefinitionServiceException
331     {
332         List<BuildDefinition> buildDefinitions = new ArrayList<BuildDefinition>();
333         for ( BuildDefinition buildDefinition : (List<BuildDefinition>) template.getBuildDefinitions() )
334         {
335             // due to CONTINUUM-1207 CONTINUUM-1436 user can do what they want with arguments
336             // we must remove if exists --non-recursive or -N
337             if ( !loadRecursiveProjects )
338             {
339                 if ( StringUtils.isEmpty( buildDefinition.getArguments() ) )
340                 {
341                     // strange for a mvn build 
342                     log.info( "build definition '" + buildDefinition.getId() + "' has empty args" );
343                 }
344                 else
345                 {
346                     String arguments = buildDefinition.getArguments().replace( "--non-recursive", "" );
347                     arguments = arguments.replace( "-N", "" );
348                     buildDefinition.setArguments( arguments );
349                 }
350             }
351             buildDefinition.setTemplate( false );
352             buildDefinitions.add( buildDefinition );
353         }
354         return buildDefinitions;
355 
356     }
357 
358     private ProjectGroup buildProjectGroup( MavenProject mavenProject, ContinuumProjectBuildingResult result )
359     {
360         ProjectGroup projectGroup = new ProjectGroup();
361 
362         // ----------------------------------------------------------------------
363         // Group id
364         // ----------------------------------------------------------------------
365 
366         if ( StringUtils.isEmpty( mavenProject.getGroupId() ) )
367         {
368             result.addError( ContinuumProjectBuildingResult.ERROR_MISSING_GROUPID );
369 
370             return null;
371         }
372 
373         projectGroup.setGroupId( mavenProject.getGroupId() );
374 
375         // ----------------------------------------------------------------------
376         // Name
377         // ----------------------------------------------------------------------
378 
379         String name = mavenProject.getName();
380 
381         if ( StringUtils.isEmpty( name ) )
382         {
383             name = mavenProject.getGroupId();
384         }
385 
386         projectGroup.setName( name );
387 
388         // ----------------------------------------------------------------------
389         // Description
390         // ----------------------------------------------------------------------
391 
392         projectGroup.setDescription( mavenProject.getDescription() );
393 
394         // ----------------------------------------------------------------------
395         // Local Repository
396         // ----------------------------------------------------------------------
397 
398         try
399         {
400             LocalRepository repository = localRepositoryDao.getLocalRepositoryByName( "DEFAULT" );
401 
402             projectGroup.setLocalRepository( repository );
403         }
404         catch ( ContinuumStoreException e )
405         {
406             log.warn( "Can't get default repository.", e );
407         }
408 
409         return projectGroup;
410     }
411 
412 
413     public BuildDefinitionTemplate getDefaultBuildDefinitionTemplate()
414         throws ContinuumProjectBuilderException
415     {
416         try
417         {
418             return buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate();
419         }
420         catch ( BuildDefinitionServiceException e )
421         {
422             throw new ContinuumProjectBuilderException( e.getMessage(), e );
423         }
424     }
425 
426 }