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