9ab373509e8af0af16645809c043b1e2ea1a9045
[sdc.git] /
1 /*
2  * Copyright © 2018 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on a "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.openecomp.sdc.onboarding;
18
19 import static org.openecomp.sdc.onboarding.Constants.CLASS_EXT;
20 import static org.openecomp.sdc.onboarding.Constants.JAVA_EXT;
21 import static org.openecomp.sdc.onboarding.Constants.MAIN;
22 import static org.openecomp.sdc.onboarding.Constants.RESOURCES_CHANGED;
23 import static org.openecomp.sdc.onboarding.Constants.SKIP_TEST_RUN;
24 import static org.openecomp.sdc.onboarding.Constants.UNICORN;
25
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.UncheckedIOException;
29 import java.nio.file.Files;
30 import java.nio.file.Path;
31 import java.nio.file.Paths;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.stream.Collectors;
38 import org.apache.maven.artifact.Artifact;
39 import org.apache.maven.plugin.AbstractMojo;
40 import org.apache.maven.plugin.MojoExecutionException;
41 import org.apache.maven.plugins.annotations.LifecyclePhase;
42 import org.apache.maven.plugins.annotations.Mojo;
43 import org.apache.maven.plugins.annotations.Parameter;
44 import org.apache.maven.plugins.annotations.ResolutionScope;
45 import org.apache.maven.project.MavenProject;
46
47 @Mojo(name = "post-compile-helper", threadSafe = true, defaultPhase = LifecyclePhase.PROCESS_TEST_CLASSES,
48         requiresDependencyResolution = ResolutionScope.TEST)
49 public class PostCompileHelperMojo extends AbstractMojo {
50
51     @Parameter(defaultValue = "${project}", readonly = true)
52     private MavenProject project;
53     @Parameter(defaultValue = "${project.artifact.groupId}:${project.artifact.artifactId}")
54     private String moduleCoordinates;
55     @Parameter
56     private Long staleThreshold;
57     @Parameter
58     private String excludePackaging;
59     @Parameter
60     private List<String> excludeDependencies;
61     @Parameter
62     private File mainSourceLocation;
63     @Parameter
64     private File testSourceLocation;
65     @Parameter
66     private File mainCompiledLocation;
67     @Parameter
68     private File testCompiledLocation;
69     @Parameter
70     private File inputSourceFilesList;
71     @Parameter
72     private File inputTestFilesList;
73     @Parameter
74     private BuildState buildState;
75     @Parameter
76     private File mainResourceLocation;
77     @Parameter
78     private File testResourceLocation;
79     @Parameter
80     private File compiledTestFilesList;
81
82
83     private File[] getCompiledClasses(File compiledFiles) {
84         if (!compiledFiles.exists()) {
85             return new File[0];
86         }
87         File[] list = null;
88         try {
89             list = Files.walk(Paths.get(compiledFiles.getAbsolutePath()))
90                         .filter(p -> p.toFile().getAbsolutePath().endsWith(CLASS_EXT)).map(p -> p.toFile())
91                         .sorted(this::compare).collect(Collectors.toList()).toArray(new File[0]);
92         } catch (IOException e) {
93             e.printStackTrace();
94         }
95         if (list == null || list.length == 0) {
96             return new File[0];
97         }
98         return list;
99     }
100
101     private int compare(File file1, File file2) {
102         if (file1.lastModified() > file2.lastModified()) {
103             return 1;
104         }
105         if (file1.lastModified() < file2.lastModified()) {
106             return -1;
107         }
108         return 0;
109     }
110
111     private File[] getStaleCompiledClasses(File[] compiledClasses, File javaSourceLocation) {
112         List<File> staleFiles = new ArrayList<>();
113         for (File file : compiledClasses) {
114             String classLocation = file.getAbsolutePath().replace(
115                     project.getBasedir().getAbsolutePath() + File.separator + "target" + File.separator, "");
116             String classLocationWithPackageOnly =
117                     classLocation.substring(classLocation.indexOf(File.separatorChar) + 1);
118             String sourceFilePath = javaSourceLocation.getAbsolutePath() + File.separator + classLocationWithPackageOnly
119                                                                                                     .replace(CLASS_EXT,
120                                                                                                             JAVA_EXT);
121             if (Paths.get(sourceFilePath).toFile().exists()) {
122                 return staleFiles.toArray(new File[0]);
123             } else {
124                 staleFiles.add(file);
125             }
126         }
127         return staleFiles.toArray(new File[0]);
128     }
129
130     private boolean deleteAll(File[] files) {
131         for (File file : files) {
132             if (!file.delete()) {
133                 return false;
134             }
135         }
136         return true;
137     }
138
139     public void execute() throws MojoExecutionException {
140         if (!System.getProperties().containsKey(UNICORN)) {
141             return;
142         }
143         if (project.getPackaging().equals(excludePackaging)) {
144             return;
145         }
146         String moduleLocation = project.getBasedir().getAbsolutePath();
147
148         File[] mainClasses = getCompiledClasses(mainCompiledLocation);
149         processStaleClassesIfAny(mainClasses, mainSourceLocation, inputSourceFilesList);
150
151         File[] testClasses = getCompiledClasses(testCompiledLocation);
152         processStaleClassesIfAny(testClasses, testSourceLocation, inputTestFilesList);
153
154         if (mainClasses.length == 0 && testClasses.length == 0) {
155             return;
156         }
157         buildState.addModuleBuildTime(project.getGroupId() + ":" + project.getArtifactId(),
158                 mainClasses.length > 0 ? mainClasses[mainClasses.length - 1].lastModified() :
159                         testClasses.length > 0 ? testClasses[testClasses.length - 1].lastModified() : 0);
160         buildState.saveModuleBuildData(moduleCoordinates);
161         Map<String, Object> resourceBuildData = getCurrentResourceBuildData();
162         Map<String, Object> lastTimeResourceBuildData = buildState.readResourceBuildData();
163         boolean resourceDataSame = resourceBuildData.equals(lastTimeResourceBuildData);
164         if (!resourceDataSame) {
165             buildState.addResourceBuildData(moduleCoordinates, resourceBuildData);
166             project.getProperties().setProperty(SKIP_TEST_RUN, Boolean.FALSE.toString());
167         }
168         boolean resourceMainBuildDataSameWithPreviousBuild =
169                 lastTimeResourceBuildData.get(MAIN) != null && resourceBuildData.get(MAIN)
170                                                                                 .equals(lastTimeResourceBuildData
171                                                                                                 .get(MAIN));
172         if (!resourceMainBuildDataSameWithPreviousBuild) {
173             project.getProperties().setProperty(RESOURCES_CHANGED, Boolean.TRUE.toString());
174         }
175         if (!project.getProperties().containsKey(SKIP_TEST_RUN)) {
176             if (compiledTestFilesList.exists()
177                         && compiledTestFilesList.lastModified() > System.currentTimeMillis() - staleThreshold) {
178                 project.getProperties().setProperty(SKIP_TEST_RUN, Boolean.FALSE.toString());
179             }
180         }
181     }
182
183     private void processStaleClassesIfAny(File[] classes, File sourceLocation, File listFile)
184             throws MojoExecutionException {
185         if (classes.length > 0) {
186             List<File> list = new ArrayList<>(Arrays.asList(classes));
187             File[] staleClasses = null;
188             boolean allStale = listFile.isFile() && listFile.length() == 0;
189             if (allStale) {
190                 staleClasses = classes;
191                 listFile.delete();
192             } else {
193                 list.removeIf(f -> f.lastModified() > classes[classes.length - 1].lastModified() - staleThreshold);
194                 staleClasses = getStaleCompiledClasses(list.toArray(new File[0]), sourceLocation);
195             }
196             if (!deleteAll(staleClasses)) {
197                 throw new MojoExecutionException(
198                         "****** Please remove 'target' directory manually under path " + project.getBasedir()
199                                                                                                 .getAbsolutePath());
200             }
201         }
202     }
203
204     private Map<String, Object> getCurrentResourceBuildData() {
205         HashMap<String, Object> resourceBuildStateData = new HashMap<>();
206         try {
207             resourceBuildStateData.put("main", readResources(mainResourceLocation));
208             resourceBuildStateData.put("test", readResources(testResourceLocation));
209             resourceBuildStateData.put("dependency", getDependencies());
210         } catch (IOException ioException) {
211             throw new UncheckedIOException(ioException);
212         }
213         return resourceBuildStateData;
214     }
215
216     private Map<String, Long> readResources(File file) throws IOException {
217         Map<String, Long> resources = new HashMap<>();
218         if (file.exists()) {
219             List<Path> list = Files.walk(Paths.get(file.getAbsolutePath())).filter(Files::isRegularFile)
220                                    .collect(Collectors.toList());
221             for (Path path : list) {
222                 resources.put(path.toFile().getAbsolutePath(), path.toFile().lastModified());
223             }
224         }
225         return resources;
226     }
227
228     private Map<String, String> getDependencies() {
229         Map<String, String> dependencies = new HashMap<>();
230         for (Artifact d : project.getArtifacts()) {
231             dependencies.put(d.getGroupId() + ":" + d.getArtifactId(), d.getVersion());
232         }
233         return dependencies;
234     }
235 }