Skip to content

Commit

Permalink
Propage parent-first flag
Browse files Browse the repository at this point in the history
  • Loading branch information
aloubyansky committed Dec 10, 2022
1 parent d4e5ec7 commit abcd375
Show file tree
Hide file tree
Showing 4 changed files with 280 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package io.quarkus.deployment.runnerjar;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

import io.quarkus.bootstrap.model.ApplicationModel;
import io.quarkus.bootstrap.resolver.TsArtifact;
import io.quarkus.bootstrap.resolver.TsQuarkusExt;
import io.quarkus.maven.dependency.ArtifactCoords;
import io.quarkus.maven.dependency.ArtifactDependency;
import io.quarkus.maven.dependency.Dependency;
import io.quarkus.maven.dependency.DependencyFlags;

public class ParentFirstFlagPropagationTest extends BootstrapFromOriginalJarTestBase {

@Override
protected TsArtifact composeApplication() {

final TsArtifact extADep1 = TsArtifact.jar("ext-a-dep");
addToExpectedLib(extADep1);
final TsArtifact extBDep1 = TsArtifact.jar("ext-b-dep");
addToExpectedLib(extBDep1);
final TsArtifact extBDepTrans1 = TsArtifact.jar("ext-b-dep-trans");
addToExpectedLib(extBDepTrans1);
extBDep1.addDependency(extBDepTrans1);

final TsQuarkusExt extA = new TsQuarkusExt("ext-a");
extA.getRuntime()
.addDependency(extADep1)
.addDependency(extBDep1, extBDepTrans1);
addToExpectedLib(extA.getRuntime());
final TsQuarkusExt extB = new TsQuarkusExt("ext-b");
addToExpectedLib(extB.getRuntime());
extB.getRuntime().addDependency(extBDep1);
extB.addDependency(extA);
extB.setDependencyFlag(extBDep1.getKey(), DependencyFlags.CLASSLOADER_PARENT_FIRST);

return TsArtifact.jar("app")
.addManagedDependency(platformDescriptor())
.addManagedDependency(platformProperties())
.addDependency(extB);
}

@Override
protected void assertAppModel(ApplicationModel appModel) throws Exception {
final Set<Dependency> expectedDeployDeps = Set.of(
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-b-deployment", "1"), "compile",
DependencyFlags.DEPLOYMENT_CP),
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-deployment", "1"), "compile",
DependencyFlags.DEPLOYMENT_CP));
assertEquals(expectedDeployDeps, appModel.getDependencies().stream().filter(d -> d.isDeploymentCp() && !d.isRuntimeCp())
.map(d -> new ArtifactDependency(d)).collect(Collectors.toSet()));

