1   package org.apache.maven.plugins.assembly.utils;
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collections;
25  import java.util.List;
26  import java.util.ListIterator;
27  import java.util.Properties;
28  
29  import javax.annotation.Nonnull;
30  import javax.annotation.Nullable;
31  
32  import org.apache.maven.artifact.Artifact;
33  import org.apache.maven.execution.MavenSession;
34  import org.apache.maven.plugins.assembly.AssemblerConfigurationSource;
35  import org.apache.maven.plugins.assembly.format.AssemblyFormattingException;
36  import org.apache.maven.plugins.assembly.model.Assembly;
37  import org.apache.maven.project.MavenProject;
38  import org.apache.maven.shared.utils.Os;
39  import org.codehaus.plexus.interpolation.fixed.FixedStringSearchInterpolator;
40  import org.codehaus.plexus.interpolation.fixed.MapBasedValueSource;
41  import org.codehaus.plexus.interpolation.fixed.PrefixedObjectValueSource;
42  import org.codehaus.plexus.interpolation.fixed.PrefixedPropertiesValueSource;
43  import org.codehaus.plexus.interpolation.fixed.PropertiesBasedValueSource;
44  import org.codehaus.plexus.logging.Logger;
45  import org.codehaus.plexus.util.StringUtils;
46  
47  
48  
49  
50  public final class AssemblyFormatUtils
51  {
52  
53      private AssemblyFormatUtils()
54      {
55      }
56  
57      
58  
59  
60  
61  
62  
63      public static String getDistributionName( final Assembly assembly, final AssemblerConfigurationSource configSource )
64      {
65          final String finalName = configSource.getFinalName();
66          final boolean appendAssemblyId = configSource.isAssemblyIdAppended();
67  
68          String distributionName = finalName;
69          if ( appendAssemblyId )
70          {
71              distributionName = finalName + "-" + assembly.getId();
72          }
73  
74          return distributionName;
75      }
76  
77  
78      @Nonnull
79      public static FixedStringSearchInterpolator finalNameInterpolator( String finalName )
80      {
81          final Properties specialExpressionOverrides = new Properties();
82  
83          if ( finalName != null )
84          {
85              specialExpressionOverrides.setProperty( "finalName", finalName );
86              specialExpressionOverrides.setProperty( "build.finalName", finalName );
87          }
88          else
89          {
90              return FixedStringSearchInterpolator.empty();
91          }
92  
93          return FixedStringSearchInterpolator.create( new PropertiesBasedValueSource( specialExpressionOverrides ) );
94      }
95  
96      @Nonnull
97      public static FixedStringSearchInterpolator moduleProjectInterpolator( final MavenProject moduleProject )
98      {
99          if ( moduleProject != null )
100         {
101             return FixedStringSearchInterpolator.createWithPermittedNulls(
102                 new PrefixedObjectValueSource( "module.", moduleProject ),
103                 new PrefixedPropertiesValueSource( "module.properties.", moduleProject.getProperties() ),
104                 moduleProject.getArtifact() != null
105                     ? new PrefixedObjectValueSource( "module.", moduleProject.getArtifact() )
106                     : null );
107         }
108         else
109         {
110             return FixedStringSearchInterpolator.empty();
111         }
112 
113     }
114 
115     public static FixedStringSearchInterpolator moduleArtifactInterpolator( Artifact moduleArtifact )
116     {
117         if ( moduleArtifact != null )
118         {
119             final String groupIdPath = moduleArtifact.getGroupId().replace( '.', '/' );
120 
121             return FixedStringSearchInterpolator.create(
122                      new MapBasedValueSource( Collections.singletonMap( "module.groupIdPath", groupIdPath ) ),
123                      new PrefixedObjectValueSource( "module.", moduleArtifact ),
124                      new PrefixedObjectValueSource( "module.", moduleArtifact.getArtifactHandler() ),
125                      new PrefixedObjectValueSource( "module.handler.", moduleArtifact.getArtifactHandler() ) );
126         }
127         else
128         {
129             return FixedStringSearchInterpolator.empty();
130         }
131 
132     }
133 
134     @Nonnull
135     public static FixedStringSearchInterpolator artifactProjectInterpolator( final MavenProject artifactProject )
136     {
137         if ( artifactProject != null )
138         {
139             PrefixedObjectValueSource vs = null;
140             if ( artifactProject.getArtifact() != null )
141             {
142                 vs = new PrefixedObjectValueSource( "artifact.", artifactProject.getArtifact() );
143             }
144 
145             final String groupIdPath = artifactProject.getGroupId().replace( '.', '/' );
146 
147             return FixedStringSearchInterpolator.createWithPermittedNulls(
148                 new MapBasedValueSource( Collections.singletonMap( "artifact.groupIdPath", groupIdPath ) ),
149                 new PrefixedObjectValueSource( "artifact.", artifactProject ),
150                 new PrefixedPropertiesValueSource( "artifact.properties.", artifactProject.getProperties() ), vs );
151         }
152         else
153         {
154             return FixedStringSearchInterpolator.empty();
155         }
156     }
157 
158     @Nonnull
159     public static FixedStringSearchInterpolator artifactInterpolator( @Nonnull final Artifact artifact )
160     {
161         final String groupIdPath = artifact.getGroupId().replace( '.', '/' );
162 
163         return FixedStringSearchInterpolator.create( 
164                          new MapBasedValueSource( Collections.singletonMap( "artifact.groupIdPath", groupIdPath ) ),
165                          new PrefixedObjectValueSource( "artifact.", artifact ),
166                          new PrefixedObjectValueSource( "artifact.", artifact.getArtifactHandler() ),
167                          new PrefixedObjectValueSource( "artifact.handler.", artifact.getArtifactHandler() ) );
168     }
169 
170 
171     @Nonnull
172     public static FixedStringSearchInterpolator classifierRules( final Artifact artifact )
173     {
174         final Properties specialRules = new Properties();
175 
176         final String classifier = ProjectUtils.getClassifier( artifact );
177         if ( classifier != null )
178         {
179             specialRules.setProperty( "dashClassifier?", "-" + classifier );
180             specialRules.setProperty( "dashClassifier", "-" + classifier );
181         }
182         else
183         {
184             specialRules.setProperty( "dashClassifier?", "" );
185             specialRules.setProperty( "dashClassifier", "" );
186         }
187 
188         return FixedStringSearchInterpolator.create( new PropertiesBasedValueSource( specialRules ) );
189     }
190 
191 
192     
193 
194 
195 
196 
197 
198 
199 
200 
201 
202 
203 
204 
205 
206 
207 
208 
209 
210 
211 
212 
213 
214 
215 
216 
217 
218     public static String getOutputDirectory( final String output, final MavenProject artifactProject,
219                                              final String finalName, final AssemblerConfigurationSource configSource )
220         throws AssemblyFormattingException
221     {
222         return getOutputDirectory( output, finalName, configSource, moduleProjectInterpolator( null ),
223                                    artifactProjectInterpolator( artifactProject ) );
224     }
225 
226 
227     private static FixedStringSearchInterpolator executionPropertiesInterpolator(
228         AssemblerConfigurationSource configSource )
229     {
230         MavenSession session;
231 
232         if ( configSource != null )
233         {
234             session = configSource.getMavenSession();
235 
236             if ( session != null )
237             {
238                 Properties userProperties = session.getExecutionProperties(); 
239 
240                 if ( userProperties != null )
241                 {
242                     return FixedStringSearchInterpolator.create( new PropertiesBasedValueSource( userProperties ) );
243                 }
244             }
245         }
246         return FixedStringSearchInterpolator.empty();
247     }
248 
249     private static FixedStringSearchInterpolator mainProjectOnlyInterpolator( MavenProject mainProject )
250     {
251         if ( mainProject != null )
252         {
253             
254             return FixedStringSearchInterpolator.create(
255                 new org.codehaus.plexus.interpolation.fixed.PrefixedObjectValueSource(
256                     InterpolationConstants.PROJECT_PREFIXES, mainProject, true ) );
257         }
258         else
259         {
260             return FixedStringSearchInterpolator.empty();
261         }
262     }
263 
264 
265     
266 
267 
268 
269 
270 
271 
272 
273 
274 
275 
276 
277 
278 
279 
280 
281 
282 
283 
284 
285 
286 
287 
288 
289 
290 
291 
292 
293 
294 
295 
296 
297 
298 
299 
300 
301     @Nonnull
302     public static String fixRelativeRefs( @Nonnull String src )
303     {
304         String value = src;
305 
306         String[] separators = { "/", "\\" };
307 
308         String finalSep = null;
309         for ( String sep : separators )
310         {
311             if ( value.endsWith( sep ) )
312             {
313                 finalSep = sep;
314             }
315 
316             if ( value.contains( "." + sep ) )
317             {
318                 List<String> parts = new ArrayList<>();
319                 parts.addAll( Arrays.asList( value.split( sep.replace( "\\", "\\\\" ) ) ) );
320 
321                 for ( ListIterator<String> it = parts.listIterator(); it.hasNext(); )
322                 {
323                     String part = it.next();
324                     if ( ".".equals( part ) )
325                     {
326                         it.remove();
327                     }
328                     else if ( "..".equals( part ) )
329                     {
330                         it.remove();
331                         if ( it.hasPrevious() )
332                         {
333                             it.previous();
334                             it.remove();
335                         }
336                     }
337                 }
338 
339                 value = StringUtils.join( parts.iterator(), sep );
340             }
341         }
342 
343         if ( finalSep != null && value.length() > 0 && !value.endsWith( finalSep ) )
344         {
345             value += finalSep;
346         }
347 
348         return value;
349     }
350 
351 
352     
353 
354 
355 
356 
357 
358 
359 
360 
361 
362 
363 
364 
365 
366 
367 
368 
369 
370 
371 
372 
373 
374 
375 
376 
377 
378 
379 
380 
381 
382 
383 
384 
385 
386     public static String evaluateFileNameMapping( final String expression, @Nonnull final Artifact artifact,
387                                                   @Nullable final MavenProject mainProject,
388                                                   @Nullable final Artifact moduleArtifact,
389                                                   @Nonnull final AssemblerConfigurationSource configSource,
390                                                   FixedStringSearchInterpolator moduleProjectInterpolator,
391                                                   FixedStringSearchInterpolator artifactProjectInterpolator )
392         throws AssemblyFormattingException
393     {
394         String value = expression;
395 
396         final FixedStringSearchInterpolator interpolator =
397             FixedStringSearchInterpolator.create( moduleArtifactInterpolator( moduleArtifact ),
398                                                   moduleProjectInterpolator, artifactInterpolator( artifact ),
399                                                   artifactProjectInterpolator,
400                                                   mainProjectOnlyInterpolator( mainProject ),
401                                                   classifierRules( artifact ),
402                                                   executionPropertiesInterpolator( configSource ),
403                                                   configSource.getMainProjectInterpolator(),
404                                                   configSource.getCommandLinePropsInterpolator(),
405                                                   configSource.getEnvInterpolator() );
406 
407         value = interpolator.interpolate( value );
408 
409         value = StringUtils.replace( value, "//", "/" );
410         value = StringUtils.replace( value, "\\\\", "\\" );
411         value = fixRelativeRefs( value );
412 
413         return value;
414     }
415 
416     
417 
418 
419 
420 
421 
422 
423 
424 
425 
426 
427 
428 
429 
430 
431 
432 
433 
434 
435 
436 
437 
438 
439 
440 
441 
442     public static String getOutputDirectory( final String output, final String finalName,
443                                              final AssemblerConfigurationSource configSource,
444                                              FixedStringSearchInterpolator moduleProjectIntrpolator,
445                                              FixedStringSearchInterpolator artifactProjectInterpolator )
446         throws AssemblyFormattingException
447     {
448         String value = output;
449         if ( value == null )
450         {
451             value = "";
452         }
453 
454         final FixedStringSearchInterpolator interpolator =
455             FixedStringSearchInterpolator.create( finalNameInterpolator( finalName ), moduleProjectIntrpolator,
456                                                   artifactProjectInterpolator,
457                                                   executionPropertiesInterpolator( configSource ),
458                                                   configSource.getMainProjectInterpolator(),
459                                                   configSource.getCommandLinePropsInterpolator(),
460                                                   configSource.getEnvInterpolator() );
461 
462         value = interpolator.interpolate( value );
463 
464         if ( ( value.length() > 0 ) && !value.endsWith( "/" ) && !value.endsWith( "\\" ) )
465         {
466             value += "/";
467         }
468 
469         if ( ( value.length() > 0 ) && ( value.startsWith( "/" ) || value.startsWith( "\\" ) ) )
470         {
471             value = value.substring( 1 );
472         }
473 
474         value = StringUtils.replace( value, "//", "/" );
475         value = StringUtils.replace( value, "\\\\", "\\" );
476         value = fixRelativeRefs( value );
477 
478         return value;
479     }
480 
481     public static void warnForPlatformSpecifics( Logger logger, String destDirectory )
482     {
483         if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
484         {
485             if ( isUnixRootReference( destDirectory ) )
486             {
487                 logger.error( "OS=Windows and the assembly descriptor contains a *nix-specific root-relative reference"
488                                   + " (starting with slash): " + destDirectory );
489             }
490             else if ( isWindowsPath( destDirectory ) )
491             {
492                 logger.warn( "The assembly descriptor contains a Windows-specific directory reference"
493                                  + " (with a drive letter). This is not portable and will fail on non-Windows: "
494                                  + destDirectory );
495             }
496         }
497         else
498         {
499             if ( isWindowsPath( destDirectory ) )
500             {
501                 logger.error(
502                     "OS=Non-Windows and the assembly descriptor contains a Windows-specific directory reference"
503                         + " (with a drive letter): " + destDirectory );
504             }
505             else if ( isUnixRootReference( destDirectory ) )
506             {
507                 logger.warn( "The assembly descriptor contains a *nix-specific root-relative reference"
508                                  + " (starting with slash). This is not portable and might fail on Windows: "
509                                  + destDirectory );
510             }
511         }
512     }
513 
514     static boolean isWindowsPath( String destDirectory )
515     {
516         return ( destDirectory != null && destDirectory.length() >= 2 && destDirectory.charAt( 1 ) == ':' );
517     }
518 
519     static boolean isUnixRootReference( String destDirectory )
520     {
521         return ( destDirectory != null && destDirectory.startsWith( "/" ) );
522     }
523 
524 
525 }