1 package net.sf.environments;
2
3 import java.io.File;
4 import java.io.FileFilter;
5 import java.io.IOException;
6 import java.util.ArrayList;
7 import java.util.Arrays;
8 import java.util.Collections;
9 import java.util.LinkedHashSet;
10 import java.util.List;
11 import java.util.logging.Level;
12 import java.util.logging.Logger;
13 import static net.sf.environments.EnvironmentArchiveConfiguration.MANIFEST_ENVIRONMENT_KEY;
14
15 import org.apache.maven.archiver.MavenArchiveConfiguration;
16 import org.apache.maven.archiver.MavenArchiver;
17 import org.apache.maven.artifact.Artifact;
18 import org.apache.maven.artifact.DependencyResolutionRequiredException;
19 import org.apache.maven.execution.MavenSession;
20 import org.apache.maven.model.Resource;
21 import org.apache.maven.plugin.AbstractMojo;
22 import org.apache.maven.plugin.MojoExecutionException;
23 import org.apache.maven.plugin.MojoFailureException;
24 import org.apache.maven.plugins.annotations.Component;
25 import org.apache.maven.plugins.annotations.Parameter;
26 import org.apache.maven.project.MavenProject;
27 import org.apache.maven.project.MavenProjectHelper;
28 import org.apache.maven.shared.filtering.MavenFilteringException;
29 import org.apache.maven.shared.filtering.MavenResourcesExecution;
30 import org.apache.maven.shared.filtering.MavenResourcesFiltering;
31 import org.codehaus.plexus.archiver.ArchiverException;
32 import org.codehaus.plexus.archiver.jar.JarArchiver;
33 import org.codehaus.plexus.archiver.jar.ManifestException;
34 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
35 import org.codehaus.plexus.archiver.util.DefaultFileSet;
36 import org.codehaus.plexus.util.FileUtils;
37 import org.codehaus.plexus.util.StringUtils;
38
39
40
41
42
43 public abstract class AbstractEnvironmentsMojo
44 extends AbstractMojo {
45
46 private static final String TARGET_PATHS_COMMAND_LINE_KEY = "mem.env-target-path";
47 private static final String INDIVIDUAL_ENVIRONMENT_COMMAND_LINE_KEY = "em.env";
48
49
50
51
52 @Parameter(defaultValue = "${project}", required = true, readonly = true)
53 private MavenProject mavenProject;
54
55
56
57
58 @Parameter(defaultValue = "${session}", required = true, readonly = true)
59 private MavenSession mavenSession;
60
61
62
63
64 @Parameter(defaultValue = "${project.build.directory}", required = true, readonly = true)
65 private File outputDirectory;
66
67
68
69
70
71 @Parameter(defaultValue = "${basedir}/src/main/environments")
72 private File sourceDirectory;
73
74
75
76
77 @Parameter(defaultValue = "${project.build.sourceEncoding}")
78 private String encoding;
79
80
81
82
83 @Parameter(defaultValue = "${project.build.finalName}", readonly = true)
84 private String finalName;
85
86 @Component
87 private MavenProjectHelper projectHelper;
88
89
90
91
92
93
94 @Parameter
95 private List<EnvironmentArchiveConfiguration> archives;
96
97
98
99
100
101 @Parameter
102 private String escapeString;
103
104
105
106
107 @Parameter(defaultValue = "true")
108 private boolean escapeWindowsPaths;
109
110
111
112
113
114
115
116 @Parameter
117 private List<String> filters;
118
119
120
121
122 @Parameter(defaultValue = "false")
123 private boolean fileNameFiltering;
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146 @Parameter
147 private LinkedHashSet<String> delimiters;
148
149
150
151
152 @Parameter(defaultValue = "true")
153 private boolean useDefaultDelimiters;
154
155
156
157
158 @Parameter(defaultValue = "true")
159 private boolean includeEmptyDirs;
160
161
162
163
164
165 @Parameter
166 private List<String> nonFilteredFileExtensions;
167
168
169
170
171 @Parameter(defaultValue = "", name = "excludeEnvironments", required = false)
172 protected String excludeEnvironments;
173
174
175
176
177 @Parameter(defaultValue = "false")
178 private boolean supportMultiLineFiltering;
179
180
181
182
183
184
185
186
187
188
189
190
191
192 @Parameter
193 private String commonDir;
194
195
196
197
198
199
200
201
202
203
204
205
206
207 @Parameter
208 private String targetPath;
209
210
211
212
213 @Parameter
214 private List<String> dirs;
215
216 @Component(role = MavenResourcesFiltering.class, hint = "default")
217 protected MavenResourcesFiltering mavenResourcesFiltering;
218
219
220
221
222 private boolean showCommonDirWarningMsg = true;
223 private boolean showCommonDirErrorMsg = true;
224
225 public List<EnvironmentArchiveConfiguration> getArchives() {
226 return archives;
227 }
228
229 public MavenArchiveConfiguration getArchive(final String environment) {
230 if (StringUtils.isBlank(environment) || getArchives() == null) {
231 return new MavenArchiveConfiguration();
232 }
233
234 for (final EnvironmentArchiveConfiguration archiveWrapper: getArchives()) {
235 if (StringUtils.isNotBlank(archiveWrapper.getEnvironment())
236 && environment.trim().equals(archiveWrapper.getEnvironment())) {
237 return archiveWrapper.getArchive();
238 }
239 }
240
241 return new MavenArchiveConfiguration();
242 }
243
244 protected MavenArchiveConfiguration addEnvironmentToManifest(final MavenArchiveConfiguration archive, final String environment) {
245 if (archive == null) return archive;
246 String env = environment;
247 if (StringUtils.isBlank(env)) env = "";
248
249 if (!archive.getManifestEntries().containsKey(MANIFEST_ENVIRONMENT_KEY)) {
250 archive.addManifestEntry(MANIFEST_ENVIRONMENT_KEY, env);
251 }
252
253 return archive;
254 }
255
256 public MavenProject getMavenProject() {
257 return mavenProject;
258 }
259
260 public MavenSession getMavenSession() {
261 return mavenSession;
262 }
263
264 public File getOutputDirectory() {
265 return outputDirectory;
266 }
267
268 public MavenProjectHelper getProjectHelper() {
269 return projectHelper;
270 }
271
272 public File getSourceDirectory() {
273 return sourceDirectory;
274 }
275
276 public String getFinalName() {
277 return finalName;
278 }
279
280 public String getEncoding() {
281 return encoding;
282 }
283
284
285
286
287
288
289
290 protected String[] getTheEnvironments(File resourceResult) {
291 File[] theResultingFolders = resourceResult.listFiles(new FileFilter() {
292 @Override
293 public boolean accept(File pathname) {
294 return pathname.isDirectory() && pathname.exists();
295 }
296 });
297
298 String[] result = new String[theResultingFolders.length];
299 for (int i = 0; i < theResultingFolders.length; i++) {
300 getLog().debug("Folders: " + theResultingFolders[i].getName());
301 result[i] = theResultingFolders[i].getName().toLowerCase();
302 }
303 return result;
304 }
305
306
307
308
309
310
311
312
313
314
315 protected List<String> environmentNamesAreValid(String[] environmens) {
316 List<String> result = new ArrayList<>();
317 for (String item : environmens) {
318 if (item.contains(" ")) {
319 result.add(item);
320 }
321 }
322 return result;
323 }
324
325
326
327
328
329
330
331
332
333
334 protected File getArchiveFile(File basedir, String finalName, String classifier, String archiveExt) {
335 if (basedir == null) {
336 throw new IllegalArgumentException("basedir is not allowed to be null");
337 }
338 if (finalName == null) {
339 throw new IllegalArgumentException("finalName is not allowed to be null");
340 }
341 if (archiveExt == null) {
342 throw new IllegalArgumentException("archiveExt is not allowed to be null");
343 }
344
345 if (finalName.isEmpty()) {
346 throw new IllegalArgumentException("finalName is not allowed to be empty.");
347 }
348 if (archiveExt.isEmpty()) {
349 throw new IllegalArgumentException("archiveExt is not allowed to be empty.");
350 }
351
352 StringBuilder fileName = new StringBuilder(finalName);
353
354 if (hasClassifier(classifier)) {
355 fileName.append("-").append(classifier);
356 }
357
358 fileName.append('.');
359 fileName.append(archiveExt);
360
361 return new File(basedir, fileName.toString());
362 }
363
364 public String getEscapeString() {
365 return escapeString;
366 }
367
368 public boolean isEscapeWindowsPaths() {
369 return escapeWindowsPaths;
370 }
371
372 public List<String> getFilters() {
373 return filters;
374 }
375
376 public boolean isFileNameFiltering() {
377 return fileNameFiltering;
378 }
379
380 public LinkedHashSet<String> getDelimiters() {
381 return delimiters;
382 }
383
384 public boolean isUseDefaultDelimiters() {
385 return useDefaultDelimiters;
386 }
387
388 public List<String> getNonFilteredFileExtensions() {
389 return nonFilteredFileExtensions;
390 }
391
392 public boolean isSupportMultiLineFiltering() {
393 return supportMultiLineFiltering;
394 }
395
396 public String getExcludeEnvironments() {
397 return excludeEnvironments;
398 }
399
400 public void setExcludeEnvironments(String excludeEnvironments) {
401 this.excludeEnvironments = excludeEnvironments;
402 }
403
404 private boolean hasClassifier(String classifier) {
405 boolean result = false;
406 if (classifier != null && classifier.trim().length() > 0) {
407 result = true;
408 }
409
410 return result;
411 }
412
413 protected void deleteDirectoryOfPreviousRunIfExist(File directoryOfPreviousRun)
414 throws MojoExecutionException {
415
416 if (directoryOfPreviousRun.exists()) {
417 try {
418 FileUtils.deleteDirectory(directoryOfPreviousRun);
419 } catch (IOException e) {
420 throw new MojoExecutionException("Failure while deleting " + directoryOfPreviousRun.getAbsolutePath(),
421 e);
422 }
423 }
424 }
425
426
427
428
429
430
431
432
433 protected File createUnpackDirectory() throws MojoFailureException, MojoExecutionException {
434
435 File unpackDirectory = new File(getOutputDirectory(), "multienv-maven-plugin-unpack");
436
437 deleteDirectoryOfPreviousRunIfExist(unpackDirectory);
438
439 if (!unpackDirectory.mkdirs()) {
440 throw new MojoExecutionException("The unpack directory " + unpackDirectory.getAbsolutePath()
441 + " couldn't generated!");
442 }
443 return unpackDirectory;
444 }
445
446 protected String getArchiveExtensionOfTheProjectMainArtifact()
447 throws MojoExecutionException {
448 if (getMavenProject().getArtifact() == null) {
449 throw new MojoExecutionException("No main artifact has been set yet.");
450 }
451
452 if (getMavenProject().getArtifact().getFile() == null) {
453 throw new MojoExecutionException("No main artifact file has been set yet.");
454 }
455
456 return FileUtils.getExtension(getMavenProject().getArtifact().getFile().getAbsolutePath()).toLowerCase();
457
458 }
459
460 protected String getArchiveExtensionOfTheArtifact(Artifact artifact)
461 throws MojoExecutionException {
462 if (artifact == null) {
463 throw new MojoExecutionException("No artifact has been set yet.");
464 }
465
466 if (artifact.getFile() == null) {
467 throw new MojoExecutionException("No artifact file has been set yet.");
468 }
469
470 return FileUtils.getExtension(artifact.getFile().getAbsolutePath()).toLowerCase();
471
472 }
473
474 protected File createPluginResourceOutput()
475 throws MojoExecutionException {
476
477 File resourceResult = new File(getOutputDirectory(), "multienv-maven-plugin-resource-output");
478
479 deleteDirectoryOfPreviousRunIfExist(resourceResult);
480
481 if (!resourceResult.mkdirs()) {
482 throw new MojoExecutionException("Failure while trying to create " + resourceResult.getAbsolutePath());
483 }
484
485 return resourceResult;
486 }
487
488 public boolean isIncludeEmptyDirs() {
489 return includeEmptyDirs;
490 }
491
492 public void setIncludeEmptyDirs(boolean includeEmptyDirs) {
493 this.includeEmptyDirs = includeEmptyDirs;
494 }
495
496
497
498
499
500
501
502 protected void filterResources(File outputDir, final String environment, boolean singleEnvironment, final boolean ignoreTargetPath)
503 throws MojoExecutionException {
504 List<Resource> resources = new ArrayList<>();
505 Resource res = new Resource();
506
507 String baseEnvironmentResourcePath = StringUtils.join(new String[]{getSourceDirectory().getAbsolutePath(), environment}, "/");
508 res.setDirectory(baseEnvironmentResourcePath);
509 res.setFiltering(true);
510
511 res.setIncludes(Collections.singletonList("**/*"));
512
513 if (!ignoreTargetPath) {
514 res.setTargetPath(getTargetPath(singleEnvironment, environment));
515 }
516
517 resources.add(res);
518
519 List<String> filtersFile = new ArrayList<>();
520
521 addCommonDirResource(environment, filtersFile, resources, singleEnvironment, outputDir, ignoreTargetPath);
522
523 MavenResourcesExecution execution
524 = new MavenResourcesExecution(resources, outputDir, getMavenProject(),
525 getEncoding(), filtersFile, getNonFilteredFileExtensions(),
526 getMavenSession());
527
528 execution.setEscapeString(getEscapeString());
529 execution.setSupportMultiLineFiltering(isSupportMultiLineFiltering());
530 execution.setIncludeEmptyDirs(isIncludeEmptyDirs());
531 execution.setEscapeWindowsPaths(isEscapeWindowsPaths());
532 execution.setFilterFilenames(isFileNameFiltering());
533
534
535
536
537 execution.setOverwrite(true);
538 execution.setDelimiters(getDelimiters(), isUseDefaultDelimiters());
539 execution.setEncoding(getEncoding());
540
541
542
543 if (getNonFilteredFileExtensions() != null) {
544 execution.setNonFilteredFileExtensions(getNonFilteredFileExtensions());
545 }
546
547 try {
548 mavenResourcesFiltering.filterResources(execution);
549 } catch (MavenFilteringException e) {
550 getLog().error("Failure during filtering.", e);
551 throw new MojoExecutionException("Failure during filtering", e);
552 }
553
554 }
555
556 protected void filterResourcesToTarget(String[] identifiedEnvironments) throws MojoExecutionException {
557 File classes = new File(getOutputDirectory(), "classes");
558 filterResourcesToDirectory(identifiedEnvironments, classes, true);
559 }
560
561 protected void filterResourcesToAdditionalDirectories(String[] identifiedEnvironments) throws MojoExecutionException {
562 if (dirs != null && !dirs.isEmpty()) {
563 for (final String dir: dirs) {
564 File d = new File(StringUtils.join(new String[]{mavenProject.getFile().getParentFile().getAbsolutePath(), dir }, "/"));
565 if (!d.exists()) {
566 d.mkdirs();
567 }
568 filterResourcesToDirectory(identifiedEnvironments, d, true);
569 }
570 }
571 }
572
573 private void filterResourcesToDirectory(final String[] identifiedEnvironments, final File dir, final boolean ignoreTargetPath) throws MojoExecutionException {
574 String memEnv = getMavenSession().getUserProperties().getProperty("em.env", null);
575
576 if (StringUtils.isNotBlank(memEnv)) {
577 if (Arrays.asList(identifiedEnvironments).contains(memEnv)) {
578 filterResources(dir, memEnv, true, ignoreTargetPath);
579 } else {
580 getLog().error(String.format("Environment '%s' doesn't exist", memEnv));
581 }
582 }
583 }
584
585 protected String getTargetPath(final boolean singleEnvironment, final String environment) {
586 String tp = "";
587 if (singleEnvironment) {
588 if (StringUtils.isNotBlank(targetPath)) {
589 tp = targetPath;
590 }
591 } else {
592 if (StringUtils.isNotBlank(targetPath)) {
593 tp = StringUtils.join(new String[]{environment, targetPath}, "/");
594 } else {
595 tp = environment;
596 }
597 }
598
599 return tp;
600 }
601
602 private void addCommonDirResource(final String environment, final List<String> filtersFile, final List<Resource> resources,
603 final boolean singleEnvironment, final File outputDir, final boolean ignoreTargetPath) {
604 if (StringUtils.isNotBlank(environment)) {
605 if (getFilters() != null && StringUtils.isNotBlank(commonDir)) {
606 Resource common = new Resource();
607
608 common.setDirectory(StringUtils.join(new String[]{getSourceDirectory().getAbsolutePath(), getCommonDir()}, "/"));
609
610 if (!ignoreTargetPath) {
611 common.setTargetPath(getTargetPath(singleEnvironment, environment));
612 }
613
614 common.setFiltering(true);
615 common.setIncludes(Collections.singletonList("**/*"));
616 resources.add(common);
617
618 List<String> filtersRelativePaths = getFilters();
619
620 for (final String fileRelativePath : filtersRelativePaths) {
621 String path = StringUtils.join(new String[]{getSourceDirectory().getPath(), environment, fileRelativePath}, "/");
622 filtersFile.add(path);
623 }
624 } else if ((getFilters() == null || getFilters().isEmpty()) && StringUtils.isNotBlank(commonDir) && showCommonDirWarningMsg) {
625 getLog().warn("A common directory is configured but no Filters are configured on MultiEnv maven plugin. Files in common directory will not be filtered but will be included in archives.");
626 showCommonDirWarningMsg = false;
627 } else if ((getFilters() != null && !getFilters().isEmpty()) && StringUtils.isBlank(commonDir) && showCommonDirErrorMsg) {
628 getLog().error("Found filter configuration but no common directory configuration on MultiEnv maven plugin. MultiEnv maven filters configuration will have no effect.");
629 showCommonDirErrorMsg = false;
630 }
631 }
632 }
633
634
635
636
637
638
639
640
641
642
643
644
645
646 protected boolean shouldSkip(final String environment) {
647 boolean skip = false;
648
649 List<String> excludedEnvs = new ArrayList<>();
650 if (StringUtils.isNotBlank(excludeEnvironments)) {
651 for (final String excludedEnv : excludeEnvironments.split(",")) {
652 if (StringUtils.isNotBlank(excludedEnv.trim())) {
653 excludedEnvs.add(excludedEnv.trim());
654 }
655 }
656 }
657
658 if (excludedEnvs.contains(environment)) {
659 getLog().info(" - Excluding Environment: '" + environment + "'");
660 skip = true;
661 } else if (StringUtils.isNotBlank(getCommonDir()) && getCommonDir().equals(environment)) {
662 getLog().info(" - Excluding common directory: '" + environment + "'");
663 skip = true;
664 } else {
665 getLog().info("Building Environment: '" + environment + "'");
666 }
667
668 return skip;
669 }
670
671 protected void createLoggingOutput(String[] identifiedEnvironments) {
672 getLog().info("");
673 getLog().info("We have found " + identifiedEnvironments.length + " environments.");
674
675 StringBuilder sb = new StringBuilder();
676 for (String identifiedEnvironment : identifiedEnvironments) {
677 if (sb.length() > 0) {
678 sb.append(',');
679 }
680 sb.append(identifiedEnvironment);
681 }
682
683 getLog().info("We have the following environments: " + sb.toString());
684 getLog().info("");
685 }
686
687
688
689
690
691
692
693
694 protected void validateEnvironments(String[] identifiedEnvironments)
695 throws MojoFailureException {
696 List<String> environmentNamesAreValid = environmentNamesAreValid(identifiedEnvironments);
697 if (!environmentNamesAreValid.isEmpty()) {
698 for (String invalidEnv : environmentNamesAreValid) {
699 getLog().error("Your environment '" + invalidEnv + "' name contains spaces which is not allowed.");
700
701 }
702 throw new MojoFailureException("Your environment names contain spaces which are not allowed."
703 + "See previous error messages for details.");
704 }
705 }
706
707
708 protected File createArchiveFile(File unpackDirectory, File targetDirectory, String directory, String archiveExt)
709 throws NoSuchArchiverException, IOException, MojoExecutionException {
710 final MavenArchiver mavenArchiver = new MavenArchiver();
711
712 mavenArchiver.setArchiver(getJarArchiver());
713
714 getJarArchiver().addFileSet(new DefaultFileSet(targetDirectory));
715
716 if (unpackDirectory != null) {
717 getJarArchiver().addFileSet(new DefaultFileSet(unpackDirectory));
718 }
719
720
721 File resultArchive = getArchiveFile(getOutputDirectory(), getFinalName(), directory, archiveExt);
722
723 mavenArchiver.setOutputFile(resultArchive);
724 try {
725 MavenArchiveConfiguration archive = getArchive(directory);
726 mavenArchiver.createArchive(getMavenSession(), getMavenProject(), addEnvironmentToManifest(archive, directory));
727 getJarArchiver().reset();
728 } catch (ArchiverException | ManifestException | DependencyResolutionRequiredException e) {
729 getLog().error(e.getMessage(), e);
730 throw new MojoExecutionException(e.getMessage(), e);
731 }
732
733 return resultArchive;
734
735 }
736
737 protected String getCommonDir() {
738 return commonDir;
739 }
740
741 public String getTargetPath() {
742 return targetPath;
743 }
744
745 abstract protected JarArchiver getJarArchiver();
746
747 }