Skip to content

Commit

Permalink
Merge pull request #305 from aloubyansky/domino-quarkus
Browse files Browse the repository at this point in the history
domino quarkus command
  • Loading branch information
aloubyansky authored Dec 8, 2023
2 parents 518fd49 + 6390bea commit 00e81e6
Show file tree
Hide file tree
Showing 5 changed files with 795 additions and 1 deletion.
43 changes: 43 additions & 0 deletions domino/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,49 @@ Before intergating the SCM locator library from the AppStudio, Domino used its o
java -jar domino.jar report --bom=io.vertx:vertx-dependencies:4.3.4.redhat-00007 --output-file=report.txt --legacy-scm-locator
```

#### Quarkus platform dependency tracing

`quarkus` command was developed to support a couple of use-cases:

1. to check whether a given artifact is found among dependencies of Quarkus extensions included in a given platform release;
2. pre-download extensions artifacts and their dependencies for a given platform release.

##### Tracing dependencies

`quarkus` command allows checking whether a given artifact (or an artifact coordinates pattern) matches any extension artifacts and/or their dependencies included in a given platform release.

For example, the following command will find all the extensions that have an artifact with artifactId matching `snappy*` GLOB pattern among their dependencies as well as matching dependency version constraints from all the platform member BOMs:
```
java -jar domino.jar quarkus --version=3.2.9.Final --trace snappy*
```

By default, only the extension artifacts having the matching artifact and the matching artifact itself are logged in the report. Add `--full-chain` to see complete dependency chains from each extension artifact to the matched artifacts.
```
java -jar domino.jar quarkus --version=3.2.9.Final --trace snappy* --full-chain
```

Analysis could be limited to selected members using `--members` argument that accepts a comma-separated list of platform member BOM `artifactId`s, for example
```
java -jar domino.jar quarkus --version=3.2.9.Final --trace snappy* --members=quarkus-camel-bom
```

Limiting analysis to only runtime extension artifacts could be done by adding `--runtime-only` argument
```
java -jar domino.jar quarkus --version=3.2.9.Final --trace snappy* --members=quarkus-camel-bom --runtime-only
```

##### Downloading platform dependencies

`quarkus` command can be used to pre-download Quarkus extension artifacts and their dependencies to a local Maven repository for a given Quarkus platform release. Here is an example
```
java -jar domino.jar quarkus --version=3.2.9.Final --resolve
```

A custom local Maven repository location can be provided using `--repo-dir` argument.
```
java -jar domino.jar quarkus --version=3.2.9.Final --resolve --repo-dir=repo-3.2.9
```

### Maven plugin

There is also a Maven plugin goal that can be used to generate a dependency report. For example, here is one for Vert.X:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package io.quarkus.domino.tree.quarkus;

import io.quarkus.maven.dependency.ArtifactCoords;
import java.util.List;
import java.util.Objects;

public class QuarkusPlatformInfo {

private Member core;
private List<Member> members;
private ArtifactCoords mavenPlugin;

public QuarkusPlatformInfo(Member core, List<Member> members, ArtifactCoords mavenPlugin) {
this.core = core;
this.members = List.copyOf(members);
this.mavenPlugin = Objects.requireNonNull(mavenPlugin);
}

public Member getCore() {
return core;
}

public List<Member> getMembers() {
return members;
}

public ArtifactCoords getMavenPlugin() {
return mavenPlugin;
}

public static class Member {
private final ArtifactCoords bom;
private final String quarkusCoreVersion;
private final List<ArtifactCoords> extensions;
private final Release release;

public Member(ArtifactCoords bom, String quarkusCoreVersion, List<ArtifactCoords> extensions, Release release) {
this.bom = bom;
this.quarkusCoreVersion = quarkusCoreVersion;
this.extensions = List.copyOf(extensions);
this.release = release;
}

public ArtifactCoords getBom() {
return bom;
}

public String getQuarkusCoreVersion() {
return quarkusCoreVersion;
}

public List<ArtifactCoords> getExtensions() {
return extensions;
}

public Release getRelease() {
return release;
}
}

public static class Release {
private final String platformKey;
private final String stream;
private final String version;
private final List<ArtifactCoords> memberBoms;

public Release(String platformKey, String stream, String version, List<ArtifactCoords> memberBoms) {
this.platformKey = Objects.requireNonNull(platformKey);
this.stream = Objects.requireNonNull(stream);
this.version = Objects.requireNonNull(version);
this.memberBoms = List.copyOf(memberBoms);
}

public String getPlatformKey() {
return platformKey;
}

public String getStream() {
return stream;
}

public String getVersion() {
return version;
}

public List<ArtifactCoords> getMemberBoms() {
return memberBoms;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package io.quarkus.domino.tree.quarkus;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ArrayNode;
import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException;
import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver;
import io.quarkus.maven.dependency.ArtifactCoords;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.aether.artifact.DefaultArtifact;

public class QuarkusPlatformInfoReader {

private static volatile ObjectMapper mapper;

private static final String PLATFORM_COMMUNITY_GROUP_ID = "io.quarkus.platform";
private static final String PLATFORM_REDHAT_GROUP_ID = "com.redhat.quarkus.platform";
private static final String QUARKUS_BOM = "quarkus-bom";
private static final String QUARKUS_PLATFORM_DESCRIPTOR = "-quarkus-platform-descriptor";
private static final String REDHAT = "redhat";

public static Builder builder() {
return new QuarkusPlatformInfoReader().new Builder();
}

public class Builder {

private boolean built;

private Builder() {
}

public Builder setResolver(MavenArtifactResolver resolver) {
ensureNotBuilt();
QuarkusPlatformInfoReader.this.resolver = resolver;
return this;
}

public Builder setVersion(String version) {
ensureNotBuilt();
QuarkusPlatformInfoReader.this.version = version;
return this;
}

public Builder setPlatformKey(String platformKey) {
ensureNotBuilt();
QuarkusPlatformInfoReader.this.platformKey = platformKey;
return this;
}

public QuarkusPlatformInfoReader build() {
ensureNotBuilt();
built = true;
return QuarkusPlatformInfoReader.this;
}

private void ensureNotBuilt() {
if (built) {
throw new RuntimeException("This builder instance has already been built");
}
}
}

private MavenArtifactResolver resolver;
private String platformKey;
private String version;

private QuarkusPlatformInfoReader() {
}

public QuarkusPlatformInfo readPlatformInfo() {
if (isBlank(version)) {
throw new IllegalArgumentException("Platform version wasn't provided");
}

if (isBlank(platformKey)) {
platformKey = version.contains(REDHAT) ? PLATFORM_REDHAT_GROUP_ID : PLATFORM_COMMUNITY_GROUP_ID;
}

if (resolver == null) {
throw new IllegalArgumentException("Artifact resolver was not initialized");
}

var coreMember = readMember(platformKey, QUARKUS_BOM, version);
var allMembers = new ArrayList<QuarkusPlatformInfo.Member>(coreMember.getRelease().getMemberBoms().size());
allMembers.add(coreMember);
for (var memberBom : coreMember.getRelease().getMemberBoms()) {
if (!memberBom.equals(coreMember.getBom())) {
allMembers.add(readMember(memberBom.getGroupId(), memberBom.getArtifactId(), memberBom.getVersion()));
}
}
return new QuarkusPlatformInfo(coreMember, allMembers,
ArtifactCoords.jar(coreMember.getBom().getGroupId(), "quarkus-maven-plugin", coreMember.getBom().getVersion()));
}

private QuarkusPlatformInfo.Member readMember(String bomGroupId, String bomArtifactId, String bomVersion) {
final File quarkusBomJson;
try {
quarkusBomJson = resolver.resolve(new DefaultArtifact(bomGroupId, bomArtifactId + QUARKUS_PLATFORM_DESCRIPTOR,
bomVersion, "json", bomVersion)).getArtifact().getFile();
} catch (BootstrapMavenException e) {
throw new RuntimeException(e);
}
return QuarkusPlatformInfoReader.readMember(quarkusBomJson);
}

private static boolean isBlank(String s) {
return s == null || s.isEmpty();
}

private static ObjectMapper getMapper() {
if (mapper == null) {
ObjectMapper om = new ObjectMapper();
om.enable(SerializationFeature.INDENT_OUTPUT);
om.enable(JsonParser.Feature.ALLOW_COMMENTS);
om.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
om.setPropertyNamingStrategy(PropertyNamingStrategies.KEBAB_CASE);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper = om;
}
return mapper;
}

static QuarkusPlatformInfo.Member readMember(File jsonFile) {
final JsonNode root;
try (BufferedReader reader = new BufferedReader(new FileReader(jsonFile))) {
root = getMapper().readTree(reader);
} catch (IOException e) {
throw new UncheckedIOException("Failed to deserialize " + jsonFile, e);
}
return new QuarkusPlatformInfo.Member(
ArtifactCoords.fromString(readTextValue(root, "bom")),
readTextValue(root, "quarkus-core-version"),
readMember(root),
readRelease(root));
}

static List<ArtifactCoords> readMember(JsonNode root) {
var node = root.get("extensions");
if (node == null || !node.isArray()) {
throw new RuntimeException("Failed to locate extensions array in the extension catalog");
}
var arr = (ArrayNode) node;
final List<ArtifactCoords> extCoords = new ArrayList<>(arr.size());
for (var e : arr) {
extCoords.add(ArtifactCoords.fromString(readTextValue(e, "artifact")));
}
return extCoords;
}

private static QuarkusPlatformInfo.Release readRelease(JsonNode root) {
var node = root.get("metadata");
if (node == null) {
return null;
}
node = node.get("platform-release");
if (node == null) {
return null;
}
var members = node.get("members");
if (members == null || !members.isArray()) {
throw new RuntimeException("Failed to locate field metadata/platform-release/members");
}
var memberArr = (ArrayNode) members;
var memberBoms = new ArrayList<ArtifactCoords>(memberArr.size());
for (var m : memberArr) {
var coords = ArtifactCoords.fromString(m.asText());
memberBoms.add(ArtifactCoords.pom(coords.getGroupId(),
coords.getArtifactId().replace(QUARKUS_PLATFORM_DESCRIPTOR, ""), coords.getVersion()));
}
return new QuarkusPlatformInfo.Release(
readTextValue(node, "platform-key"),
readTextValue(node, "stream"),
readTextValue(node, "version"),
memberBoms);
}

private static String readTextValue(JsonNode node, String fieldName) {
var value = node.get(fieldName);
if (value == null) {
throw new RuntimeException("Field " + fieldName + " isn't present");
}
return value.textValue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

@TopCommand
@CommandLine.Command(mixinStandardHelpOptions = true, subcommands = { Report.class, FromMaven.class, FromGradle.class,
FromConfig.class, Project.class, Dependency.class, Version.class })
FromConfig.class, Project.class, Dependency.class, Quarkus.class, Version.class })
public class EntryCommand {

}
Loading

0 comments on commit 00e81e6

Please sign in to comment.