View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.execution;
20  
21  import javax.inject.Named;
22  import javax.inject.Singleton;
23  
24  import java.io.IOException;
25  import java.io.Reader;
26  import java.io.Writer;
27  import java.nio.file.Files;
28  import java.nio.file.Path;
29  import java.nio.file.Paths;
30  import java.util.Properties;
31  import java.util.stream.Stream;
32  
33  import org.apache.commons.lang3.StringUtils;
34  import org.apache.maven.project.MavenProject;
35  import org.slf4j.Logger;
36  import org.slf4j.LoggerFactory;
37  
38  /**
39   * This implementation of {@link BuildResumptionDataRepository} persists information in a properties file. The file is
40   * stored in the build output directory under the Maven execution root.
41   */
42  @Named
43  @Singleton
44  public class DefaultBuildResumptionDataRepository implements BuildResumptionDataRepository {
45      private static final String RESUME_PROPERTIES_FILENAME = "resume.properties";
46      private static final String REMAINING_PROJECTS = "remainingProjects";
47      private static final String PROPERTY_DELIMITER = ", ";
48      private static final Logger LOGGER = LoggerFactory.getLogger(DefaultBuildResumptionDataRepository.class);
49  
50      @Override
51      public void persistResumptionData(MavenProject rootProject, BuildResumptionData buildResumptionData)
52              throws BuildResumptionPersistenceException {
53          Properties properties = convertToProperties(buildResumptionData);
54  
55          Path resumeProperties = Paths.get(rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME);
56          try {
57              Files.createDirectories(resumeProperties.getParent());
58              try (Writer writer = Files.newBufferedWriter(resumeProperties)) {
59                  properties.store(writer, null);
60              }
61          } catch (IOException e) {
62              String message = "Could not create " + RESUME_PROPERTIES_FILENAME + " file.";
63              throw new BuildResumptionPersistenceException(message, e);
64          }
65      }
66  
67      private Properties convertToProperties(final BuildResumptionData buildResumptionData) {
68          Properties properties = new Properties();
69  
70          String value = String.join(PROPERTY_DELIMITER, buildResumptionData.getRemainingProjects());
71          properties.setProperty(REMAINING_PROJECTS, value);
72  
73          return properties;
74      }
75  
76      @Override
77      public void applyResumptionData(MavenExecutionRequest request, MavenProject rootProject) {
78          Properties properties =
79                  loadResumptionFile(Paths.get(rootProject.getBuild().getDirectory()));
80          applyResumptionProperties(request, properties);
81      }
82  
83      @Override
84      public void removeResumptionData(MavenProject rootProject) {
85          Path resumeProperties = Paths.get(rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME);
86          try {
87              Files.deleteIfExists(resumeProperties);
88          } catch (IOException e) {
89              LOGGER.warn("Could not delete {} file. ", RESUME_PROPERTIES_FILENAME, e);
90          }
91      }
92  
93      private Properties loadResumptionFile(Path rootBuildDirectory) {
94          Properties properties = new Properties();
95          Path path = rootBuildDirectory.resolve(RESUME_PROPERTIES_FILENAME);
96          if (!Files.exists(path)) {
97              LOGGER.warn("The {} file does not exist. The --resume / -r feature will not work.", path);
98              return properties;
99          }
100 
101         try (Reader reader = Files.newBufferedReader(path)) {
102             properties.load(reader);
103         } catch (IOException e) {
104             LOGGER.warn("Unable to read {}. The --resume / -r feature will not work.", path);
105         }
106 
107         return properties;
108     }
109 
110     // This method is made package-private for testing purposes
111     void applyResumptionProperties(MavenExecutionRequest request, Properties properties) {
112         if (properties.containsKey(REMAINING_PROJECTS) && StringUtils.isEmpty(request.getResumeFrom())) {
113             String propertyValue = properties.getProperty(REMAINING_PROJECTS);
114             Stream.of(propertyValue.split(PROPERTY_DELIMITER))
115                     .filter(StringUtils::isNotEmpty)
116                     .forEach(request.getProjectActivation()::activateOptionalProject);
117             LOGGER.info("Resuming from {} due to the --resume / -r feature.", propertyValue);
118         }
119     }
120 }