1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.codehaus.plexus.archiver;
18
19 import javax.annotation.Nonnull;
20 import javax.inject.Inject;
21 import javax.inject.Provider;
22
23 import java.io.Closeable;
24 import java.io.File;
25 import java.io.IOException;
26 import java.lang.reflect.UndeclaredThrowableException;
27 import java.nio.charset.Charset;
28 import java.nio.file.Files;
29 import java.nio.file.attribute.FileTime;
30 import java.util.ArrayList;
31 import java.util.Comparator;
32 import java.util.Date;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.NoSuchElementException;
39 import java.util.Set;
40
41 import org.codehaus.plexus.archiver.manager.ArchiverManager;
42 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
43 import org.codehaus.plexus.components.io.attributes.PlexusIoResourceAttributeUtils;
44 import org.codehaus.plexus.components.io.attributes.PlexusIoResourceAttributes;
45 import org.codehaus.plexus.components.io.attributes.SimpleResourceAttributes;
46 import org.codehaus.plexus.components.io.functions.ResourceAttributeSupplier;
47 import org.codehaus.plexus.components.io.resources.AbstractPlexusIoResourceCollection;
48 import org.codehaus.plexus.components.io.resources.EncodingSupported;
49 import org.codehaus.plexus.components.io.resources.PlexusIoArchivedResourceCollection;
50 import org.codehaus.plexus.components.io.resources.PlexusIoFileResourceCollection;
51 import org.codehaus.plexus.components.io.resources.PlexusIoResource;
52 import org.codehaus.plexus.components.io.resources.PlexusIoResourceCollection;
53 import org.codehaus.plexus.components.io.resources.proxy.PlexusIoProxyResourceCollection;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 import static org.codehaus.plexus.archiver.util.DefaultArchivedFileSet.archivedFileSet;
58 import static org.codehaus.plexus.archiver.util.DefaultFileSet.fileSet;
59
60 public abstract class AbstractArchiver implements Archiver, FinalizerEnabled {
61
62 private final Logger logger = LoggerFactory.getLogger(getClass());
63
64 protected Logger getLogger() {
65 return logger;
66 }
67
68 private File destFile;
69
70
71
72
73
74
75
76
77
78
79 private final List<Object> resources = new ArrayList<>();
80
81 private boolean includeEmptyDirs = true;
82
83 private int forcedFileMode = -1;
84
85 private int forcedDirectoryMode = -1;
86
87 private int defaultFileMode = -1;
88
89 private int defaultDirectoryMode = -1;
90
91 private int umask = -1;
92
93 private boolean forced = true;
94
95 private List<ArchiveFinalizer> finalizers;
96
97 private File dotFileDirectory;
98
99 private String duplicateBehavior = Archiver.DUPLICATES_SKIP;
100
101
102 private final boolean replacePathSlashesToJavaPaths = File.separatorChar == '/';
103
104 private final List<Closeable> closeables = new ArrayList<>();
105
106
107
108
109
110
111 private boolean useJvmChmod = true;
112
113 private FileTime lastModifiedTime;
114
115
116
117
118 private Comparator<String> filenameComparator;
119
120
121
122
123 private int overrideUid = -1;
124
125
126
127
128 private String overrideUserName;
129
130
131
132
133 private int overrideGid = -1;
134
135
136
137
138 private String overrideGroupName;
139
140
141
142
143
144 @Inject
145 private Provider<ArchiverManager> archiverManagerProvider;
146
147 private static class AddedResourceCollection {
148
149 private final PlexusIoResourceCollection resources;
150
151 private final int forcedFileMode;
152
153 private final int forcedDirectoryMode;
154
155 public AddedResourceCollection(PlexusIoResourceCollection resources, int forcedFileMode, int forcedDirMode) {
156 this.resources = resources;
157 this.forcedFileMode = forcedFileMode;
158 this.forcedDirectoryMode = forcedDirMode;
159 }
160
161 private int maybeOverridden(int suggestedMode, boolean isDir) {
162 if (isDir) {
163 return forcedDirectoryMode >= 0 ? forcedDirectoryMode : suggestedMode;
164 } else {
165 return forcedFileMode >= 0 ? forcedFileMode : suggestedMode;
166 }
167 }
168 }
169
170
171
172
173 private boolean ignorePermissions = false;
174
175 @Override
176 public String getDuplicateBehavior() {
177 return duplicateBehavior;
178 }
179
180 @Override
181 public void setDuplicateBehavior(final String duplicate) {
182 if (!Archiver.DUPLICATES_VALID_BEHAVIORS.contains(duplicate)) {
183 throw new IllegalArgumentException("Invalid duplicate-file behavior: '" + duplicate
184 + "'. Please specify one of: " + Archiver.DUPLICATES_VALID_BEHAVIORS);
185 }
186
187 duplicateBehavior = duplicate;
188 }
189
190 @Override
191 public final void setFileMode(final int mode) {
192 if (mode >= 0) {
193 forcedFileMode = (mode & UnixStat.PERM_MASK) | UnixStat.FILE_FLAG;
194 } else {
195 forcedFileMode = -1;
196 }
197 }
198
199 @Override
200 public final void setDefaultFileMode(final int mode) {
201 defaultFileMode = (mode & UnixStat.PERM_MASK) | UnixStat.FILE_FLAG;
202 }
203
204 @Override
205 public final int getOverrideFileMode() {
206 return forcedFileMode;
207 }
208
209 @Override
210 public final int getFileMode() {
211 if (forcedFileMode < 0) {
212 if (defaultFileMode < 0) {
213 return DEFAULT_FILE_MODE;
214 }
215
216 return defaultFileMode;
217 }
218
219 return forcedFileMode;
220 }
221
222 @Override
223 public final int getDefaultFileMode() {
224 return defaultFileMode;
225 }
226
227
228
229
230 @Deprecated
231 public final int getRawDefaultFileMode() {
232 return getDefaultFileMode();
233 }
234
235 @Override
236 public final void setDirectoryMode(final int mode) {
237 if (mode >= 0) {
238 forcedDirectoryMode = (mode & UnixStat.PERM_MASK) | UnixStat.DIR_FLAG;
239 } else {
240 forcedDirectoryMode = -1;
241 }
242 }
243
244 @Override
245 public final void setDefaultDirectoryMode(final int mode) {
246 defaultDirectoryMode = (mode & UnixStat.PERM_MASK) | UnixStat.DIR_FLAG;
247 }
248
249 @Override
250 public final int getOverrideDirectoryMode() {
251 return forcedDirectoryMode;
252 }
253
254 @Override
255 public final int getDirectoryMode() {
256 if (forcedDirectoryMode < 0) {
257 if (defaultDirectoryMode < 0) {
258 return DEFAULT_DIR_MODE;
259 }
260
261 return defaultDirectoryMode;
262 }
263
264 return forcedDirectoryMode;
265 }
266
267 @Override
268 public final int getDefaultDirectoryMode() {
269 if (defaultDirectoryMode < 0) {
270 return DEFAULT_DIR_MODE;
271 } else {
272 return defaultDirectoryMode;
273 }
274 }
275
276 @Override
277 public boolean getIncludeEmptyDirs() {
278 return includeEmptyDirs;
279 }
280
281 @Override
282 public void setIncludeEmptyDirs(final boolean includeEmptyDirs) {
283 this.includeEmptyDirs = includeEmptyDirs;
284 }
285
286 @Override
287 public void addDirectory(@Nonnull final File directory) throws ArchiverException {
288 addFileSet(fileSet(directory).prefixed("").includeExclude(null, null).includeEmptyDirs(includeEmptyDirs));
289 }
290
291 @Override
292 public void addDirectory(@Nonnull final File directory, final String prefix) throws ArchiverException {
293 addFileSet(
294 fileSet(directory).prefixed(prefix).includeExclude(null, null).includeEmptyDirs(includeEmptyDirs));
295 }
296
297 @Override
298 public void addDirectory(@Nonnull final File directory, final String[] includes, final String[] excludes)
299 throws ArchiverException {
300 addFileSet(fileSet(directory)
301 .prefixed("")
302 .includeExclude(includes, excludes)
303 .includeEmptyDirs(includeEmptyDirs));
304 }
305
306 @Override
307 public void addDirectory(
308 @Nonnull final File directory, final String prefix, final String[] includes, final String[] excludes)
309 throws ArchiverException {
310 addFileSet(fileSet(directory)
311 .prefixed(prefix)
312 .includeExclude(includes, excludes)
313 .includeEmptyDirs(includeEmptyDirs));
314 }
315
316 @Override
317 public void addFileSet(@Nonnull final FileSet fileSet) throws ArchiverException {
318 final File directory = fileSet.getDirectory();
319 if (directory == null) {
320 throw new ArchiverException("The file sets base directory is null.");
321 }
322
323 if (!directory.isDirectory()) {
324 throw new ArchiverException(directory.getAbsolutePath() + " isn't a directory.");
325 }
326
327
328
329 final PlexusIoFileResourceCollection collection = new PlexusIoFileResourceCollection();
330 collection.setFollowingSymLinks(false);
331
332 collection.setIncludes(fileSet.getIncludes());
333 collection.setExcludes(fileSet.getExcludes());
334 collection.setBaseDir(directory);
335 collection.setFileSelectors(fileSet.getFileSelectors());
336 collection.setIncludingEmptyDirectories(fileSet.isIncludingEmptyDirectories());
337 collection.setPrefix(fileSet.getPrefix());
338 collection.setCaseSensitive(fileSet.isCaseSensitive());
339 collection.setUsingDefaultExcludes(fileSet.isUsingDefaultExcludes());
340 collection.setStreamTransformer(fileSet.getStreamTransformer());
341 collection.setFileMappers(fileSet.getFileMappers());
342 collection.setFilenameComparator(getFilenameComparator());
343
344 if (getOverrideDirectoryMode() > -1
345 || getOverrideFileMode() > -1
346 || getOverrideUid() > -1
347 || getOverrideGid() > -1
348 || getOverrideUserName() != null
349 || getOverrideGroupName() != null) {
350 collection.setOverrideAttributes(
351 getOverrideUid(),
352 getOverrideUserName(),
353 getOverrideGid(),
354 getOverrideGroupName(),
355 getOverrideFileMode(),
356 getOverrideDirectoryMode());
357 }
358
359 if (getDefaultDirectoryMode() > -1 || getDefaultFileMode() > -1) {
360 collection.setDefaultAttributes(-1, null, -1, null, getDefaultFileMode(), getDefaultDirectoryMode());
361 }
362
363 addResources(collection);
364 }
365
366 @Override
367 public void addFile(@Nonnull final File inputFile, @Nonnull final String destFileName) throws ArchiverException {
368 int permissions;
369 if (forcedFileMode > 0) {
370 permissions = forcedFileMode;
371 } else {
372 permissions = PlexusIoResourceAttributes.UNKNOWN_OCTAL_MODE;
373 try {
374 permissions = PlexusIoResourceAttributeUtils.getFileAttributes(inputFile)
375 .getOctalMode();
376 } catch (IOException ioe) {
377
378 }
379 }
380
381 addFile(inputFile, destFileName, permissions);
382 }
383
384 @Override
385 public void addSymlink(String symlinkName, String symlinkDestination) throws ArchiverException {
386 final int fileMode = getOverrideFileMode();
387
388 addSymlink(symlinkName, fileMode, symlinkDestination);
389 }
390
391 @Override
392 public void addSymlink(String symlinkName, int permissions, String symlinkDestination) throws ArchiverException {
393 doAddResource(
394 ArchiveEntry.createSymlinkEntry(symlinkName, permissions, symlinkDestination, getDirectoryMode()));
395 }
396
397 private ArchiveEntry updateArchiveEntryAttributes(ArchiveEntry entry) {
398 if (getOverrideUid() > -1
399 || getOverrideGid() > -1
400 || getOverrideUserName() != null
401 || getOverrideGroupName() != null) {
402 entry.setResourceAttributes(new SimpleResourceAttributes(
403 getOverrideUid(),
404 getOverrideUserName(),
405 getOverrideGid(),
406 getOverrideGroupName(),
407 entry.getMode()));
408 }
409 return entry;
410 }
411
412 protected ArchiveEntry asArchiveEntry(
413 @Nonnull final PlexusIoResource resource,
414 final String destFileName,
415 int permissions,
416 PlexusIoResourceCollection collection)
417 throws ArchiverException {
418 if (!resource.isExisting()) {
419 throw new ArchiverException(resource.getName() + " not found.");
420 }
421
422 if (umask > 0 && permissions != PlexusIoResourceAttributes.UNKNOWN_OCTAL_MODE) {
423 permissions &= ~umask;
424 }
425
426 ArchiveEntry entry;
427 if (resource.isFile()) {
428 entry = ArchiveEntry.createFileEntry(destFileName, resource, permissions, collection, getDirectoryMode());
429 } else {
430 entry = ArchiveEntry.createDirectoryEntry(destFileName, resource, permissions, getDirectoryMode());
431 }
432
433 return updateArchiveEntryAttributes(entry);
434 }
435
436 private ArchiveEntry asArchiveEntry(final AddedResourceCollection collection, final PlexusIoResource resource)
437 throws ArchiverException {
438 final String destFileName = collection.resources.getName(resource);
439
440 int fromResource = PlexusIoResourceAttributes.UNKNOWN_OCTAL_MODE;
441 if (resource instanceof ResourceAttributeSupplier) {
442 final PlexusIoResourceAttributes attrs = ((ResourceAttributeSupplier) resource).getAttributes();
443
444 if (attrs != null) {
445 fromResource = attrs.getOctalMode();
446 }
447 }
448
449 return asArchiveEntry(
450 resource,
451 destFileName,
452 collection.maybeOverridden(fromResource, resource.isDirectory()),
453 collection.resources);
454 }
455
456 @Override
457 public void addResource(final PlexusIoResource resource, final String destFileName, final int permissions)
458 throws ArchiverException {
459 doAddResource(asArchiveEntry(resource, destFileName, permissions, null));
460 }
461
462 @Override
463 public void addFile(@Nonnull final File inputFile, @Nonnull String destFileName, int permissions)
464 throws ArchiverException {
465 if (!inputFile.isFile() || !inputFile.exists()) {
466 throw new ArchiverException(inputFile.getAbsolutePath() + " isn't a file.");
467 }
468
469 if (replacePathSlashesToJavaPaths) {
470 destFileName = destFileName.replace('\\', '/');
471 }
472
473 if (permissions < 0) {
474 permissions = getOverrideFileMode();
475 }
476
477 if (umask > 0 && permissions != PlexusIoResourceAttributes.UNKNOWN_OCTAL_MODE) {
478 permissions &= ~umask;
479 }
480
481 try {
482
483 ArchiveEntry entry = ArchiveEntry.createFileEntry(destFileName, inputFile, permissions, getDirectoryMode());
484 doAddResource(updateArchiveEntryAttributes(entry));
485 } catch (final IOException e) {
486 throw new ArchiverException("Failed to determine inclusion status for: " + inputFile, e);
487 }
488 }
489
490 @Nonnull
491 @Override
492 public ResourceIterator getResources() throws ArchiverException {
493 return new ResourceIterator() {
494
495 private final Iterator<Object> addedResourceIter = resources.iterator();
496
497 private AddedResourceCollection currentResourceCollection;
498
499 private Iterator ioResourceIter;
500
501 private ArchiveEntry nextEntry;
502
503 private final Set<String> seenEntries = new HashSet<>();
504
505 @Override
506 public boolean hasNext() {
507 do {
508 if (nextEntry == null) {
509 if (ioResourceIter == null) {
510 if (addedResourceIter.hasNext()) {
511 final Object o = addedResourceIter.next();
512 if (o instanceof ArchiveEntry) {
513 nextEntry = (ArchiveEntry) o;
514 } else if (o instanceof AddedResourceCollection) {
515 currentResourceCollection = (AddedResourceCollection) o;
516
517 try {
518 ioResourceIter = currentResourceCollection.resources.getResources();
519 } catch (final IOException e) {
520 throw new ArchiverException(e.getMessage(), e);
521 }
522 } else {
523 return throwIllegalResourceType(o);
524 }
525 } else {
526 nextEntry = null;
527 }
528 } else {
529 if (ioResourceIter.hasNext()) {
530 final PlexusIoResource resource = (PlexusIoResource) ioResourceIter.next();
531 nextEntry = asArchiveEntry(currentResourceCollection, resource);
532 } else {
533
534
535
536
537
538 addCloseable(ioResourceIter);
539 ioResourceIter = null;
540 }
541 }
542 }
543
544 if (nextEntry != null && seenEntries.contains(normalizedForDuplicateCheck(nextEntry))) {
545 final String path = nextEntry.getName();
546
547 if (Archiver.DUPLICATES_PRESERVE.equals(duplicateBehavior)
548 || Archiver.DUPLICATES_SKIP.equals(duplicateBehavior)) {
549 if (nextEntry.getType() == ArchiveEntry.FILE) {
550 getLogger().debug(path + " already added, skipping");
551 }
552
553 nextEntry = null;
554 } else if (Archiver.DUPLICATES_FAIL.equals(duplicateBehavior)) {
555 throw new ArchiverException("Duplicate file " + path + " was found and the duplicate "
556 + "attribute is 'fail'.");
557 } else {
558
559 getLogger().debug("duplicate file " + path + " found, adding.");
560 }
561 }
562 } while (nextEntry == null && !(ioResourceIter == null && !addedResourceIter.hasNext()));
563
564 return nextEntry != null;
565 }
566
567 private boolean throwIllegalResourceType(Object o) {
568 throw new IllegalStateException(
569 "An invalid resource of type: " + o.getClass().getName() + " was added to archiver: "
570 + getClass().getName());
571 }
572
573 @Override
574 public ArchiveEntry next() {
575 if (!hasNext()) {
576 throw new NoSuchElementException();
577 }
578
579 final ArchiveEntry next = nextEntry;
580 nextEntry = null;
581
582 seenEntries.add(normalizedForDuplicateCheck(next));
583
584 return next;
585 }
586
587 @Override
588 public void remove() {
589 throw new UnsupportedOperationException("Does not support iterator");
590 }
591
592 private String normalizedForDuplicateCheck(ArchiveEntry entry) {
593 return entry.getName().replace('\\', '/');
594 }
595 };
596 }
597
598 private static void closeIfCloseable(Object resource) throws IOException {
599 if (resource == null) {
600 return;
601 }
602 if (resource instanceof Closeable) {
603 ((Closeable) resource).close();
604 }
605 }
606
607 private static void closeQuietlyIfCloseable(Object resource) {
608 try {
609 closeIfCloseable(resource);
610 } catch (IOException e) {
611 throw new RuntimeException(e);
612 }
613 }
614
615 @Override
616 public Map<String, ArchiveEntry> getFiles() {
617 try {
618 final Map<String, ArchiveEntry> map = new HashMap<>();
619 for (final ResourceIterator iter = getResources(); iter.hasNext(); ) {
620 final ArchiveEntry entry = iter.next();
621 if (includeEmptyDirs || entry.getType() == ArchiveEntry.FILE) {
622 map.put(entry.getName(), entry);
623 }
624 }
625 return map;
626 } catch (final ArchiverException e) {
627 throw new UndeclaredThrowableException(e);
628 }
629 }
630
631 @Override
632 public File getDestFile() {
633 return destFile;
634 }
635
636 @Override
637 public void setDestFile(final File destFile) {
638 this.destFile = destFile;
639
640 if (destFile != null && destFile.getParentFile() != null) {
641 destFile.getParentFile().mkdirs();
642 }
643 }
644
645 protected PlexusIoResourceCollection asResourceCollection(final ArchivedFileSet fileSet, Charset charset)
646 throws ArchiverException {
647 final File archiveFile = fileSet.getArchive();
648
649 final PlexusIoResourceCollection resources;
650 try {
651 resources = archiverManagerProvider.get().getResourceCollection(archiveFile);
652 } catch (final NoSuchArchiverException e) {
653 throw new ArchiverException(
654 "Error adding archived file-set. PlexusIoResourceCollection not found for: " + archiveFile, e);
655 }
656
657 if (resources instanceof EncodingSupported) {
658 ((EncodingSupported) resources).setEncoding(charset);
659 }
660
661 if (resources instanceof PlexusIoArchivedResourceCollection) {
662 ((PlexusIoArchivedResourceCollection) resources).setFile(fileSet.getArchive());
663 } else {
664 throw new ArchiverException("Expected " + PlexusIoArchivedResourceCollection.class.getName() + ", got "
665 + resources.getClass().getName());
666 }
667
668 if (resources instanceof AbstractPlexusIoResourceCollection) {
669 ((AbstractPlexusIoResourceCollection) resources).setStreamTransformer(fileSet.getStreamTransformer());
670 }
671 final PlexusIoProxyResourceCollection proxy = new PlexusIoProxyResourceCollection(resources);
672
673 proxy.setExcludes(fileSet.getExcludes());
674 proxy.setIncludes(fileSet.getIncludes());
675 proxy.setIncludingEmptyDirectories(fileSet.isIncludingEmptyDirectories());
676 proxy.setCaseSensitive(fileSet.isCaseSensitive());
677 proxy.setPrefix(fileSet.getPrefix());
678 proxy.setUsingDefaultExcludes(fileSet.isUsingDefaultExcludes());
679 proxy.setFileSelectors(fileSet.getFileSelectors());
680 proxy.setStreamTransformer(fileSet.getStreamTransformer());
681 proxy.setFileMappers(fileSet.getFileMappers());
682
683 if (getOverrideDirectoryMode() > -1 || getOverrideFileMode() > -1) {
684 proxy.setOverrideAttributes(-1, null, -1, null, getOverrideFileMode(), getOverrideDirectoryMode());
685 }
686
687 if (getDefaultDirectoryMode() > -1 || getDefaultFileMode() > -1) {
688 proxy.setDefaultAttributes(-1, null, -1, null, getDefaultFileMode(), getDefaultDirectoryMode());
689 }
690
691 return proxy;
692 }
693
694
695
696
697 @Override
698 public void addResources(final PlexusIoResourceCollection collection) throws ArchiverException {
699 doAddResource(new AddedResourceCollection(collection, forcedFileMode, forcedDirectoryMode));
700 }
701
702 private void doAddResource(Object item) {
703 resources.add(item);
704 }
705
706 @Override
707 public void addArchivedFileSet(final ArchivedFileSet fileSet) throws ArchiverException {
708 final PlexusIoResourceCollection resourceCollection = asResourceCollection(fileSet, null);
709 addResources(resourceCollection);
710 }
711
712 @Override
713 public void addArchivedFileSet(final ArchivedFileSet fileSet, Charset charset) throws ArchiverException {
714 final PlexusIoResourceCollection resourceCollection = asResourceCollection(fileSet, charset);
715 addResources(resourceCollection);
716 }
717
718
719
720
721 @Override
722 public void addArchivedFileSet(
723 @Nonnull final File archiveFile, final String prefix, final String[] includes, final String[] excludes)
724 throws ArchiverException {
725 addArchivedFileSet(archivedFileSet(archiveFile)
726 .prefixed(prefix)
727 .includeExclude(includes, excludes)
728 .includeEmptyDirs(includeEmptyDirs));
729 }
730
731
732
733
734 @Override
735 public void addArchivedFileSet(@Nonnull final File archiveFile, final String prefix) throws ArchiverException {
736 addArchivedFileSet(archivedFileSet(archiveFile).prefixed(prefix).includeEmptyDirs(includeEmptyDirs));
737 }
738
739
740
741
742 @Override
743 public void addArchivedFileSet(@Nonnull final File archiveFile, final String[] includes, final String[] excludes)
744 throws ArchiverException {
745 addArchivedFileSet(
746 archivedFileSet(archiveFile).includeExclude(includes, excludes).includeEmptyDirs(includeEmptyDirs));
747 }
748
749
750
751
752 @Override
753 public void addArchivedFileSet(@Nonnull final File archiveFile) throws ArchiverException {
754 addArchivedFileSet(archivedFileSet(archiveFile).includeEmptyDirs(includeEmptyDirs));
755 }
756
757 @Override
758 public boolean isForced() {
759 return forced;
760 }
761
762 @Override
763 public void setForced(final boolean forced) {
764 this.forced = forced;
765 }
766
767 @Override
768 public void addArchiveFinalizer(final ArchiveFinalizer finalizer) {
769 if (finalizers == null) {
770 finalizers = new ArrayList<>();
771 }
772
773 finalizers.add(finalizer);
774 }
775
776 @Override
777 public void setArchiveFinalizers(final List<ArchiveFinalizer> archiveFinalizers) {
778 finalizers = archiveFinalizers;
779 }
780
781 @Override
782 public void setDotFileDirectory(final File dotFileDirectory) {
783 this.dotFileDirectory = dotFileDirectory;
784 }
785
786 protected boolean isUptodate() throws ArchiverException {
787 final File zipFile = getDestFile();
788 if (!zipFile.exists()) {
789 getLogger().debug("isUp2date: false (Destination " + zipFile.getPath() + " not found.)");
790 return false;
791 }
792 final long destTimestamp = getFileLastModifiedTime(zipFile);
793
794 final Iterator<Object> it = resources.iterator();
795 if (!it.hasNext()) {
796 getLogger().debug("isUp2date: false (No input files.)");
797 return false;
798 }
799
800 while (it.hasNext()) {
801 final Object o = it.next();
802 final long l;
803 if (o instanceof ArchiveEntry) {
804 l = ((ArchiveEntry) o).getResource().getLastModified();
805 } else if (o instanceof AddedResourceCollection) {
806 try {
807 l = ((AddedResourceCollection) o).resources.getLastModified();
808 } catch (final IOException e) {
809 throw new ArchiverException(e.getMessage(), e);
810 }
811 } else {
812 throw new IllegalStateException(
813 "Invalid object type: " + o.getClass().getName());
814 }
815 if (l == PlexusIoResource.UNKNOWN_MODIFICATION_DATE) {
816
817 getLogger().debug("isUp2date: false (Resource with unknown modification date found.)");
818 return false;
819 }
820 if (l > destTimestamp) {
821 getLogger().debug("isUp2date: false (Resource with newer modification date found.)");
822 return false;
823 }
824 }
825
826 getLogger().debug("isUp2date: true");
827 return true;
828 }
829
830
831
832
833
834
835
836
837 private long getFileLastModifiedTime(File file) throws ArchiverException {
838 try {
839 return Files.getLastModifiedTime(file.toPath()).toMillis();
840 } catch (IOException e) {
841 throw new ArchiverException(e.getMessage(), e);
842 }
843 }
844
845 protected boolean checkForced() throws ArchiverException {
846 if (!isForced() && isSupportingForced() && isUptodate()) {
847 getLogger().debug("Archive " + getDestFile() + " is uptodate.");
848 return false;
849 }
850 return true;
851 }
852
853 @Override
854 public boolean isSupportingForced() {
855 return false;
856 }
857
858 protected void runArchiveFinalizers() throws ArchiverException {
859 if (finalizers != null) {
860 for (final ArchiveFinalizer finalizer : finalizers) {
861 finalizer.finalizeArchiveCreation(this);
862 }
863 }
864 }
865
866 @Override
867 public final void createArchive() throws ArchiverException, IOException {
868 validate();
869 try {
870 try {
871 if (dotFileDirectory != null) {
872 addArchiveFinalizer(new DotDirectiveArchiveFinalizer(dotFileDirectory));
873 }
874
875 runArchiveFinalizers();
876
877 execute();
878 } finally {
879 close();
880 }
881 } catch (final IOException e) {
882 String msg = "Problem creating " + getArchiveType() + ": " + e.getMessage();
883
884 final StringBuffer revertBuffer = new StringBuffer();
885 if (!revert(revertBuffer)) {
886 msg += revertBuffer.toString();
887 }
888
889 throw new ArchiverException(msg, e);
890 } finally {
891 cleanUp();
892 }
893
894 postCreateArchive();
895 }
896
897 protected boolean hasVirtualFiles() {
898 if (finalizers != null) {
899 for (final ArchiveFinalizer finalizer : finalizers) {
900 final List virtualFiles = finalizer.getVirtualFiles();
901
902 if ((virtualFiles != null) && !virtualFiles.isEmpty()) {
903 return true;
904 }
905 }
906 }
907 return false;
908 }
909
910 protected boolean revert(final StringBuffer messageBuffer) {
911 return true;
912 }
913
914 protected void validate() throws ArchiverException, IOException {}
915
916
917
918
919
920
921
922
923
924
925
926 protected void postCreateArchive() throws ArchiverException, IOException {}
927
928 protected abstract String getArchiveType();
929
930 private void addCloseable(Object maybeCloseable) {
931 if (maybeCloseable instanceof Closeable) {
932 closeables.add((Closeable) maybeCloseable);
933 }
934 }
935
936 private void closeIterators() {
937 for (Closeable closeable : closeables) {
938 closeQuietlyIfCloseable(closeable);
939 }
940 }
941
942 protected abstract void close() throws IOException;
943
944 protected void cleanUp() throws IOException {
945 closeIterators();
946
947 for (Object resource : resources) {
948 if (resource instanceof PlexusIoProxyResourceCollection) {
949 resource = ((PlexusIoProxyResourceCollection) resource).getSrc();
950 }
951
952 closeIfCloseable(resource);
953 }
954 resources.clear();
955 }
956
957 protected abstract void execute() throws ArchiverException, IOException;
958
959
960
961
962 @Override
963 public boolean isUseJvmChmod() {
964 return useJvmChmod;
965 }
966
967
968
969
970 @Override
971 public void setUseJvmChmod(final boolean useJvmChmod) {
972 this.useJvmChmod = useJvmChmod;
973 }
974
975
976
977
978 @Override
979 public boolean isIgnorePermissions() {
980 return ignorePermissions;
981 }
982
983
984
985
986 @Override
987 public void setIgnorePermissions(final boolean ignorePermissions) {
988 this.ignorePermissions = ignorePermissions;
989 }
990
991
992
993
994 @Override
995 @Deprecated
996 public void setLastModifiedDate(Date lastModifiedDate) {
997 this.lastModifiedTime = lastModifiedDate != null ? FileTime.fromMillis(lastModifiedDate.getTime()) : null;
998 }
999
1000
1001
1002
1003 @Override
1004 @Deprecated
1005 public Date getLastModifiedDate() {
1006 return lastModifiedTime != null ? new Date(lastModifiedTime.toMillis()) : null;
1007 }
1008
1009 @Override
1010 public void setLastModifiedTime(FileTime lastModifiedTime) {
1011 this.lastModifiedTime = lastModifiedTime;
1012 }
1013
1014 @Override
1015 public FileTime getLastModifiedTime() {
1016 return lastModifiedTime;
1017 }
1018
1019 @Override
1020 public void setFilenameComparator(Comparator<String> filenameComparator) {
1021 this.filenameComparator = filenameComparator;
1022 }
1023
1024 public Comparator<String> getFilenameComparator() {
1025 return filenameComparator;
1026 }
1027
1028 @Override
1029 public void setOverrideUid(int uid) {
1030 overrideUid = uid;
1031 }
1032
1033 @Override
1034 public void setOverrideUserName(String userName) {
1035 overrideUserName = userName;
1036 }
1037
1038 @Override
1039 public int getOverrideUid() {
1040 return overrideUid;
1041 }
1042
1043 @Override
1044 public String getOverrideUserName() {
1045 return overrideUserName;
1046 }
1047
1048 @Override
1049 public void setOverrideGid(int gid) {
1050 overrideGid = gid;
1051 }
1052
1053 @Override
1054 public void setOverrideGroupName(String groupName) {
1055 overrideGroupName = groupName;
1056 }
1057
1058 @Override
1059 public int getOverrideGid() {
1060 return overrideGid;
1061 }
1062
1063 @Override
1064 public String getOverrideGroupName() {
1065 return overrideGroupName;
1066 }
1067
1068 @Override
1069 public void setUmask(int umask) {
1070 this.umask = umask;
1071 }
1072
1073 @Override
1074 public int getUmask() {
1075 return umask;
1076 }
1077
1078
1079
1080
1081 @Override
1082 @Deprecated
1083 public void configureReproducible(Date lastModifiedDate) {
1084 configureReproducibleBuild(FileTime.fromMillis(lastModifiedDate.getTime()));
1085 }
1086
1087 @Override
1088 public void configureReproducibleBuild(FileTime lastModifiedTime) {
1089
1090 setLastModifiedTime(normalizeLastModifiedTime(lastModifiedTime));
1091
1092
1093 setFilenameComparator(String::compareTo);
1094
1095
1096 setOverrideUid(0);
1097 setOverrideUserName("root");
1098 setOverrideGid(0);
1099 setOverrideGroupName("root");
1100
1101
1102 setUmask(0_022);
1103 }
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117 protected FileTime normalizeLastModifiedTime(FileTime lastModifiedTime) {
1118 return lastModifiedTime;
1119 }
1120 }