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