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