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.buildcache;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.nio.charset.StandardCharsets;
24  import java.nio.file.FileVisitResult;
25  import java.nio.file.Files;
26  import java.nio.file.Path;
27  import java.nio.file.SimpleFileVisitor;
28  import java.nio.file.attribute.BasicFileAttributes;
29  import java.nio.file.attribute.FileTime;
30  import java.util.Arrays;
31  import java.util.Collection;
32  import java.util.List;
33  import java.util.NoSuchElementException;
34  import java.util.function.Supplier;
35  import java.util.zip.ZipEntry;
36  import java.util.zip.ZipInputStream;
37  import java.util.zip.ZipOutputStream;
38  
39  import org.apache.commons.lang3.StringUtils;
40  import org.apache.maven.artifact.Artifact;
41  import org.apache.maven.artifact.handler.ArtifactHandler;
42  import org.apache.maven.buildcache.xml.build.Scm;
43  import org.apache.maven.execution.MavenSession;
44  import org.apache.maven.model.Dependency;
45  import org.apache.maven.plugin.MojoExecution;
46  import org.apache.maven.project.MavenProject;
47  import org.eclipse.aether.SessionData;
48  import org.slf4j.Logger;
49  
50  import static org.apache.commons.lang3.StringUtils.removeStart;
51  import static org.apache.commons.lang3.StringUtils.trim;
52  import static org.apache.maven.artifact.Artifact.LATEST_VERSION;
53  import static org.apache.maven.artifact.Artifact.SNAPSHOT_VERSION;
54  
55  /**
56   * Cache Utils
57   */
58  public class CacheUtils {
59  
60      public static boolean isPom(MavenProject project) {
61          return project.getPackaging().equals("pom");
62      }
63  
64      public static boolean isPom(Dependency dependency) {
65          return dependency.getType().equals("pom");
66      }
67  
68      public static boolean isSnapshot(String version) {
69          return version.endsWith(SNAPSHOT_VERSION) || version.endsWith(LATEST_VERSION);
70      }
71  
72      public static String normalizedName(Artifact artifact) {
73          if (artifact.getFile() == null) {
74              return null;
75          }
76  
77          StringBuilder filename = new StringBuilder(artifact.getArtifactId());
78  
79          if (artifact.hasClassifier()) {
80              filename.append("-").append(artifact.getClassifier());
81          }
82  
83          final ArtifactHandler artifactHandler = artifact.getArtifactHandler();
84          if (artifactHandler != null && StringUtils.isNotBlank(artifactHandler.getExtension())) {
85              filename.append(".").append(artifactHandler.getExtension());
86          }
87          return filename.toString();
88      }
89  
90      public static String mojoExecutionKey(MojoExecution mojo) {
91          return StringUtils.join(
92                  Arrays.asList(
93                          StringUtils.defaultIfEmpty(mojo.getExecutionId(), "emptyExecId"),
94                          StringUtils.defaultIfEmpty(mojo.getGoal(), "emptyGoal"),
95                          StringUtils.defaultIfEmpty(mojo.getLifecyclePhase(), "emptyLifecyclePhase"),
96                          StringUtils.defaultIfEmpty(mojo.getArtifactId(), "emptyArtifactId"),
97                          StringUtils.defaultIfEmpty(mojo.getGroupId(), "emptyGroupId")),
98                  ":");
99      }
100 
101     public static Path getMultimoduleRoot(MavenSession session) {
102         return session.getRequest().getMultiModuleProjectDirectory().toPath();
103     }
104 
105     public static Scm readGitInfo(MavenSession session) throws IOException {
106         final Scm scmCandidate = new Scm();
107         final Path gitDir = getMultimoduleRoot(session).resolve(".git");
108         if (Files.isDirectory(gitDir)) {
109             final Path headFile = gitDir.resolve("HEAD");
110             if (Files.exists(headFile)) {
111                 String headRef = readFirstLine(headFile, "<missing branch>");
112                 if (headRef.startsWith("ref: ")) {
113                     String branch = trim(removeStart(headRef, "ref: "));
114                     scmCandidate.setSourceBranch(branch);
115                     final Path refPath = gitDir.resolve(branch);
116                     if (Files.exists(refPath)) {
117                         String revision = readFirstLine(refPath, "<missing revision>");
118                         scmCandidate.setRevision(trim(revision));
119                     }
120                 } else {
121                     scmCandidate.setSourceBranch(headRef);
122                     scmCandidate.setRevision(headRef);
123                 }
124             }
125         }
126         return scmCandidate;
127     }
128 
129     private static String readFirstLine(Path path, String defaultValue) throws IOException {
130         return Files.lines(path, StandardCharsets.UTF_8).findFirst().orElse(defaultValue);
131     }
132 
133     public static <T> T getLast(List<T> list) {
134         int size = list.size();
135         if (size > 0) {
136             return list.get(size - 1);
137         }
138         throw new NoSuchElementException();
139     }
140 
141     public static <T> T getOrCreate(MavenSession session, Object key, Supplier<T> supplier) {
142         SessionData data = session.getRepositorySession().getData();
143         while (true) {
144             T t = (T) data.get(key);
145             if (t == null) {
146                 t = supplier.get();
147                 if (data.set(key, null, t)) {
148                     continue;
149                 }
150             }
151             return t;
152         }
153     }
154 
155     public static boolean isArchive(File file) {
156         String fileName = file.getName();
157         if (!file.isFile() || file.isHidden()) {
158             return false;
159         }
160         return StringUtils.endsWithAny(fileName, ".jar", ".zip", ".war", ".ear");
161     }
162 
163     public static void zip(Path dir, Path zip) throws IOException {
164         try (ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(zip))) {
165             Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
166 
167                 @Override
168                 public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes)
169                         throws IOException {
170                     final ZipEntry zipEntry = new ZipEntry(dir.relativize(path).toString());
171                     zipOutputStream.putNextEntry(zipEntry);
172                     Files.copy(path, zipOutputStream);
173                     zipOutputStream.closeEntry();
174                     return FileVisitResult.CONTINUE;
175                 }
176             });
177         }
178     }
179 
180     public static void unzip(Path zip, Path out) throws IOException {
181         try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(zip))) {
182             ZipEntry entry = zis.getNextEntry();
183             while (entry != null) {
184                 Path file = out.resolve(entry.getName());
185                 if (!file.normalize().startsWith(out.normalize())) {
186                     throw new RuntimeException("Bad zip entry");
187                 }
188                 if (entry.isDirectory()) {
189                     Files.createDirectory(file);
190                 } else {
191                     Path parent = file.getParent();
192                     Files.createDirectories(parent);
193                     Files.copy(zis, file);
194                 }
195                 Files.setLastModifiedTime(file, FileTime.fromMillis(entry.getTime()));
196                 entry = zis.getNextEntry();
197             }
198         }
199     }
200 
201     public static <T> void debugPrintCollection(
202             Logger logger, Collection<T> values, String heading, String elementCaption) {
203         if (logger.isDebugEnabled() && values != null && !values.isEmpty()) {
204             final int size = values.size();
205             int i = 0;
206             logger.debug("{} (total {})", heading, size);
207             for (T value : values) {
208                 i++;
209                 logger.debug("{} {} of {} : {}", elementCaption, i, size, value);
210             }
211         }
212     }
213 }