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 java.io.IOException;
22  import java.io.Reader;
23  import java.io.Writer;
24  import java.nio.file.Files;
25  import java.nio.file.Path;
26  import java.nio.file.Paths;
27  import java.util.Properties;
28  import java.util.stream.Stream;
29  import javax.inject.Named;
30  import javax.inject.Singleton;
31  import org.apache.commons.lang3.StringUtils;
32  import org.apache.maven.project.MavenProject;
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  
36  /**
37   * This implementation of {@link BuildResumptionDataRepository} persists information in a properties file. The file is
38   * stored in the build output directory under the Maven execution root.
39   */
40  @Named
41  @Singleton
42  public class DefaultBuildResumptionDataRepository implements BuildResumptionDataRepository {
43      private static final String RESUME_PROPERTIES_FILENAME = "resume.properties";
44      private static final String REMAINING_PROJECTS = "remainingProjects";
45      private static final String PROPERTY_DELIMITER = ", ";
46      private static final Logger LOGGER = LoggerFactory.getLogger(DefaultBuildResumptionDataRepository.class);
47  
48      @Override
49      public void persistResumptionData(MavenProject rootProject, BuildResumptionData buildResumptionData)
50              throws BuildResumptionPersistenceException {
51          Properties properties = convertToProperties(buildResumptionData);
52  
53          Path resumeProperties = Paths.get(rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME);
54          try {
55              Files.createDirectories(resumeProperties.getParent());
56              try (Writer writer = Files.newBufferedWriter(resumeProperties)) {
57                  properties.store(writer, null);
58              }
59          } catch (IOException e) {
60              String message = "Could not create " + RESUME_PROPERTIES_FILENAME + " file.";
61              throw new BuildResumptionPersistenceException(message, e);
62          }
63      }
64  
65      private Properties convertToProperties(final BuildResumptionData buildResumptionData) {
66          Properties properties = new Properties();
67  
68          String value = String.join(PROPERTY_DELIMITER, buildResumptionData.getRemainingProjects());
69          properties.setProperty(REMAINING_PROJECTS, value);
70  
71          return properties;
72      }
73  
74      @Override
75      public void applyResumptionData(MavenExecutionRequest request, MavenProject rootProject) {
76          Properties properties =
77                  loadResumptionFile(Paths.get(rootProject.getBuild().getDirectory()));
78          applyResumptionProperties(request, properties);
79      }
80  
81      @Override
82      public void removeResumptionData(MavenProject rootProject) {
83          Path resumeProperties = Paths.get(rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME);
84          try {
85              Files.deleteIfExists(resumeProperties);
86          } catch (IOException e) {
87              LOGGER.warn("Could not delete {} file. ", RESUME_PROPERTIES_FILENAME, e);
88          }
89      }
90  
91      private Properties loadResumptionFile(Path rootBuildDirectory) {
92          Properties properties = new Properties();
93          Path path = rootBuildDirectory.resolve(RESUME_PROPERTIES_FILENAME);
94          if (!Files.exists(path)) {
95              LOGGER.warn("The {} file does not exist. The --resume / -r feature will not work.", path);
96              return properties;
97          }
98  
99          try (Reader reader = Files.newBufferedReader(path)) {
100             properties.load(reader);
101         } catch (IOException e) {
102             LOGGER.warn("Unable to read {}. The --resume / -r feature will not work.", path);
103         }
104 
105         return properties;
106     }
107 
108     // This method is made package-private for testing purposes
109     void applyResumptionProperties(MavenExecutionRequest request, Properties properties) {
110         if (properties.containsKey(REMAINING_PROJECTS) && StringUtils.isEmpty(request.getResumeFrom())) {
111             String propertyValue = properties.getProperty(REMAINING_PROJECTS);
112             Stream.of(propertyValue.split(PROPERTY_DELIMITER))
113                     .filter(StringUtils::isNotEmpty)
114                     .forEach(request.getProjectActivation()::activateOptionalProject);
115             LOGGER.info("Resuming from {} due to the --resume / -r feature.", propertyValue);
116         }
117     }
118 }