re base code
[sdc.git] / openecomp-be / tools / compile-helper-plugin / src / main / java / org / openecomp / sdc / onboarding / BuildState.java
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.BuildHelper.readState;
20 import static org.openecomp.sdc.onboarding.Constants.ANSI_COLOR_RESET;
21 import static org.openecomp.sdc.onboarding.Constants.ANSI_YELLOW;
22 import static org.openecomp.sdc.onboarding.Constants.FULL_BUILD_DATA;
23 import static org.openecomp.sdc.onboarding.Constants.FULL_RESOURCE_BUILD_DATA;
24 import static org.openecomp.sdc.onboarding.Constants.JAR;
25 import static org.openecomp.sdc.onboarding.Constants.MODULE_BUILD_DATA;
26 import static org.openecomp.sdc.onboarding.Constants.RESOURCES_CHANGED;
27 import static org.openecomp.sdc.onboarding.Constants.RESOURCE_BUILD_DATA;
28 import static org.openecomp.sdc.onboarding.Constants.SKIP_MAIN_SOURCE_COMPILE;
29
30 import java.io.File;
31 import java.io.FileInputStream;
32 import java.io.FileOutputStream;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.ObjectInputStream;
36 import java.io.ObjectOutputStream;
37 import java.nio.file.Paths;
38 import java.util.Collection;
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.Map;
42 import java.util.Optional;
43 import java.util.Set;
44 import java.util.function.Function;
45
46 import org.apache.maven.artifact.Artifact;
47 import org.apache.maven.project.MavenProject;
48
49 public class BuildState {
50
51     private static final String SHUTDOWN_TIME = "shutdownTime";
52     private static final String VERSION = "version";
53
54     private static Map<String, Map> compileDataStore = new HashMap<>();
55     private static Map<String, Object> moduleBuildData = new HashMap<>();
56     private static Map<String, Object> resourceBuildData = new HashMap<>();
57     private static Map<String, Artifact> artifacts = new HashMap<>();
58     private static Set<String> executeTestsIfDependsOnStore = new HashSet<>();
59     private static Set<String> pmdExecutedInRun = new HashSet<>();
60     private static File stateFileLocation =
61             new File(Paths.get(System.getProperties().getProperty("java.io.tmpdir")).toFile(), "compileState.dat");
62
63     private static File compileStateFile;
64     private MavenProject project;
65     private String compileStateFilePath;
66
67     static {
68         initializeStore();
69         Optional<HashMap> masterStore = readState("compile.dat", HashMap.class);
70         compileDataStore = masterStore.isPresent() ? masterStore.get() : compileDataStore;
71         String version = String.class.cast(compileDataStore.get(VERSION));
72         if (version != null) {
73             stateFileLocation = new File(Paths.get(System.getProperties().getProperty("java.io.tmpdir")).toFile(),
74                     "compileState.dat-" + version);
75         }
76         if (stateFileLocation.exists()) {
77             HashMap dat = loadState(stateFileLocation);
78             if (swapStates((HashMap<?, ?>) compileDataStore, dat)) {
79                 compileDataStore = dat;
80             }
81         }
82     }
83
84
85     void init() {
86         artifacts.clear();
87         for (Artifact artifact : project.getArtifacts()) {
88             if (artifact.isSnapshot() && JAR.equals(artifact.getType())) {
89                 artifacts.put(artifact.getGroupId() + ":" + artifact.getArtifactId(), artifact);
90             }
91         }
92         if (compileStateFile == null) {
93             setCompileStateFile(
94                     getCompileStateFile(compileStateFilePath.substring(0, compileStateFilePath.indexOf('/')), project));
95         }
96     }
97
98     private static void setCompileStateFile(File file) {
99         compileStateFile = file;
100     }
101
102     static void initializeStore() {
103         compileDataStore.put(FULL_BUILD_DATA, new HashMap<>());
104         compileDataStore.put(FULL_RESOURCE_BUILD_DATA, new HashMap<>());
105         compileDataStore.put(MODULE_BUILD_DATA, new HashMap<>());
106         compileDataStore.put(RESOURCE_BUILD_DATA, new HashMap<>());
107     }
108
109
110     static void recordPMDRun(String moduleCoordinates) {
111         pmdExecutedInRun.add(moduleCoordinates);
112     }
113
114     static boolean isPMDRun(String moduleCoordintes) {
115         return pmdExecutedInRun.contains(moduleCoordintes);
116     }
117
118     private void writeCompileState() throws IOException {
119         writeState(compileStateFile, compileDataStore);
120     }
121
122     private void writeState(File file, Map store) throws IOException {
123         try (FileOutputStream fos = new FileOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(fos)) {
124             oos.writeObject(store);
125         }
126     }
127
128
129     private File getCompileStateFile(String moduleCoordinate, MavenProject proj) {
130         return getStateFile(moduleCoordinate, proj, compileStateFilePath);
131     }
132
133
134     private File getStateFile(String moduleCoordinate, MavenProject proj, String filePath) {
135         return new File(getTopParentProject(moduleCoordinate, proj).getBasedir(),
136                 filePath.substring(filePath.indexOf('/') + 1));
137     }
138
139     MavenProject getTopParentProject(String moduleCoordinate, MavenProject proj) {
140         if (getModuleCoordinate(proj).equals(moduleCoordinate) || proj.getParent() == null) {
141             return proj;
142         } else {
143             return getTopParentProject(moduleCoordinate, proj.getParent());
144         }
145     }
146
147     private String getModuleCoordinate(MavenProject project) {
148         return project.getGroupId() + ":" + project.getArtifactId();
149     }
150
151     void addModuleBuildTime(String moduleCoordinates, Long buildTime) {
152         Long lastTime = Long.class.cast(compileDataStore.get(FULL_BUILD_DATA).put(moduleCoordinates, buildTime));
153         try {
154             if (lastTime == null || !lastTime.equals(buildTime)) {
155                 boolean skipMainCompile = project.getProperties().containsKey(SKIP_MAIN_SOURCE_COMPILE);
156                 if (!skipMainCompile) {
157                     writeCompileState();
158                 }
159             }
160         } catch (IOException ignored) {
161             // ignored. No need to handle. System will take care.
162         }
163     }
164
165     void addResourceBuildTime(String moduleCoordinates, Long buildTime) {
166         if (project.getProperties().containsKey(RESOURCES_CHANGED)
167                     || compileDataStore.get(FULL_RESOURCE_BUILD_DATA).get(moduleCoordinates) == null) {
168             try {
169                 compileDataStore.get(FULL_RESOURCE_BUILD_DATA).put(moduleCoordinates, buildTime);
170                 writeCompileState();
171             } catch (IOException ignored) {
172                 // ignored. No need to handle. System will take care.
173             }
174         }
175     }
176
177     void addModuleBuildData(String moduleCoordinates, Map moduleBuildDependencies) {
178         moduleBuildData.put(moduleCoordinates, moduleBuildDependencies);
179     }
180
181     Map<String, Object> readModuleBuildData() {
182         return HashMap.class.cast(compileDataStore.get(MODULE_BUILD_DATA).get(getModuleCoordinate(project)));
183     }
184
185     void saveModuleBuildData(String moduleCoordinate) {
186         if (moduleBuildData.get(moduleCoordinate) != null) {
187             compileDataStore.get(MODULE_BUILD_DATA).put(moduleCoordinate, moduleBuildData.get(moduleCoordinate));
188         }
189         saveCompileData();
190     }
191
192     void saveResourceBuildData(String moduleCoordinate) {
193         if (resourceBuildData.get(moduleCoordinate) != null) {
194             compileDataStore.get(RESOURCE_BUILD_DATA).put(moduleCoordinate, resourceBuildData.get(moduleCoordinate));
195         }
196         saveCompileData();
197     }
198
199     void saveCompileData() {
200         saveBuildData(compileStateFile, compileDataStore);
201     }
202
203     void markTestsMandatoryModule(String moduleCoordinates) {
204         executeTestsIfDependsOnStore.add(moduleCoordinates);
205     }
206
207     private void saveBuildData(File file, Object dataToSave) {
208         file.getParentFile().mkdirs();
209         if (dataToSave != null) {
210             try (FileOutputStream fos = new FileOutputStream(file);
211                  ObjectOutputStream ois = new ObjectOutputStream(fos)) {
212                 ois.writeObject(dataToSave);
213             } catch (IOException ignored) {
214                 // ignored. No need to handle. System will take care.
215             }
216         }
217     }
218
219     Map<String, Object> readResourceBuildData() {
220         return HashMap.class.cast(compileDataStore.get(RESOURCE_BUILD_DATA).get(getModuleCoordinate(project)));
221     }
222
223
224     void addResourceBuildData(String moduleCoordinates, Map currentModuleResourceBuildData) {
225         resourceBuildData.put(moduleCoordinates, currentModuleResourceBuildData);
226     }
227
228     Long getBuildTime(String moduleCoordinates) {
229         Long buildTime = Long.class.cast(compileDataStore.get(FULL_BUILD_DATA).get(moduleCoordinates));
230         return buildTime == null ? 0 : buildTime;
231     }
232
233     Long getResourceBuildTime(String moduleCoordinates) {
234         Long resourceBuildTime = Long.class.cast(compileDataStore.get(FULL_RESOURCE_BUILD_DATA).get(moduleCoordinates));
235         return resourceBuildTime == null ? 0 : resourceBuildTime;
236     }
237
238     boolean isCompileMust(String moduleCoordinates, Collection<String> dependencies) {
239         for (String d : dependencies) {
240             if (artifacts.containsKey(d) && JAR.equals(artifacts.get(d).getType())) {
241                 boolean versionEqual = artifacts.get(d).getVersion().equals(project.getVersion());
242                 if (versionEqual && getBuildTime(d) == 0) {
243                     System.err.println(ANSI_YELLOW + "[WARNING:]" + "You have module[" + d
244                                                + "] not locally compiled even once, please compile your project once daily from root to have reliable build results."
245                                                + ANSI_COLOR_RESET);
246                     return true;
247                 }
248             }
249         }
250         return isMust(this::getBuildTime, moduleCoordinates, dependencies);
251     }
252
253     boolean isTestExecutionMandatory() {
254         for (String d : artifacts.keySet()) {
255             if (executeTestsIfDependsOnStore.contains(d)) {
256                 return true;
257             }
258         }
259         return false;
260     }
261
262     boolean isTestMust(String moduleCoordinates) {
263         return getBuildTime(moduleCoordinates) > getResourceBuildTime(moduleCoordinates) || isMust(
264                 this::getResourceBuildTime, moduleCoordinates, artifacts.keySet());
265     }
266
267     private boolean isMust(Function<String, Long> funct, String moduleCoordinates, Collection<String> dependencies) {
268         Long time = funct.apply(moduleCoordinates);
269         if (time == null || time == 0) {
270             return true;
271         }
272         for (String module : dependencies) {
273             Long buildTime = funct.apply(module);
274             if (buildTime >= time) {
275                 return true;
276             }
277         }
278         return false;
279     }
280
281     private static HashMap loadState(File file) {
282         try (InputStream is = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(is)) {
283             return HashMap.class.cast(ois.readObject());
284         } catch (Exception e) {
285             return new HashMap<>();
286         }
287     }
288
289     private static boolean swapStates(HashMap repo, HashMap last) {
290         Long repoTime = repo.get(SHUTDOWN_TIME) == null ? 0 : (Long) repo.get(SHUTDOWN_TIME);
291         Long lastTime = last.get(SHUTDOWN_TIME) == null ? 0 : (Long) last.get(SHUTDOWN_TIME);
292         String repoVersion = repo.get(VERSION) == null ? "" : (String) repo.get(VERSION);
293         String lastVersion = last.get(VERSION) == null ? "" : (String) last.get(VERSION);
294         long repoBuildNumber = repoTime % 1000;
295         long lastBuildNumber = lastTime % 1000;
296         if (repoBuildNumber != lastBuildNumber) {
297             return false;
298         }
299         if (!repoVersion.equals(lastVersion)) {
300             return false;
301         }
302         return Long.compare(repoTime, lastTime) < 0;
303     }
304
305
306 }