View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.assembly.archive.phase;
20  
21  import javax.inject.Named;
22  import javax.inject.Singleton;
23  
24  import java.io.File;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.SequenceInputStream;
28  import java.nio.file.Files;
29  import java.util.ArrayList;
30  import java.util.Collection;
31  import java.util.Collections;
32  import java.util.List;
33  
34  import org.apache.maven.plugins.assembly.AssemblerConfigurationSource;
35  import org.apache.maven.plugins.assembly.InvalidAssemblerConfigurationException;
36  import org.apache.maven.plugins.assembly.archive.ArchiveCreationException;
37  import org.apache.maven.plugins.assembly.format.AssemblyFormattingException;
38  import org.apache.maven.plugins.assembly.format.ReaderFormatter;
39  import org.apache.maven.plugins.assembly.model.Assembly;
40  import org.apache.maven.plugins.assembly.model.FileItem;
41  import org.apache.maven.plugins.assembly.utils.AssemblyFileUtils;
42  import org.apache.maven.plugins.assembly.utils.AssemblyFormatUtils;
43  import org.apache.maven.plugins.assembly.utils.TypeConversionUtils;
44  import org.codehaus.plexus.archiver.Archiver;
45  import org.codehaus.plexus.archiver.ArchiverException;
46  import org.codehaus.plexus.components.io.functions.ContentSupplier;
47  import org.codehaus.plexus.components.io.functions.InputStreamTransformer;
48  import org.codehaus.plexus.components.io.resources.PlexusIoFileResource;
49  import org.codehaus.plexus.components.io.resources.PlexusIoResource;
50  import org.slf4j.Logger;
51  import org.slf4j.LoggerFactory;
52  
53  import static org.codehaus.plexus.components.io.resources.ResourceFactory.createResource;
54  
55  /**
56   * Handles the top-level <files/> section of the assembly descriptor.
57   *
58   *
59   */
60  @Singleton
61  @Named("file-items")
62  public class FileItemAssemblyPhase implements AssemblyArchiverPhase, PhaseOrder {
63      private static final Logger LOGGER = LoggerFactory.getLogger(FileItemAssemblyPhase.class);
64  
65      /**
66       * {@inheritDoc}
67       */
68      @Override
69      public void execute(
70              final Assembly assembly, final Archiver archiver, final AssemblerConfigurationSource configSource)
71              throws ArchiveCreationException, AssemblyFormattingException, InvalidAssemblerConfigurationException {
72          final List<FileItem> fileList = assembly.getFiles();
73          final File basedir = configSource.getBasedir();
74  
75          for (final FileItem fileItem : fileList) {
76              if (fileItem.getSource() != null ^ fileItem.getSources().isEmpty()) {
77                  throw new InvalidAssemblerConfigurationException(
78                          "Misconfigured file: one of source or sources must be set");
79              }
80  
81              String destName = fileItem.getDestName();
82  
83              final String sourcePath;
84              if (fileItem.getSource() != null) {
85                  sourcePath = fileItem.getSource();
86              } else if (destName != null) {
87                  // because createResource() requires a file
88                  sourcePath = fileItem.getSources().get(0);
89              } else {
90                  throw new InvalidAssemblerConfigurationException(
91                          "Misconfigured file: specify destName when using sources");
92              }
93  
94              // ensure source file is in absolute path for reactor build to work
95              File source = new File(sourcePath);
96  
97              // save the original sourcefile's name, because filtration may
98              // create a temp file with a different name.
99              final String sourceName = source.getName();
100 
101             if (!AssemblyFileUtils.isAbsolutePath(source)) {
102                 source = new File(basedir, sourcePath);
103             }
104             if (destName == null) {
105                 destName = sourceName;
106             }
107 
108             final String outputDirectory1 = fileItem.getOutputDirectory();
109 
110             final String outputDirectory = AssemblyFormatUtils.getOutputDirectory(
111                     outputDirectory1,
112                     configSource.getFinalName(),
113                     configSource,
114                     AssemblyFormatUtils.moduleProjectInterpolator(configSource.getProject()),
115                     AssemblyFormatUtils.artifactProjectInterpolator(null));
116 
117             String target;
118 
119             // omit the last char if ends with / or \\
120             if (outputDirectory.endsWith("/") || outputDirectory.endsWith("\\")) {
121                 target = outputDirectory + destName;
122             } else if (outputDirectory.length() < 1) {
123                 target = destName;
124             } else {
125                 target = outputDirectory + "/" + destName;
126             }
127 
128             try {
129                 final InputStreamTransformer fileSetTransformers = ReaderFormatter.getFileSetTransformers(
130                         configSource, fileItem.isFiltered(), Collections.emptySet(), fileItem.getLineEnding());
131 
132                 final PlexusIoResource restoUse;
133                 if (!fileItem.getSources().isEmpty()) {
134                     List<InputStream> content =
135                             new ArrayList<>(fileItem.getSources().size());
136                     for (String contentSourcePath : fileItem.getSources()) {
137                         File contentSource = new File(contentSourcePath);
138                         if (!AssemblyFileUtils.isAbsolutePath(contentSource)) {
139                             contentSource = new File(basedir, contentSourcePath);
140                         }
141                         content.add(Files.newInputStream(contentSource.toPath()));
142                     }
143 
144                     String name = PlexusIoFileResource.getName(source);
145                     restoUse = createResource(source, name, getContentSupplier(content), fileSetTransformers);
146                 } else {
147                     restoUse = createResource(source, fileSetTransformers);
148                 }
149 
150                 int mode = TypeConversionUtils.modeToInt(fileItem.getFileMode(), LOGGER);
151                 archiver.addResource(restoUse, target, mode);
152             } catch (final ArchiverException | IOException e) {
153                 throw new ArchiveCreationException("Error adding file to archive: " + e.getMessage(), e);
154             }
155         }
156     }
157 
158     @Override
159     public int order() {
160         return 10;
161     }
162 
163     private ContentSupplier getContentSupplier(final Collection<InputStream> contentStreams) {
164         return new ContentSupplier() {
165             @Override
166             public InputStream getContents() throws IOException {
167                 return new SequenceInputStream(Collections.enumeration(contentStreams));
168             }
169         };
170     }
171 }