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