View Javadoc
1   package org.apache.maven.plugin.assembly.archive.phase;
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.commons.io.IOUtils;
23  import org.apache.commons.io.output.DeferredFileOutputStream;
24  import org.apache.maven.plugin.assembly.AssemblerConfigurationSource;
25  import org.apache.maven.plugin.assembly.archive.ArchiveCreationException;
26  import org.apache.maven.plugin.assembly.format.AssemblyFormattingException;
27  import org.apache.maven.plugin.assembly.format.ReaderFormatter;
28  import org.apache.maven.plugin.assembly.model.Assembly;
29  import org.apache.maven.plugin.assembly.model.FileItem;
30  import org.apache.maven.plugin.assembly.utils.AssemblyFormatUtils;
31  import org.apache.maven.plugin.assembly.utils.TypeConversionUtils;
32  import org.apache.maven.shared.utils.StringUtils;
33  import org.codehaus.plexus.archiver.Archiver;
34  import org.codehaus.plexus.archiver.ArchiverException;
35  import org.codehaus.plexus.archiver.util.ArchiverAttributeUtils;
36  import org.codehaus.plexus.component.annotations.Component;
37  import org.codehaus.plexus.components.io.functions.InputStreamTransformer;
38  import org.codehaus.plexus.components.io.resources.PlexusIoFileResource;
39  import org.codehaus.plexus.components.io.resources.PlexusIoResource;
40  import org.codehaus.plexus.components.io.resources.PlexusIoSymlink;
41  import org.codehaus.plexus.components.io.resources.proxy.PlexusIoProxyResource;
42  import org.codehaus.plexus.components.io.resources.proxy.PlexusIoProxySymlinkResource;
43  import org.codehaus.plexus.logging.AbstractLogEnabled;
44  
45  import javax.annotation.Nonnull;
46  import java.io.ByteArrayInputStream;
47  import java.io.File;
48  import java.io.FileInputStream;
49  import java.io.IOException;
50  import java.io.InputStream;
51  import java.util.List;
52  
53  /**
54   * Handles the top-level <files/> section of the assembly descriptor.
55   *
56   * @version $Id: FileItemAssemblyPhase.java 1639728 2014-11-14 18:42:39Z krosenvold $
57   */
58  @Component( role = AssemblyArchiverPhase.class, hint = "file-items" )
59  public class FileItemAssemblyPhase
60      extends AbstractLogEnabled
61      implements AssemblyArchiverPhase, PhaseOrder
62  {
63  
64      /**
65       * {@inheritDoc}
66       */
67      public void execute( final Assembly assembly, final Archiver archiver,
68                           final AssemblerConfigurationSource configSource )
69          throws ArchiveCreationException, AssemblyFormattingException
70      {
71          final List<FileItem> fileList = assembly.getFiles();
72          final File basedir = configSource.getBasedir();
73  
74          for ( final FileItem fileItem : fileList )
75          {
76              final String sourcePath = fileItem.getSource();
77  
78              // ensure source file is in absolute path for reactor build to work
79              File source = new File( sourcePath );
80  
81              // save the original sourcefile's name, because filtration may
82              // create a temp file with a different name.
83              final String sourceName = source.getName();
84  
85              if ( !source.isAbsolute() )
86              {
87                  source = new File( basedir, sourcePath );
88              }
89  
90              String destName = fileItem.getDestName();
91  
92              if ( destName == null )
93              {
94                  destName = sourceName;
95              }
96  
97              final String outputDirectory1 = fileItem.getOutputDirectory();
98  
99              final String outputDirectory =
100                 AssemblyFormatUtils.getOutputDirectory( outputDirectory1, configSource.getFinalName(), configSource,
101                                                         AssemblyFormatUtils.moduleProjectInterpolator(
102                                                             configSource.getProject() ),
103                                                         AssemblyFormatUtils.artifactProjectInterpolator( null ) );
104 
105             String target;
106 
107             // omit the last char if ends with / or \\
108             if ( outputDirectory.endsWith( "/" ) || outputDirectory.endsWith( "\\" ) )
109             {
110                 target = outputDirectory + destName;
111             }
112             else if ( outputDirectory.length() < 1 )
113             {
114                 target = destName;
115             }
116             else
117             {
118                 target = outputDirectory + "/" + destName;
119             }
120 
121             final PlexusIoFileResource res =
122                 new PlexusIoFileResource( source, ArchiverAttributeUtils.getFileAttributes( source ) );
123             PlexusIoResource restoUse = res;
124             try
125             {
126                 final InputStreamTransformer fileSetTransformers =
127                     ReaderFormatter.getFileSetTransformers( configSource, fileItem.isFiltered(),
128                                                             fileItem.getLineEnding() );
129 
130                 if ( fileSetTransformers != null )
131                 {
132                     restoUse = new Deferred( res )
133                     {
134                         @Override
135                         protected InputStream getInputStream()
136                             throws IOException
137                         {
138                             return fileSetTransformers.transform( res, res.getContents() );
139                         }
140 
141                         @Override
142                         public String getName()
143                         {
144                             return res.getName();
145                         }
146                     }.asResource();
147                 }
148 
149                 int mode = TypeConversionUtils.modeToInt( fileItem.getFileMode(), getLogger() );
150                 archiver.addResource( restoUse, target, mode );
151             }
152             catch ( final ArchiverException e )
153             {
154                 throw new ArchiveCreationException( "Error adding file to archive: " + e.getMessage(), e );
155             }
156             catch ( IOException e )
157             {
158                 throw new ArchiveCreationException( "Error adding file to archive: " + e.getMessage(), e );
159             }
160         }
161     }
162 
163     // Nicked from archiver until I can get a better solution. I am the author :)
164     abstract class Deferred
165     {
166         final DeferredFileOutputStream dfos;
167 
168         final PlexusIoResource resource;
169 
170         public Deferred( final PlexusIoResource resource )
171             throws IOException
172         {
173             this.resource = resource;
174             dfos = new DeferredFileOutputStream( 1000000, "m-assembly-archiver", null, null );
175             InputStream inputStream = getInputStream();
176             IOUtils.copy( inputStream, dfos );
177             IOUtils.closeQuietly( inputStream );
178         }
179 
180         protected abstract InputStream getInputStream()
181             throws IOException;
182 
183         @Nonnull
184         public InputStream getContents()
185             throws IOException
186         {
187             if ( dfos.isInMemory() )
188             {
189                 return new ByteArrayInputStream( dfos.getData() );
190             }
191             else
192             {
193                 return new FileInputStream( dfos.getFile() )
194                 {
195                     @Override
196                     public void close()
197                         throws IOException
198                     {
199                         super.close();
200                         dfos.getFile().delete();
201                     }
202                 };
203             }
204         }
205 
206         public long getSize()
207         {
208             if ( dfos == null )
209             {
210                 return resource.getSize();
211             }
212             if ( dfos.isInMemory() )
213             {
214                 return dfos.getByteCount();
215             }
216             else
217             {
218                 return dfos.getFile().length();
219             }
220         }
221 
222         public abstract String getName();
223 
224         private PlexusIoResource asSymlinkResource()
225         {
226             return new PlexusIoProxySymlinkResource( resource )
227             {
228                 @Override
229                 public String getName()
230                 {
231                     return Deferred.this.getName();
232                 }
233 
234                 @Nonnull
235                 @Override
236                 public InputStream getContents()
237                     throws IOException
238                 {
239                     return Deferred.this.getContents();
240                 }
241 
242                 @Override
243                 public long getSize()
244                 {
245                     return Deferred.this.getSize();
246                 }
247             };
248         }
249 
250         public PlexusIoResource asResource()
251         {
252             if ( resource instanceof PlexusIoSymlink )
253             {
254                 return asSymlinkResource();
255             }
256 
257             return new PlexusIoProxyResource( resource )
258             {
259                 @Override
260                 public String getName()
261                 {
262                     return Deferred.this.getName();
263                 }
264 
265                 @Nonnull
266                 @Override
267                 public InputStream getContents()
268                     throws IOException
269                 {
270                     return Deferred.this.getContents();
271                 }
272 
273                 @Override
274                 public long getSize()
275                 {
276                     return Deferred.this.getSize();
277                 }
278             };
279         }
280 
281     }
282 
283     public int order()
284     {
285         return 10;
286     }
287 }