View Javadoc
1   package org.apache.maven.plugin.assembly.utils;
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.artifact.Artifact;
23  import org.apache.maven.execution.MavenSession;
24  import org.apache.maven.plugin.assembly.AssemblerConfigurationSource;
25  import org.apache.maven.plugin.assembly.format.AssemblyFormattingException;
26  import org.apache.maven.plugin.assembly.model.Assembly;
27  import org.apache.maven.project.MavenProject;
28  import org.codehaus.plexus.interpolation.fixed.FixedStringSearchInterpolator;
29  import org.codehaus.plexus.interpolation.fixed.PrefixedObjectValueSource;
30  import org.codehaus.plexus.interpolation.fixed.PrefixedPropertiesValueSource;
31  import org.codehaus.plexus.interpolation.fixed.PropertiesBasedValueSource;
32  import org.codehaus.plexus.util.StringUtils;
33  
34  import javax.annotation.Nonnull;
35  import javax.annotation.Nullable;
36  import java.util.ArrayList;
37  import java.util.Arrays;
38  import java.util.List;
39  import java.util.ListIterator;
40  import java.util.Properties;
41  
42  /**
43   * @version $Id: AssemblyFormatUtils.java 1641677 2014-11-25 19:44:07Z krosenvold $
44   */
45  public final class AssemblyFormatUtils
46  {
47  
48      private AssemblyFormatUtils()
49      {
50      }
51  
52      /**
53       * Get the full name of the distribution artifact
54       *
55       * @param assembly the assembly
56       * @return the distribution name
57       */
58      public static String getDistributionName( final Assembly assembly, final AssemblerConfigurationSource configSource )
59      {
60          final String finalName = configSource.getFinalName();
61          final boolean appendAssemblyId = configSource.isAssemblyIdAppended();
62          final String classifier = configSource.getClassifier();
63  
64          String distributionName = finalName;
65          if ( appendAssemblyId )
66          {
67              if ( !StringUtils.isEmpty( assembly.getId() ) )
68              {
69                  distributionName = finalName + "-" + assembly.getId();
70              }
71          }
72          else if ( classifier != null )
73          {
74              distributionName = finalName + "-" + classifier;
75          }
76  
77          return distributionName;
78      }
79  
80  
81      @Nonnull
82      public static FixedStringSearchInterpolator finalNameInterpolator( String finalName )
83      {
84          final Properties specialExpressionOverrides = new Properties();
85  
86          if ( finalName != null )
87          {
88              specialExpressionOverrides.setProperty( "finalName", finalName );
89              specialExpressionOverrides.setProperty( "build.finalName", finalName );
90          }
91          else
92          {
93              return FixedStringSearchInterpolator.empty();
94          }
95  
96          return FixedStringSearchInterpolator.create( new PropertiesBasedValueSource( specialExpressionOverrides ) );
97      }
98  
99      @Nonnull
100     public static FixedStringSearchInterpolator moduleProjectInterpolator( final MavenProject moduleProject )
101     {
102         if ( moduleProject != null )
103         {
104             return FixedStringSearchInterpolator.createWithPermittedNulls(
105                 new PrefixedObjectValueSource( "module.", moduleProject ),
106                 new PrefixedPropertiesValueSource( "module.properties.", moduleProject.getProperties() ),
107                 moduleProject.getArtifact() != null
108                     ? new PrefixedObjectValueSource( "module.", moduleProject.getArtifact() )
109                     : null );
110         }
111         else
112         {
113             return FixedStringSearchInterpolator.empty();
114         }
115 
116     }
117 
118     public static FixedStringSearchInterpolator moduleArtifactInterpolator( Artifact moduleArtifact )
119     {
120         if ( moduleArtifact != null )
121         {
122             // CHECKSTYLE_OFF: LineLength
123             return FixedStringSearchInterpolator.create( new PrefixedObjectValueSource( "module.", moduleArtifact ),
124                                                          new PrefixedObjectValueSource( "module.",
125                                                                                         moduleArtifact.getArtifactHandler() ),
126                                                          new PrefixedObjectValueSource( "module.handler.",
127                                                                                         moduleArtifact.getArtifactHandler() ) );
128             // CHECKSTYLE_ON: LineLength
129         }
130         else
131         {
132             return FixedStringSearchInterpolator.empty();
133         }
134 
135     }
136 
137     @Nonnull
138     public static FixedStringSearchInterpolator artifactProjectInterpolator( final MavenProject artifactProject )
139     {
140         if ( artifactProject != null )
141         {
142             PrefixedObjectValueSource vs = null;
143             if ( artifactProject.getArtifact() != null )
144             {
145                 vs = new PrefixedObjectValueSource( "artifact.", artifactProject.getArtifact() );
146             }
147 
148             return FixedStringSearchInterpolator.createWithPermittedNulls(
149                 new PrefixedObjectValueSource( "artifact.", artifactProject ),
150                 new PrefixedPropertiesValueSource( "artifact.properties.", artifactProject.getProperties() ), vs );
151 
152 
153         }
154         else
155         {
156             return FixedStringSearchInterpolator.empty();
157         }
158 
159 
160     }
161 
162     @Nonnull
163     public static FixedStringSearchInterpolator artifactInterpolator( @Nonnull final Artifact artifact )
164     {
165         return FixedStringSearchInterpolator.create( new PrefixedObjectValueSource( "artifact.", artifact ),
166                                                      new PrefixedObjectValueSource( "artifact.",
167                                                                                     artifact.getArtifactHandler() ),
168                                                      new PrefixedObjectValueSource( "artifact.handler.",
169                                                                                     artifact.getArtifactHandler() ) );
170     }
171 
172 
173     @Nonnull
174     public static FixedStringSearchInterpolator classifierRules( final Artifact artifact )
175     {
176         final Properties specialRules = new Properties();
177 
178         final String classifier = ProjectUtils.getClassifier( artifact );
179         if ( classifier != null )
180         {
181             specialRules.setProperty( "dashClassifier?", "-" + classifier );
182             specialRules.setProperty( "dashClassifier", "-" + classifier );
183         }
184         else
185         {
186             specialRules.setProperty( "dashClassifier?", "" );
187             specialRules.setProperty( "dashClassifier", "" );
188         }
189 
190         return FixedStringSearchInterpolator.create( new PropertiesBasedValueSource( specialRules ) );
191     }
192 
193 
194     /**
195      * ORDER OF INTERPOLATION PRECEDENCE:
196      * <ol>
197      * <li>Support for special expressions, like ${finalName} (use the assembly plugin configuration not the build
198      * config)</li>
199      * <li>prefixed with "module." if moduleProject is non-null
200      * <ol>
201      * <li>MavenProject instance for module being assembled</li>
202      * </ol>
203      * </li>
204      * <li>prefixed with "artifact." if artifactProject is non-null
205      * <ol>
206      * <li>MavenProject instance for artifact</li>
207      * </ol>
208      * </li>
209      * <li>user-defined properties from the command line</li>
210      * <li>prefixed with "pom." or "project.", or no prefix at all
211      * <ol>
212      * <li>MavenProject instance from current build</li>
213      * </ol>
214      * </li>
215      * <li>properties from main project</li>
216      * <li>system properties, from the MavenSession instance (to support IDEs)</li>
217      * <li>environment variables.</li>
218      * </ol>
219      */
220     public static String getOutputDirectory( final String output, final MavenProject artifactProject,
221                                              final String finalName, final AssemblerConfigurationSource configSource )
222         throws AssemblyFormattingException
223     {
224         return getOutputDirectory( output, finalName, configSource, moduleProjectInterpolator( null ),
225                                    artifactProjectInterpolator( artifactProject ) );
226     }
227 
228 
229     private static FixedStringSearchInterpolator executionPropertiesInterpolator(
230         AssemblerConfigurationSource configSource )
231     {
232         MavenSession session;
233 
234         if ( configSource != null )
235         {
236             session = configSource.getMavenSession();
237 
238             if ( session != null )
239             {
240                 Properties userProperties = session.getExecutionProperties(); // this is added twice....
241 
242                 if ( userProperties != null )
243                 {
244                     return FixedStringSearchInterpolator.create( new PropertiesBasedValueSource( userProperties ) );
245                 }
246             }
247         }
248         return FixedStringSearchInterpolator.empty();
249     }
250 
251     private static FixedStringSearchInterpolator mainProjectOnlyInterpolator( MavenProject mainProject )
252     {
253         if ( mainProject != null )
254         {
255             // 5
256             return FixedStringSearchInterpolator.create(
257                 new org.codehaus.plexus.interpolation.fixed.PrefixedObjectValueSource(
258                     InterpolationConstants.PROJECT_PREFIXES, mainProject, true ) );
259         }
260         else
261         {
262             return FixedStringSearchInterpolator.empty();
263         }
264     }
265 
266 
267     /**
268      * ORDER OF INTERPOLATION PRECEDENCE:
269      * <ol>
270      * <li>prefixed with "module.", if moduleProject != null
271      * <ol>
272      * <li>Artifact instance for module, if moduleArtifact != null</li>
273      * <li>ArtifactHandler instance for module, if moduleArtifact != null</li>
274      * <li>MavenProject instance for module</li>
275      * </ol>
276      * </li>
277      * <li>prefixed with "artifact."
278      * <ol>
279      * <li>Artifact instance</li>
280      * <li>ArtifactHandler instance for artifact</li>
281      * <li>MavenProject instance for artifact</li>
282      * </ol>
283      * </li>
284      * <li>prefixed with "pom." or "project."
285      * <ol>
286      * <li>MavenProject instance from current build</li>
287      * </ol>
288      * </li>
289      * <li>no prefix, using main project instance
290      * <ol>
291      * <li>MavenProject instance from current build</li>
292      * </ol>
293      * </li>
294      * <li>Support for special expressions, like ${dashClassifier?}</li>
295      * <li>user-defined properties from the command line</li>
296      * <li>properties from main project</li>
297      * <li>system properties, from the MavenSession instance (to support IDEs)</li>
298      * <li>environment variables.</li>
299      * </ol>
300      */
301 
302 
303     @Nonnull
304     public static String fixRelativeRefs( @Nonnull String src )
305     {
306         String value = src;
307 
308         String[] separators = { "/", "\\" };
309 
310         String finalSep = null;
311         for ( String sep : separators )
312         {
313             if ( value.endsWith( sep ) )
314             {
315                 finalSep = sep;
316             }
317 
318             if ( value.contains( "." + sep ) )
319             {
320                 List<String> parts = new ArrayList<String>();
321                 parts.addAll( Arrays.asList( value.split( sep.replace( "\\", "\\\\" ) ) ) );
322 
323                 for ( ListIterator<String> it = parts.listIterator(); it.hasNext(); )
324                 {
325                     String part = it.next();
326                     if ( ".".equals( part ) )
327                     {
328                         it.remove();
329                     }
330                     else if ( "..".equals( part ) )
331                     {
332                         it.remove();
333                         if ( it.hasPrevious() )
334                         {
335                             it.previous();
336                             it.remove();
337                         }
338                     }
339                 }
340 
341                 value = StringUtils.join( parts.iterator(), sep );
342             }
343         }
344 
345         if ( finalSep != null && value.length() > 0 && !value.endsWith( finalSep ) )
346         {
347             value += finalSep;
348         }
349 
350         return value;
351     }
352 
353 
354     /**
355      * ORDER OF INTERPOLATION PRECEDENCE:
356      * <ol>
357      * <li>prefixed with "module.", if moduleProject != null
358      * <ol>
359      * <li>Artifact instance for module, if moduleArtifact != null</li>
360      * <li>ArtifactHandler instance for module, if moduleArtifact != null</li>
361      * <li>MavenProject instance for module</li>
362      * </ol>
363      * </li>
364      * <li>prefixed with "artifact."
365      * <ol>
366      * <li>Artifact instance</li>
367      * <li>ArtifactHandler instance for artifact</li>
368      * <li>MavenProject instance for artifact</li>
369      * </ol>
370      * </li>
371      * <li>prefixed with "pom." or "project."
372      * <ol>
373      * <li>MavenProject instance from current build</li>
374      * </ol>
375      * </li>
376      * <li>no prefix, using main project instance
377      * <ol>
378      * <li>MavenProject instance from current build</li>
379      * </ol>
380      * </li>
381      * <li>Support for special expressions, like ${dashClassifier?}</li>
382      * <li>user-defined properties from the command line</li>
383      * <li>properties from main project</li>
384      * <li>system properties, from the MavenSession instance (to support IDEs)</li>
385      * <li>environment variables.</li>
386      * </ol>
387      */
388     public static String evaluateFileNameMapping( final String expression, @Nonnull final Artifact artifact,
389                                                   @Nullable final MavenProject mainProject,
390                                                   @Nullable final Artifact moduleArtifact,
391                                                   @Nonnull final AssemblerConfigurationSource configSource,
392                                                   FixedStringSearchInterpolator moduleProjectInterpolator,
393                                                   FixedStringSearchInterpolator artifactProjectInterpolator )
394         throws AssemblyFormattingException
395     {
396         String value = expression;
397 
398         final FixedStringSearchInterpolator interpolator =
399             FixedStringSearchInterpolator.create( moduleArtifactInterpolator( moduleArtifact ),
400                                                   moduleProjectInterpolator, artifactInterpolator( artifact ),
401                                                   artifactProjectInterpolator,
402                                                   mainProjectOnlyInterpolator( mainProject ),
403                                                   classifierRules( artifact ),
404                                                   executionPropertiesInterpolator( configSource ),
405                                                   configSource.getMainProjectInterpolator(),
406                                                   configSource.getCommandLinePropsInterpolator(),
407                                                   configSource.getEnvInterpolator() );
408 
409         value = interpolator.interpolate( value );
410 
411         value = StringUtils.replace( value, "//", "/" );
412         value = StringUtils.replace( value, "\\\\", "\\" );
413         value = fixRelativeRefs( value );
414 
415         return value;
416     }
417 
418     /**
419      * ORDER OF INTERPOLATION PRECEDENCE:
420      * <ol>
421      * <li>Support for special expressions, like ${finalName} (use the assembly plugin configuration not the build
422      * config)</li>
423      * <li>prefixed with "module." if moduleProject is non-null
424      * <ol>
425      * <li>MavenProject instance for module being assembled</li>
426      * </ol>
427      * </li>
428      * <li>prefixed with "artifact." if artifactProject is non-null
429      * <ol>
430      * <li>MavenProject instance for artifact</li>
431      * </ol>
432      * </li>
433      * <li>user-defined properties from the command line</li>
434      * <li>prefixed with "pom." or "project.", or no prefix at all
435      * <ol>
436      * <li>MavenProject instance from current build</li>
437      * </ol>
438      * </li>
439      * <li>properties from main project</li>
440      * <li>system properties, from the MavenSession instance (to support IDEs)</li>
441      * <li>environment variables.</li>
442      * </ol>
443      */
444     public static String getOutputDirectory( final String output, final String finalName,
445                                              final AssemblerConfigurationSource configSource,
446                                              FixedStringSearchInterpolator moduleProjectIntrpolator,
447                                              FixedStringSearchInterpolator artifactProjectInterpolator )
448         throws AssemblyFormattingException
449     {
450         String value = output;
451         if ( value == null )
452         {
453             value = "";
454         }
455 
456         final FixedStringSearchInterpolator interpolator =
457             FixedStringSearchInterpolator.create( finalNameInterpolator( finalName ), moduleProjectIntrpolator,
458                                                   artifactProjectInterpolator,
459                                                   executionPropertiesInterpolator( configSource ),
460                                                   configSource.getMainProjectInterpolator(),
461                                                   configSource.getCommandLinePropsInterpolator(),
462                                                   configSource.getEnvInterpolator() );
463 
464         value = interpolator.interpolate( value );
465 
466         if ( ( value.length() > 0 ) && !value.endsWith( "/" ) && !value.endsWith( "\\" ) )
467         {
468             value += "/";
469         }
470 
471         if ( ( value.length() > 0 ) && ( value.startsWith( "/" ) || value.startsWith( "\\" ) ) )
472         {
473             value = value.substring( 1 );
474         }
475 
476         value = StringUtils.replace( value, "//", "/" );
477         value = StringUtils.replace( value, "\\\\", "\\" );
478         value = fixRelativeRefs( value );
479 
480         return value;
481     }
482 
483 }