View Javadoc

1   package org.apache.maven.shared.release.phase;
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.IOException;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.apache.maven.artifact.ArtifactUtils;
27  import org.apache.maven.model.Scm;
28  import org.apache.maven.project.MavenProject;
29  import org.apache.maven.scm.repository.ScmRepository;
30  import org.apache.maven.shared.release.ReleaseExecutionException;
31  import org.apache.maven.shared.release.ReleaseResult;
32  import org.apache.maven.shared.release.config.ReleaseDescriptor;
33  import org.apache.maven.shared.release.scm.ScmTranslator;
34  import org.apache.maven.shared.release.util.ReleaseUtil;
35  import org.codehaus.plexus.util.StringUtils;
36  import org.jdom.Element;
37  import org.jdom.Namespace;
38  
39  /**
40   * Rewrite POMs for release.
41   *
42   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
43   */
44  public class RewritePomsForReleasePhase
45      extends AbstractRewritePomsPhase
46  {
47      /**
48       * SCM URL translators mapped by provider name.
49       */
50      private Map<String, ScmTranslator> scmTranslators;
51  
52      protected void transformScm( MavenProject project, Element rootElement, Namespace namespace,
53                                   ReleaseDescriptor releaseDescriptor, String projectId, ScmRepository scmRepository,
54                                   ReleaseResult result, String commonBasedir )
55      throws ReleaseExecutionException
56      {
57          // If SCM is null in original model, it is inherited, no mods needed
58          if ( project.getScm() != null )
59          {
60              Element scmRoot = rootElement.getChild( "scm", namespace );
61              if ( scmRoot != null )
62              {
63                  Scm scm = buildScm( project );
64                  releaseDescriptor.mapOriginalScmInfo( projectId, scm );
65  
66                  try
67                  {
68                      translateScm( project, releaseDescriptor, scmRoot, namespace, scmRepository, result, commonBasedir );
69                  }
70                  catch ( IOException e )
71                  {
72                      throw new ReleaseExecutionException( e.getMessage(), e );
73                  }
74              }
75              else
76              {
77                  releaseDescriptor.mapOriginalScmInfo( projectId, null );
78  
79                  MavenProject parent = project.getParent();
80                  if ( parent != null )
81                  {
82                      // If the SCM element is not present, only add it if the parent was not mapped (ie, it's external to
83                      // the release process and so has not been modified, so the values will not be correct on the tag),
84                      String parentId = ArtifactUtils.versionlessKey( parent.getGroupId(), parent.getArtifactId() );
85                      if ( !releaseDescriptor.getOriginalScmInfo().containsKey( parentId ) )
86                      {
87                          // we need to add it, since it has changed from the inherited value
88                          scmRoot = new Element( "scm" );
89                          scmRoot.addContent( "\n  " );
90  
91                          try
92                          {
93                              if ( translateScm( project, releaseDescriptor, scmRoot, namespace, scmRepository, result,
94                                                 commonBasedir ) )
95                              {
96                                  rootElement.addContent( "\n  " ).addContent( scmRoot ).addContent( "\n" );
97                              }
98                          }
99                          catch ( IOException e )
100                         {
101                             throw new ReleaseExecutionException( e.getMessage(), e );
102                         }
103                     }
104                 }
105             }
106         }
107     }
108 
109     private boolean translateScm( MavenProject project, ReleaseDescriptor releaseDescriptor, Element scmRoot,
110                                   Namespace namespace, ScmRepository scmRepository, ReleaseResult relResult,
111                                   String commonBasedir ) throws IOException
112     {
113         ScmTranslator translator = scmTranslators.get( scmRepository.getProvider() );
114         boolean result = false;
115         if ( translator != null )
116         {
117             Scm scm = project.getOriginalModel().getScm();
118             if ( scm == null )
119             {
120                 scm = project.getScm();
121             }
122 
123             String tag = releaseDescriptor.getScmReleaseLabel();
124             String tagBase = releaseDescriptor.getScmTagBase();
125 
126             // TODO: svn utils should take care of prepending this
127             if ( tagBase != null )
128             {
129                 tagBase = "scm:svn:" + tagBase;
130             }
131 
132             String workingDirectory =
133                 ReleaseUtil.isSymlink( project.getBasedir() ) ? project.getBasedir().getCanonicalPath()
134                                 : project.getBasedir().getAbsolutePath();
135             int count =
136                 ReleaseUtil.getBaseWorkingDirectoryParentCount( commonBasedir, workingDirectory );
137             if ( scm.getConnection() != null )
138             {
139                 String rootUrl = ReleaseUtil.realignScmUrl( count, scm.getConnection() );
140 
141                 String subDirectoryTag = scm.getConnection().substring( rootUrl.length() );
142                 if ( !subDirectoryTag.startsWith( "/" ) )
143                 {
144                     subDirectoryTag = "/" + subDirectoryTag;
145                 }
146 
147                 String scmConnectionTag = tagBase;
148                 if ( scmConnectionTag != null )
149                 {
150                     String trunkUrl = scm.getDeveloperConnection();
151                     if ( trunkUrl == null )
152                     {
153                         trunkUrl = scm.getConnection();
154                     }
155                     scmConnectionTag = this.translateUrlPath( trunkUrl, tagBase, scm.getConnection() );
156                 }
157                 String value =
158                     translator.translateTagUrl( scm.getConnection(), tag + subDirectoryTag, scmConnectionTag );
159 
160                 if ( !value.equals( scm.getConnection() ) )
161                 {
162                     rewriteElement( "connection", value, scmRoot, namespace );
163                     result = true;
164                 }
165             }
166 
167             if ( scm.getDeveloperConnection() != null )
168             {
169                 String rootUrl = ReleaseUtil.realignScmUrl( count, scm.getDeveloperConnection() );
170 
171                 String subDirectoryTag = scm.getDeveloperConnection().substring( rootUrl.length() );
172                 if ( !subDirectoryTag.startsWith( "/" ) )
173                 {
174                     subDirectoryTag = "/" + subDirectoryTag;
175                 }
176 
177                 String value =
178                     translator.translateTagUrl( scm.getDeveloperConnection(), tag + subDirectoryTag, tagBase );
179 
180                 if ( !value.equals( scm.getDeveloperConnection() ) )
181                 {
182                     rewriteElement( "developerConnection", value, scmRoot, namespace );
183                     result = true;
184                 }
185             }
186 
187             if ( scm.getUrl() != null )
188             {
189                 String rootUrl = ReleaseUtil.realignScmUrl( count, scm.getUrl() );
190 
191                 String subDirectoryTag = scm.getUrl().substring( rootUrl.length() );
192                 if ( !subDirectoryTag.startsWith( "/" ) )
193                 {
194                     subDirectoryTag = "/" + subDirectoryTag;
195                 }
196 
197                 String tagScmUrl = tagBase;
198                 if ( tagScmUrl != null )
199                 {
200                     String trunkUrl = scm.getDeveloperConnection();
201                     if ( trunkUrl == null )
202                     {
203                         trunkUrl = scm.getConnection();
204                     }
205                     tagScmUrl = this.translateUrlPath( trunkUrl, tagBase, scm.getUrl() );
206                 }
207                 // use original tag base without protocol
208                 String value = translator.translateTagUrl( scm.getUrl(), tag + subDirectoryTag, tagScmUrl );
209                 if ( !value.equals( scm.getUrl() ) )
210                 {
211                     rewriteElement( "url", value, scmRoot, namespace );
212                     result = true;
213                 }
214             }
215 
216             if ( tag != null )
217             {
218                 String value = translator.resolveTag( tag );
219                 if ( value != null && !value.equals( scm.getTag() ) )
220                 {
221                     rewriteElement( "tag", value, scmRoot, namespace );
222                     result = true;
223                 }
224             }
225         }
226         else
227         {
228             String message = "No SCM translator found - skipping rewrite";
229 
230             relResult.appendDebug( message );
231 
232             getLogger().debug( message );
233         }
234         return result;
235     }
236 
237     protected Map<String, String> getOriginalVersionMap( ReleaseDescriptor releaseDescriptor,
238                                                          List<MavenProject> reactorProjects, boolean simulate )
239     {
240         return releaseDescriptor.getOriginalVersions( reactorProjects );
241     }
242 
243     @SuppressWarnings( "unchecked" )
244     protected Map<String,String> getNextVersionMap( ReleaseDescriptor releaseDescriptor )
245     {
246         return releaseDescriptor.getReleaseVersions();
247     }
248 
249     protected String getResolvedSnapshotVersion( String artifactVersionlessKey,
250                                                  Map<String, Map<String, String>> resolvedSnapshotsMap )
251     {
252         Map<String, String> versionsMap = resolvedSnapshotsMap.get( artifactVersionlessKey );
253 
254         if ( versionsMap != null )
255         {
256             return versionsMap.get( ReleaseDescriptor.RELEASE_KEY );
257         }
258         else
259         {
260             return null;
261         }
262     }
263 
264     /**
265      * Determines the relative path from trunk to tag, and adds this relative path
266      * to the url.
267      *
268      * @param trunkPath - The trunk url
269      * @param tagPath   - The tag base
270      * @param urlPath   - scm.url or scm.connection
271      * @return The url path for the tag.
272      */
273     private String translateUrlPath( String trunkPath, String tagPath, String urlPath )
274     {
275         trunkPath = trunkPath.trim();
276         tagPath = tagPath.trim();
277         //Strip the slash at the end if one is present
278         if ( trunkPath.endsWith( "/" ) )
279         {
280             trunkPath = trunkPath.substring( 0, trunkPath.length() - 1 );
281         }
282         if ( tagPath.endsWith( "/" ) )
283         {
284             tagPath = tagPath.substring( 0, tagPath.length() - 1 );
285         }
286         char[] tagPathChars = trunkPath.toCharArray();
287         char[] trunkPathChars = tagPath.toCharArray();
288         // Find the common path between trunk and tags
289         int i = 0;
290         while ( ( i < tagPathChars.length ) && ( i < trunkPathChars.length ) && tagPathChars[i] == trunkPathChars[i] )
291         {
292             ++i;
293         }
294         // If there is nothing common between trunk and tags, or the relative
295         // path does not exist in the url, then just return the tag.
296         if ( i == 0 || urlPath.indexOf( trunkPath.substring( i ) ) < 0 )
297         {
298             return tagPath;
299         }
300         else
301         {
302             return StringUtils.replace( urlPath, trunkPath.substring( i ), tagPath.substring( i ) );
303         }
304     }
305 }