1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.assembly.archive;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.StringReader;
27 import java.nio.file.attribute.FileTime;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Map;
31
32 import org.apache.maven.plugins.assembly.AssemblerConfigurationSource;
33 import org.apache.maven.plugins.assembly.InvalidAssemblerConfigurationException;
34 import org.apache.maven.plugins.assembly.archive.archiver.AssemblyProxyArchiver;
35 import org.apache.maven.plugins.assembly.archive.phase.AssemblyArchiverPhase;
36 import org.apache.maven.plugins.assembly.archive.phase.AssemblyArchiverPhaseComparator;
37 import org.apache.maven.plugins.assembly.artifact.DependencyResolutionException;
38 import org.apache.maven.plugins.assembly.filter.ComponentsXmlArchiverFileFilter;
39 import org.apache.maven.plugins.assembly.filter.ContainerDescriptorHandler;
40 import org.apache.maven.plugins.assembly.format.AssemblyFormattingException;
41 import org.apache.maven.plugins.assembly.internal.DebugConfigurationListener;
42 import org.apache.maven.plugins.assembly.interpolation.AssemblyExpressionEvaluator;
43 import org.apache.maven.plugins.assembly.model.Assembly;
44 import org.apache.maven.plugins.assembly.model.ContainerDescriptorHandlerConfig;
45 import org.apache.maven.plugins.assembly.utils.AssemblyFileUtils;
46 import org.apache.maven.plugins.assembly.utils.AssemblyFormatUtils;
47 import org.codehaus.plexus.PlexusContainer;
48 import org.codehaus.plexus.archiver.ArchiveFinalizer;
49 import org.codehaus.plexus.archiver.Archiver;
50 import org.codehaus.plexus.archiver.ArchiverException;
51 import org.codehaus.plexus.archiver.diags.DryRunArchiver;
52 import org.codehaus.plexus.archiver.filters.JarSecurityFileSelector;
53 import org.codehaus.plexus.archiver.jar.JarArchiver;
54 import org.codehaus.plexus.archiver.manager.ArchiverManager;
55 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
56 import org.codehaus.plexus.archiver.tar.TarArchiver;
57 import org.codehaus.plexus.archiver.tar.TarLongFileMode;
58 import org.codehaus.plexus.archiver.war.WarArchiver;
59 import org.codehaus.plexus.archiver.zip.AbstractZipArchiver;
60 import org.codehaus.plexus.component.configurator.BasicComponentConfigurator;
61 import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
62 import org.codehaus.plexus.component.configurator.ConfigurationListener;
63 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
64 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
65 import org.codehaus.plexus.components.io.fileselectors.FileSelector;
66 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
67 import org.codehaus.plexus.util.StringUtils;
68 import org.codehaus.plexus.util.xml.Xpp3Dom;
69 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
70 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74 import static java.util.Objects.requireNonNull;
75
76
77
78
79
80
81
82
83
84
85 @Named
86 public class DefaultAssemblyArchiver implements AssemblyArchiver {
87 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAssemblyArchiver.class);
88
89 private final ArchiverManager archiverManager;
90
91 private final List<AssemblyArchiverPhase> assemblyPhases;
92
93 @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
94 private final Map<String, ContainerDescriptorHandler> containerDescriptorHandlers;
95
96 private final PlexusContainer container;
97
98 private final BasicComponentConfigurator configurator;
99
100 @Inject
101 public DefaultAssemblyArchiver(
102 ArchiverManager archiverManager,
103 List<AssemblyArchiverPhase> assemblyPhases,
104 Map<String, ContainerDescriptorHandler> containerDescriptorHandlers,
105 PlexusContainer container,
106 BasicComponentConfigurator configurator) {
107 this.archiverManager = requireNonNull(archiverManager);
108 this.assemblyPhases = requireNonNull(assemblyPhases);
109 this.containerDescriptorHandlers = requireNonNull(containerDescriptorHandlers);
110 this.container = requireNonNull(container);
111 this.configurator = requireNonNull(configurator);
112 }
113
114 private List<AssemblyArchiverPhase> sortedPhases() {
115 List<AssemblyArchiverPhase> sorted = new ArrayList<>(assemblyPhases);
116 sorted.sort(new AssemblyArchiverPhaseComparator());
117 return sorted;
118 }
119
120
121
122
123 @Override
124 public File createArchive(
125 final Assembly assembly,
126 final String fullName,
127 final String format,
128 final AssemblerConfigurationSource configSource,
129 FileTime outputTimestamp)
130 throws ArchiveCreationException, AssemblyFormattingException, InvalidAssemblerConfigurationException {
131 validate(assembly);
132
133 String filename = fullName;
134 if (!configSource.isIgnoreDirFormatExtensions() || !format.startsWith("dir")) {
135 filename += "." + format;
136 }
137
138 AssemblyFileUtils.verifyTempDirectoryAvailability(configSource.getTemporaryRootDirectory());
139
140 final File outputDirectory = configSource.getOutputDirectory();
141
142 final File destFile = new File(outputDirectory, filename);
143
144 try {
145 final String finalName = configSource.getFinalName();
146 final String specifiedBasedir = assembly.getBaseDirectory();
147
148 String basedir = finalName;
149
150 if (specifiedBasedir != null) {
151 basedir = AssemblyFormatUtils.getOutputDirectory(
152 specifiedBasedir,
153 finalName,
154 configSource,
155 AssemblyFormatUtils.moduleProjectInterpolator(configSource.getProject()),
156 AssemblyFormatUtils.artifactProjectInterpolator(null));
157 }
158
159 final List<ContainerDescriptorHandler> containerHandlers =
160 selectContainerDescriptorHandlers(assembly.getContainerDescriptorHandlers(), configSource);
161
162 final Archiver archiver = createArchiver(
163 format,
164 assembly.isIncludeBaseDirectory(),
165 basedir,
166 configSource,
167 containerHandlers,
168 outputTimestamp);
169
170 archiver.setDestFile(destFile);
171
172 for (AssemblyArchiverPhase phase : sortedPhases()) {
173 phase.execute(assembly, archiver, configSource);
174 }
175
176 archiver.createArchive();
177 } catch (final ArchiverException | IOException e) {
178 throw new ArchiveCreationException(
179 "Error creating assembly archive " + assembly.getId() + ": " + e.getMessage(), e);
180 } catch (final NoSuchArchiverException e) {
181 throw new ArchiveCreationException(
182 "Unable to obtain archiver for extension '" + format + "', for assembly: '" + assembly.getId()
183 + "'",
184 e);
185 } catch (final DependencyResolutionException e) {
186 throw new ArchiveCreationException(
187 "Unable to resolve dependencies for assembly '" + assembly.getId() + "'", e);
188 }
189
190 return destFile;
191 }
192
193 private void validate(final Assembly assembly) throws InvalidAssemblerConfigurationException {
194 if (assembly.getId() == null || assembly.getId().trim().length() < 1) {
195 throw new InvalidAssemblerConfigurationException("Assembly ID must be present and non-empty.");
196 }
197 }
198
199
200 private List<ContainerDescriptorHandler> selectContainerDescriptorHandlers(
201 List<ContainerDescriptorHandlerConfig> requestedContainerDescriptorHandlers,
202 final AssemblerConfigurationSource configSource)
203 throws InvalidAssemblerConfigurationException
204
205 {
206 LOGGER.debug("All known ContainerDescriptorHandler components: "
207 + (containerDescriptorHandlers == null
208 ? "none; map is null."
209 : "" + containerDescriptorHandlers.keySet()));
210
211 if (requestedContainerDescriptorHandlers == null) {
212 requestedContainerDescriptorHandlers = new ArrayList<>();
213 }
214
215 final List<ContainerDescriptorHandler> handlers = new ArrayList<>();
216 final List<String> hints = new ArrayList<>();
217
218 if (!requestedContainerDescriptorHandlers.isEmpty()) {
219 for (final ContainerDescriptorHandlerConfig config : requestedContainerDescriptorHandlers) {
220 final String hint = config.getHandlerName();
221 final ContainerDescriptorHandler handler = containerDescriptorHandlers.get(hint);
222
223 if (handler == null) {
224 throw new InvalidAssemblerConfigurationException(
225 "Cannot find ContainerDescriptorHandler with hint: " + hint);
226 }
227
228 LOGGER.debug("Found container descriptor handler with hint: " + hint + " (component: " + handler + ")");
229
230 if (config.getConfiguration() != null) {
231 LOGGER.debug("Configuring handler with:\n\n" + config.getConfiguration() + "\n\n");
232
233 configureContainerDescriptorHandler(handler, (Xpp3Dom) config.getConfiguration(), configSource);
234 }
235
236 handlers.add(handler);
237 hints.add(hint);
238 }
239 }
240
241 if (!hints.contains("plexus")) {
242 handlers.add(new ComponentsXmlArchiverFileFilter());
243 }
244
245 return handlers;
246 }
247
248
249
250
251
252
253
254
255
256
257
258
259
260 protected Archiver createArchiver(
261 final String format,
262 final boolean includeBaseDir,
263 final String finalName,
264 final AssemblerConfigurationSource configSource,
265 final List<ContainerDescriptorHandler> containerHandlers,
266 FileTime outputTimestamp)
267 throws NoSuchArchiverException {
268
269 Archiver archiver = archiverManager.getArchiver(format);
270
271 if (archiver instanceof TarArchiver) {
272 ((TarArchiver) archiver).setLongfile(TarLongFileMode.valueOf(configSource.getTarLongFileMode()));
273 }
274
275 if (archiver instanceof WarArchiver) {
276 ((WarArchiver) archiver).setExpectWebXml(false);
277 }
278
279 if (archiver instanceof AbstractZipArchiver) {
280 ((AbstractZipArchiver) archiver).setRecompressAddedZips(configSource.isRecompressZippedFiles());
281 }
282
283 final List<FileSelector> extraSelectors = new ArrayList<>();
284 final List<ArchiveFinalizer> extraFinalizers = new ArrayList<>();
285 if (archiver instanceof JarArchiver) {
286 configureJarArchiver((JarArchiver) archiver, configSource.getMergeManifestMode());
287
288 extraSelectors.add(new JarSecurityFileSelector());
289
290 extraFinalizers.add(new ManifestCreationFinalizer(
291 configSource.getMavenSession(),
292 configSource.getProject(),
293 configSource.getJarArchiveConfiguration()));
294 }
295
296 if (configSource.getArchiverConfig() != null) {
297 configureArchiver(archiver, configSource);
298 }
299
300 String prefix = "";
301 if (includeBaseDir) {
302 prefix = finalName;
303 }
304
305 archiver = new AssemblyProxyArchiver(
306 prefix,
307 archiver,
308 containerHandlers,
309 extraSelectors,
310 extraFinalizers,
311 configSource.getWorkingDirectory());
312 if (configSource.isDryRun()) {
313 archiver = new DryRunArchiver(archiver, LOGGER);
314 }
315
316 archiver.setIgnorePermissions(configSource.isIgnorePermissions());
317 archiver.setForced(!configSource.isUpdateOnly());
318
319
320 if (outputTimestamp != null) {
321 archiver.configureReproducibleBuild(outputTimestamp);
322 }
323
324 if (configSource.getOverrideUid() != null) {
325 archiver.setOverrideUid(configSource.getOverrideUid());
326 }
327 if (StringUtils.isNotBlank(configSource.getOverrideUserName())) {
328 archiver.setOverrideUserName(StringUtils.trim(configSource.getOverrideUserName()));
329 }
330 if (configSource.getOverrideGid() != null) {
331 archiver.setOverrideGid(configSource.getOverrideGid());
332 }
333 if (StringUtils.isNotBlank(configSource.getOverrideGroupName())) {
334 archiver.setOverrideGroupName(StringUtils.trim(configSource.getOverrideGroupName()));
335 }
336
337 return archiver;
338 }
339
340 private void configureJarArchiver(JarArchiver archiver, String mergeManifestMode) {
341
342 if (mergeManifestMode != null) {
343 archiver.setFilesetmanifest(JarArchiver.FilesetManifestConfig.valueOf(mergeManifestMode));
344 }
345
346 archiver.setMinimalDefaultManifest(true);
347 }
348
349 private void configureContainerDescriptorHandler(
350 final ContainerDescriptorHandler handler,
351 final Xpp3Dom config,
352 final AssemblerConfigurationSource configSource)
353 throws InvalidAssemblerConfigurationException {
354 LOGGER.debug("Configuring handler: '" + handler.getClass().getName() + "' -->");
355
356 try {
357 configureComponent(handler, config, configSource);
358 } catch (final ComponentConfigurationException e) {
359 throw new InvalidAssemblerConfigurationException(
360 "Failed to configure handler: " + handler.getClass().getName(), e);
361 } catch (final ComponentLookupException e) {
362 throw new InvalidAssemblerConfigurationException(
363 "Failed to lookup configurator for setup of handler: "
364 + handler.getClass().getName(),
365 e);
366 }
367
368 LOGGER.debug("-- end configuration --");
369 }
370
371 private void configureArchiver(final Archiver archiver, final AssemblerConfigurationSource configSource) {
372 Xpp3Dom config;
373 try {
374 config = Xpp3DomBuilder.build(new StringReader(configSource.getArchiverConfig()));
375 } catch (final XmlPullParserException | IOException e) {
376 throw new ArchiverException(
377 "Failed to parse archiver configuration for: "
378 + archiver.getClass().getName(),
379 e);
380 }
381
382 LOGGER.debug("Configuring archiver: '" + archiver.getClass().getName() + "' -->");
383
384 try {
385 configureComponent(archiver, config, configSource);
386 } catch (final ComponentConfigurationException e) {
387 throw new ArchiverException(
388 "Failed to configure archiver: " + archiver.getClass().getName(), e);
389 } catch (final ComponentLookupException e) {
390 throw new ArchiverException(
391 "Failed to lookup configurator for setup of archiver: "
392 + archiver.getClass().getName(),
393 e);
394 }
395
396 LOGGER.debug("-- end configuration --");
397 }
398
399 private void configureComponent(
400 final Object component, final Xpp3Dom config, final AssemblerConfigurationSource configSource)
401 throws ComponentLookupException, ComponentConfigurationException {
402
403 final ConfigurationListener listener = new DebugConfigurationListener(LOGGER);
404
405 final ExpressionEvaluator expressionEvaluator = new AssemblyExpressionEvaluator(configSource);
406
407 final XmlPlexusConfiguration configuration = new XmlPlexusConfiguration(config);
408
409 configurator.configureComponent(
410 component, configuration, expressionEvaluator, container.getContainerRealm(), listener);
411 }
412 }