View Javadoc

1   package org.apache.maven.continuum.core.action;
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 org.apache.maven.continuum.ContinuumException;
23  import org.apache.maven.continuum.execution.maven.m2.SettingsConfigurationException;
24  import org.apache.maven.continuum.model.project.BuildDefinitionTemplate;
25  import org.apache.maven.continuum.model.project.Project;
26  import org.apache.maven.continuum.project.builder.ContinuumProjectBuilder;
27  import org.apache.maven.continuum.project.builder.ContinuumProjectBuilderException;
28  import org.apache.maven.continuum.project.builder.ContinuumProjectBuildingResult;
29  import org.apache.maven.continuum.project.builder.manager.ContinuumProjectBuilderManager;
30  import org.apache.maven.continuum.project.builder.manager.ContinuumProjectBuilderManagerException;
31  import org.apache.maven.continuum.utils.ContinuumUrlValidator;
32  import org.apache.maven.continuum.utils.URLUserInfo;
33  import org.apache.maven.settings.MavenSettingsBuilder;
34  import org.apache.maven.settings.Server;
35  import org.apache.maven.settings.Settings;
36  import org.codehaus.plexus.util.StringUtils;
37  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
38  
39  import java.io.IOException;
40  import java.net.MalformedURLException;
41  import java.net.URISyntaxException;
42  import java.net.URL;
43  import java.util.List;
44  import java.util.Map;
45  
46  /**
47   * Resolve the project url being passed in and gather authentication information
48   * if the url is so configured, then create the projects
49   * <p/>
50   * Supports:
51   * <p/>
52   * - standard maven-scm url
53   * - MungedUrl https://username:password@host
54   * - maven settings based, server = host and scm info set to username and password
55   *
56   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
57   * @version $Id: CreateProjectsFromMetadataAction.java 1391353 2012-09-28 07:50:49Z brett $
58   * @plexus.component role="org.codehaus.plexus.action.Action"
59   * role-hint="create-projects-from-metadata"
60   */
61  public class CreateProjectsFromMetadataAction
62      extends AbstractContinuumAction
63  {
64      /**
65       * Metadata url for adding projects.
66       */
67      private static final String KEY_URL = "url";
68  
69      private static final String KEY_PROJECT_BUILDER_ID = "builderId";
70  
71      private static final String KEY_PROJECT_BUILDING_RESULT = "projectBuildingResult";
72  
73      private static final String KEY_LOAD_RECURSIVE_PROJECTS = "loadRecursiveProjects";
74  
75      public static final String KEY_CHECKOUT_PROJECTS_IN_SINGLE_DIRECTORY = "checkoutProjectsInSingleDirectory";
76  
77      /**
78       * @plexus.requirement
79       */
80      private ContinuumProjectBuilderManager projectBuilderManager;
81  
82      /**
83       * @plexus.requirement
84       */
85      private MavenSettingsBuilder mavenSettingsBuilder;
86  
87      /**
88       * @plexus.requirement role-hint="continuumUrl"
89       */
90      private ContinuumUrlValidator urlValidator;
91  
92      public void execute( Map context )
93          throws ContinuumException, ContinuumProjectBuilderManagerException, ContinuumProjectBuilderException
94      {
95          String projectBuilderId = getProjectBuilderId( context );
96  
97          boolean loadRecursiveProjects = isLoadRecursiveProject( context );
98  
99          boolean checkoutProjectsInSingleDirectory = getBoolean( context, KEY_CHECKOUT_PROJECTS_IN_SINGLE_DIRECTORY );
100 
101         int projectGroupId = getProjectGroupId( context );
102 
103         String curl = getUrl( context );
104 
105         URL url;
106 
107         ContinuumProjectBuilder projectBuilder = projectBuilderManager.getProjectBuilder( projectBuilderId );
108 
109         ContinuumProjectBuildingResult result;
110 
111         try
112         {
113             BuildDefinitionTemplate buildDefinitionTemplate = getBuildDefinitionTemplate( context );
114             if ( buildDefinitionTemplate == null )
115             {
116                 buildDefinitionTemplate = projectBuilder.getDefaultBuildDefinitionTemplate();
117             }
118             if ( !curl.startsWith( "http" ) )
119             {
120                 url = new URL( curl );
121 
122                 result = projectBuilder.buildProjectsFromMetadata( url, null, null, loadRecursiveProjects,
123                                                                    buildDefinitionTemplate,
124                                                                    checkoutProjectsInSingleDirectory, projectGroupId );
125 
126             }
127             else
128             {
129                 url = new URL( curl );
130                 String username = null;
131                 String password = null;
132 
133                 try
134                 {
135                     Settings settings = getSettings();
136 
137                     getLogger().info( "checking for settings auth setup" );
138                     if ( settings != null && settings.getServer( url.getHost() ) != null )
139                     {
140                         getLogger().info( "found setting based auth setup, using" );
141                         Server server = settings.getServer( url.getHost() );
142 
143                         username = server.getUsername();
144                         password = server.getPassword();
145                     }
146                 }
147                 catch ( SettingsConfigurationException se )
148                 {
149                     getLogger().warn( "problem with settings file, disabling scm resolution of username and password" );
150                 }
151 
152                 if ( username == null )
153                 {
154                     URLUserInfo urlUserInfo = urlValidator.extractURLUserInfo( curl );
155                     username = urlUserInfo.getUsername();
156                     password = urlUserInfo.getPassword();
157                 }
158 
159                 if ( urlValidator.isValid( curl ) )
160                 {
161 
162                     result = projectBuilder.buildProjectsFromMetadata( url, username, password, loadRecursiveProjects,
163                                                                        buildDefinitionTemplate,
164                                                                        checkoutProjectsInSingleDirectory,
165                                                                        projectGroupId );
166 
167                 }
168                 else
169                 {
170                     result = new ContinuumProjectBuildingResult();
171                     getLogger().info( "Malformed URL (MungedHttpsURL is not valid): " + hidePasswordInUrl( curl ) );
172                     result.addError( ContinuumProjectBuildingResult.ERROR_MALFORMED_URL );
173                 }
174             }
175 
176             if ( result.getProjects() != null )
177             {
178                 String scmRootUrl = getScmRootUrl( result.getProjects() );
179 
180                 if ( scmRootUrl == null || scmRootUrl.equals( "" ) )
181                 {
182                     if ( curl.indexOf( "pom.xml" ) > 0 )
183                     {
184                         scmRootUrl = curl.substring( 0, curl.indexOf( "pom.xml" ) - 1 );
185                     }
186                     else
187                     {
188                         scmRootUrl = curl;
189                     }
190                 }
191 
192                 //setUrl( context, scmRootUrl );
193                 setProjectScmRootUrl( context, scmRootUrl );
194             }
195         }
196         catch ( MalformedURLException e )
197         {
198             getLogger().info( "Malformed URL: " + hidePasswordInUrl( curl ), e );
199             result = new ContinuumProjectBuildingResult();
200             result.addError( ContinuumProjectBuildingResult.ERROR_MALFORMED_URL );
201         }
202         catch ( URISyntaxException e )
203         {
204             getLogger().info( "Malformed URL: " + hidePasswordInUrl( curl ), e );
205             result = new ContinuumProjectBuildingResult();
206             result.addError( ContinuumProjectBuildingResult.ERROR_MALFORMED_URL );
207         }
208 
209         setProjectBuildingResult( context, result );
210     }
211 
212     private String hidePasswordInUrl( String url )
213     {
214         int indexAt = url.indexOf( "@" );
215 
216         if ( indexAt < 0 )
217         {
218             return url;
219         }
220 
221         String s = url.substring( 0, indexAt );
222 
223         int pos = s.lastIndexOf( ":" );
224 
225         return s.substring( 0, pos + 1 ) + "*****" + url.substring( indexAt );
226     }
227 
228     private Settings getSettings()
229         throws SettingsConfigurationException
230     {
231         try
232         {
233             return mavenSettingsBuilder.buildSettings();
234         }
235         catch ( IOException e )
236         {
237             throw new SettingsConfigurationException( "Error reading settings file", e );
238         }
239         catch ( XmlPullParserException e )
240         {
241             throw new SettingsConfigurationException( e.getMessage(), e.getDetail(), e.getLineNumber(),
242                                                       e.getColumnNumber() );
243         }
244     }
245 
246     private String getScmRootUrl( List<Project> projects )
247     {
248         String scmRootUrl = "";
249 
250         for ( Project project : projects )
251         {
252             String scmUrl = project.getScmUrl();
253 
254             scmRootUrl = getCommonPath( scmUrl, scmRootUrl );
255         }
256 
257         return scmRootUrl;
258     }
259 
260     private String getCommonPath( String path1, String path2 )
261     {
262         if ( path2 == null || path2.equals( "" ) )
263         {
264             return path1;
265         }
266         else
267         {
268             int indexDiff = StringUtils.differenceAt( path1, path2 );
269             String commonPath = path1.substring( 0, indexDiff );
270 
271             if ( commonPath.lastIndexOf( '/' ) != commonPath.length() - 1 && !( path1.contains( new String(
272                 commonPath + "/" ) ) || path2.contains( new String( commonPath + "/" ) ) ) )
273             {
274                 while ( commonPath.lastIndexOf( '/' ) != commonPath.length() - 1 )
275                 {
276                     commonPath = commonPath.substring( 0, commonPath.length() - 1 );
277                 }
278             }
279 
280             return commonPath;
281         }
282     }
283 
284     public ContinuumProjectBuilderManager getProjectBuilderManager()
285     {
286         return projectBuilderManager;
287     }
288 
289     public void setProjectBuilderManager( ContinuumProjectBuilderManager projectBuilderManager )
290     {
291         this.projectBuilderManager = projectBuilderManager;
292     }
293 
294     public MavenSettingsBuilder getMavenSettingsBuilder()
295     {
296         return mavenSettingsBuilder;
297     }
298 
299     public void setMavenSettingsBuilder( MavenSettingsBuilder mavenSettingsBuilder )
300     {
301         this.mavenSettingsBuilder = mavenSettingsBuilder;
302     }
303 
304     public ContinuumUrlValidator getUrlValidator()
305     {
306         return urlValidator;
307     }
308 
309     public void setUrlValidator( ContinuumUrlValidator urlValidator )
310     {
311         this.urlValidator = urlValidator;
312     }
313 
314     public static String getUrl( Map<String, Object> context )
315     {
316         return getString( context, KEY_URL );
317     }
318 
319     public static void setUrl( Map<String, Object> context, String url )
320     {
321         context.put( KEY_URL, url );
322     }
323 
324     public static String getProjectBuilderId( Map<String, Object> context )
325     {
326         return getString( context, KEY_PROJECT_BUILDER_ID );
327     }
328 
329     public static void setProjectBuilderId( Map<String, Object> context, String projectBuilderId )
330     {
331         context.put( KEY_PROJECT_BUILDER_ID, projectBuilderId );
332     }
333 
334     public static ContinuumProjectBuildingResult getProjectBuildingResult( Map<String, Object> context )
335     {
336         return (ContinuumProjectBuildingResult) getObject( context, KEY_PROJECT_BUILDING_RESULT );
337     }
338 
339     private static void setProjectBuildingResult( Map<String, Object> context, ContinuumProjectBuildingResult result )
340     {
341         context.put( KEY_PROJECT_BUILDING_RESULT, result );
342     }
343 
344     public static boolean isLoadRecursiveProject( Map<String, Object> context )
345     {
346         return getBoolean( context, KEY_LOAD_RECURSIVE_PROJECTS );
347     }
348 
349     public static void setLoadRecursiveProject( Map<String, Object> context, boolean loadRecursiveProject )
350     {
351         context.put( KEY_LOAD_RECURSIVE_PROJECTS, loadRecursiveProject );
352     }
353 
354     public static boolean isCheckoutProjectsInSingleDirectory( Map<String, Object> context )
355     {
356         return getBoolean( context, KEY_CHECKOUT_PROJECTS_IN_SINGLE_DIRECTORY );
357     }
358 
359     public static void setCheckoutProjectsInSingleDirectory( Map<String, Object> context,
360                                                              boolean checkoutProjectsInSingleDirectory )
361     {
362         context.put( KEY_CHECKOUT_PROJECTS_IN_SINGLE_DIRECTORY, checkoutProjectsInSingleDirectory );
363     }
364 }