1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.apache.maven.archiver;
20  
21  import javax.lang.model.SourceVersion;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.nio.file.attribute.FileTime;
27  import java.time.Instant;
28  import java.time.OffsetDateTime;
29  import java.time.ZoneOffset;
30  import java.time.format.DateTimeParseException;
31  import java.time.temporal.ChronoUnit;
32  import java.util.ArrayList;
33  import java.util.Collections;
34  import java.util.Date;
35  import java.util.List;
36  import java.util.Map;
37  import java.util.Optional;
38  import java.util.Properties;
39  import java.util.Set;
40  import java.util.jar.Attributes;
41  
42  import org.apache.maven.artifact.Artifact;
43  import org.apache.maven.artifact.DependencyResolutionRequiredException;
44  import org.apache.maven.artifact.versioning.ArtifactVersion;
45  import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
46  import org.apache.maven.execution.MavenSession;
47  import org.apache.maven.project.MavenProject;
48  import org.codehaus.plexus.archiver.jar.JarArchiver;
49  import org.codehaus.plexus.archiver.jar.Manifest;
50  import org.codehaus.plexus.archiver.jar.ManifestException;
51  import org.codehaus.plexus.interpolation.InterpolationException;
52  import org.codehaus.plexus.interpolation.Interpolator;
53  import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
54  import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
55  import org.codehaus.plexus.interpolation.PrefixedPropertiesValueSource;
56  import org.codehaus.plexus.interpolation.RecursionInterceptor;
57  import org.codehaus.plexus.interpolation.StringSearchInterpolator;
58  import org.codehaus.plexus.interpolation.ValueSource;
59  
60  import static org.apache.maven.archiver.ManifestConfiguration.CLASSPATH_LAYOUT_TYPE_CUSTOM;
61  import static org.apache.maven.archiver.ManifestConfiguration.CLASSPATH_LAYOUT_TYPE_REPOSITORY;
62  import static org.apache.maven.archiver.ManifestConfiguration.CLASSPATH_LAYOUT_TYPE_SIMPLE;
63  
64  
65  
66  
67  
68  
69  
70  public class MavenArchiver {
71  
72      private static final String CREATED_BY = "Maven Archiver";
73  
74      
75  
76  
77      public static final String SIMPLE_LAYOUT =
78              "${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}";
79  
80      
81  
82  
83      public static final String REPOSITORY_LAYOUT =
84              "${artifact.groupIdPath}/${artifact.artifactId}/" + "${artifact.baseVersion}/${artifact.artifactId}-"
85                      + "${artifact.version}${dashClassifier?}.${artifact.extension}";
86  
87      
88  
89  
90      public static final String SIMPLE_LAYOUT_NONUNIQUE =
91              "${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}";
92  
93      
94  
95  
96      public static final String REPOSITORY_LAYOUT_NONUNIQUE =
97              "${artifact.groupIdPath}/${artifact.artifactId}/" + "${artifact.baseVersion}/${artifact.artifactId}-"
98                      + "${artifact.baseVersion}${dashClassifier?}.${artifact.extension}";
99  
100     private static final List<String> ARTIFACT_EXPRESSION_PREFIXES;
101 
102     static {
103         List<String> artifactExpressionPrefixes = new ArrayList<>();
104         artifactExpressionPrefixes.add("artifact.");
105 
106         ARTIFACT_EXPRESSION_PREFIXES = artifactExpressionPrefixes;
107     }
108 
109     static boolean isValidModuleName(String name) {
110         return SourceVersion.isName(name);
111     }
112 
113     private JarArchiver archiver;
114 
115     private File archiveFile;
116 
117     private String createdBy;
118 
119     private boolean buildJdkSpecDefaultEntry = true;
120 
121     
122 
123 
124 
125 
126 
127 
128 
129 
130 
131     public Manifest getManifest(MavenSession session, MavenProject project, MavenArchiveConfiguration config)
132             throws ManifestException, DependencyResolutionRequiredException {
133         boolean hasManifestEntries = !config.isManifestEntriesEmpty();
134         Map<String, String> entries = hasManifestEntries ? config.getManifestEntries() : Collections.emptyMap();
135 
136         Manifest manifest = getManifest(session, project, config.getManifest(), entries);
137 
138         
139         if (hasManifestEntries) {
140 
141             for (Map.Entry<String, String> entry : entries.entrySet()) {
142                 String key = entry.getKey();
143                 String value = entry.getValue();
144                 Manifest.Attribute attr = manifest.getMainSection().getAttribute(key);
145                 if (key.equals(Attributes.Name.CLASS_PATH.toString()) && attr != null) {
146                     
147                     
148                     
149                     attr.setValue(value + " " + attr.getValue());
150                 } else {
151                     addManifestAttribute(manifest, key, value);
152                 }
153             }
154         }
155 
156         
157         if (!config.isManifestSectionsEmpty()) {
158             for (ManifestSection section : config.getManifestSections()) {
159                 Manifest.Section theSection = new Manifest.Section();
160                 theSection.setName(section.getName());
161 
162                 if (!section.isManifestEntriesEmpty()) {
163                     Map<String, String> sectionEntries = section.getManifestEntries();
164 
165                     for (Map.Entry<String, String> entry : sectionEntries.entrySet()) {
166                         String key = entry.getKey();
167                         String value = entry.getValue();
168                         Manifest.Attribute attr = new Manifest.Attribute(key, value);
169                         theSection.addConfiguredAttribute(attr);
170                     }
171                 }
172 
173                 manifest.addConfiguredSection(theSection);
174             }
175         }
176 
177         return manifest;
178     }
179 
180     
181 
182 
183 
184 
185 
186 
187 
188 
189     
190     public Manifest getManifest(MavenProject project, ManifestConfiguration config)
191             throws ManifestException, DependencyResolutionRequiredException {
192         return getManifest(null, project, config, Collections.emptyMap());
193     }
194 
195     
196 
197 
198 
199 
200 
201 
202 
203 
204 
205 
206     public Manifest getManifest(MavenSession mavenSession, MavenProject project, ManifestConfiguration config)
207             throws ManifestException, DependencyResolutionRequiredException {
208         return getManifest(mavenSession, project, config, Collections.emptyMap());
209     }
210 
211     private void addManifestAttribute(Manifest manifest, Map<String, String> map, String key, String value)
212             throws ManifestException {
213         if (map.containsKey(key)) {
214             return; 
215         }
216         addManifestAttribute(manifest, key, value);
217     }
218 
219     private void addManifestAttribute(Manifest manifest, String key, String value) throws ManifestException {
220         if (!(value == null || value.isEmpty())) {
221             Manifest.Attribute attr = new Manifest.Attribute(key, value);
222             manifest.addConfiguredAttribute(attr);
223         } else {
224             
225             
226             Manifest.Attribute attr = new Manifest.Attribute(key, "");
227             manifest.addConfiguredAttribute(attr);
228         }
229     }
230 
231     
232 
233 
234 
235 
236 
237 
238 
239 
240 
241 
242 
243     protected Manifest getManifest(
244             MavenSession session, MavenProject project, ManifestConfiguration config, Map<String, String> entries)
245             throws ManifestException, DependencyResolutionRequiredException {
246         
247 
248         Manifest m = new Manifest();
249 
250         if (config.isAddDefaultEntries()) {
251             handleDefaultEntries(project, m, entries);
252         }
253 
254         if (config.isAddBuildEnvironmentEntries()) {
255             handleBuildEnvironmentEntries(session, m, entries);
256         }
257 
258         if (config.isAddClasspath()) {
259             StringBuilder classpath = new StringBuilder();
260 
261             List<String> artifacts = project.getRuntimeClasspathElements();
262             String classpathPrefix = config.getClasspathPrefix();
263             String layoutType = config.getClasspathLayoutType();
264             String layout = config.getCustomClasspathLayout();
265 
266             Interpolator interpolator = new StringSearchInterpolator();
267 
268             for (String artifactFile : artifacts) {
269                 File f = new File(artifactFile);
270                 if (f.getAbsoluteFile().isFile()) {
271                     Artifact artifact = findArtifactWithFile(project.getArtifacts(), f);
272 
273                     if (classpath.length() > 0) {
274                         classpath.append(" ");
275                     }
276                     classpath.append(classpathPrefix);
277 
278                     
279                     
280                     if (artifact == null || layoutType == null) {
281                         classpath.append(f.getName());
282                     } else {
283                         List<ValueSource> valueSources = new ArrayList<>();
284 
285                         handleExtraExpression(artifact, valueSources);
286 
287                         for (ValueSource vs : valueSources) {
288                             interpolator.addValueSource(vs);
289                         }
290 
291                         RecursionInterceptor recursionInterceptor =
292                                 new PrefixAwareRecursionInterceptor(ARTIFACT_EXPRESSION_PREFIXES);
293 
294                         try {
295                             switch (layoutType) {
296                                 case CLASSPATH_LAYOUT_TYPE_SIMPLE:
297                                     if (config.isUseUniqueVersions()) {
298                                         classpath.append(interpolator.interpolate(SIMPLE_LAYOUT, recursionInterceptor));
299                                     } else {
300                                         classpath.append(interpolator.interpolate(
301                                                 SIMPLE_LAYOUT_NONUNIQUE, recursionInterceptor));
302                                     }
303                                     break;
304                                 case CLASSPATH_LAYOUT_TYPE_REPOSITORY:
305                                     
306                                     
307                                     
308                                     if (config.isUseUniqueVersions()) {
309                                         classpath.append(
310                                                 interpolator.interpolate(REPOSITORY_LAYOUT, recursionInterceptor));
311                                     } else {
312                                         classpath.append(interpolator.interpolate(
313                                                 REPOSITORY_LAYOUT_NONUNIQUE, recursionInterceptor));
314                                     }
315                                     break;
316                                 case CLASSPATH_LAYOUT_TYPE_CUSTOM:
317                                     if (layout == null) {
318                                         throw new ManifestException(CLASSPATH_LAYOUT_TYPE_CUSTOM
319                                                 + " layout type was declared, but custom layout expression was not"
320                                                 + " specified. Check your <archive><manifest><customLayout/>"
321                                                 + " element.");
322                                     }
323 
324                                     classpath.append(interpolator.interpolate(layout, recursionInterceptor));
325                                     break;
326                                 default:
327                                     throw new ManifestException("Unknown classpath layout type: '" + layoutType
328                                             + "'. Check your <archive><manifest><layoutType/> element.");
329                             }
330                         } catch (InterpolationException e) {
331                             ManifestException error = new ManifestException(
332                                     "Error interpolating artifact path for classpath entry: " + e.getMessage());
333 
334                             error.initCause(e);
335                             throw error;
336                         } finally {
337                             for (ValueSource vs : valueSources) {
338                                 interpolator.removeValuesSource(vs);
339                             }
340                         }
341                     }
342                 }
343             }
344 
345             if (classpath.length() > 0) {
346                 
347                 
348                 addManifestAttribute(m, "Class-Path", classpath.toString());
349             }
350         }
351 
352         if (config.isAddDefaultSpecificationEntries()) {
353             handleSpecificationEntries(project, entries, m);
354         }
355 
356         if (config.isAddDefaultImplementationEntries()) {
357             handleImplementationEntries(project, entries, m);
358         }
359 
360         String mainClass = config.getMainClass();
361         if (mainClass != null && !"".equals(mainClass)) {
362             addManifestAttribute(m, entries, "Main-Class", mainClass);
363         }
364 
365         if (config.isAddExtensions()) {
366             handleExtensions(project, entries, m);
367         }
368 
369         addCustomEntries(m, entries, config);
370 
371         return m;
372     }
373 
374     private void handleExtraExpression(Artifact artifact, List<ValueSource> valueSources) {
375         valueSources.add(new PrefixedObjectValueSource(ARTIFACT_EXPRESSION_PREFIXES, artifact, true));
376         valueSources.add(
377                 new PrefixedObjectValueSource(ARTIFACT_EXPRESSION_PREFIXES, artifact.getArtifactHandler(), true));
378 
379         Properties extraExpressions = new Properties();
380         
381         
382         if (!artifact.isSnapshot()) {
383             extraExpressions.setProperty("baseVersion", artifact.getVersion());
384         }
385 
386         extraExpressions.setProperty("groupIdPath", artifact.getGroupId().replace('.', '/'));
387         String classifier = artifact.getClassifier();
388         if (classifier != null && !classifier.isEmpty()) {
389             extraExpressions.setProperty("dashClassifier", "-" + classifier);
390             extraExpressions.setProperty("dashClassifier?", "-" + classifier);
391         } else {
392             extraExpressions.setProperty("dashClassifier", "");
393             extraExpressions.setProperty("dashClassifier?", "");
394         }
395         valueSources.add(new PrefixedPropertiesValueSource(ARTIFACT_EXPRESSION_PREFIXES, extraExpressions, true));
396     }
397 
398     private void handleExtensions(MavenProject project, Map<String, String> entries, Manifest m)
399             throws ManifestException {
400         
401         StringBuilder extensionsList = new StringBuilder();
402         Set<Artifact> artifacts = project.getArtifacts();
403 
404         for (Artifact artifact : artifacts) {
405             if (!Artifact.SCOPE_TEST.equals(artifact.getScope())) {
406                 if ("jar".equals(artifact.getType())) {
407                     if (extensionsList.length() > 0) {
408                         extensionsList.append(" ");
409                     }
410                     extensionsList.append(artifact.getArtifactId());
411                 }
412             }
413         }
414 
415         if (extensionsList.length() > 0) {
416             addManifestAttribute(m, entries, "Extension-List", extensionsList.toString());
417         }
418 
419         for (Artifact artifact : artifacts) {
420             
421             
422             if ("jar".equals(artifact.getType())) {
423                 String artifactId = artifact.getArtifactId().replace('.', '_');
424                 String ename = artifactId + "-Extension-Name";
425                 addManifestAttribute(m, entries, ename, artifact.getArtifactId());
426                 String iname = artifactId + "-Implementation-Version";
427                 addManifestAttribute(m, entries, iname, artifact.getVersion());
428 
429                 if (artifact.getRepository() != null) {
430                     iname = artifactId + "-Implementation-URL";
431                     String url = artifact.getRepository().getUrl() + "/" + artifact;
432                     addManifestAttribute(m, entries, iname, url);
433                 }
434             }
435         }
436     }
437 
438     private void handleImplementationEntries(MavenProject project, Map<String, String> entries, Manifest m)
439             throws ManifestException {
440         addManifestAttribute(m, entries, "Implementation-Title", project.getName());
441         addManifestAttribute(m, entries, "Implementation-Version", project.getVersion());
442 
443         if (project.getOrganization() != null) {
444             addManifestAttribute(
445                     m,
446                     entries,
447                     "Implementation-Vendor",
448                     project.getOrganization().getName());
449         }
450     }
451 
452     private void handleSpecificationEntries(MavenProject project, Map<String, String> entries, Manifest m)
453             throws ManifestException {
454         addManifestAttribute(m, entries, "Specification-Title", project.getName());
455 
456         try {
457             ArtifactVersion version = project.getArtifact().getSelectedVersion();
458             String specVersion = String.format("%s.%s", version.getMajorVersion(), version.getMinorVersion());
459             addManifestAttribute(m, entries, "Specification-Version", specVersion);
460         } catch (OverConstrainedVersionException e) {
461             throw new ManifestException("Failed to get selected artifact version to calculate"
462                     + " the specification version: " + e.getMessage());
463         }
464 
465         if (project.getOrganization() != null) {
466             addManifestAttribute(
467                     m,
468                     entries,
469                     "Specification-Vendor",
470                     project.getOrganization().getName());
471         }
472     }
473 
474     private void addCustomEntries(Manifest m, Map<String, String> entries, ManifestConfiguration config)
475             throws ManifestException {
476         
477 
478 
479 
480 
481         if (config.getPackageName() != null) {
482             addManifestAttribute(m, entries, "Package", config.getPackageName());
483         }
484     }
485 
486     
487 
488 
489 
490 
491     public JarArchiver getArchiver() {
492         return archiver;
493     }
494 
495     
496 
497 
498 
499 
500     public void setArchiver(JarArchiver archiver) {
501         this.archiver = archiver;
502     }
503 
504     
505 
506 
507 
508 
509     public void setOutputFile(File outputFile) {
510         archiveFile = outputFile;
511     }
512 
513     
514 
515 
516 
517 
518 
519 
520 
521 
522 
523 
524     public void createArchive(
525             MavenSession session, MavenProject project, MavenArchiveConfiguration archiveConfiguration)
526             throws ManifestException, IOException, DependencyResolutionRequiredException {
527         
528         
529         MavenProject workingProject = project.clone();
530 
531         boolean forced = archiveConfiguration.isForced();
532         if (archiveConfiguration.isAddMavenDescriptor()) {
533             
534             
535             
536             
537             
538             
539             
540             
541             
542             
543 
544             if (workingProject.getArtifact().isSnapshot()) {
545                 workingProject.setVersion(workingProject.getArtifact().getVersion());
546             }
547 
548             String groupId = workingProject.getGroupId();
549 
550             String artifactId = workingProject.getArtifactId();
551 
552             archiver.addFile(project.getFile(), "META-INF/maven/" + groupId + "/" + artifactId + "/pom.xml");
553 
554             
555             
556             
557 
558             File customPomPropertiesFile = archiveConfiguration.getPomPropertiesFile();
559             File dir = new File(workingProject.getBuild().getDirectory(), "maven-archiver");
560             File pomPropertiesFile = new File(dir, "pom.properties");
561 
562             new PomPropertiesUtil()
563                     .createPomProperties(workingProject, archiver, customPomPropertiesFile, pomPropertiesFile, forced);
564         }
565 
566         
567         
568         
569 
570         archiver.setMinimalDefaultManifest(true);
571 
572         File manifestFile = archiveConfiguration.getManifestFile();
573 
574         if (manifestFile != null) {
575             archiver.setManifest(manifestFile);
576         }
577 
578         Manifest manifest = getManifest(session, workingProject, archiveConfiguration);
579 
580         
581         archiver.addConfiguredManifest(manifest);
582         archiver.setCompress(archiveConfiguration.isCompress());
583         archiver.setRecompressAddedZips(archiveConfiguration.isRecompressAddedZips());
584         archiver.setDestFile(archiveFile);
585 
586         archiver.setForced(forced);
587         if (!archiveConfiguration.isForced() && archiver.isSupportingForced()) {
588             
589             
590             
591         }
592 
593         String automaticModuleName = manifest.getMainSection().getAttributeValue("Automatic-Module-Name");
594         if (automaticModuleName != null) {
595             if (automaticModuleName.isEmpty()) {
596                 manifest.getMainSection().removeAttribute("Automatic-Module-Name");
597             } else if (!isValidModuleName(automaticModuleName)) {
598                 throw new ManifestException("Invalid automatic module name: '" + automaticModuleName + "'");
599             }
600         }
601 
602         
603         archiver.createArchive();
604     }
605 
606     private void handleDefaultEntries(MavenProject project, Manifest m, Map<String, String> entries)
607             throws ManifestException {
608         String createdBy = this.createdBy;
609         if (createdBy == null) {
610             createdBy = createdBy(CREATED_BY, "org.apache.maven", "maven-archiver");
611         }
612         addManifestAttribute(m, entries, "Created-By", createdBy);
613         String javaVersion = BuildHelper.discoverJavaRelease(project);
614         if (javaVersion != null) {
615             addManifestAttribute(m, entries, "Java-Version", javaVersion);
616         }
617         if (buildJdkSpecDefaultEntry) {
618             addManifestAttribute(m, entries, "Build-Jdk-Spec", System.getProperty("java.specification.version"));
619         }
620     }
621 
622     private void handleBuildEnvironmentEntries(MavenSession session, Manifest m, Map<String, String> entries)
623             throws ManifestException {
624         addManifestAttribute(
625                 m,
626                 entries,
627                 "Build-Tool",
628                 session != null ? session.getSystemProperties().getProperty("maven.build.version") : "Apache Maven");
629         addManifestAttribute(
630                 m,
631                 entries,
632                 "Build-Jdk",
633                 String.format("%s (%s)", System.getProperty("java.version"), System.getProperty("java.vendor")));
634         addManifestAttribute(
635                 m,
636                 entries,
637                 "Build-Os",
638                 String.format(
639                         "%s (%s; %s)",
640                         System.getProperty("os.name"),
641                         System.getProperty("os.version"),
642                         System.getProperty("os.arch")));
643     }
644 
645     private Artifact findArtifactWithFile(Set<Artifact> artifacts, File file) {
646         for (Artifact artifact : artifacts) {
647             
648             if (artifact.getFile() != null) {
649                 if (artifact.getFile().equals(file)) {
650                     return artifact;
651                 }
652             }
653         }
654         return null;
655     }
656 
657     private static String getCreatedByVersion(String groupId, String artifactId) {
658         final Properties properties = loadOptionalProperties(MavenArchiver.class.getResourceAsStream(
659                 "/META-INF/maven/" + groupId + "/" + artifactId + "/pom.properties"));
660 
661         return properties.getProperty("version");
662     }
663 
664     private static Properties loadOptionalProperties(final InputStream inputStream) {
665         Properties properties = new Properties();
666         if (inputStream != null) {
667             try (InputStream in = inputStream) {
668                 properties.load(in);
669             } catch (IllegalArgumentException | IOException ex) {
670                 
671             }
672         }
673         return properties;
674     }
675 
676     
677 
678 
679 
680 
681 
682 
683 
684     public void setCreatedBy(String description, String groupId, String artifactId) {
685         createdBy = createdBy(description, groupId, artifactId);
686     }
687 
688     private String createdBy(String description, String groupId, String artifactId) {
689         String createdBy = description;
690         String version = getCreatedByVersion(groupId, artifactId);
691         if (version != null) {
692             createdBy += " " + version;
693         }
694         return createdBy;
695     }
696 
697     
698 
699 
700 
701 
702 
703 
704 
705     public void setBuildJdkSpecDefaultEntry(boolean buildJdkSpecDefaultEntry) {
706         this.buildJdkSpecDefaultEntry = buildJdkSpecDefaultEntry;
707     }
708 
709     
710 
711 
712 
713 
714 
715 
716 
717 
718 
719 
720 
721     @Deprecated
722     public Date parseOutputTimestamp(String outputTimestamp) {
723         return parseBuildOutputTimestamp(outputTimestamp).map(Date::from).orElse(null);
724     }
725 
726     
727 
728 
729 
730 
731 
732 
733 
734 
735     @Deprecated
736     public Date configureReproducible(String outputTimestamp) {
737         configureReproducibleBuild(outputTimestamp);
738         return parseOutputTimestamp(outputTimestamp);
739     }
740 
741     
742 
743 
744 
745 
746 
747 
748 
749 
750 
751 
752 
753 
754 
755 
756 
757 
758     public static Optional<Instant> parseBuildOutputTimestamp(String outputTimestamp) {
759         
760         
761         if (outputTimestamp == null || (outputTimestamp.length() < 2 && !isNumeric(outputTimestamp))) {
762             
763             outputTimestamp = System.getenv("SOURCE_DATE_EPOCH");
764             if (outputTimestamp == null) {
765                 return Optional.empty();
766             }
767         }
768 
769         
770         if (isNumeric(outputTimestamp)) {
771             final Instant date = Instant.ofEpochSecond(Long.parseLong(outputTimestamp));
772             return Optional.of(date);
773         }
774 
775         try {
776             
777             final Instant date = OffsetDateTime.parse(outputTimestamp)
778                     .withOffsetSameInstant(ZoneOffset.UTC)
779                     .truncatedTo(ChronoUnit.SECONDS)
780                     .toInstant();
781             return Optional.of(date);
782         } catch (DateTimeParseException pe) {
783             throw new IllegalArgumentException(
784                     "Invalid project.build.outputTimestamp value '" + outputTimestamp + "'", pe);
785         }
786     }
787 
788     private static boolean isNumeric(String str) {
789         if (str.isEmpty()) {
790             return false;
791         }
792 
793         for (char c : str.toCharArray()) {
794             if (!Character.isDigit(c)) {
795                 return false;
796             }
797         }
798 
799         return true;
800     }
801 
802     
803 
804 
805 
806 
807 
808 
809     public void configureReproducibleBuild(String outputTimestamp) {
810         parseBuildOutputTimestamp(outputTimestamp).map(FileTime::from).ifPresent(modifiedTime -> getArchiver()
811                 .configureReproducibleBuild(modifiedTime));
812     }
813 }