1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package io.wcm.devops.conga.plugins.aem.maven.allpackage;
21
22 import static io.wcm.devops.conga.generator.util.FileUtil.getCanonicalPath;
23 import static io.wcm.devops.conga.plugins.aem.maven.allpackage.RunModeUtil.RUNMODE_AUTHOR;
24 import static io.wcm.devops.conga.plugins.aem.maven.allpackage.RunModeUtil.RUNMODE_PUBLISH;
25 import static io.wcm.devops.conga.plugins.aem.maven.allpackage.RunModeUtil.eliminateAuthorPublishDuplicates;
26 import static io.wcm.devops.conga.plugins.aem.maven.allpackage.RunModeUtil.isAuthorAndPublish;
27 import static io.wcm.devops.conga.plugins.aem.maven.allpackage.RunModeUtil.isOnlyAuthor;
28 import static io.wcm.devops.conga.plugins.aem.maven.allpackage.RunModeUtil.isOnlyPublish;
29 import static org.apache.jackrabbit.vault.packaging.PackageProperties.NAME_DEPENDENCIES;
30 import static org.apache.jackrabbit.vault.packaging.PackageProperties.NAME_NAME;
31 import static org.apache.jackrabbit.vault.packaging.PackageProperties.NAME_PACKAGE_TYPE;
32 import static org.apache.jackrabbit.vault.packaging.PackageProperties.NAME_VERSION;
33
34 import java.io.File;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collection;
41 import java.util.Collections;
42 import java.util.Enumeration;
43 import java.util.HashSet;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Objects;
47 import java.util.Optional;
48 import java.util.Properties;
49 import java.util.Set;
50 import java.util.stream.Collectors;
51
52 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
53 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
54 import org.apache.commons.compress.archivers.zip.ZipFile;
55 import org.apache.commons.io.FileUtils;
56 import org.apache.commons.io.FilenameUtils;
57 import org.apache.commons.io.IOUtils;
58 import org.apache.commons.lang3.StringUtils;
59 import org.apache.commons.lang3.Strings;
60 import org.apache.jackrabbit.vault.packaging.Dependency;
61 import org.apache.jackrabbit.vault.packaging.DependencyUtil;
62 import org.apache.jackrabbit.vault.packaging.PackageType;
63 import org.apache.jackrabbit.vault.packaging.VersionRange;
64 import org.apache.maven.artifact.ArtifactUtils;
65 import org.apache.maven.plugin.logging.Log;
66 import org.apache.maven.plugin.logging.SystemStreamLog;
67 import org.jetbrains.annotations.NotNull;
68 import org.jetbrains.annotations.Nullable;
69
70 import io.wcm.devops.conga.plugins.aem.maven.AutoDependenciesMode;
71 import io.wcm.devops.conga.plugins.aem.maven.BuildOutputTimestamp;
72 import io.wcm.devops.conga.plugins.aem.maven.PackageTypeValidation;
73 import io.wcm.devops.conga.plugins.aem.maven.PackageVersionMode;
74 import io.wcm.devops.conga.plugins.aem.maven.RunModeOptimization;
75 import io.wcm.devops.conga.plugins.aem.maven.model.BundleFile;
76 import io.wcm.devops.conga.plugins.aem.maven.model.ContentPackageFile;
77 import io.wcm.devops.conga.plugins.aem.maven.model.InstallableFile;
78 import io.wcm.tooling.commons.contentpackagebuilder.ContentPackage;
79 import io.wcm.tooling.commons.contentpackagebuilder.ContentPackageBuilder;
80 import io.wcm.tooling.commons.contentpackagebuilder.PackageFilter;
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 public final class AllPackageBuilder {
106
107 private final File targetFile;
108 private final String groupName;
109 private final String packageName;
110 private String version;
111 private AutoDependenciesMode autoDependenciesMode = AutoDependenciesMode.OFF;
112 private RunModeOptimization runModeOptimization = RunModeOptimization.OFF;
113 private PackageTypeValidation packageTypeValidation = PackageTypeValidation.STRICT;
114 private PackageVersionMode packageVersionMode = PackageVersionMode.DEFAULT;
115 private Log log;
116 private BuildOutputTimestamp buildOutputTimestamp;
117
118 private static final String RUNMODE_DEFAULT = "$default$";
119 private static final Set<String> ALLOWED_PACKAGE_TYPES = Set.of(
120 PackageType.APPLICATION.name().toLowerCase(),
121 PackageType.CONTAINER.name().toLowerCase(),
122 PackageType.CONTENT.name().toLowerCase());
123 private static final String VERSION_SUFFIX_SEPARATOR = "-";
124
125 private final List<ContentPackageFileSet> contentPackageFileSets = new ArrayList<>();
126 private final List<BundleFileSet> bundleFileSets = new ArrayList<>();
127
128
129
130
131
132
133
134 public AllPackageBuilder(File targetFile, String groupName, String packageName) {
135 this.targetFile = targetFile;
136 this.groupName = groupName;
137 this.packageName = packageName;
138 }
139
140
141
142
143
144
145 public AllPackageBuilder autoDependenciesMode(AutoDependenciesMode value) {
146 this.autoDependenciesMode = value;
147 return this;
148 }
149
150
151
152
153
154
155 public AllPackageBuilder runModeOptimization(RunModeOptimization value) {
156 this.runModeOptimization = value;
157 return this;
158 }
159
160
161
162
163
164
165 public AllPackageBuilder packageTypeValidation(PackageTypeValidation value) {
166 this.packageTypeValidation = value;
167 return this;
168 }
169
170
171
172
173
174
175 public AllPackageBuilder packageVersionMode(PackageVersionMode value) {
176 this.packageVersionMode = value;
177 return this;
178 }
179
180
181
182
183
184
185 public AllPackageBuilder logger(Log value) {
186 this.log = value;
187 return this;
188 }
189
190
191
192
193
194
195 public AllPackageBuilder version(String value) {
196 this.version = value;
197 return this;
198 }
199
200
201
202
203
204
205 public AllPackageBuilder buildOutputTimestamp(BuildOutputTimestamp value) {
206 this.buildOutputTimestamp = value;
207 return this;
208 }
209
210 private Log getLog() {
211 if (this.log == null) {
212 this.log = new SystemStreamLog();
213 }
214 return this.log;
215 }
216
217
218
219
220
221
222
223 public void add(List<InstallableFile> files, Set<String> cloudManagerTarget) {
224 List<ContentPackageFile> contentPackages = filterFiles(files, ContentPackageFile.class);
225
226
227 List<String> environmentRunModes = new ArrayList<>();
228 if (cloudManagerTarget.isEmpty()) {
229 environmentRunModes.add(RUNMODE_DEFAULT);
230 }
231 else {
232 environmentRunModes.addAll(cloudManagerTarget);
233 }
234
235 List<ContentPackageFile> validContentPackages;
236 switch (packageTypeValidation) {
237 case STRICT:
238 validContentPackages = getValidContentPackagesStrictValidation(contentPackages);
239 break;
240 case WARN:
241 validContentPackages = getValidContentPackagesWarnValidation(contentPackages);
242 break;
243 default:
244 throw new IllegalArgumentException("Unsupported package type validation: " + packageTypeValidation);
245 }
246
247 if (!validContentPackages.isEmpty()) {
248 contentPackageFileSets.add(new ContentPackageFileSet(validContentPackages, environmentRunModes));
249 }
250
251
252 List<BundleFile> bundles = filterFiles(files, BundleFile.class);
253 if (!bundles.isEmpty()) {
254 bundleFileSets.add(new BundleFileSet(bundles, environmentRunModes));
255 }
256 }
257
258
259
260
261
262
263
264 private List<ContentPackageFile> getValidContentPackagesStrictValidation(List<? extends ContentPackageFile> contentPackages) {
265
266 contentPackages.stream()
267 .filter(pkg -> !hasPackageType(pkg))
268 .forEach(pkg -> getLog().warn("Skipping content package without package type: " + getCanonicalPath(pkg.getFile())));
269
270
271 List<ContentPackageFile> invalidPackageTypeContentPackages = contentPackages.stream()
272 .filter(AllPackageBuilder::hasPackageType)
273 .filter(pkg -> !isValidPackageType(pkg))
274 .collect(Collectors.toList());
275 if (!invalidPackageTypeContentPackages.isEmpty()) {
276 throw new IllegalArgumentException("Content packages found with unsupported package types: " +
277 invalidPackageTypeContentPackages.stream()
278 .map(pkg -> pkg.getName() + " -> " + pkg.getPackageType())
279 .collect(Collectors.joining(", ")));
280 }
281
282
283 return contentPackages.stream()
284 .filter(AllPackageBuilder::hasPackageType)
285 .collect(Collectors.toList());
286 }
287
288
289
290
291
292
293 private List<ContentPackageFile> getValidContentPackagesWarnValidation(List<? extends ContentPackageFile> contentPackages) {
294
295 contentPackages.stream()
296 .filter(pkg -> !hasPackageType(pkg))
297 .forEach(pkg -> getLog().warn("Found content package without package type: " + getCanonicalPath(pkg.getFile())));
298
299
300 contentPackages.stream()
301 .filter(AllPackageBuilder::hasPackageType)
302 .filter(pkg -> !isValidPackageType(pkg))
303 .forEach(pkg -> getLog().warn("Found content package with invalid package type: "
304 + getCanonicalPath(pkg.getFile()) + " -> " + pkg.getPackageType()));
305
306
307 return contentPackages.stream().collect(Collectors.toList());
308 }
309
310 private static <T> List<T> filterFiles(List<? extends InstallableFile> files, Class<T> fileClass) {
311 return files.stream()
312 .filter(fileClass::isInstance)
313 .map(fileClass::cast)
314 .toList();
315 }
316
317
318
319
320
321
322
323 public boolean build(Map<String, String> properties) throws IOException {
324
325 if (contentPackageFileSets.isEmpty()) {
326 return false;
327 }
328
329
330 ContentPackageBuilder builder = new ContentPackageBuilder()
331 .group(groupName)
332 .name(packageName)
333 .packageType("container");
334 if (version != null) {
335 builder.version(version);
336 }
337
338
339 String rootPath = buildRootPath(groupName, packageName);
340 builder.filter(new PackageFilter(rootPath));
341
342
343 if (properties != null) {
344 properties.entrySet().forEach(entry -> builder.property(entry.getKey(), entry.getValue()));
345 }
346
347
348 try (ContentPackage contentPackage = builder.build(targetFile)) {
349 buildAddContentPackages(contentPackage, rootPath);
350 buildAddBundles(contentPackage, rootPath);
351 }
352
353 return true;
354 }
355
356 @SuppressWarnings("java:S3776")
357 private void buildAddContentPackages(ContentPackage contentPackage, String rootPath) throws IOException {
358
359 Set<Dependency> allPackagesFromFileSets = new HashSet<>();
360 for (ContentPackageFileSet fileSet : contentPackageFileSets) {
361 for (ContentPackageFile pkg : fileSet.getFiles()) {
362 addDependencyInformation(allPackagesFromFileSets, pkg);
363 }
364 }
365
366 Collection<ContentPackageFileSet> processedFileSets;
367 if (runModeOptimization == RunModeOptimization.ELIMINATE_DUPLICATES) {
368
369 processedFileSets = eliminateAuthorPublishDuplicates(contentPackageFileSets,
370 environmentRunMode -> new ContentPackageFileSet(new ArrayList<>(), Collections.singletonList(environmentRunMode)));
371 }
372 else {
373 processedFileSets = contentPackageFileSets;
374 }
375
376 for (ContentPackageFileSet fileSet : processedFileSets) {
377 for (String environmentRunMode : fileSet.getEnvironmentRunModes()) {
378 List<ContentPackageFile> previousPackages = new ArrayList<>();
379 for (ContentPackageFile pkg : fileSet.getFiles()) {
380 ContentPackageFile previousPkg = getDependencyChainPreviousPackage(pkg, previousPackages);
381
382
383 List<TemporaryContentPackageFile> processedFiles = processContentPackage(pkg, previousPkg, environmentRunMode, allPackagesFromFileSets);
384
385
386 try {
387 for (TemporaryContentPackageFile processedFile : processedFiles) {
388 String path = buildPackagePath(processedFile, rootPath, environmentRunMode);
389 contentPackage.addFile(path, processedFile.getFile());
390 if (log.isDebugEnabled()) {
391 log.debug(" Add " + processedFile.getPackageInfoWithDependencies());
392 }
393 }
394 }
395 finally {
396 processedFiles.stream()
397 .map(TemporaryContentPackageFile::getFile)
398 .forEach(FileUtils::deleteQuietly);
399 }
400
401 previousPackages.add(pkg);
402 }
403 }
404 }
405 }
406
407
408
409
410
411
412
413 private @Nullable ContentPackageFile getDependencyChainPreviousPackage(@NotNull ContentPackageFile currentPackage,
414 @NotNull List<ContentPackageFile> previousPackages) {
415 if ((autoDependenciesMode == AutoDependenciesMode.OFF)
416 || (autoDependenciesMode == AutoDependenciesMode.IMMUTABLE_ONLY && isMutable(currentPackage))) {
417 return null;
418 }
419
420 return previousPackages.stream()
421
422 .filter(item -> (autoDependenciesMode == AutoDependenciesMode.IMMUTABLE_MUTABLE_COMBINED) || mutableMatches(item, currentPackage))
423
424 .filter(item -> isAuthorAndPublish(item)
425 || (isOnlyAuthor(item) && isOnlyAuthor(currentPackage))
426 || (isOnlyPublish(item) && isOnlyPublish(currentPackage)))
427
428 .filter(item -> !item.isDependencyChainIgnore())
429
430 .reduce((first, second) -> second).orElse(null);
431 }
432
433 private void buildAddBundles(ContentPackage contentPackage, String rootPath) throws IOException {
434 Collection<BundleFileSet> processedFileSets;
435 if (runModeOptimization == RunModeOptimization.ELIMINATE_DUPLICATES) {
436
437 processedFileSets = eliminateAuthorPublishDuplicates(bundleFileSets,
438 environmentRunMode -> new BundleFileSet(new ArrayList<>(), Collections.singletonList(environmentRunMode)));
439 }
440 else {
441 processedFileSets = bundleFileSets;
442 }
443
444 for (BundleFileSet bundleFileSet : processedFileSets) {
445 for (String environmentRunMode : bundleFileSet.getEnvironmentRunModes()) {
446 for (BundleFile bundleFile : bundleFileSet.getFiles()) {
447 String path = buildBundlePath(bundleFile, rootPath, environmentRunMode);
448 contentPackage.addFile(path, bundleFile.getFile());
449 }
450 }
451 }
452 }
453
454 private static boolean hasPackageType(ContentPackageFile pkg) {
455
456 return pkg.getPackageType() != null;
457 }
458
459 private static boolean isValidPackageType(ContentPackageFile pkg) {
460
461 return ALLOWED_PACKAGE_TYPES.contains(pkg.getPackageType());
462 }
463
464 private static boolean isMutable(ContentPackageFile pkg) {
465 return Strings.CS.equals("content", pkg.getPackageType());
466 }
467
468 private static boolean mutableMatches(ContentPackageFile pkg1, ContentPackageFile pkg2) {
469 if (pkg1 == null || pkg2 == null) {
470 return false;
471 }
472 return isMutable(pkg1) == isMutable(pkg2);
473 }
474
475
476
477
478
479
480
481 private static String buildRootPath(String groupName, String packageName) {
482 return "/apps/" + groupName + "-" + packageName + "-packages";
483 }
484
485
486
487
488
489
490 private static String buildRunModeSuffix(InstallableFile file, String environmentRunMode) {
491 StringBuilder runModeSuffix = new StringBuilder();
492 if (isOnlyAuthor(file)) {
493 runModeSuffix.append(".").append(RUNMODE_AUTHOR);
494 }
495 else if (isOnlyPublish(file)) {
496 runModeSuffix.append(".").append(RUNMODE_PUBLISH);
497 }
498 if (!Strings.CS.equals(environmentRunMode, RUNMODE_DEFAULT)) {
499 runModeSuffix.append(".").append(environmentRunMode);
500 }
501 return runModeSuffix.toString();
502 }
503
504
505
506
507
508
509
510 private String buildVersionSuffix(ContentPackageFile pkg, boolean ignoreSnapshot) {
511 StringBuilder versionSuffix = new StringBuilder();
512
513 if (this.packageVersionMode == PackageVersionMode.RELEASE_SUFFIX_VERSION
514 && (!ArtifactUtils.isSnapshot(pkg.getVersion()) || !ignoreSnapshot)
515 && !Strings.CS.equals(pkg.getVersion(), this.version)
516 && this.version != null) {
517 versionSuffix.append(VERSION_SUFFIX_SEPARATOR)
518
519 .append(Strings.CS.replace(this.version, ".", "_"));
520 }
521
522 return versionSuffix.toString();
523 }
524
525
526
527
528
529
530
531 @SuppressWarnings("java:S1075")
532 private String buildPackagePath(ContentPackageFile pkg, String rootPath, String environmentRunMode) {
533 if (packageTypeValidation == PackageTypeValidation.STRICT && !isValidPackageType(pkg)) {
534 throw new IllegalArgumentException("Package " + pkg.getPackageInfo() + " has invalid package type: '" + pkg.getPackageType() + "'.");
535 }
536
537 String runModeSuffix = buildRunModeSuffix(pkg, environmentRunMode);
538
539
540 String path = rootPath + "/" + Objects.toString(pkg.getPackageType(), "misc") + "/install" + runModeSuffix;
541
542 String versionSuffix = "";
543 String packageVersion = pkg.getVersion();
544 String packageVersionWithoutSuffix = packageVersion;
545 if (this.packageVersionMode == PackageVersionMode.RELEASE_SUFFIX_VERSION && this.version != null) {
546 packageVersionWithoutSuffix = Strings.CS.removeEnd(packageVersion, buildVersionSuffix(pkg, false));
547 }
548 if (packageVersion != null && pkg.getFile().getName().contains(packageVersionWithoutSuffix)) {
549 versionSuffix = "-" + packageVersion;
550 }
551 String fileName = pkg.getName() + versionSuffix
552 + "." + FilenameUtils.getExtension(pkg.getFile().getName());
553 return path + "/" + fileName;
554 }
555
556
557
558
559
560
561
562 private static String buildBundlePath(BundleFile bundleFile, String rootPath, String environmentRunMode) {
563 String runModeSuffix = buildRunModeSuffix(bundleFile, environmentRunMode);
564
565
566 String path = rootPath + "/application/install" + runModeSuffix;
567
568 return path + "/" + bundleFile.getFile().getName();
569 }
570
571
572
573
574
575
576
577
578
579
580
581
582 @SuppressWarnings("java:S3776")
583 private List<TemporaryContentPackageFile> processContentPackage(ContentPackageFile pkg,
584 ContentPackageFile previousPkg, String environmentRunMode,
585 Set<Dependency> allPackagesFromFileSets) throws IOException {
586
587 List<TemporaryContentPackageFile> result = new ArrayList<>();
588 List<TemporaryContentPackageFile> subPackages = new ArrayList<>();
589
590
591 File tempFile = File.createTempFile(FilenameUtils.getBaseName(pkg.getFile().getName()), ".zip");
592
593
594 try (ZipFile zipFileIn = new ZipFile.Builder().setFile(pkg.getFile()).get()) {
595
596
597 try (FileOutputStream fos = new FileOutputStream(tempFile);
598 ZipArchiveOutputStream zipOut = new ZipArchiveOutputStream(fos)) {
599 Enumeration<? extends ZipArchiveEntry> zipInEntries = zipFileIn.getEntries();
600 while (zipInEntries.hasMoreElements()) {
601 ZipArchiveEntry zipInEntry = zipInEntries.nextElement();
602 if (!zipInEntry.isDirectory()) {
603 try (InputStream is = zipFileIn.getInputStream(zipInEntry)) {
604 boolean processedEntry = false;
605
606
607 if (Strings.CS.equals(zipInEntry.getName(), "META-INF/vault/properties.xml")) {
608 FileVaultProperties fileVaultProps = new FileVaultProperties(is);
609 Properties props = fileVaultProps.getProperties();
610 addSuffixToPackageName(props, pkg, environmentRunMode);
611 addSuffixToVersion(props, pkg);
612
613
614 ContentPackageFile dependencyFile = previousPkg;
615 if (autoDependenciesMode == AutoDependenciesMode.OFF || pkg.isDependencyChainIgnore()) {
616 dependencyFile = null;
617 }
618 updateDependencies(pkg, props, dependencyFile, environmentRunMode, allPackagesFromFileSets);
619
620
621 String packageType = pkg.getPackageType();
622 if (props.get(NAME_PACKAGE_TYPE) == null && packageType != null) {
623 props.put(NAME_PACKAGE_TYPE, packageType);
624 }
625
626 ZipArchiveEntry zipOutEntry = newZipEntry(zipInEntry);
627 zipOut.putArchiveEntry(zipOutEntry);
628 fileVaultProps.storeToXml(zipOut);
629 zipOut.closeArchiveEntry();
630 processedEntry = true;
631 }
632
633
634 else if (Strings.CS.equals(FilenameUtils.getExtension(zipInEntry.getName()), "zip")) {
635 File tempSubPackageFile = File.createTempFile(FilenameUtils.getBaseName(zipInEntry.getName()), ".zip");
636 try (FileOutputStream subPackageFos = new FileOutputStream(tempSubPackageFile)) {
637 IOUtils.copy(is, subPackageFos);
638 }
639
640
641
642
643 TemporaryContentPackageFile tempSubPackage = new TemporaryContentPackageFile(tempSubPackageFile, pkg.getVariants());
644 if (packageTypeValidation == PackageTypeValidation.STRICT && !isValidPackageType(tempSubPackage)) {
645 throw new IllegalArgumentException("Package " + pkg.getPackageInfo() + " contains sub package " + tempSubPackage.getPackageInfo()
646 + " with invalid package type: '" + StringUtils.defaultString(tempSubPackage.getPackageType()) + "'");
647 }
648 if (StringUtils.isNoneBlank(tempSubPackage.getGroup(), tempSubPackage.getName())) {
649 subPackages.add(tempSubPackage);
650 processedEntry = true;
651 }
652 else {
653 FileUtils.deleteQuietly(tempSubPackageFile);
654 }
655 }
656
657
658 if (!processedEntry) {
659 ZipArchiveEntry zipOutEntry = newZipEntry(zipInEntry);
660 zipOut.putArchiveEntry(zipOutEntry);
661 IOUtils.copy(is, zipOut);
662 zipOut.closeArchiveEntry();
663 }
664 }
665
666 }
667 }
668 }
669
670
671 for (TemporaryContentPackageFile tempSubPackage : subPackages) {
672 addDependencyInformation(allPackagesFromFileSets, tempSubPackage);
673 }
674
675
676 for (TemporaryContentPackageFile tempSubPackage : subPackages) {
677 result.addAll(processContentPackage(tempSubPackage, previousPkg, environmentRunMode, allPackagesFromFileSets));
678 }
679
680 result.add(new TemporaryContentPackageFile(tempFile, pkg.getVariants()));
681 }
682 return result;
683 }
684
685 private ZipArchiveEntry newZipEntry(ZipArchiveEntry in) {
686 ZipArchiveEntry out = new ZipArchiveEntry(in.getName());
687 if (buildOutputTimestamp != null && buildOutputTimestamp.isValid()) {
688 out.setLastModifiedTime(buildOutputTimestamp.toFileTime());
689 }
690 else if (in.getLastModifiedTime() != null) {
691 out.setLastModifiedTime(in.getLastModifiedTime());
692 }
693 return out;
694 }
695
696
697
698
699
700
701
702
703 private void updateDependencies(ContentPackageFile pkg, Properties props, ContentPackageFile dependencyFile,
704 String environmentRunMode, Set<Dependency> allPackagesFromFileSets) {
705 String[] existingDepsStrings = StringUtils.split(props.getProperty(NAME_DEPENDENCIES), ",");
706 Dependency[] existingDeps = null;
707 if (existingDepsStrings != null && existingDepsStrings.length > 0) {
708 existingDeps = Dependency.fromString(existingDepsStrings);
709 }
710 if (existingDeps != null) {
711 existingDeps = autoDependenciesMode == AutoDependenciesMode.OFF
712 ? rewriteReferencesToManagedPackages(pkg, environmentRunMode, allPackagesFromFileSets, existingDeps)
713 : removeReferencesToManagedPackages(existingDeps, allPackagesFromFileSets);
714 }
715
716 Dependency[] deps;
717 if (dependencyFile != null) {
718 Dependency newDependency = createDependencyFromContentPackageFile(dependencyFile, environmentRunMode);
719 deps = addDependency(existingDeps, newDependency);
720 }
721 else {
722 deps = existingDeps;
723 }
724
725 if (deps != null) {
726 String dependenciesString = Dependency.toString(deps);
727 props.put(NAME_DEPENDENCIES, dependenciesString);
728 }
729 }
730
731 private @NotNull Dependency createDependencyFromContentPackageFile(@NotNull ContentPackageFile dependencyFile,
732 @NotNull String environmentRunMode) {
733 String runModeSuffix = buildRunModeSuffix(dependencyFile, environmentRunMode);
734 String dependencyVersion = dependencyFile.getVersion() + buildVersionSuffix(dependencyFile, true);
735 return new Dependency(dependencyFile.getGroup(),
736 dependencyFile.getName() + runModeSuffix,
737 VersionRange.fromString(dependencyVersion));
738 }
739
740 private static Dependency[] addDependency(Dependency[] existingDeps, Dependency newDependency) {
741 if (existingDeps != null) {
742 return DependencyUtil.add(existingDeps, newDependency);
743 }
744 else {
745 return new Dependency[] { newDependency };
746 }
747 }
748
749 private static void addSuffixToPackageName(Properties props, ContentPackageFile pkg, String environmentRunMode) {
750 String runModeSuffix = buildRunModeSuffix(pkg, environmentRunMode);
751 String packageName = props.getProperty(NAME_NAME) + runModeSuffix;
752 props.put(NAME_NAME, packageName);
753 }
754
755 private void addSuffixToVersion(Properties props, ContentPackageFile pkg) {
756
757 if (StringUtils.isEmpty(pkg.getVersion())) {
758 return;
759 }
760 String suffixedVersion = pkg.getVersion() + buildVersionSuffix(pkg, true);
761 props.put(NAME_VERSION, suffixedVersion);
762 }
763
764 private @NotNull Dependency[] rewriteReferencesToManagedPackages(@NotNull ContentPackageFile pkg,
765 @NotNull String environmentRunMode, @NotNull Set<Dependency> allPackagesFromFileSets, @NotNull Dependency[] deps) {
766 return Arrays.stream(deps)
767 .map(dep -> rewriteReferenceIfDependencyIsManagedPackage(pkg, environmentRunMode, allPackagesFromFileSets, dep))
768 .toArray(Dependency[]::new);
769 }
770
771 private @NotNull Dependency rewriteReferenceIfDependencyIsManagedPackage(@NotNull ContentPackageFile pkg,
772 @NotNull String environmentRunMode, @NotNull Set<Dependency> allPackagesFromFileSets, @NotNull Dependency dep) {
773
774 if (!allPackagesFromFileSets.contains(dep)) {
775 return dep;
776 }
777 return findContentPackageFileForDependency(pkg, dep)
778
779 .map(contentPackageFile -> createDependencyFromContentPackageFile(contentPackageFile, environmentRunMode))
780
781 .orElseGet(() -> createDependencyWithCurrentPackageRunModeSuffix(pkg, environmentRunMode, dep));
782 }
783
784 private @NotNull Optional<ContentPackageFile> findContentPackageFileForDependency(@NotNull ContentPackageFile pkg,
785 @NotNull Dependency dep) {
786
787 return contentPackageFileSets.stream()
788
789 .sorted((fileSet1, fileSet2) -> sortFileSetsContainingPackageFirst(pkg, fileSet1, fileSet2))
790 .flatMap(fileSet -> fileSet.getFiles().stream())
791 .filter(contentPackageFile -> isContentPackageForDependency(contentPackageFile, dep))
792 .findFirst();
793 }
794
795 private int sortFileSetsContainingPackageFirst(@NotNull ContentPackageFile pkg,
796 @NotNull ContentPackageFileSet fileSet1, @NotNull ContentPackageFileSet fileSet2) {
797 int fileSet1ContainsPackage = fileSet1.getFiles().contains(pkg) ? 1 : 0;
798 int fileSet2ContainsPackage = fileSet2.getFiles().contains(pkg) ? 1 : 0;
799 return fileSet2ContainsPackage - fileSet1ContainsPackage;
800 }
801
802 private boolean isContentPackageForDependency(@NotNull ContentPackageFile contentPackageFile, @NotNull Dependency dep) {
803 return contentPackageFile.getGroup().equals(dep.getGroup())
804 && contentPackageFile.getName().equals(dep.getName());
805 }
806
807 private @NotNull Dependency createDependencyWithCurrentPackageRunModeSuffix(@NotNull ContentPackageFile pkg,
808 @NotNull String environmentRunMode, @NotNull Dependency dep) {
809 String runModeSuffix = buildRunModeSuffix(pkg, environmentRunMode);
810 return new Dependency(dep.getGroup(), dep.getName() + runModeSuffix, dep.getRange());
811 }
812
813
814
815
816
817
818
819
820 private static Dependency[] removeReferencesToManagedPackages(Dependency[] deps, Set<Dependency> allPackagesFromFileSets) {
821 return Arrays.stream(deps)
822 .filter(dep -> !allPackagesFromFileSets.contains(dep))
823 .toArray(size -> new Dependency[size]);
824 }
825
826 private static void addDependencyInformation(Set<Dependency> allPackagesFromFileSets, ContentPackageFile pkg) {
827 allPackagesFromFileSets.add(new Dependency(pkg.getGroup(), pkg.getName(), VersionRange.fromString(pkg.getVersion())));
828 }
829
830
831
832
833 public String getGroupName() {
834 return this.groupName;
835 }
836
837
838
839
840 public String getPackageName() {
841 return this.packageName;
842 }
843
844
845
846
847 public File getTargetFile() {
848 return this.targetFile;
849 }
850
851 }