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;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.nio.file.Files;
25 import java.nio.file.Path;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Set;
29
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.maven.plugin.MojoExecutionException;
32 import org.apache.maven.plugin.MojoFailureException;
33 import org.apache.maven.plugins.annotations.Component;
34 import org.apache.maven.plugins.annotations.Mojo;
35 import org.apache.maven.plugins.annotations.Parameter;
36 import org.codehaus.plexus.archiver.Archiver;
37 import org.codehaus.plexus.archiver.ArchiverException;
38 import org.codehaus.plexus.archiver.zip.ZipArchiver;
39
40 import io.wcm.devops.conga.generator.util.FileUtil;
41 import io.wcm.devops.conga.plugins.aem.maven.model.ModelParser;
42
43
44
45
46
47
48 @Mojo(name = "cloudmanager-dispatcher-config", threadSafe = true)
49 public final class CloudManagerDispatcherConfigMojo extends AbstractCloudManagerMojo {
50
51 private static final String ROLE_AEM_DISPATCHER_CLOUD = "aem-dispatcher-cloud";
52
53
54
55
56 @Parameter(property = "conga.cloudManager.dispatcherConfig.skip", defaultValue = "false")
57 private boolean skip;
58
59 @Component(role = Archiver.class, hint = "zip")
60 private ZipArchiver zipArchiver;
61
62 @Parameter(defaultValue = "${project.build.outputTimestamp}")
63 private String outputTimestamp;
64
65 @Override
66 public void execute() throws MojoExecutionException, MojoFailureException {
67 if (skip) {
68 return;
69 }
70
71 int dispatcherNodeCount = 0;
72 List<File> environmentDirs = getEnvironmentDir();
73 for (File environmentDir : environmentDirs) {
74 List<File> nodeDirs = getNodeDirs(environmentDir);
75 for (File nodeDir : nodeDirs) {
76 ModelParser modelParser = new ModelParser(nodeDir);
77 if (modelParser.hasRole(ROLE_AEM_DISPATCHER_CLOUD)) {
78 buildDispatcherConfig(environmentDir, nodeDir);
79 dispatcherNodeCount++;
80 }
81 }
82 }
83
84 if (dispatcherNodeCount > 1) {
85 throw new MojoFailureException("More than one node with role '" + ROLE_AEM_DISPATCHER_CLOUD + "' found - "
86 + "AEM Cloud service supports only a single dispatcher configuration.");
87 }
88 }
89
90 private void buildDispatcherConfig(File environmentDir, File nodeDir) throws MojoExecutionException {
91 File targetFile = new File(getTargetDir(), environmentDir.getName() + "." + nodeDir.getName() + ".dispatcher-config.zip");
92
93 try {
94 String basePath = toZipDirectoryPath(nodeDir);
95 addZipDirectory(basePath, nodeDir, Collections.singleton(ModelParser.MODEL_FILE));
96 zipArchiver.setDestFile(targetFile);
97
98 BuildOutputTimestamp buildOutputTimestamp = new BuildOutputTimestamp(outputTimestamp);
99 if (buildOutputTimestamp.isValid()) {
100 zipArchiver.configureReproducibleBuild(buildOutputTimestamp.toFileTime());
101 }
102
103 zipArchiver.createArchive();
104 }
105 catch (ArchiverException | IOException ex) {
106 throw new MojoExecutionException("Unable to build file " + targetFile.getPath() + ": " + ex.getMessage(), ex);
107 }
108 }
109
110
111
112
113
114
115
116
117
118 @SuppressWarnings("java:S3776")
119 private void addZipDirectory(String basePath, File directory, Set<String> excludeFiles) throws IOException {
120 String directoryPath = toZipDirectoryPath(directory);
121 if (StringUtils.startsWith(directoryPath, basePath)) {
122 String relativeDirectoryPath = StringUtils.substring(directoryPath, basePath.length());
123 File[] files = directory.listFiles();
124 if (files != null) {
125 for (File file : files) {
126 if (excludeFiles.contains(file.getName())) {
127 continue;
128 }
129 if (file.isDirectory()) {
130 addZipDirectory(basePath, file, Collections.emptySet());
131 }
132 else if (Files.isSymbolicLink(file.toPath())) {
133 Path linkPath = file.toPath();
134 Path targetPath = linkPath.toRealPath();
135 Path symlinkPath = file.getParentFile().toPath().relativize(targetPath);
136 zipArchiver.addSymlink(relativeDirectoryPath + file.getName(), sanitizePathSeparators(symlinkPath.toString()));
137 }
138 else {
139 zipArchiver.addFile(file, relativeDirectoryPath + file.getName());
140 }
141 }
142 }
143 }
144 }
145
146 private String toZipDirectoryPath(File directory) {
147 String canoncialPath = FileUtil.getCanonicalPath(directory);
148 return sanitizePathSeparators(canoncialPath) + "/";
149 }
150
151 private String sanitizePathSeparators(String path) {
152 return StringUtils.replace(path, "\\", "/");
153 }
154
155 }