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