View Javadoc
1   package org.apache.maven.shared.release.util;
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.io.IOException;
24  import java.io.Reader;
25  import java.nio.file.Path;
26  import java.nio.file.Paths;
27  import java.util.Arrays;
28  import java.util.List;
29  
30  import org.apache.commons.lang3.StringUtils;
31  import org.apache.maven.model.Model;
32  import org.apache.maven.project.MavenProject;
33  import org.apache.maven.shared.release.ReleaseExecutionException;
34  import org.apache.maven.shared.release.config.ReleaseDescriptor;
35  import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder;
36  import org.apache.maven.shared.release.config.ReleaseUtils;
37  import org.codehaus.plexus.interpolation.InterpolationException;
38  import org.codehaus.plexus.interpolation.MapBasedValueSource;
39  import org.codehaus.plexus.interpolation.ObjectBasedValueSource;
40  import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
41  import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
42  import org.codehaus.plexus.interpolation.StringSearchInterpolator;
43  import org.codehaus.plexus.util.IOUtil;
44  import org.codehaus.plexus.util.ReaderFactory;
45  
46  /**
47   * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
48   */
49  public class ReleaseUtil
50  {
51      @SuppressWarnings( "checkstyle:constantname" )
52      public static final String RELEASE_POMv4 = "release-pom.xml";
53  
54      @SuppressWarnings( "checkstyle:constantname" )
55      public static final String POMv4 = "pom.xml";
56  
57      /**
58       * The line separator to use.
59       */
60      public static final String LS = System.getProperty( "line.separator" );
61  
62      private ReleaseUtil()
63      {
64          // noop
65      }
66  
67      public static MavenProject getRootProject( List<MavenProject> reactorProjects )
68      {
69          MavenProject project = reactorProjects.get( 0 );
70          for ( MavenProject currentProject : reactorProjects )
71          {
72              if ( currentProject.isExecutionRoot() )
73              {
74                  project = currentProject;
75                  break;
76              }
77          }
78  
79          return project;
80      }
81  
82      public static File getStandardPom( MavenProject project )
83      {
84          if ( project == null )
85          {
86              return null;
87          }
88  
89          File pom = project.getFile();
90  
91          if ( pom == null )
92          {
93              return null;
94          }
95  
96          File releasePom = getReleasePom( project );
97          if ( pom.equals( releasePom ) )
98          {
99              pom = new File( pom.getParent(), POMv4 );
100         }
101 
102         return pom;
103     }
104 
105     public static File getReleasePom( MavenProject project )
106     {
107         if ( project == null )
108         {
109             return null;
110         }
111 
112         File pom = project.getFile();
113 
114         if ( pom == null )
115         {
116             return null;
117         }
118 
119         return new File( pom.getParent(), RELEASE_POMv4 );
120     }
121 
122     /**
123      * Gets the string contents of the specified XML file. Note: In contrast to an XML processor, the line separators in
124      * the returned string will be normalized to use the platform's native line separator. This is basically to save
125      * another normalization step when writing the string contents back to an XML file.
126      *
127      * @param file The path to the XML file to read in, must not be <code>null</code>.
128      * @return The string contents of the XML file.
129      * @throws IOException If the file could not be opened/read.
130      */
131     public static String readXmlFile( File file )
132         throws IOException
133     {
134         return readXmlFile( file, LS );
135     }
136 
137     public static String readXmlFile( File file, String ls )
138         throws IOException
139     {
140         try ( Reader reader = ReaderFactory.newXmlReader( file ) )
141         {
142             return normalizeLineEndings( IOUtil.toString( reader ), ls );
143         }
144     }
145 
146     /**
147      * Normalizes the line separators in the specified string.
148      *
149      * @param text The string to normalize, may be <code>null</code>.
150      * @param separator The line separator to use for normalization, typically "\n" or "\r\n", must not be
151      *            <code>null</code>.
152      * @return The input string with normalized line separators or <code>null</code> if the string was <code>null</code>
153      *         .
154      */
155     public static String normalizeLineEndings( String text, String separator )
156     {
157         String norm = text;
158         if ( text != null )
159         {
160             norm = text.replaceAll( "(\r\n)|(\n)|(\r)", separator );
161         }
162         return norm;
163     }
164 
165     public static ReleaseDescriptor createBasedirAlignedReleaseDescriptor( ReleaseDescriptor releaseDescriptor,
166                                                                            List<MavenProject> reactorProjects )
167         throws ReleaseExecutionException
168     {
169         int parentLevels = Paths.get( releaseDescriptor.getPomFileName() ).getNameCount() - 1;
170 
171         String url = releaseDescriptor.getScmSourceUrl();
172         url = realignScmUrl( parentLevels, url );
173 
174         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
175         builder.setWorkingDirectory( releaseDescriptor.getWorkingDirectory() );
176         builder.setScmSourceUrl( url );
177 
178         return ReleaseUtils.buildReleaseDescriptor( builder );
179     }
180 
181     public static int getBaseWorkingDirectoryParentCount( final Path baseDirectory, final Path workingDirectory )
182     {
183         return Math.max( 0, workingDirectory.normalize().getNameCount() - baseDirectory.normalize().getNameCount() );
184     }
185 
186     public static String realignScmUrl( int parentLevels, String url )
187     {
188         if ( !StringUtils.isEmpty( url ) )
189         {
190             // normalize
191             url = url.replaceAll( "/\\./", "/" ).replaceAll( "/\\.$", "" ).
192                             replaceAll( "/[^/]+/\\.\\./", "/" ).replaceAll( "/[^/]+/\\.\\.$", "" );
193 
194             int index = url.length();
195             String suffix = "";
196             if ( url.endsWith( "/" ) )
197             {
198                 index--;
199                 suffix = "/";
200             }
201 
202             for ( int i = 0; i < parentLevels && index > 0; i++ )
203             {
204                 index = url.lastIndexOf( '/', index - 1 );
205             }
206 
207             if ( index > 0 )
208             {
209                 url = url.substring( 0, index ) + suffix;
210             }
211 
212         }
213         return url;
214     }
215 
216     public static String interpolate( String value, Model model )
217         throws ReleaseExecutionException
218     {
219         if ( value != null && value.contains( "${" ) )
220         {
221             StringSearchInterpolator interpolator = new StringSearchInterpolator();
222             List<String> pomPrefixes = Arrays.asList( "pom.", "project." );
223             interpolator.addValueSource( new PrefixedObjectValueSource( pomPrefixes, model, false ) );
224             interpolator.addValueSource( new MapBasedValueSource( model.getProperties() ) );
225             interpolator.addValueSource( new ObjectBasedValueSource( model ) );
226             try
227             {
228                 value = interpolator.interpolate( value, new PrefixAwareRecursionInterceptor( pomPrefixes ) );
229             }
230             catch ( InterpolationException e )
231             {
232                 throw new ReleaseExecutionException(
233                                                      "Failed to interpolate " + value + " for project " + model.getId(),
234                                                      e );
235             }
236         }
237         return value;
238     }
239 }