final Set<Dependency> expectedRuntimeDeps = Set.of(
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a", "1"), "compile",
DependencyFlags.RUNTIME_EXTENSION_ARTIFACT, DependencyFlags.RUNTIME_CP, DependencyFlags.DEPLOYMENT_CP),
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-dep", "1"), "compile",
DependencyFlags.RUNTIME_CP, DependencyFlags.DEPLOYMENT_CP),
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-b", "1"), "compile",
DependencyFlags.DIRECT, DependencyFlags.RUNTIME_EXTENSION_ARTIFACT, DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP, DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT),
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-b-dep", "1"), "compile",
DependencyFlags.RUNTIME_CP, DependencyFlags.DEPLOYMENT_CP, DependencyFlags.CLASSLOADER_PARENT_FIRST),
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-b-dep-trans", "1"), "compile",
DependencyFlags.RUNTIME_CP, DependencyFlags.DEPLOYMENT_CP, DependencyFlags.CLASSLOADER_PARENT_FIRST));
assertEquals(expectedRuntimeDeps,
appModel.getRuntimeDependencies().stream().map(d -> new ArtifactDependency(d)).collect(Collectors.toSet()));
final Set<Dependency> expectedFullDeps = new HashSet<>();
expectedFullDeps.addAll(expectedDeployDeps);
expectedFullDeps.addAll(expectedRuntimeDeps);
assertEquals(expectedFullDeps,
appModel.getDependencies().stream().map(d -> new ArtifactDependency(d)).collect(Collectors.toSet()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package io.quarkus.deployment.runnerjar;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

import io.quarkus.bootstrap.model.ApplicationModel;
import io.quarkus.bootstrap.resolver.TsArtifact;
import io.quarkus.bootstrap.resolver.TsQuarkusExt;
import io.quarkus.maven.dependency.ArtifactCoords;
import io.quarkus.maven.dependency.ArtifactDependency;
import io.quarkus.maven.dependency.Dependency;
import io.quarkus.maven.dependency.DependencyFlags;

public class RunnerParentFirstFlagPropagationTest extends BootstrapFromOriginalJarTestBase {
@Override
protected TsArtifact composeApplication() {

final TsArtifact extADep1 = TsArtifact.jar("ext-a-dep");
addToExpectedLib(extADep1);
final TsArtifact extBDep1 = TsArtifact.jar("ext-b-dep");
addToExpectedLib(extBDep1);
final TsArtifact extBDepTrans1 = TsArtifact.jar("ext-b-dep-trans");
addToExpectedLib(extBDepTrans1);
extBDep1.addDependency(extBDepTrans1);

final TsQuarkusExt extA = new TsQuarkusExt("ext-a");
extA.getRuntime()
.addDependency(extADep1)
.addDependency(extBDep1, extBDepTrans1);
addToExpectedLib(extA.getRuntime());
final TsQuarkusExt extB = new TsQuarkusExt("ext-b");
addToExpectedLib(extB.getRuntime());
extB.getRuntime().addDependency(extBDep1);
extB.addDependency(extA);
extB.setDependencyFlag(extBDep1.getKey(), DependencyFlags.CLASSLOADER_PARENT_FIRST);

return TsArtifact.jar("app")
.addManagedDependency(platformDescriptor())
.addManagedDependency(platformProperties())
.addDependency(extB);
}

@Override
protected void assertAppModel(ApplicationModel appModel) throws Exception {
final Set<Dependency> expectedDeployDeps = Set.of(
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-b-deployment", "1"), "compile",
DependencyFlags.DEPLOYMENT_CP),
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-deployment", "1"), "compile",
DependencyFlags.DEPLOYMENT_CP));
assertEquals(expectedDeployDeps, appModel.getDependencies().stream().filter(d -> d.isDeploymentCp() && !d.isRuntimeCp())
.map(d -> new ArtifactDependency(d)).collect(Collectors.toSet()));

final Set<Dependency> expectedRuntimeDeps = Set.of(
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a", "1"), "compile",
DependencyFlags.RUNTIME_EXTENSION_ARTIFACT, DependencyFlags.RUNTIME_CP, DependencyFlags.DEPLOYMENT_CP),
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-dep", "1"), "compile",
DependencyFlags.RUNTIME_CP, DependencyFlags.DEPLOYMENT_CP),
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-b", "1"), "compile",
DependencyFlags.DIRECT, DependencyFlags.RUNTIME_EXTENSION_ARTIFACT, DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP, DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT),
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-b-dep", "1"), "compile",
DependencyFlags.RUNTIME_CP, DependencyFlags.DEPLOYMENT_CP, DependencyFlags.CLASSLOADER_PARENT_FIRST),
new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-b-dep-trans", "1"), "compile",
DependencyFlags.RUNTIME_CP, DependencyFlags.DEPLOYMENT_CP, DependencyFlags.CLASSLOADER_PARENT_FIRST));
assertEquals(expectedRuntimeDeps,
appModel.getRuntimeDependencies().stream().map(d -> new ArtifactDependency(d)).collect(Collectors.toSet()));
final Set<Dependency> expectedFullDeps = new HashSet<>();
expectedFullDeps.addAll(expectedDeployDeps);
expectedFullDeps.addAll(expectedRuntimeDeps);
assertEquals(expectedFullDeps,
appModel.getDependencies().stream().map(d -> new ArtifactDependency(d)).collect(Collectors.toSet()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.Map;
import java.util.StringJoiner;
import java.util.stream.Collectors;

import io.quarkus.bootstrap.BootstrapConstants;
import io.quarkus.maven.dependency.ArtifactKey;
import io.quarkus.maven.dependency.DependencyFlags;

public class TsQuarkusExt {

Expand All @@ -16,6 +20,7 @@ public class TsQuarkusExt {
protected final TsJar rtContent;
protected final PropsBuilder rtDescr = PropsBuilder.newInstance();
private boolean installed;
private Map<Integer, List<ArtifactKey>> flags = new HashMap<>();

public TsQuarkusExt(String artifactId) {
this(artifactId, TsArtifact.DEFAULT_VERSION);
Expand All @@ -30,6 +35,11 @@ public TsQuarkusExt(String artifactId, String version) {
rtDescr.set(BootstrapConstants.PROP_DEPLOYMENT_ARTIFACT, deployment.toString());
}

public TsQuarkusExt setDependencyFlag(ArtifactKey dep, int flag) {
this.flags.computeIfAbsent(flag, k -> new ArrayList<>()).add(dep);
return this;
}

public TsQuarkusExt setConditionalDeps(TsQuarkusExt... exts) {
final StringBuilder buf = new StringBuilder();
int i = 0;
Expand Down Expand Up @@ -83,15 +93,25 @@ public void install(TsRepoBuilder repo) {
}
installed = true;

rtContent.addEntry(rtDescr.build(), BootstrapConstants.DESCRIPTOR_PATH);

if (!extDeps.isEmpty()) {
for (TsQuarkusExt e : extDeps) {
e.install(repo);
}
}
Properties props = rtDescr.build();
rtContent.addEntry(props, BootstrapConstants.DESCRIPTOR_PATH);
for (Map.Entry<Integer, List<ArtifactKey>> e : flags.entrySet()) {
switch (e.getKey()) {
case DependencyFlags.CLASSLOADER_PARENT_FIRST:
final StringJoiner sj = new StringJoiner(",");
for (ArtifactKey k : e.getValue()) {
sj.add(k.toString());
}
rtDescr.set(BootstrapConstants.PARENT_FIRST_ARTIFACTS, sj.toString());
break;
default:
throw new RuntimeException("Not yet supported flag " + e.getKey());
}
}
rtContent.addEntry(rtDescr.build(), BootstrapConstants.DESCRIPTOR_PATH);
deployment.install(repo);
runtime.install(repo);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import io.quarkus.maven.dependency.ArtifactCoords;
import io.quarkus.maven.dependency.ArtifactKey;
import io.quarkus.maven.dependency.DependencyFlags;
import io.quarkus.maven.dependency.GACT;
import io.quarkus.maven.dependency.ResolvedDependencyBuilder;
import io.quarkus.paths.PathList;
import io.quarkus.paths.PathTree;
Expand Down Expand Up @@ -209,21 +210,42 @@ public void resolve(CollectRequest collectRtDepsRequest) throws AppModelResolver
buildTreeConsumer);
buildDepsVisitor.visit(root);

if (!CONVERGED_TREE_ONLY && collectReloadableModules) {
for (ResolvedDependencyBuilder db : appBuilder.getDependencies()) {
if (db.isFlagSet(DependencyFlags.RELOADABLE | DependencyFlags.VISITED)) {
continue;
for (ExtensionInfo e : allExtensions.values()) {
if (!e.activated) {
continue;
}
e.handleExtensionProperties();
}

if (!CONVERGED_TREE_ONLY) {
if (collectReloadableModules) {
for (ResolvedDependencyBuilder db : appBuilder.getDependencies()) {
if (!db.isFlagSet(DependencyFlags.RELOADABLE | DependencyFlags.VISITED)) {
propagateFlags(db, DependencyFlags.RELOADABLE, 0);
}
}
clearReloadableFlag(db);
clearVisitedFlag();
}
propagateFlag(DependencyFlags.CLASSLOADER_PARENT_FIRST);
propagateFlag(DependencyFlags.CLASSLOADER_RUNNER_PARENT_FIRST);
}

collectPlatformProperties();
}

private void propagateFlag(int flag) {
for (ResolvedDependencyBuilder db : appBuilder.getDependencies()) {
db.clearFlag(DependencyFlags.VISITED);
appBuilder.addDependency(db);
if (db.isFlagSet(flag) && !db.isFlagSet(DependencyFlags.VISITED)) {
propagateFlags(db, 0, flag);
}
}
clearVisitedFlag();
}

collectPlatformProperties();
private void clearVisitedFlag() {
for (ResolvedDependencyBuilder db : appBuilder.getDependencies()) {
db.clearFlag(DependencyFlags.VISITED);
}
}

private void collectPlatformProperties() throws AppModelResolverException {
Expand All @@ -245,7 +267,7 @@ private void collectPlatformProperties() throws AppModelResolverException {
appBuilder.setPlatformImports(platformReleases);
}

private void clearReloadableFlag(ResolvedDependencyBuilder db) {
private void propagateFlags(ResolvedDependencyBuilder db, int toClear, int toSet) {
final Set<ArtifactKey> deps = artifactDeps.get(db.getArtifactCoords());
if (deps == null || deps.isEmpty()) {
return;
Expand All @@ -255,9 +277,9 @@ private void clearReloadableFlag(ResolvedDependencyBuilder db) {
if (dep == null || dep.isFlagSet(DependencyFlags.VISITED)) {
continue;
}
dep.setFlags(DependencyFlags.VISITED);
dep.clearFlag(DependencyFlags.RELOADABLE);
clearReloadableFlag(dep);
dep.setFlags(DependencyFlags.VISITED | toSet);
dep.clearFlag(toClear);
propagateFlags(dep, toClear, toSet);
}
}

Expand Down Expand Up @@ -673,13 +695,79 @@ private class ExtensionInfo {
.parseDependencyCondition(props.getProperty(BootstrapConstants.DEPENDENCY_CONDITION));
}

public void handleExtensionProperties() {
for (Map.Entry<Object, Object> prop : props.entrySet()) {
if (prop.getValue() == null) {
continue;
}
final String value = prop.getValue().toString();
if (value.isBlank()) {
continue;
}
final String name = prop.getKey().toString();
switch (name) {
case ApplicationModelBuilder.PARENT_FIRST_ARTIFACTS:
for (String artifact : value.split(",")) {
final ResolvedDependencyBuilder d = appBuilder.getDependency(new GACT(artifact.split(":")));
if (d != null) {
d.setFlags(DependencyFlags.CLASSLOADER_PARENT_FIRST);
}
}
break;
case ApplicationModelBuilder.RUNNER_PARENT_FIRST_ARTIFACTS:
for (String artifact : value.split(",")) {
final ResolvedDependencyBuilder d = appBuilder.getDependency(new GACT(artifact.split(":")));
if (d != null) {
d.setFlags(DependencyFlags.CLASSLOADER_RUNNER_PARENT_FIRST);
}
}
break;
case ApplicationModelBuilder.LESSER_PRIORITY_ARTIFACTS:
String[] artifacts = value.split(",");
for (String artifact : artifacts) {
final ResolvedDependencyBuilder d = appBuilder.getDependency(new GACT(artifact.split(":")));
if (d != null) {
log.debugf("Extension %s is making %s a lesser priority artifact", runtimeArtifact, artifact);
d.setFlags(DependencyFlags.CLASSLOADER_LESSER_PRIORITY);
}
}
break;
case ApplicationModelBuilder.EXCLUDED_ARTIFACTS:
for (String artifact : value.split(",")) {
appBuilder.addExcludedArtifact(new GACT(artifact.split(":")));
log.debugf("Extension %s is excluding %s", runtimeArtifact, artifact);
}
break;
default:
if (name.startsWith(ApplicationModelBuilder.REMOVED_RESOURCES_DOT)) {
final String keyStr = name.substring(ApplicationModelBuilder.REMOVED_RESOURCES_DOT.length());
if (!keyStr.isBlank()) {
ArtifactKey key = null;
try {
key = ArtifactKey.fromString(keyStr);
} catch (IllegalArgumentException e) {
log.warnf("Failed to parse artifact key %s in %s from descriptor of extension %s", keyStr,
name,
runtimeArtifact);
}
if (key != null) {
final Set<String> resources = Set.of(value.split(","));
appBuilder.addRemovedResources(key, resources);
log.debugf("Extension %s is excluding resources %s from artifact %s", runtimeArtifact,
resources,
key);
}
}
}
}
}
}

void ensureActivated() {
if (activated) {
return;
}
activated = true;
appBuilder.handleExtensionProperties(props, runtimeArtifact.toString());

final String providesCapabilities = props.getProperty(BootstrapConstants.PROP_PROVIDES_CAPABILITIES);
final String requiresCapabilities = props.getProperty(BootstrapConstants.PROP_REQUIRES_CAPABILITIES);
if (providesCapabilities != null || requiresCapabilities != null) {
Expand Down

0 comments on commit abcd375

Please sign in to comment.