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