From c676902fab2313a13a634ec707315dd583127352 Mon Sep 17 00:00:00 2001 From: Slawomir Jaranowski Date: Mon, 9 Oct 2023 19:43:46 +0200 Subject: [PATCH] Support SNAPSHOT versions by localRepo --- .../codehaus/mojo/mrm/api/maven/Artifact.java | 47 ++-- mrm-maven-plugin/src/it/hostedrepo/pom.xml | 6 +- .../src/it/local-repo-snapshot-dep/pom.xml | 26 ++ .../artifact1-1.0.0-SNAPSHOT.jar | 0 .../artifact1-1.0.0-SNAPSHOT.pom | 23 ++ .../artifact1-1.0.0-20231008.222929-9999.jar | 0 .../artifact1-1.0.0-20231008.222929-9999.pom | 23 ++ .../artifact2-1.0.0-20231008.222929-1.jar | 0 .../artifact2-1.0.0-20231008.222929-1.pom | 23 ++ .../impl/maven/CompositeArtifactStore.java | 94 +------ .../mrm/impl/maven/DiskArtifactStore.java | 244 +++++++++++++++--- .../maven/CompositeArtifactStoreTest.java | 58 +++++ .../mrm/impl/maven/DiskArtifactStoreTest.java | 77 ++++++ .../artifact1/1.0.0/artifact1-1.0.0.pom | 24 ++ .../artifact2-1.0.0-SNAPSHOT-build.pom | 24 ++ .../artifact2-1.0.0-SNAPSHOT.jar | 0 .../artifact2-1.0.0-SNAPSHOT.pom | 24 ++ .../artifact2-1.0.0-SNAPSHOT-build.pom | 24 ++ .../artifact2-1.0.0-SNAPSHOT.pom | 24 ++ ...rtifact2-2.0.0-20231008.222929-1-build.pom | 24 ++ .../artifact2-2.0.0-20231008.222929-1.jar | 0 .../artifact2-2.0.0-20231008.222929-1.pom | 24 ++ 22 files changed, 640 insertions(+), 149 deletions(-) create mode 100644 mrm-maven-plugin/src/it/hostedrepo/src/it/local-repo-snapshot-dep/pom.xml create mode 100644 mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact1/1.0.0-SNAPSHOT/artifact1-1.0.0-SNAPSHOT.jar create mode 100644 mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact1/1.0.0-SNAPSHOT/artifact1-1.0.0-SNAPSHOT.pom create mode 100644 mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact1-1.0.0-20231008.222929-9999.jar create mode 100644 mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact1-1.0.0-20231008.222929-9999.pom create mode 100644 mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-20231008.222929-1.jar create mode 100644 mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-20231008.222929-1.pom create mode 100644 mrm-servlet/src/test/resources/local-repo-unit/org/group1/artifact1/1.0.0/artifact1-1.0.0.pom create mode 100644 mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT-build.pom create mode 100644 mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT.jar create mode 100644 mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT.pom create mode 100644 mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT-build.pom create mode 100644 mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT.pom create mode 100644 mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-2.0.0-20231008.222929-1-build.pom create mode 100644 mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-2.0.0-20231008.222929-1.jar create mode 100644 mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-2.0.0-20231008.222929-1.pom diff --git a/mrm-api/src/main/java/org/codehaus/mojo/mrm/api/maven/Artifact.java b/mrm-api/src/main/java/org/codehaus/mojo/mrm/api/maven/Artifact.java index ff0fe261..b4af3d3e 100644 --- a/mrm-api/src/main/java/org/codehaus/mojo/mrm/api/maven/Artifact.java +++ b/mrm-api/src/main/java/org/codehaus/mojo/mrm/api/maven/Artifact.java @@ -16,12 +16,16 @@ package org.codehaus.mojo.mrm.api.maven; -import java.text.MessageFormat; import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.Objects; import java.util.TimeZone; +import org.apache.commons.lang.StringUtils; + /** * Represents a specific artifact in a Maven repository. Implements {@link Comparable} to sort based on * {@link #getGroupId()} and then {@link #getName()}. @@ -82,13 +86,6 @@ public final class Artifact implements Comparable { */ private final Integer buildNumber; - /** - * The lazy idempotent cache of the artifact's name. - * - * @since 1.0 - */ - private String name; - /** * The lazy idempotent cache of the artifact's timestamp version string (which will be equal to the {@link #version} * for either a release version or a non-timestamped SNAPSHOT. @@ -199,13 +196,17 @@ public Artifact(String groupId, String artifactId, String version, String type) * @since 1.0 */ public String getName() { - if (name == null) { - name = MessageFormat.format( - "{0}-{1}{2}.{3}", - new Object[] {artifactId, getTimestampVersion(), (classifier == null ? "" : "-" + classifier), type - }); - } - return name; + return artifactId + "-" + getTimestampVersion() + (classifier == null ? "" : "-" + classifier) + "." + type; + } + + /** + * Returns the name of the artifact. + * + * @return the name of the artifact. + * @since 1.0 + */ + public String getBaseVersionName() { + return artifactId + "-" + version + (classifier == null ? "" : "-" + classifier) + "." + type; } /** @@ -312,15 +313,13 @@ public String getTimestampVersion() { if (timestampVersion == null) { if (timestamp != null) { assert isSnapshot(); - SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd.HHmmss"); - fmt.setTimeZone(TimeZone.getTimeZone("GMT")); - timestampVersion = MessageFormat.format( - "{0}-{1}-{2}", - new Object[] { - this.version.substring(0, this.version.length() - "-SNAPSHOT".length()), - fmt.format(new Date(timestamp.longValue())), - buildNumber - }); + + DateTimeFormatter timestampFormatter = + DateTimeFormatter.ofPattern("yyyyMMdd.HHmmss").withZone(ZoneId.of("UTC")); + + timestampVersion = StringUtils.removeEnd(version, "-SNAPSHOT") + + "-" + timestampFormatter.format(Instant.ofEpochMilli(timestamp)) + + "-" + buildNumber; } else { timestampVersion = version; } diff --git a/mrm-maven-plugin/src/it/hostedrepo/pom.xml b/mrm-maven-plugin/src/it/hostedrepo/pom.xml index 6dca14d7..a0d2775f 100644 --- a/mrm-maven-plugin/src/it/hostedrepo/pom.xml +++ b/mrm-maven-plugin/src/it/hostedrepo/pom.xml @@ -68,9 +68,9 @@ - - ${project.build.directory}/mock-repo - + + ${project.basedir}/src/mrm-local-repo + diff --git a/mrm-maven-plugin/src/it/hostedrepo/src/it/local-repo-snapshot-dep/pom.xml b/mrm-maven-plugin/src/it/hostedrepo/src/it/local-repo-snapshot-dep/pom.xml new file mode 100644 index 00000000..7f496a32 --- /dev/null +++ b/mrm-maven-plugin/src/it/hostedrepo/src/it/local-repo-snapshot-dep/pom.xml @@ -0,0 +1,26 @@ + + + + 4.0.0 + + org.mojohaus.mrm.hostedrepo.its + local-repo-snapshot-dep + 1.0.0 + + Test snapshot dependencies from local repo + + + + + org.group1 + artifact1 + 1.0.0-SNAPSHOT + + + + org.group1 + artifact2 + 1.0.0-SNAPSHOT + + + diff --git a/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact1/1.0.0-SNAPSHOT/artifact1-1.0.0-SNAPSHOT.jar b/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact1/1.0.0-SNAPSHOT/artifact1-1.0.0-SNAPSHOT.jar new file mode 100644 index 00000000..e69de29b diff --git a/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact1/1.0.0-SNAPSHOT/artifact1-1.0.0-SNAPSHOT.pom b/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact1/1.0.0-SNAPSHOT/artifact1-1.0.0-SNAPSHOT.pom new file mode 100644 index 00000000..292fc11f --- /dev/null +++ b/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact1/1.0.0-SNAPSHOT/artifact1-1.0.0-SNAPSHOT.pom @@ -0,0 +1,23 @@ + + + + 4.0.0 + org.group1 + artifact2 + 1.0.0-SNAPSHOT + diff --git a/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact1-1.0.0-20231008.222929-9999.jar b/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact1-1.0.0-20231008.222929-9999.jar new file mode 100644 index 00000000..e69de29b diff --git a/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact1-1.0.0-20231008.222929-9999.pom b/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact1-1.0.0-20231008.222929-9999.pom new file mode 100644 index 00000000..9b0b8416 --- /dev/null +++ b/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact1-1.0.0-20231008.222929-9999.pom @@ -0,0 +1,23 @@ + + + + 4.0.0 + org.group1 + artifact1 + 1.0.0-SNAPSHOT + diff --git a/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-20231008.222929-1.jar b/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-20231008.222929-1.jar new file mode 100644 index 00000000..e69de29b diff --git a/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-20231008.222929-1.pom b/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-20231008.222929-1.pom new file mode 100644 index 00000000..9b0b8416 --- /dev/null +++ b/mrm-maven-plugin/src/it/hostedrepo/src/mrm-local-repo/org/group1/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-20231008.222929-1.pom @@ -0,0 +1,23 @@ + + + + 4.0.0 + org.group1 + artifact1 + 1.0.0-SNAPSHOT + diff --git a/mrm-servlet/src/main/java/org/codehaus/mojo/mrm/impl/maven/CompositeArtifactStore.java b/mrm-servlet/src/main/java/org/codehaus/mojo/mrm/impl/maven/CompositeArtifactStore.java index 6eafb886..75da7798 100644 --- a/mrm-servlet/src/main/java/org/codehaus/mojo/mrm/impl/maven/CompositeArtifactStore.java +++ b/mrm-servlet/src/main/java/org/codehaus/mojo/mrm/impl/maven/CompositeArtifactStore.java @@ -18,17 +18,11 @@ import java.io.IOException; import java.io.InputStream; -import java.util.HashSet; import java.util.Set; import java.util.TreeSet; -import org.apache.commons.lang.StringUtils; import org.apache.maven.archetype.catalog.ArchetypeCatalog; import org.apache.maven.artifact.repository.metadata.Metadata; -import org.apache.maven.artifact.repository.metadata.Plugin; -import org.apache.maven.artifact.repository.metadata.Snapshot; -import org.apache.maven.artifact.repository.metadata.SnapshotVersion; -import org.apache.maven.artifact.repository.metadata.Versioning; import org.codehaus.mojo.mrm.api.maven.ArchetypeCatalogNotFoundException; import org.codehaus.mojo.mrm.api.maven.Artifact; import org.codehaus.mojo.mrm.api.maven.ArtifactNotFoundException; @@ -152,92 +146,22 @@ public void set(Artifact artifact, InputStream content) throws IOException { @Override public Metadata getMetadata(String path) throws IOException, MetadataNotFoundException { - boolean found = false; - Metadata result = new Metadata(); - Set pluginArtifactIds = new HashSet<>(); - Set snapshotVersions = new HashSet<>(); + Metadata result = null; + for (ArtifactStore store : stores) { try { - Metadata partial = store.getMetadata(path); - if (StringUtils.isEmpty(result.getArtifactId()) && !StringUtils.isEmpty(partial.getArtifactId())) { - result.setArtifactId(partial.getArtifactId()); - found = true; - } - if (StringUtils.isEmpty(result.getGroupId()) && !StringUtils.isEmpty(partial.getGroupId())) { - result.setGroupId(partial.getGroupId()); - found = true; - } - if (StringUtils.isEmpty(result.getVersion()) && !StringUtils.isEmpty(partial.getVersion())) { - result.setVersion(partial.getVersion()); - found = true; - } - if (partial.getPlugins() != null && !partial.getPlugins().isEmpty()) { - for (Plugin plugin : partial.getPlugins()) { - if (!pluginArtifactIds.contains(plugin.getArtifactId())) { - result.addPlugin(plugin); - pluginArtifactIds.add(plugin.getArtifactId()); - } - } - found = true; - } - if (partial.getVersioning() != null) { - Versioning rVers = result.getVersioning(); - if (rVers == null) { - rVers = new Versioning(); - } - Versioning pVers = partial.getVersioning(); - String rLU = found ? rVers.getLastUpdated() : null; - String pLU = pVers.getLastUpdated(); - if (pLU != null && (rLU == null || rLU.compareTo(pLU) < 0)) { - // partial is newer or only - if (!StringUtils.isEmpty(pVers.getLatest())) { - rVers.setLatest(pVers.getLatest()); - } - - if (!StringUtils.isEmpty(pVers.getRelease())) { - rVers.setRelease(pVers.getRelease()); - } - rVers.setLastUpdated(pVers.getLastUpdated()); - } - for (String version : pVers.getVersions()) { - if (!rVers.getVersions().contains(version)) { - rVers.addVersion(version); - } - } - if (pVers.getSnapshot() != null) { - if (rVers.getSnapshot() == null - || pVers.getSnapshot().getBuildNumber() - > rVers.getSnapshot().getBuildNumber()) { - Snapshot snapshot = new Snapshot(); - snapshot.setBuildNumber(pVers.getSnapshot().getBuildNumber()); - snapshot.setTimestamp(pVers.getSnapshot().getTimestamp()); - rVers.setSnapshot(snapshot); - } - } - try { - if (pVers.getSnapshotVersions() != null - && !pVers.getSnapshotVersions().isEmpty()) { - for (SnapshotVersion snapshotVersion : pVers.getSnapshotVersions()) { - String key = snapshotVersion.getVersion() + "-" + snapshotVersion.getClassifier() + "." - + snapshotVersion.getExtension(); - if (!snapshotVersions.contains(key)) { - rVers.addSnapshotVersion(snapshotVersion); - snapshotVersions.add(key); - } - } - } - } catch (NoSuchMethodError e) { - // Maven 2 - } - - result.setVersioning(rVers); - found = true; + Metadata metadata = store.getMetadata(path); + if (result == null) { + result = metadata; + } else { + result.merge(metadata); } } catch (MetadataNotFoundException e) { // ignore } } - if (!found) { + + if (result == null) { throw new MetadataNotFoundException(path); } return result; diff --git a/mrm-servlet/src/main/java/org/codehaus/mojo/mrm/impl/maven/DiskArtifactStore.java b/mrm-servlet/src/main/java/org/codehaus/mojo/mrm/impl/maven/DiskArtifactStore.java index 3adf41da..fdd3edb3 100644 --- a/mrm-servlet/src/main/java/org/codehaus/mojo/mrm/impl/maven/DiskArtifactStore.java +++ b/mrm-servlet/src/main/java/org/codehaus/mojo/mrm/impl/maven/DiskArtifactStore.java @@ -21,24 +21,35 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.UncheckedIOException; import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.GregorianCalendar; import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; import java.util.Set; -import java.util.Stack; import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.maven.archetype.catalog.ArchetypeCatalog; import org.apache.maven.archetype.catalog.io.xpp3.ArchetypeCatalogXpp3Reader; import org.apache.maven.artifact.repository.metadata.Metadata; +import org.apache.maven.artifact.repository.metadata.Snapshot; +import org.apache.maven.artifact.repository.metadata.SnapshotVersion; +import org.apache.maven.artifact.repository.metadata.Versioning; import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader; import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer; import org.codehaus.mojo.mrm.api.maven.ArchetypeCatalogNotFoundException; @@ -207,7 +218,7 @@ public Artifact get(File file) { @Override public long getLastModified(Artifact artifact) throws IOException, ArtifactNotFoundException { - File file = getFile(artifact); + File file = getFileByBasename(artifact); if (!file.isFile()) { throw new ArtifactNotFoundException(artifact); } @@ -216,7 +227,7 @@ public long getLastModified(Artifact artifact) throws IOException, ArtifactNotFo @Override public long getSize(Artifact artifact) throws IOException, ArtifactNotFoundException { - File file = getFile(artifact); + File file = getFileByBasename(artifact); if (!file.isFile()) { throw new ArtifactNotFoundException(artifact); } @@ -225,7 +236,7 @@ public long getSize(Artifact artifact) throws IOException, ArtifactNotFoundExcep @Override public InputStream get(Artifact artifact) throws IOException, ArtifactNotFoundException { - File file = getFile(artifact); + File file = getFileByBasename(artifact); if (!file.isFile()) { throw new ArtifactNotFoundException(artifact); } @@ -253,22 +264,13 @@ public void set(Artifact artifact, InputStream content) throws IOException { } @Override - public Metadata getMetadata(String path) throws IOException, MetadataNotFoundException { - File file = root; - String[] parts = StringUtils.strip(path, "/").split("/"); - for (String part : parts) { - file = new File(file, part); - } - file = new File(file, "maven-metadata.xml"); - if (!file.isFile()) { + public Metadata getMetadata(String path) throws MetadataNotFoundException { + MetadataInfo metadataInfo = prepareMetadata(path); + if (metadataInfo != null) { + return metadataInfo.metadata; + } else { throw new MetadataNotFoundException(path); } - - try (InputStream inputStream = Files.newInputStream(file.toPath())) { - return new MetadataXpp3Reader().read(inputStream); - } catch (XmlPullParserException e) { - throw new IOException(e.getMessage(), e); - } } @Override @@ -291,27 +293,13 @@ public void setMetadata(String path, Metadata metadata) throws IOException { } @Override - public long getMetadataLastModified(String path) throws IOException, MetadataNotFoundException { - File file = root; - String[] parts = StringUtils.strip(path, "/").split("/"); - Stack stack = new Stack<>(); - for (int i = 0; i < parts.length; i++) { - if ("..".equals(parts[i])) { - if (!stack.isEmpty()) { - file = stack.pop(); - } else { - file = root; - } - } else if (!".".equals(parts[i])) { - file = new File(file, parts[i]); - stack.push(file); - } - } - file = new File(file, "maven-metadata.xml"); - if (!file.isFile()) { + public long getMetadataLastModified(String path) throws MetadataNotFoundException { + MetadataInfo metadataInfo = prepareMetadata(path); + if (metadataInfo != null) { + return metadataInfo.lastModified; + } else { throw new MetadataNotFoundException(path); } - return file.lastModified(); } @Override @@ -337,10 +325,192 @@ public long getArchetypeCatalogLastModified() throws IOException, ArchetypeCatal return file.lastModified(); } + private File getFileByBasename(Artifact artifact) { + File groupDir = new File(root, artifact.getGroupId().replace('.', '/')); + File artifactDir = new File(groupDir, artifact.getArtifactId()); + File versionDir = new File(artifactDir, artifact.getVersion()); + File file = new File(versionDir, artifact.getName()); + if (!file.exists()) { + file = new File(versionDir, artifact.getBaseVersionName()); + } + return file; + } + private File getFile(Artifact artifact) { File groupDir = new File(root, artifact.getGroupId().replace('.', '/')); File artifactDir = new File(groupDir, artifact.getArtifactId()); File versionDir = new File(artifactDir, artifact.getVersion()); return new File(versionDir, artifact.getName()); } + + private MetadataInfo prepareMetadata(String path) { + File file = root; + String[] parts = StringUtils.strip(path, "/").split("/"); + for (String part : parts) { + file = new File(file, part); + } + + MetadataInfo metadataInfo = null; + try { + metadataInfo = getMetadataFromLocalPath(file); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + if (metadataInfo == null) { + try { + metadataInfo = getMetadataFromSnapshotVersion(path); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + return metadataInfo; + } + + private MetadataInfo getMetadataFromLocalPath(File path) throws IOException { + + File file = new File(path, "maven-metadata.xml"); + + if (!file.isFile()) { + return null; + } + + try (InputStream inputStream = Files.newInputStream(file.toPath())) { + return new MetadataInfo(new MetadataXpp3Reader().read(inputStream), file.lastModified()); + } catch (XmlPullParserException e) { + throw new IOException(e.getMessage(), e); + } + } + + private MetadataInfo getMetadataFromSnapshotVersion(String path) throws IOException { + + if (!path.endsWith("-SNAPSHOT")) { + return null; + } + + Path artifactPath = root.toPath().resolve(path); + if (!Files.exists(artifactPath)) { + return null; + } + + LinkedList pathItems = + new LinkedList<>(Arrays.asList(StringUtils.strip(path, "/").split("/"))); + + if (pathItems.size() < 3) { + return null; + } + + String version = pathItems.pollLast(); + String baseVersion = StringUtils.removeEnd(version, "-SNAPSHOT"); + String artifactId = pathItems.pollLast(); + + String groupId = String.join(".", pathItems); + + List artifactsList = getArtifactsListFromPath(artifactPath, artifactId, version); + if (artifactsList.isEmpty()) { + artifactsList = getArtifactsListFromPath(artifactPath, artifactId, baseVersion); + } + + if (artifactsList.isEmpty()) { + return null; + } + + DateTimeFormatter formatDate = DateTimeFormatter.ofPattern("yyyyMMdd").withZone(ZoneId.of("UTC")); + DateTimeFormatter formatTime = DateTimeFormatter.ofPattern("HHmmss").withZone(ZoneId.of("UTC")); + DateTimeFormatter formatDateTime = + DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(ZoneId.of("UTC")); + + Metadata metadata = new Metadata(); + metadata.setGroupId(groupId); + metadata.setArtifactId(artifactId); + metadata.setVersion(version); + + List snapshotVersions = new ArrayList<>(); + + int buildNr = -1; + Instant dateTime = null; + + // first collect items and discover the latest timestamps + for (String artifact : artifactsList) { + Pattern pattern = Pattern.compile("\\Q" + artifactId + "\\E-\\Q" + baseVersion + "\\E-" + + "(SNAPSHOT|(\\d{8})\\.(\\d{6})-(\\d+))(?:-([^.]+))?\\.(.+)"); + + Matcher matcher = pattern.matcher(artifact); + if (matcher.find()) { + SnapshotVersion snapshotVersion = new SnapshotVersion(); + if ("SNAPSHOT".equals(matcher.group(1))) { + buildNr = 9999; + Instant aDateTime = Files.getLastModifiedTime(artifactPath.resolve(artifact)) + .toInstant(); + if (dateTime == null || dateTime.isBefore(aDateTime)) { + dateTime = aDateTime; + } + } else { + buildNr = Integer.parseInt(matcher.group(4)); + dateTime = formatDateTime.parse(matcher.group(2) + matcher.group(3), Instant::from); + } + if (matcher.group(5) != null) { + snapshotVersion.setClassifier(matcher.group(5)); + } + snapshotVersion.setExtension(matcher.group(6)); + snapshotVersions.add(snapshotVersion); + } + } + + if (snapshotVersions.isEmpty()) { + // no items in directory + return null; + } + + String snapshotVersionText = + baseVersion + "-" + formatDate.format(dateTime) + "." + formatTime.format(dateTime) + "-" + buildNr; + String snapshotVersionUpdated = formatDateTime.format(dateTime); + + // next populate version and update time + snapshotVersions.forEach(snapshotVersion -> { + snapshotVersion.setVersion(snapshotVersionText); + snapshotVersion.setUpdated(snapshotVersionUpdated); + }); + + Versioning versioning = new Versioning(); + versioning.setLastUpdated(formatDateTime.format(dateTime)); + + versioning.setSnapshotVersions(snapshotVersions); + + Snapshot snapshot = new Snapshot(); + snapshot.setTimestamp(formatDate.format(dateTime) + "." + formatTime.format(dateTime)); + snapshot.setBuildNumber(buildNr); + versioning.setSnapshot(snapshot); + + metadata.setVersioning(versioning); + return new MetadataInfo(metadata, System.currentTimeMillis()); + } + + private List getArtifactsListFromPath(Path artifactPath, String artifactId, String version) + throws IOException { + + List artifactsList; + try (Stream pathStream = Files.walk(artifactPath, 1)) { + String artifactVersion = artifactId + "-" + version; + artifactsList = pathStream + .map(p -> p.getFileName().toString()) + .filter(name -> name.startsWith(artifactVersion)) + .filter(name -> !name.endsWith(".lastUpdated")) + .collect(Collectors.toList()); + } + + return artifactsList; + } + + private static class MetadataInfo { + + private final Metadata metadata; + private final long lastModified; + + private MetadataInfo(Metadata metadata, long lastModified) { + this.metadata = metadata; + this.lastModified = lastModified; + } + } } diff --git a/mrm-servlet/src/test/java/org/codehaus/mojo/mrm/impl/maven/CompositeArtifactStoreTest.java b/mrm-servlet/src/test/java/org/codehaus/mojo/mrm/impl/maven/CompositeArtifactStoreTest.java index 16f10dba..837ea4c9 100644 --- a/mrm-servlet/src/test/java/org/codehaus/mojo/mrm/impl/maven/CompositeArtifactStoreTest.java +++ b/mrm-servlet/src/test/java/org/codehaus/mojo/mrm/impl/maven/CompositeArtifactStoreTest.java @@ -1,10 +1,19 @@ package org.codehaus.mojo.mrm.impl.maven; +import java.io.IOException; +import java.util.Collections; + import org.apache.maven.archetype.catalog.ArchetypeCatalog; +import org.apache.maven.artifact.repository.metadata.Metadata; +import org.apache.maven.artifact.repository.metadata.Snapshot; +import org.apache.maven.artifact.repository.metadata.SnapshotVersion; +import org.apache.maven.artifact.repository.metadata.Versioning; import org.codehaus.mojo.mrm.api.maven.ArtifactStore; +import org.codehaus.mojo.mrm.api.maven.MetadataNotFoundException; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -21,4 +30,53 @@ void testGetArchetypeCatalog() throws Exception { assertNotNull(catalog); } + + @Test + void metadataForSnapshotShouldBeMerged() throws MetadataNotFoundException, IOException { + + Metadata metadata1 = new Metadata(); + metadata1.setArtifactId("artifactId"); + metadata1.setGroupId("groupId"); + metadata1.setVersion("1.0.0-SNAPSHOT"); + metadata1.setVersioning(aVersioning("20231008", "175511", 1)); + + Metadata metadata2 = new Metadata(); + metadata2.setArtifactId("artifactId"); + metadata2.setGroupId("groupId"); + metadata2.setVersion("1.0.0-SNAPSHOT"); + metadata2.setVersioning(aVersioning("20231008", "235511", 9999)); + + ArtifactStore store1 = mock(ArtifactStore.class); + ArtifactStore store2 = mock(ArtifactStore.class); + + when(store1.getMetadata(anyString())).thenReturn(metadata1); + when(store2.getMetadata(anyString())).thenReturn(metadata2); + ArtifactStore[] stores = new ArtifactStore[] {store1, store2}; + + CompositeArtifactStore artifactStore = new CompositeArtifactStore(stores); + + Metadata metadata = artifactStore.getMetadata("path"); + + assertNotNull(metadata); + } + + private Versioning aVersioning(String timeStampDate, String timeStampTime, int buildNr) { + + Versioning versioning = new Versioning(); + versioning.setLastUpdated(timeStampDate + timeStampTime); + + Snapshot snapshot = new Snapshot(); + snapshot.setTimestamp(timeStampDate + "." + timeStampTime); + snapshot.setBuildNumber(buildNr); + versioning.setSnapshot(snapshot); + + SnapshotVersion snapshotVersion = new SnapshotVersion(); + snapshotVersion.setVersion("1.0.0-" + timeStampDate + "." + timeStampTime + "-" + buildNr); + snapshotVersion.setExtension("jar"); + snapshotVersion.setClassifier("test"); + snapshotVersion.setUpdated(timeStampDate + timeStampTime); + + versioning.setSnapshotVersions(Collections.singletonList(snapshotVersion)); + return versioning; + } } diff --git a/mrm-servlet/src/test/java/org/codehaus/mojo/mrm/impl/maven/DiskArtifactStoreTest.java b/mrm-servlet/src/test/java/org/codehaus/mojo/mrm/impl/maven/DiskArtifactStoreTest.java index ec107f5c..603ede10 100644 --- a/mrm-servlet/src/test/java/org/codehaus/mojo/mrm/impl/maven/DiskArtifactStoreTest.java +++ b/mrm-servlet/src/test/java/org/codehaus/mojo/mrm/impl/maven/DiskArtifactStoreTest.java @@ -2,10 +2,15 @@ import org.apache.maven.archetype.catalog.Archetype; import org.apache.maven.archetype.catalog.ArchetypeCatalog; +import org.apache.maven.artifact.repository.metadata.Metadata; +import org.codehaus.mojo.mrm.api.maven.Artifact; +import org.codehaus.mojo.mrm.api.maven.MetadataNotFoundException; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import static org.junit.jupiter.api.Assertions.assertTrue; class DiskArtifactStoreTest extends AbstractTestSupport { @@ -23,4 +28,76 @@ void testArchetypeCatalog() throws Exception { assertEquals("Fileset test archetype", archetype.getDescription()); assertEquals("file://${basedir}/target/test-classes/repositories/central", archetype.getRepository()); } + + @Test + void sizeShouldBeGreaterThanZero() throws Exception { + DiskArtifactStore artifactStore = new DiskArtifactStore(getResourceAsFile("/local-repo-unit")); + + long size = artifactStore.getSize(new Artifact("org.group1", "artifact1", "1.0.0", "pom")); + assertTrue(size > 0); + } + + @Test + void sizeShouldBeGreaterThanZeroForSnapshot() throws Exception { + DiskArtifactStore artifactStore = new DiskArtifactStore(getResourceAsFile("/local-repo-unit")); + + long size = artifactStore.getSize(new Artifact("org.group2", "artifact2", "1.0.0-SNAPSHOT", "pom")); + assertTrue(size > 0); + } + + @Test + void sizeShouldBeGreaterThanZeroForSnapshotTimeStamped() throws Exception { + DiskArtifactStore artifactStore = new DiskArtifactStore(getResourceAsFile("/local-repo-unit")); + + long size = artifactStore.getSize( + new Artifact("org.group2", "artifact2", "1.0.0-SNAPSHOT", "pom", System.currentTimeMillis(), 9999)); + assertTrue(size > 0); + } + + @Test + void metaDataShouldNotExistForReleaseVersion() throws Exception { + DiskArtifactStore artifactStore = new DiskArtifactStore(getResourceAsFile("/local-repo-unit")); + + assertThrowsExactly( + MetadataNotFoundException.class, () -> artifactStore.getMetadata("org/group1/artifact1/1.0.0")); + } + + @Test + void metaDataShouldExistForSnapshotVersion() throws Exception { + DiskArtifactStore artifactStore = new DiskArtifactStore(getResourceAsFile("/local-repo-unit")); + + Metadata metadata = artifactStore.getMetadata("org/group2/artifact2/1.0.0-SNAPSHOT"); + + assertNotNull(metadata); + assertNotNull(metadata.getGroupId()); + assertNotNull(metadata.getArtifactId()); + assertNotNull(metadata.getVersion()); + assertNotNull(metadata.getVersioning().getSnapshot().getTimestamp()); + assertEquals(9999, metadata.getVersioning().getSnapshot().getBuildNumber()); + assertEquals(3, metadata.getVersioning().getSnapshotVersions().size()); + } + + @Test + void metaDataShouldExistForSnapshotTimestampVersion() throws Exception { + DiskArtifactStore artifactStore = new DiskArtifactStore(getResourceAsFile("/local-repo-unit")); + + Metadata metadata = artifactStore.getMetadata("org/group2/artifact2/2.0.0-SNAPSHOT"); + + assertNotNull(metadata); + assertNotNull(metadata.getGroupId()); + assertNotNull(metadata.getArtifactId()); + assertNotNull(metadata.getVersion()); + assertNotNull(metadata.getVersioning().getSnapshot().getTimestamp()); + assertEquals(1, metadata.getVersioning().getSnapshot().getBuildNumber()); + assertEquals(3, metadata.getVersioning().getSnapshotVersions().size()); + } + + @Test + void metaDataNotFoundForSnapshotVersion() throws Exception { + DiskArtifactStore artifactStore = new DiskArtifactStore(getResourceAsFile("/local-repo-unit")); + + assertThrowsExactly( + MetadataNotFoundException.class, + () -> artifactStore.getMetadata("org/group1/artifact1/9.9.9-SNAPSHOT")); + } } diff --git a/mrm-servlet/src/test/resources/local-repo-unit/org/group1/artifact1/1.0.0/artifact1-1.0.0.pom b/mrm-servlet/src/test/resources/local-repo-unit/org/group1/artifact1/1.0.0/artifact1-1.0.0.pom new file mode 100644 index 00000000..e6e806af --- /dev/null +++ b/mrm-servlet/src/test/resources/local-repo-unit/org/group1/artifact1/1.0.0/artifact1-1.0.0.pom @@ -0,0 +1,24 @@ + + + + 4.0.0 + org.example-group + example-artifact + 1.0.0 + pom + diff --git a/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT-build.pom b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT-build.pom new file mode 100644 index 00000000..e6e806af --- /dev/null +++ b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT-build.pom @@ -0,0 +1,24 @@ + + + + 4.0.0 + org.example-group + example-artifact + 1.0.0 + pom + diff --git a/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT.jar b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT.jar new file mode 100644 index 00000000..e69de29b diff --git a/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT.pom b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT.pom new file mode 100644 index 00000000..e6e806af --- /dev/null +++ b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/1.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT.pom @@ -0,0 +1,24 @@ + + + + 4.0.0 + org.example-group + example-artifact + 1.0.0 + pom + diff --git a/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT-build.pom b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT-build.pom new file mode 100644 index 00000000..e6e806af --- /dev/null +++ b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT-build.pom @@ -0,0 +1,24 @@ + + + + 4.0.0 + org.example-group + example-artifact + 1.0.0 + pom + diff --git a/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT.pom b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT.pom new file mode 100644 index 00000000..e6e806af --- /dev/null +++ b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-1.0.0-SNAPSHOT.pom @@ -0,0 +1,24 @@ + + + + 4.0.0 + org.example-group + example-artifact + 1.0.0 + pom + diff --git a/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-2.0.0-20231008.222929-1-build.pom b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-2.0.0-20231008.222929-1-build.pom new file mode 100644 index 00000000..e6e806af --- /dev/null +++ b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-2.0.0-20231008.222929-1-build.pom @@ -0,0 +1,24 @@ + + + + 4.0.0 + org.example-group + example-artifact + 1.0.0 + pom + diff --git a/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-2.0.0-20231008.222929-1.jar b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-2.0.0-20231008.222929-1.jar new file mode 100644 index 00000000..e69de29b diff --git a/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-2.0.0-20231008.222929-1.pom b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-2.0.0-20231008.222929-1.pom new file mode 100644 index 00000000..e6e806af --- /dev/null +++ b/mrm-servlet/src/test/resources/local-repo-unit/org/group2/artifact2/2.0.0-SNAPSHOT/artifact2-2.0.0-20231008.222929-1.pom @@ -0,0 +1,24 @@ + + + + 4.0.0 + org.example-group + example-artifact + 1.0.0 + pom +