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