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.tooling.maven.plugin;
21
22 import static io.wcm.devops.conga.generator.GeneratorOptions.CLASSPATH_ENVIRONMENTS_DIR;
23 import static io.wcm.devops.conga.generator.GeneratorOptions.CLASSPATH_ROLES_DIR;
24 import static io.wcm.devops.conga.generator.GeneratorOptions.CLASSPATH_TEMPLATES_DIR;
25 import static io.wcm.devops.conga.tooling.maven.plugin.BuildConstants.CLASSIFIER_DEFINITION;
26 import static io.wcm.devops.conga.tooling.maven.plugin.BuildConstants.FILE_EXTENSION_DEFINITION;
27 import static io.wcm.devops.conga.tooling.maven.plugin.BuildConstants.PACKAGING_CONFIGURATION;
28 import static io.wcm.devops.conga.tooling.maven.plugin.BuildConstants.PACKAGING_DEFINITION;
29
30 import java.io.File;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.nio.file.Files;
34 import java.util.Arrays;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.SortedSet;
38
39 import org.apache.commons.io.FileUtils;
40 import org.apache.commons.io.IOUtils;
41 import org.apache.commons.lang3.StringUtils;
42 import org.apache.maven.archiver.MavenArchiveConfiguration;
43 import org.apache.maven.archiver.MavenArchiver;
44 import org.apache.maven.artifact.DependencyResolutionRequiredException;
45 import org.apache.maven.execution.MavenSession;
46 import org.apache.maven.plugin.AbstractMojo;
47 import org.apache.maven.plugin.MojoExecutionException;
48 import org.apache.maven.plugin.MojoFailureException;
49 import org.apache.maven.plugins.annotations.Component;
50 import org.apache.maven.plugins.annotations.Parameter;
51 import org.apache.maven.project.MavenProject;
52 import org.apache.maven.project.MavenProjectHelper;
53 import org.codehaus.plexus.archiver.Archiver;
54 import org.codehaus.plexus.archiver.ArchiverException;
55 import org.codehaus.plexus.archiver.jar.JarArchiver;
56 import org.codehaus.plexus.archiver.jar.ManifestException;
57
58 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
59 import io.wcm.devops.conga.generator.export.ModelExport;
60 import io.wcm.devops.conga.resource.Resource;
61 import io.wcm.devops.conga.resource.ResourceCollection;
62 import io.wcm.devops.conga.resource.ResourceLoader;
63 import io.wcm.devops.conga.tooling.maven.plugin.util.PluginConfigUtil;
64
65
66
67
68 abstract class AbstractCongaMojo extends AbstractMojo {
69
70
71
72
73 @Parameter(defaultValue = "${basedir}/src/main/templates")
74 private File templateDir;
75
76
77
78
79 @Parameter(defaultValue = "${basedir}/src/main/roles")
80 private File roleDir;
81
82
83
84
85 @Parameter(defaultValue = "${project.build.directory}/configuration")
86 private File target;
87
88
89
90
91 @Parameter(defaultValue = "${basedir}/src/main/environments")
92 private File environmentDir;
93
94
95
96
97 @Parameter(defaultValue = "${project.build.directory}/definitions")
98 private String definitionTarget;
99
100
101
102
103
104
105 @Parameter(defaultValue = "yaml")
106 private String modelExportNode;
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128 @Parameter
129 private String valueProvider;
130
131
132
133
134
135
136
137
138
139
140
141
142
143 @Parameter
144 private String pluginConfig;
145
146
147
148
149
150
151 @Parameter
152 private Map<String,String> artifactTypeMappings;
153
154 @Parameter(property = "project", required = true, readonly = true)
155 private MavenProject project;
156
157 @Component(role = Archiver.class, hint = "jar")
158 private JarArchiver jarArchiver;
159
160
161
162
163
164 @Parameter
165 @SuppressWarnings("PMD.ImmutableField")
166 private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
167
168 @Parameter(property = "session", readonly = true, required = true)
169 private MavenSession mavenSession;
170
171 @Component
172 protected MavenProjectHelper projectHelper;
173
174 private static final Map<String, String> DEFAULT_ARTIFACT_TYPE_MAPPINGS = Map.of(
175 "bundle", "jar",
176 "content-package", "zip");
177
178 protected File getTemplateDir() {
179 return templateDir;
180 }
181
182 protected File getRoleDir() {
183 return roleDir;
184 }
185
186 protected File getEnvironmentDir() {
187 return environmentDir;
188 }
189
190 protected File getTargetDir() {
191 return target;
192 }
193
194 protected MavenProject getProject() {
195 return project;
196 }
197
198 protected ModelExport getModelExport() {
199 ModelExport modelExport = new ModelExport();
200
201 String[] nodeExportPlugins = StringUtils.split(this.modelExportNode, ",");
202 if (nodeExportPlugins != null) {
203 modelExport.setNode(Arrays.asList(nodeExportPlugins));
204 }
205
206 return modelExport;
207 }
208
209 protected Map<String, Map<String, Object>> getValueProviderConfig() {
210 return PluginConfigUtil.getConfigMap(this.valueProvider);
211 }
212
213 protected Map<String, Map<String, Object>> getPluginConfig() {
214 return PluginConfigUtil.getConfigMap(this.pluginConfig);
215 }
216
217 protected Map<String, String> getArtifactTypeMappings() {
218 Map<String, String> mappings = this.artifactTypeMappings;
219 if (mappings == null) {
220 mappings = DEFAULT_ARTIFACT_TYPE_MAPPINGS;
221 }
222 return mappings;
223 }
224
225
226
227
228
229
230 protected void buildDefinitionsJarFile() throws MojoExecutionException, MojoFailureException {
231
232
233 File definitionDir = copyDefinitions();
234
235
236 File outputFile = buildJarFile(definitionDir);
237
238
239 if (StringUtils.equalsAny(project.getPackaging(), PACKAGING_DEFINITION, PACKAGING_CONFIGURATION)) {
240 project.getArtifact().setFile(outputFile);
241 }
242 else {
243 projectHelper.attachArtifact(project, outputFile, CLASSIFIER_DEFINITION);
244 }
245 }
246
247
248
249
250
251
252 private File buildJarFile(File contentDirectory) throws MojoExecutionException {
253 File jarFile = new File(project.getBuild().getDirectory(), buildJarFileName());
254
255 MavenArchiver archiver = new MavenArchiver();
256 archiver.setArchiver(jarArchiver);
257 archiver.setOutputFile(jarFile);
258 archive.setForced(true);
259
260
261 archiver.getArchiver().addDirectory(contentDirectory);
262
263
264 for (org.apache.maven.model.Resource resource : project.getResources()) {
265 File resourceDir = new File(resource.getDirectory());
266 if (resourceDir.exists()) {
267 archiver.getArchiver().addDirectory(resourceDir,
268 toArray(resource.getIncludes()), toArray(resource.getExcludes()));
269 }
270 }
271
272 try {
273 archiver.createArchive(mavenSession, project, archive);
274 }
275 catch (ArchiverException | ManifestException | IOException | DependencyResolutionRequiredException ex) {
276 throw new MojoExecutionException("Unable to build file " + jarFile.getPath() + ": " + ex.getMessage(), ex);
277 }
278
279 return jarFile;
280 }
281
282 @SuppressWarnings("java:S1168")
283 private String[] toArray(List<String> values) {
284 if (values == null || values.isEmpty()) {
285 return null;
286 }
287 return values.toArray(new String[0]);
288 }
289
290 private String buildJarFileName() {
291 StringBuilder sb = new StringBuilder();
292 sb.append(project.getBuild().getFinalName());
293 if (!StringUtils.equalsAny(project.getPackaging(), PACKAGING_DEFINITION, PACKAGING_CONFIGURATION)) {
294 sb.append("-").append(CLASSIFIER_DEFINITION);
295 }
296 sb.append(".").append(FILE_EXTENSION_DEFINITION);
297 return sb.toString();
298 }
299
300
301
302
303 @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE")
304 private File copyDefinitions() throws MojoExecutionException {
305 File outputDir = new File(definitionTarget);
306 if (!outputDir.exists()) {
307 outputDir.mkdirs();
308 }
309
310 ResourceLoader resourceLoader = new ResourceLoader();
311 ResourceCollection roleDirCol = resourceLoader.getResourceCollection(ResourceLoader.FILE_PREFIX + getRoleDir());
312 ResourceCollection templateDirCol = resourceLoader.getResourceCollection(ResourceLoader.FILE_PREFIX + getTemplateDir());
313 ResourceCollection environmentDirCol = resourceLoader.getResourceCollection(ResourceLoader.FILE_PREFIX + getEnvironmentDir());
314
315
316 try {
317 copyDefinitions(roleDirCol, outputDir, outputDir, CLASSPATH_ROLES_DIR);
318 copyDefinitions(templateDirCol, outputDir, outputDir, CLASSPATH_TEMPLATES_DIR);
319 copyDefinitions(environmentDirCol, outputDir, outputDir, CLASSPATH_ENVIRONMENTS_DIR);
320 }
321 catch (IOException ex) {
322 throw new MojoExecutionException("Unable to copy definitions:" + ex.getMessage(), ex);
323 }
324
325 return outputDir;
326 }
327
328 @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE")
329 private void copyDefinitions(ResourceCollection sourceDir, File rootOutputDir, File parentTargetDir, String dirName) throws IOException {
330 if (!sourceDir.exists()) {
331 return;
332 }
333 SortedSet<Resource> files = sourceDir.getResources();
334 SortedSet<ResourceCollection> dirs = sourceDir.getResourceCollections();
335 if (files.isEmpty() && dirs.isEmpty()) {
336 return;
337 }
338
339 File targetDir = new File(parentTargetDir, dirName);
340 if (!targetDir.exists()) {
341 targetDir.mkdirs();
342 }
343
344 for (Resource file : files) {
345 File targetFile = new File(targetDir, file.getName());
346
347 getLog().info("Include " + getPathForLog(rootOutputDir, targetFile));
348
349 if (targetFile.exists()) {
350 Files.delete(targetFile.toPath());
351 }
352 try (InputStream is = file.getInputStream()) {
353 byte[] data = IOUtils.toByteArray(is);
354 FileUtils.writeByteArrayToFile(targetFile, data);
355 }
356 }
357
358 for (ResourceCollection dir : dirs) {
359 copyDefinitions(dir, rootOutputDir, targetDir, dir.getName());
360 }
361 }
362
363 @SuppressWarnings("java:S1075")
364 private String getPathForLog(File rootOutputDir, File file) throws IOException {
365 String path = unifySlashes(file.getCanonicalPath());
366 String rootPath = unifySlashes(rootOutputDir.getCanonicalPath()) + "/";
367 return StringUtils.substringAfter(path, rootPath);
368 }
369
370 private String unifySlashes(String path) {
371 return StringUtils.replace(path, "\\", "/");
372 }
373
374 }