2 * Copyright © 2018 European Support Limited
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.openecomp.sdc.onboarding;
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;
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;
42 import java.util.Optional;
44 import java.util.function.Function;
46 import org.apache.maven.artifact.Artifact;
47 import org.apache.maven.project.MavenProject;
49 public class BuildState {
51 private static final String SHUTDOWN_TIME = "shutdownTime";
52 private static final String VERSION = "version";
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");
63 private static File compileStateFile;
64 private MavenProject project;
65 private String compileStateFilePath;
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);
76 if (stateFileLocation.exists()) {
77 HashMap dat = loadState(stateFileLocation);
78 if (swapStates((HashMap<?, ?>) compileDataStore, dat)) {
79 compileDataStore = dat;
87 for (Artifact artifact : project.getArtifacts()) {
88 if (artifact.isSnapshot() && JAR.equals(artifact.getType())) {
89 artifacts.put(artifact.getGroupId() + ":" + artifact.getArtifactId(), artifact);
92 if (compileStateFile == null) {
94 getCompileStateFile(compileStateFilePath.substring(0, compileStateFilePath.indexOf('/')), project));
98 private static void setCompileStateFile(File file) {
99 compileStateFile = file;
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<>());
110 static void recordPMDRun(String moduleCoordinates) {
111 pmdExecutedInRun.add(moduleCoordinates);
114 static boolean isPMDRun(String moduleCoordintes) {
115 return pmdExecutedInRun.contains(moduleCoordintes);
118 private void writeCompileState() throws IOException {
119 writeState(compileStateFile, compileDataStore);
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);
129 private File getCompileStateFile(String moduleCoordinate, MavenProject proj) {
130 return getStateFile(moduleCoordinate, proj, compileStateFilePath);
134 private File getStateFile(String moduleCoordinate, MavenProject proj, String filePath) {
135 return new File(getTopParentProject(moduleCoordinate, proj).getBasedir(),
136 filePath.substring(filePath.indexOf('/') + 1));
139 MavenProject getTopParentProject(String moduleCoordinate, MavenProject proj) {
140 if (getModuleCoordinate(proj).equals(moduleCoordinate) || proj.getParent() == null) {
143 return getTopParentProject(moduleCoordinate, proj.getParent());
147 private String getModuleCoordinate(MavenProject project) {
148 return project.getGroupId() + ":" + project.getArtifactId();
151 void addModuleBuildTime(String moduleCoordinates, Long buildTime) {
152 Long lastTime = Long.class.cast(compileDataStore.get(FULL_BUILD_DATA).put(moduleCoordinates, buildTime));
154 if (lastTime == null || !lastTime.equals(buildTime)) {
155 boolean skipMainCompile = project.getProperties().containsKey(SKIP_MAIN_SOURCE_COMPILE);
156 if (!skipMainCompile) {
160 } catch (IOException ignored) {
161 // ignored. No need to handle. System will take care.
165 void addResourceBuildTime(String moduleCoordinates, Long buildTime) {
166 if (project.getProperties().containsKey(RESOURCES_CHANGED)
167 || compileDataStore.get(FULL_RESOURCE_BUILD_DATA).get(moduleCoordinates) == null) {
169 compileDataStore.get(FULL_RESOURCE_BUILD_DATA).put(moduleCoordinates, buildTime);
171 } catch (IOException ignored) {
172 // ignored. No need to handle. System will take care.
177 void addModuleBuildData(String moduleCoordinates, Map moduleBuildDependencies) {
178 moduleBuildData.put(moduleCoordinates, moduleBuildDependencies);
181 Map<String, Object> readModuleBuildData() {
182 return HashMap.class.cast(compileDataStore.get(MODULE_BUILD_DATA).get(getModuleCoordinate(project)));
185 void saveModuleBuildData(String moduleCoordinate) {
186 if (moduleBuildData.get(moduleCoordinate) != null) {
187 compileDataStore.get(MODULE_BUILD_DATA).put(moduleCoordinate, moduleBuildData.get(moduleCoordinate));
192 void saveResourceBuildData(String moduleCoordinate) {
193 if (resourceBuildData.get(moduleCoordinate) != null) {
194 compileDataStore.get(RESOURCE_BUILD_DATA).put(moduleCoordinate, resourceBuildData.get(moduleCoordinate));
199 void saveCompileData() {
200 saveBuildData(compileStateFile, compileDataStore);
203 void markTestsMandatoryModule(String moduleCoordinates) {
204 executeTestsIfDependsOnStore.add(moduleCoordinates);
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.
219 Map<String, Object> readResourceBuildData() {
220 return HashMap.class.cast(compileDataStore.get(RESOURCE_BUILD_DATA).get(getModuleCoordinate(project)));
224 void addResourceBuildData(String moduleCoordinates, Map currentModuleResourceBuildData) {
225 resourceBuildData.put(moduleCoordinates, currentModuleResourceBuildData);
228 Long getBuildTime(String moduleCoordinates) {
229 Long buildTime = Long.class.cast(compileDataStore.get(FULL_BUILD_DATA).get(moduleCoordinates));
230 return buildTime == null ? 0 : buildTime;
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;
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."
250 return isMust(this::getBuildTime, moduleCoordinates, dependencies);
253 boolean isTestExecutionMandatory() {
254 for (String d : artifacts.keySet()) {
255 if (executeTestsIfDependsOnStore.contains(d)) {
262 boolean isTestMust(String moduleCoordinates) {
263 return getBuildTime(moduleCoordinates) > getResourceBuildTime(moduleCoordinates) || isMust(
264 this::getResourceBuildTime, moduleCoordinates, artifacts.keySet());
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) {
272 for (String module : dependencies) {
273 Long buildTime = funct.apply(module);
274 if (buildTime >= time) {
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<>();
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) {
299 if (!repoVersion.equals(lastVersion)) {
302 return Long.compare(repoTime, lastTime) < 0;