From 9e5dc13d33064760228babc05374cb1b142c43f3 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Sat, 23 Nov 2024 12:33:04 +0100 Subject: [PATCH] Incubating Maven resolver: do not load the workspace when the original resolver isn't aware of it --- .../ApplicationDependencyTreeResolver.java | 36 ++-- .../IncubatingApplicationModelResolver.java | 198 +++++++++++------- 2 files changed, 139 insertions(+), 95 deletions(-) diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyTreeResolver.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyTreeResolver.java index 5a9420b20a4335..93cc4aa959b2ed 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyTreeResolver.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyTreeResolver.java @@ -61,6 +61,7 @@ import io.quarkus.maven.dependency.DependencyFlags; import io.quarkus.maven.dependency.ResolvedDependencyBuilder; import io.quarkus.paths.PathTree; +import io.quarkus.paths.PathVisit; public class ApplicationDependencyTreeResolver { @@ -583,16 +584,8 @@ private ExtensionInfo getExtensionInfoOrNull(Artifact artifact, List { - if (visit == null) { - return null; - } - try { - return readDescriptor(visit.getPath()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }); + final Properties descriptor = PathTree.ofDirectoryOrArchive(path).apply(BootstrapConstants.DESCRIPTOR_PATH, + ApplicationDependencyTreeResolver::readExtensionProperties); if (descriptor != null) { ext = new ExtensionInfo(artifact, descriptor, devMode); allExtensions.put(extKey, ext); @@ -600,6 +593,21 @@ private ExtensionInfo getExtensionInfoOrNull(Artifact artifact, List collectDeploymentDeps() { private void injectDeploymentDep(ModelResolutionTaskRunner taskRunner, AppDep extDep, ConcurrentLinkedDeque injectQueue) { - taskRunner.run(() -> { - var resolvedDep = appBuilder.getDependency(getKey(extDep.ext.info.deploymentArtifact)); - if (resolvedDep == null) { + var resolvedDep = appBuilder.getDependency(getKey(extDep.ext.info.deploymentArtifact)); + if (resolvedDep == null) { + taskRunner.run(() -> { extDep.ext.collectDeploymentDeps(); injectQueue.add(extDep); - } else { - // if resolvedDep isn't null, it means the deployment artifact is on the runtime classpath - // in which case we also clear the reloadable flag on it, in case it's coming from the workspace - resolvedDep.clearFlag(DependencyFlags.RELOADABLE); - } - }); + }); + } else { + // if resolvedDep isn't null, it means the deployment artifact is on the runtime classpath + // in which case we also clear the reloadable flag on it, in case it's coming from the workspace + resolvedDep.clearFlag(DependencyFlags.RELOADABLE); + } } /** @@ -370,6 +405,12 @@ private void collectCompileOnly(CollectRequest collectRtDepsRequest, DependencyN } } + /** + * Collects platform release information and platform build properties by looking for platform properties + * artifacts among the dependency version constraints of the project (it's not a direct dependency). + * + * @throws AppModelResolverException in case a properties artifact could not be resolved + */ private void collectPlatformProperties() throws AppModelResolverException { final PlatformImportsImpl platformReleases = new PlatformImportsImpl(); for (Dependency d : managedDeps) { @@ -417,6 +458,14 @@ private DependencyNode normalize(RepositorySystemSession session, DependencyNode } } + /** + * Resolves a project's runtime dependencies. This is the first step in the Quarkus application model resolution. + * These dependencies do not include Quarkus conditional dependencies. + * + * @param request collect dependencies request + * @return the root of the resolved dependency tree + * @throws AppModelResolverException in case dependencies could not be resolved + */ private DependencyNode resolveRuntimeDeps(CollectRequest request) throws AppModelResolverException { boolean verbose = true; //Boolean.getBoolean("quarkus.bootstrap.verbose-model-resolver"); @@ -433,7 +482,8 @@ private DependencyNode resolveRuntimeDeps(CollectRequest request) .setRemoteRepositories(resolver.getRepositories()) .setRemoteRepositoryManager(resolver.getRemoteRepositoryManager()) .setCurrentProject(resolver.getMavenContext().getCurrentProject()) - .setWorkspaceDiscovery(collectReloadableModules)); + // no need to discover the workspace in case the current project isn't available + .setWorkspaceDiscovery(resolver.getMavenContext().getCurrentProject() != null)); resolver = new MavenArtifactResolver(ctx); } try { @@ -451,14 +501,12 @@ private boolean isRuntimeArtifact(ArtifactKey key) { private void processRuntimeDeps(DependencyNode root) { final AppDep appRoot = new AppDep(root); - appRoot.walkingFlags = COLLECT_TOP_EXTENSION_RUNTIME_NODES | COLLECT_DIRECT_DEPS | COLLECT_DEPLOYMENT_INJECTION_POINTS; - if (collectReloadableModules) { - appRoot.walkingFlags |= COLLECT_RELOADABLE_MODULES; - } - visitRuntimeDeps(appRoot); appBuilder.getApplicationArtifact().addDependencies(appRoot.allDeps); - appRoot.setChildFlags(); + appRoot.setChildFlags((byte) (COLLECT_TOP_EXTENSION_RUNTIME_NODES + | COLLECT_DIRECT_DEPS + | COLLECT_DEPLOYMENT_INJECTION_POINTS + | (collectReloadableModules ? COLLECT_RELOADABLE_MODULES : 0))); } private void visitRuntimeDeps(AppDep appRoot) { @@ -471,7 +519,6 @@ private class AppDep { final AppDep parent; final DependencyNode node; ExtensionDependency ext; - byte walkingFlags; ResolvedDependencyBuilder resolvedDep; final List children; final List allDeps; @@ -501,18 +548,18 @@ void addToModel() { } } - void scheduleDeploymentVisit(ModelResolutionTaskRunner taskRunner) { - taskRunner.run(this::visitDeploymentDependency); - scheduleChildVisits(taskRunner, AppDep::scheduleDeploymentVisit); + void initMissingDependencies(ModelResolutionTaskRunner taskRunner) { + if (!appBuilder.hasDependency(getKey(node.getArtifact()))) { + taskRunner.run(this::initDependencyBuilder); + } + scheduleChildVisits(taskRunner, AppDep::initMissingDependencies); } - void visitDeploymentDependency() { - if (!appBuilder.hasDependency(getKey(node.getArtifact()))) { - try { - resolvedDep = newDependencyBuilder(node, resolver); - } catch (BootstrapMavenException e) { - throw new RuntimeException(e); - } + void initDependencyBuilder() { + try { + resolvedDep = newDependencyBuilder(node, resolver); + } catch (BootstrapMavenException e) { + throw new RuntimeException(e); } } @@ -590,7 +637,7 @@ void scheduleChildVisits(ModelResolutionTaskRunner taskRunner, } } - void setChildFlags() { + void setChildFlags(byte walkingFlags) { for (var c : children) { c.setFlags(walkingFlags); } @@ -598,7 +645,6 @@ void setChildFlags() { void setFlags(byte walkingFlags) { - this.walkingFlags = walkingFlags; resolvedDep.addDependencies(allDeps); var existingDep = appBuilder.getDependency(resolvedDep.getKey()); @@ -611,15 +657,15 @@ void setFlags(byte walkingFlags) { throw new IllegalStateException(node.getArtifact() + " is already in the model"); } - resolvedDep.setDirect(isWalkingFlagOn(COLLECT_DIRECT_DEPS)); + resolvedDep.setDirect(isFlagOn(walkingFlags, COLLECT_DIRECT_DEPS)); if (ext != null) { ext.info.ensureActivated(appBuilder); - if (isWalkingFlagOn(COLLECT_TOP_EXTENSION_RUNTIME_NODES)) { + if (isFlagOn(walkingFlags, COLLECT_TOP_EXTENSION_RUNTIME_NODES)) { resolvedDep.setFlags(DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); - clearWalkingFlag(COLLECT_TOP_EXTENSION_RUNTIME_NODES); + walkingFlags = clearFlag(walkingFlags, COLLECT_TOP_EXTENSION_RUNTIME_NODES); } - if (isWalkingFlagOn(COLLECT_DEPLOYMENT_INJECTION_POINTS)) { - clearWalkingFlag(COLLECT_DEPLOYMENT_INJECTION_POINTS); + if (isFlagOn(walkingFlags, COLLECT_DEPLOYMENT_INJECTION_POINTS)) { + walkingFlags = clearFlag(walkingFlags, COLLECT_DEPLOYMENT_INJECTION_POINTS); ext.extDeps = new ArrayList<>(); deploymentInjectionPoints.add(this); } else if (!ext.presentInTargetGraph) { @@ -634,17 +680,17 @@ void setFlags(byte walkingFlags) { } ext.info.ensureActivated(appBuilder); } - if (isWalkingFlagOn(COLLECT_RELOADABLE_MODULES)) { + if (isFlagOn(walkingFlags, COLLECT_RELOADABLE_MODULES)) { if (resolvedDep.getWorkspaceModule() != null && !resolvedDep.isFlagSet(DependencyFlags.RUNTIME_EXTENSION_ARTIFACT)) { resolvedDep.setReloadable(); } else { - clearWalkingFlag(COLLECT_RELOADABLE_MODULES); + walkingFlags = clearFlag(walkingFlags, COLLECT_RELOADABLE_MODULES); } } - clearWalkingFlag(COLLECT_DIRECT_DEPS); - setChildFlags(); + walkingFlags = clearFlag(walkingFlags, COLLECT_DIRECT_DEPS); + setChildFlags(walkingFlags); } private ExtensionDependency getExtensionDependencyOrNull() @@ -696,16 +742,6 @@ Artifact getResolvedArtifact() { return result; } - private boolean isWalkingFlagOn(byte flag) { - return (walkingFlags & flag) > 0; - } - - private void clearWalkingFlag(byte flag) { - if ((walkingFlags & flag) > 0) { - walkingFlags ^= flag; - } - } - private void collectConditionalDependencies() throws BootstrapDependencyProcessingException { if (ext.info.conditionalDeps.length == 0 || ext.conditionalDepsQueued) { @@ -743,6 +779,14 @@ private void injectDeploymentDependency() { } } + private static byte clearFlag(byte flags, byte flag) { + return (flags & flag) > 0 ? (byte) (flags ^ flag) : flags; + } + + private static boolean isFlagOn(byte flags, byte flag) { + return (flags & flag) > 0; + } + private ExtensionInfo getExtensionInfoOrNull(Artifact artifact, List repos) throws BootstrapDependencyProcessingException { if (!artifact.getExtension().equals(ArtifactCoords.TYPE_JAR)) { @@ -755,16 +799,8 @@ private ExtensionInfo getExtensionInfoOrNull(Artifact artifact, List { - if (visit == null) { - return null; - } - try { - return readDescriptor(visit.getPath()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }); + final Properties descriptor = PathTree.ofDirectoryOrArchive(path).apply(BootstrapConstants.DESCRIPTOR_PATH, + IncubatingApplicationModelResolver::readExtensionProperties); if (descriptor == null) { allExtensions.put(extKey, EXT_INFO_NONE); return null; @@ -774,6 +810,21 @@ private ExtensionInfo getExtensionInfoOrNull(Artifact artifact, List exclusions, List repos) { DependencyNode root; @@ -824,14 +875,6 @@ private Artifact resolve(Artifact artifact, List repos) { } } - private static Properties readDescriptor(Path path) throws IOException { - final Properties rtProps = new Properties(); - try (BufferedReader reader = Files.newBufferedReader(path)) { - rtProps.load(reader); - } - return rtProps; - } - private class ExtensionDependency { static ExtensionDependency get(DependencyNode node) { @@ -977,23 +1020,24 @@ void activate() { } else { currentChildren.addAll(originalNode.getChildren()); } - if (collectReloadableModules) { - conditionalDep.walkingFlags |= COLLECT_RELOADABLE_MODULES; - } - conditionalDep.walkingFlags |= COLLECT_DEPLOYMENT_INJECTION_POINTS; if (conditionalDep.ext.extDeps == null) { conditionalDep.ext.extDeps = new ArrayList<>(); } - var taskRunner = new ModelResolutionTaskRunner(); - conditionalDep.scheduleRuntimeVisit(taskRunner); - taskRunner.waitForCompletion(); - conditionalDep.setFlags(conditionalDep.walkingFlags); + visitRuntimeDeps(); + conditionalDep.setFlags( + (byte) (COLLECT_DEPLOYMENT_INJECTION_POINTS | (collectReloadableModules ? COLLECT_RELOADABLE_MODULES : 0))); if (conditionalDep.parent.resolvedDep != null) { conditionalDep.parent.resolvedDep.addDependency(conditionalDep.resolvedDep.getArtifactCoords()); } conditionalDep.parent.ext.runtimeNode.getChildren().add(rtNode); } + private void visitRuntimeDeps() { + var taskRunner = new ModelResolutionTaskRunner(); + conditionalDep.scheduleRuntimeVisit(taskRunner); + taskRunner.waitForCompletion(); + } + boolean isSatisfied() { if (conditionalDep.ext.info.dependencyCondition == null) { return true;