Skip to content

Commit

Permalink
Merge pull request #300 from spyrkob/Issue-292_Record_version_of_reso…
Browse files Browse the repository at this point in the history
…lved_manifest

[#292] During channel initialisation the version of resolved manifest is made available
  • Loading branch information
jmesnil authored Oct 15, 2024
2 parents 6d6f118 + a6af073 commit 93801f2
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 38 deletions.
111 changes: 99 additions & 12 deletions core/src/main/java/org/wildfly/channel/ChannelImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package org.wildfly.channel;

import static java.util.Collections.singleton;
import static java.util.Objects.requireNonNull;
import static org.wildfly.channel.version.VersionMatcher.COMPARATOR;

Expand All @@ -24,6 +25,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand All @@ -41,7 +43,8 @@ class ChannelImpl implements AutoCloseable {

private static final Logger LOG = Logger.getLogger(ChannelImpl.class);

private Channel channelDefinition;
private final Channel channelDefinition;
private Channel resolvedChannel;

private List<ChannelImpl> requiredChannels = Collections.emptyList();

Expand All @@ -53,6 +56,7 @@ class ChannelImpl implements AutoCloseable {
private boolean dependency = false;

public Optional<Blocklist> blocklist = Optional.empty();
private ChannelManifestCoordinate resolvedCoordinate;

public ChannelManifest getManifest() {
return channelManifest;
Expand All @@ -78,8 +82,11 @@ void init(MavenVersionsResolver.Factory factory, List<ChannelImpl> channels) {

resolver = factory.create(channelDefinition.getRepositories());

final Channel.Builder resolvedChannelBuilder = new Channel.Builder(channelDefinition);
if (channelDefinition.getManifestCoordinate() != null) {
channelManifest = resolveManifest(channelDefinition.getManifestCoordinate());
final ChannelManifestCoordinate coordinate = resolveManifestVersion(channelDefinition);
resolvedChannelBuilder.setManifestCoordinate(coordinate);
channelManifest = resolveManifest(coordinate);
} else {
channelManifest = new ChannelManifest(null, null, null, Collections.emptyList());
}
Expand All @@ -94,12 +101,17 @@ void init(MavenVersionsResolver.Factory factory, List<ChannelImpl> channels) {
}

if (channelDefinition.getBlocklistCoordinate() != null) {
BlocklistCoordinate blocklistCoordinate = channelDefinition.getBlocklistCoordinate();
final List<URL> urls = resolver.resolveChannelMetadata(List.of(blocklistCoordinate));
this.blocklist = urls.stream()
.map(Blocklist::from)
.findFirst();
BlocklistCoordinate blocklistCoordinate = resolveBlocklistVersion(channelDefinition);
if (blocklistCoordinate != null) {
resolvedChannelBuilder.setBlocklistCoordinate(blocklistCoordinate);
final List<URL> urls = resolver.resolveChannelMetadata(List.of(blocklistCoordinate));
this.blocklist = urls.stream()
.map(Blocklist::from)
.findFirst();
}
}

this.resolvedChannel = resolvedChannelBuilder.build();
}

private ChannelImpl findRequiredChannel(MavenVersionsResolver.Factory factory, List<ChannelImpl> channels, ManifestRequirement manifestRequirement) {
Expand Down Expand Up @@ -179,8 +191,12 @@ boolean isDependency() {
return dependency;
}

Channel getChannelDefinition() {
return channelDefinition;
Channel getResolvedChannelDefinition() {
return resolvedChannel;
}

public Blocklist getBlocklist() {
return blocklist.orElse(null);
}

static class ResolveLatestVersionResult {
Expand All @@ -193,8 +209,79 @@ static class ResolveLatestVersionResult {
}
}

private Set<Repository> attemptedRepositories() {
return new HashSet<>(channelDefinition.getRepositories());
}

private ChannelManifestCoordinate resolveManifestVersion(Channel baseDefinition) {
final ChannelManifestCoordinate manifestCoordinate = baseDefinition.getManifestCoordinate();

// if we already have a version or it is a URL manifest, return it
if (manifestCoordinate.getUrl() != null || manifestCoordinate.getMaven().getVersion() != null) {
return manifestCoordinate;
}

final Set<String> allVersions = resolver.getAllVersions(
manifestCoordinate.getGroupId(),
manifestCoordinate.getArtifactId(),
manifestCoordinate.getExtension(),
manifestCoordinate.getClassifier()
);
Optional<String> latestVersion = VersionMatcher.getLatestVersion(allVersions);
String version = latestVersion.orElseThrow(() ->
new ArtifactTransferException(String.format("Unable to resolve the latest version of channel metadata %s:%s", manifestCoordinate.getGroupId(), manifestCoordinate.getArtifactId()),
singleton(new ArtifactCoordinate(manifestCoordinate.getGroupId(), manifestCoordinate.getArtifactId(), manifestCoordinate.getExtension(), manifestCoordinate.getClassifier(), "")),
attemptedRepositories()));

return new ChannelManifestCoordinate(manifestCoordinate.getGroupId(), manifestCoordinate.getArtifactId(), version);

}

private BlocklistCoordinate resolveBlocklistVersion(Channel baseDefinition) {
final BlocklistCoordinate blocklistCoordinate = baseDefinition.getBlocklistCoordinate();

if (blocklistCoordinate == null) {
return null;
}

// if we already have a version or it is a URL blocklist, return it
if (blocklistCoordinate.getUrl() != null || blocklistCoordinate.getMaven().getVersion() != null) {
return blocklistCoordinate;
}

final Set<String> allVersions = resolver.getAllVersions(
blocklistCoordinate.getGroupId(),
blocklistCoordinate.getArtifactId(),
blocklistCoordinate.getExtension(),
blocklistCoordinate.getClassifier()
);
Optional<String> latestVersion = VersionMatcher.getLatestVersion(allVersions);

// different from manifest resolution. If we were not able to resolve the blocklist, we assume it doesn't exist (yet) and
// we proceed without blocklist
return latestVersion
.map(v->new BlocklistCoordinate(blocklistCoordinate.getGroupId(), blocklistCoordinate.getArtifactId(), v))
.orElse(null);
}

private ChannelManifest resolveManifest(ChannelManifestCoordinate manifestCoordinate) throws UnresolvedMavenArtifactException {
return resolver.resolveChannelMetadata(List.of(manifestCoordinate))
if (manifestCoordinate.getUrl() == null && manifestCoordinate.getMaven().getVersion() == null) {
final Set<String> allVersions = resolver.getAllVersions(
manifestCoordinate.getGroupId(),
manifestCoordinate.getArtifactId(),
manifestCoordinate.getExtension(),
manifestCoordinate.getClassifier()
);
Optional<String> latestVersion = VersionMatcher.getLatestVersion(allVersions);
String version = latestVersion.orElseThrow(() ->
new ArtifactTransferException(String.format("Unable to resolve the latest version of channel metadata %s:%s", manifestCoordinate.getGroupId(), manifestCoordinate.getArtifactId()),
singleton(new ArtifactCoordinate(manifestCoordinate.getGroupId(), manifestCoordinate.getArtifactId(), manifestCoordinate.getExtension(), manifestCoordinate.getClassifier(), "")),
attemptedRepositories()));
resolvedCoordinate = new ChannelManifestCoordinate(manifestCoordinate.getGroupId(), manifestCoordinate.getArtifactId(), version);
} else {
resolvedCoordinate = manifestCoordinate;
}
return resolver.resolveChannelMetadata(List.of(resolvedCoordinate))
.stream()
.map(ChannelManifestMapper::from)
.findFirst().orElseThrow();
Expand Down Expand Up @@ -248,7 +335,7 @@ Optional<ResolveLatestVersionResult> resolveLatestVersion(String groupId, String
return Optional.of(new ResolveLatestVersionResult(latestMetadataVersion, this));
} catch (NoStreamFoundException e) {
LOG.debugf(e, "Metadata resolution for %s:%s failed in channel %s",
groupId, artifactId, this.getChannelDefinition().getName());
groupId, artifactId, this.getResolvedChannelDefinition().getName());
return Optional.empty();
}
case MAVEN_RELEASE:
Expand All @@ -260,7 +347,7 @@ Optional<ResolveLatestVersionResult> resolveLatestVersion(String groupId, String
return Optional.of(new ResolveLatestVersionResult(releaseMetadataVersion, this));
} catch (NoStreamFoundException e) {
LOG.debugf(e, "Metadata resolution for %s:%s failed in channel %s",
groupId, artifactId, this.getChannelDefinition().getName());
groupId, artifactId, this.getResolvedChannelDefinition().getName());
return Optional.empty();
}
default:
Expand Down
20 changes: 16 additions & 4 deletions core/src/main/java/org/wildfly/channel/ChannelSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@ public ChannelSession(List<Channel> channelDefinitions, MavenVersionsResolver.Fa
validateNoDuplicatedManifests();
}

/**
* Get the definitions of channels used by this session. Returned version contains resolved versions
* of channel metadata (if applicable).
*
* @return List of {@code RuntimeChannel}s used to resolve artifacts by this session
*/
public List<RuntimeChannel> getRuntimeChannels() {
return this.channels.stream()
.map(c->new RuntimeChannel(c.getResolvedChannelDefinition(), c.getManifest(), c.getBlocklist()))
.collect(Collectors.toList());
}

/**
* Resolve the Maven artifact according to the session's channels.
* <p>
Expand Down Expand Up @@ -121,7 +133,7 @@ public MavenArtifact resolveMavenArtifact(String groupId, String artifactId, Str

ChannelImpl.ResolveArtifactResult artifact = channel.resolveArtifact(groupId, artifactId, extension, classifier, latestVersion);
recorder.recordStream(groupId, artifactId, latestVersion);
return new MavenArtifact(groupId, artifactId, extension, classifier, latestVersion, artifact.file, artifact.channel.getChannelDefinition().getName());
return new MavenArtifact(groupId, artifactId, extension, classifier, latestVersion, artifact.file, artifact.channel.getResolvedChannelDefinition().getName());
}

/**
Expand Down Expand Up @@ -153,7 +165,7 @@ public List<MavenArtifact> resolveMavenArtifacts(List<ArtifactCoordinate> coordi
final MavenArtifact resolvedArtifact = new MavenArtifact(request.getGroupId(), request.getArtifactId(),
request.getExtension(), request.getClassifier(), request.getVersion(),
resolveArtifactResults.get(i).file,
resolveArtifactResults.get(i).channel.getChannelDefinition().getName());
resolveArtifactResults.get(i).channel.getResolvedChannelDefinition().getName());

recorder.recordStream(resolvedArtifact.getGroupId(), resolvedArtifact.getArtifactId(), resolvedArtifact.getVersion());
res.add(resolvedArtifact);
Expand Down Expand Up @@ -227,7 +239,7 @@ public List<MavenArtifact> resolveDirectMavenArtifacts(List<ArtifactCoordinate>
*/
public VersionResult findLatestMavenArtifactVersion(String groupId, String artifactId, String extension, String classifier, String baseVersion) throws NoStreamFoundException {
final ChannelImpl.ResolveLatestVersionResult channelWithLatestVersion = findChannelWithLatestVersion(groupId, artifactId, extension, classifier, baseVersion);
return new VersionResult(channelWithLatestVersion.version, channelWithLatestVersion.channel.getChannelDefinition().getName());
return new VersionResult(channelWithLatestVersion.version, channelWithLatestVersion.channel.getResolvedChannelDefinition().getName());
}

@Override
Expand Down Expand Up @@ -274,7 +286,7 @@ private ChannelImpl.ResolveLatestVersionResult findChannelWithLatestVersion(Stri
return foundVersions.get(foundLatestVersionInChannels.orElseThrow(() -> {
final ArtifactCoordinate coord = new ArtifactCoordinate(groupId, artifactId, extension, classifier, "");
final Set<Repository> repositories = channels.stream()
.map(ChannelImpl::getChannelDefinition)
.map(ChannelImpl::getResolvedChannelDefinition)
.flatMap(d -> d.getRepositories().stream())
.collect(Collectors.toSet());
throw new NoStreamFoundException(
Expand Down
58 changes: 58 additions & 0 deletions core/src/main/java/org/wildfly/channel/RuntimeChannel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.wildfly.channel;

import java.util.Objects;

public class RuntimeChannel {

private final Channel channel;
private final ChannelManifest channelManifest;
private final Blocklist blocklist;

public RuntimeChannel(Channel channel, ChannelManifest channelManifest, Blocklist blocklist) {
this.channel = channel;
this.channelManifest = channelManifest;
this.blocklist = blocklist;
}

public Channel getChannelDefinition() {
return channel;
}

public ChannelManifest getChannelManifest() {
return channelManifest;
}

public Blocklist getChannelBlocklist() {
return blocklist;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RuntimeChannel that = (RuntimeChannel) o;
return Objects.equals(channel, that.channel) && Objects.equals(channelManifest, that.channelManifest) && Objects.equals(blocklist, that.blocklist);
}

@Override
public int hashCode() {
return Objects.hash(channel, channelManifest, blocklist);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Set;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
Expand Down Expand Up @@ -359,6 +361,63 @@ public void duplicatedManifestIDsAreDetected() throws Exception {
assertThrows(RuntimeException.class, () -> new ChannelSession(channels, factory));
}

@Test
public void getVersionOfResolvedManifest() throws Exception {
final MavenVersionsResolver.Factory factory = mock(MavenVersionsResolver.Factory.class);
MavenVersionsResolver resolver = mock(MavenVersionsResolver.class);
when(factory.create(any())).thenReturn(resolver);

final ChannelManifest requiredManifest = new ManifestBuilder()
.setId("manifest-one")
.build();
mockManifest(resolver, requiredManifest, "test.channels:base-manifest:1.0.0");
when(resolver.getAllVersions("test.channels", "base-manifest", ChannelManifest.EXTENSION, ChannelManifest.CLASSIFIER))
.thenReturn(Set.of("1.0.0"));

final List<Channel> channels = List.of(new Channel.Builder()
.setName("channel one")
.addRepository("test", "test")
.setManifestCoordinate("test.channels", "base-manifest")
.build());
try (ChannelSession channelSession = new ChannelSession(channels, factory)) {
assertThat(channelSession.getRuntimeChannels())
.map(RuntimeChannel::getChannelDefinition)
.map(Channel::getManifestCoordinate)
.map(ChannelManifestCoordinate::getVersion)
.containsOnly("1.0.0");

}
}

@Test
public void getVersionOfResolvedBlocklist() throws Exception {
final MavenVersionsResolver.Factory factory = mock(MavenVersionsResolver.Factory.class);
MavenVersionsResolver resolver = mock(MavenVersionsResolver.class);
when(factory.create(any())).thenReturn(resolver);

final ChannelManifest requiredManifest = new ManifestBuilder()
.setId("manifest-one")
.build();
mockManifest(resolver, requiredManifest, "test.channels:base-manifest:1.0.0");
when(resolver.getAllVersions("test.channels", "blocklist", BlocklistCoordinate.EXTENSION, BlocklistCoordinate.CLASSIFIER))
.thenReturn(Set.of("1.0.0"));

final List<Channel> channels = List.of(new Channel.Builder()
.setName("channel one")
.addRepository("test", "test")
.setManifestCoordinate("test.channels", "base-manifest", "1.0.0")
.setBlocklistCoordinate(new BlocklistCoordinate("test.channels", "blocklist"))
.build());
try (ChannelSession channelSession = new ChannelSession(channels, factory)) {
assertThat(channelSession.getRuntimeChannels())
.map(RuntimeChannel::getChannelDefinition)
.map(Channel::getBlocklistCoordinate)
.map(BlocklistCoordinate::getVersion)
.containsOnly("1.0.0");

}
}

private void mockManifest(MavenVersionsResolver resolver, ChannelManifest manifest, String gav) throws IOException {
mockManifest(resolver, ChannelManifestMapper.toYaml(manifest), gav);
}
Expand Down
Loading

0 comments on commit 93801f2

Please sign in to comment.