From 8f67e0e0fd1351bc7d1d6c929e3041da30d67f24 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Mon, 6 Nov 2023 08:30:34 +0100 Subject: [PATCH] more --- .../maven/BootstrapModelResolver.java | 6 +- .../maven/workspace/RawWorkspaceReader.java | 195 ++++++++++++++++++ .../maven/workspace/WorkspaceLoader.java | 125 +++++++++-- .../project/state/WorkspaceQuarkusInfo.java | 2 +- 4 files changed, 312 insertions(+), 16 deletions(-) create mode 100644 independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/RawWorkspaceReader.java diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapModelResolver.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapModelResolver.java index 97ee36094972c5..14d4f5ef80f2b8 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapModelResolver.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapModelResolver.java @@ -38,7 +38,7 @@ public class BootstrapModelResolver implements ModelResolver { - public static ModelResolver newInstance(BootstrapMavenContext ctx, WorkspaceReader workspace) + public static BootstrapModelResolver newInstance(BootstrapMavenContext ctx, WorkspaceReader workspace) throws BootstrapMavenException { final RepositorySystem repoSystem = ctx.getRepositorySystem(); final RepositorySystemSession session = workspace == null @@ -102,6 +102,10 @@ private BootstrapModelResolver(BootstrapModelResolver original) { this.repositoryIds = new HashSet<>(original.repositoryIds); } + public RepositorySystemSession getSession() { + return session; + } + @Override public void addRepository(Repository repository) throws InvalidRepositoryException { diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/RawWorkspaceReader.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/RawWorkspaceReader.java new file mode 100644 index 00000000000000..83b597d0e27d5b --- /dev/null +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/RawWorkspaceReader.java @@ -0,0 +1,195 @@ +package io.quarkus.bootstrap.resolver.maven.workspace; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import org.apache.maven.model.Model; +import org.apache.maven.model.Parent; +import org.apache.maven.model.resolution.UnresolvableModelException; +import org.apache.maven.model.resolution.WorkspaceModelResolver; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.WorkspaceReader; +import org.eclipse.aether.repository.WorkspaceRepository; +import org.jboss.logging.Logger; + +import io.quarkus.maven.dependency.ArtifactCoords; +import io.quarkus.maven.dependency.GAV; + +public class RawWorkspaceReader implements WorkspaceReader, WorkspaceModelResolver { + + private static final String POM_XML = "pom.xml"; + + private static final Logger log = Logger.getLogger(RawWorkspaceReader.class); + + public static Builder builder() { + return new RawWorkspaceReader().new Builder(); + } + + public class Builder { + + private boolean built; + private Path modulePom; + private Path rootModulePom; + + private Builder() { + } + + public Builder setModulePom(Path modulePom) { + this.modulePom = modulePom; + return this; + } + + public Builder setRootModulePom(Path rootModulePom) { + this.rootModulePom = rootModulePom; + return this; + } + + public Builder setModelProvider(Function modelProvider) { + ensureNotBuilt(); + RawWorkspaceReader.this.modelProvider = modelProvider; + return this; + } + + public RawWorkspaceReader build() throws IOException { + ensureNotBuilt(); + if (modelProvider == null) { + modelProvider = pom -> null; + } + var loaded = new HashMap(); + if (rootModulePom != null) { + loadModule(rootModulePom, loaded); + } + loadModule(modulePom, loaded); + + return RawWorkspaceReader.this; + } + + private void loadModule(Path pomFile, Map loaded) throws IOException { + var moduleDir = pomFile.getParent(); + if (moduleDir != null) { + // the path might not be normalized, while the modelProvider below would typically recognize normalized absolute paths + moduleDir = moduleDir.normalize().toAbsolutePath(); + } + if (loaded.containsKey(moduleDir)) { + return; + } + + var rawModel = modelProvider == null ? null : modelProvider.apply(moduleDir); + if (rawModel == null) { + rawModel = readModel(pomFile); + } + loaded.put(moduleDir, rawModel); + if (rawModel == null) { + return; + } + + var added = modules.putIfAbsent( + new GAV(ModelUtils.getGroupId(rawModel), rawModel.getArtifactId(), ModelUtils.getVersion(rawModel)), + rawModel); + if (added != null) { + return; + } + for (var module : rawModel.getModules()) { + loadModule(rawModel.getProjectDirectory().toPath().resolve(module).resolve(POM_XML), loaded); + } + for (var profile : rawModel.getProfiles()) { + for (var module : profile.getModules()) { + loadModule(rawModel.getProjectDirectory().toPath().resolve(module).resolve(POM_XML), loaded); + } + } + final Path parentPom = getParentPom(pomFile, rawModel); + if (parentPom != null) { + loadModule(parentPom, loaded); + } + } + + private void ensureNotBuilt() { + if (built) { + throw new IllegalStateException("This builder instance has already been built"); + } + } + } + + private RawWorkspaceReader() { + } + + private final WorkspaceRepository wr = new WorkspaceRepository(); + private Function modelProvider; + private Map modules = new HashMap<>(); + + public Collection getModules() { + return modules.values(); + } + + @Override + public WorkspaceRepository getRepository() { + return wr; + } + + @Override + public File findArtifact(Artifact artifact) { + if (ArtifactCoords.TYPE_POM.equals(artifact.getExtension())) { + return null; + } + var model = modules.get(new GAV(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion())); + return model == null ? null : model.getPomFile(); + } + + @Override + public List findVersions(Artifact artifact) { + var model = modules.get(new GAV(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion())); + return model == null ? List.of() : List.of(ModelUtils.getVersion(model)); + } + + @Override + public Model resolveRawModel(String groupId, String artifactId, String version) throws UnresolvableModelException { + return modules.get(new GAV(groupId, artifactId, version)); + } + + @Override + public Model resolveEffectiveModel(String s, String s1, String s2) throws UnresolvableModelException { + return null; + } + + private static Path getParentPom(Path projectPom, Model rawModel) { + if (rawModel == null) { + return null; + } + Path parentPom = null; + final Parent parent = rawModel.getParent(); + if (parent != null && parent.getRelativePath() != null && !parent.getRelativePath().isEmpty()) { + parentPom = projectPom.getParent().resolve(parent.getRelativePath()).normalize(); + if (Files.isDirectory(parentPom)) { + parentPom = parentPom.resolve(POM_XML); + } + } else { + final Path parentDir = projectPom.getParent().getParent(); + if (parentDir != null) { + parentPom = parentDir.resolve(POM_XML); + } + } + return parentPom != null && Files.exists(parentPom) ? parentPom : null; + } + + private static Model readModel(Path pom) throws IOException { + try { + final Model model = ModelUtils.readModel(pom); + model.setPomFile(pom.toFile()); + return model; + } catch (NoSuchFileException e) { + // some projects may be missing pom.xml relying on Maven extensions (e.g. tycho-maven-plugin) to build them, + // which we don't support in this workspace loader + log.warn("Module(s) under " + pom.getParent() + " will be handled as thirdparty dependencies because " + pom + + " does not exist"); + return null; + } + } +} diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/WorkspaceLoader.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/WorkspaceLoader.java index e564125300ea1e..26b9dd52b6ac42 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/WorkspaceLoader.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/WorkspaceLoader.java @@ -7,8 +7,10 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Function; import org.apache.maven.model.Model; @@ -18,8 +20,6 @@ import org.apache.maven.model.building.ModelBuilder; import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.model.building.ModelCache; -import org.apache.maven.model.resolution.ModelResolver; -import org.apache.maven.model.resolution.UnresolvableModelException; import org.apache.maven.model.resolution.WorkspaceModelResolver; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.repository.WorkspaceReader; @@ -31,6 +31,8 @@ import io.quarkus.bootstrap.resolver.maven.BootstrapModelBuilderFactory; import io.quarkus.bootstrap.resolver.maven.BootstrapModelResolver; import io.quarkus.bootstrap.resolver.maven.options.BootstrapMavenOptions; +import io.quarkus.maven.dependency.ArtifactCoords; +import io.quarkus.maven.dependency.GAV; public class WorkspaceLoader implements WorkspaceModelResolver, WorkspaceReader { @@ -77,7 +79,8 @@ static Path locateCurrentProjectPom(Path path, boolean required) throws Bootstra private Function modelProvider; private ModelBuilder modelBuilder; - private ModelResolver modelResolver; + private Map preloadedRawModels; + private BootstrapModelResolver modelResolver; private ModelCache modelCache; private List activeProfileIds; private List inactiveProfileIds; @@ -89,7 +92,7 @@ static Path locateCurrentProjectPom(Path path, boolean required) throws Bootstra if (ctx != null && ctx.isEffectiveModelBuilder()) { modelBuilder = BootstrapModelBuilderFactory.getDefaultModelBuilder(); modelResolver = BootstrapModelResolver.newInstance(ctx, this); - modelCache = new BootstrapModelCache(ctx.getRepositorySystemSession()); + modelCache = new BootstrapModelCache(modelResolver.getSession()); profiles = ctx.getActiveSettingsProfiles(); final BootstrapMavenOptions cliOptions = ctx.getCliOptions(); @@ -141,6 +144,8 @@ private LocalProject loadAndCacheProject(Path pomFile) throws BootstrapMavenExce req.setRawModel(rawModel); req.setWorkspaceModelResolver(this); try { + var s = ModelUtils.getGroupId(rawModel) + ":" + rawModel.getArtifactId() + ":" + + ModelUtils.getVersion(rawModel); project = new LocalProject(modelBuilder.build(req), workspace); } catch (Exception e) { throw new BootstrapMavenException("Failed to resolve the effective model for " + pomFile, e); @@ -193,7 +198,7 @@ private LocalProject loadProject(Path projectPom, String skipModule) throws Boot private LocalProject loadParentProject(Path projectPom, final Model rawModel) throws BootstrapMavenException { final Path parentPom = getParentPom(projectPom, rawModel); - return parentPom == null || rawModelCache.containsKey(parentPom.getParent()) ? null + return parentPom == null || projectCache.containsKey(parentPom.getParent()) ? null : loadProject(parentPom, parentPom.getParent().relativize(projectPom.getParent()).toString()); } @@ -253,7 +258,89 @@ private LocalProject loadProjectModules(LocalProject project, String skipModule) return project; } + private void preLoadRawModelCache(Path projectPom, Set preloaded) throws BootstrapMavenException { + if (!preloaded.add(projectPom)) { + return; + } + final Model rawModel = rawModel(projectPom); + if (rawModel == null) { + return; + } + preloadedRawModels.put( + new GAV(ModelUtils.getGroupId(rawModel), rawModel.getArtifactId(), ModelUtils.getVersion(rawModel)), rawModel); + final Path parentPom = getParentPom(projectPom, rawModel); + if (parentPom != null) { + preLoadRawModelCache(parentPom, preloaded); + } + for (var module : rawModel.getModules()) { + preLoadRawModelCache(rawModel.getProjectDirectory().toPath().resolve(module).resolve(POM_XML), preloaded); + } + for (var profile : rawModel.getProfiles()) { + for (var module : profile.getModules()) { + preLoadRawModelCache(rawModel.getProjectDirectory().toPath().resolve(module).resolve(POM_XML), preloaded); + } + } + } + LocalProject load() throws BootstrapMavenException { + if (modelBuilder == null) { + final RawWorkspaceReader wsReader; + try { + wsReader = RawWorkspaceReader.builder() + .setModelProvider(modelProvider) + .setModulePom(currentProjectPom) + .setRootModulePom(workspaceRootPom) + .build(); + } catch (IOException e) { + throw new BootstrapMavenException("Failed to load workspace", e); + } + LocalProject currentProject = null; + for (var rawModel : wsReader.getModules()) { + var project = new LocalProject(rawModel, workspace); + if (currentProject == null && project.getDir().equals(currentProjectPom.getParent())) { + currentProject = project; + } + } + if (currentProject == null) { + throw new BootstrapMavenException("Failed to load project " + currentProjectPom); + } + return currentProject; + } else { + /* @formatter:off + final LocalProject project; + if (modelBuilder != null) { + ModelBuildingRequest req = new DefaultModelBuildingRequest(); + req.setPomFile(pomFile.toFile()); + req.setModelResolver(modelResolver); + req.setSystemProperties(System.getProperties()); + req.setUserProperties(System.getProperties()); + req.setModelCache(modelCache); + req.setActiveProfileIds(activeProfileIds); + req.setInactiveProfileIds(inactiveProfileIds); + req.setProfiles(profiles); + req.setRawModel(rawModel); + req.setWorkspaceModelResolver(this); + try { + var s = ModelUtils.getGroupId(rawModel) + ":" + rawModel.getArtifactId() + ":" + + ModelUtils.getVersion(rawModel); + project = new LocalProject(modelBuilder.build(req), workspace); + } catch (Exception e) { + throw new BootstrapMavenException("Failed to resolve the effective model for " + pomFile, e); + } + } else { + project = new LocalProject(rawModel, workspace); + } + + @formatter:on */ + } + if (modelBuilder != null) { + this.preloadedRawModels = new HashMap<>(); + var preloaded = new HashSet(); + if (workspaceRootPom != null) { + preLoadRawModelCache(workspaceRootPom, preloaded); + } + preLoadRawModelCache(currentProjectPom, preloaded); + } if (workspaceRootPom != null) { loadProject(workspaceRootPom, null); } @@ -268,18 +355,20 @@ LocalProject load() throws BootstrapMavenException { } @Override - public Model resolveRawModel(String groupId, String artifactId, String versionConstraint) - throws UnresolvableModelException { - final LocalProject project = workspace.getProject(groupId, artifactId); - // we are comparing the raw version here because in case of a CI-friendly version (e.g. ${revision}) the versionConstraint will be an expression - return project != null && ModelUtils.getRawVersion(project.getRawModel()).equals(versionConstraint) - ? project.getRawModel() - : null; + public Model resolveRawModel(String groupId, String artifactId, String versionConstraint) { + if (preloadedRawModels != null) { + return preloadedRawModels.get(new GAV(groupId, artifactId, versionConstraint)); + } else { + final LocalProject project = workspace.getProject(groupId, artifactId); + // we are comparing the raw version here because in case of a CI-friendly version (e.g. ${revision}) the versionConstraint will be an expression + return project != null && ModelUtils.getRawVersion(project.getRawModel()).equals(versionConstraint) + ? project.getRawModel() + : null; + } } @Override - public Model resolveEffectiveModel(String groupId, String artifactId, String versionConstraint) - throws UnresolvableModelException { + public Model resolveEffectiveModel(String groupId, String artifactId, String versionConstraint) { final LocalProject project = workspace.getProject(groupId, artifactId); return project != null && project.getVersion().equals(versionConstraint) ? project.getModelBuildingResult().getEffectiveModel() @@ -293,11 +382,19 @@ public WorkspaceRepository getRepository() { @Override public File findArtifact(Artifact artifact) { + if (preloadedRawModels != null && ArtifactCoords.TYPE_POM.equals(artifact.getExtension())) { + var m = preloadedRawModels.get(new GAV(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion())); + return m == null ? null : m.getPomFile(); + } return workspace.findArtifact(artifact); } @Override public List findVersions(Artifact artifact) { + if (preloadedRawModels != null) { + var m = preloadedRawModels.get(new GAV(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion())); + return m == null ? null : List.of(ModelUtils.getVersion(m)); + } return workspace.findVersions(artifact); } } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/state/WorkspaceQuarkusInfo.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/state/WorkspaceQuarkusInfo.java index 0cf8eaab322ff6..8e8380e7091a11 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/state/WorkspaceQuarkusInfo.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/state/WorkspaceQuarkusInfo.java @@ -21,7 +21,7 @@ public class WorkspaceQuarkusInfo { public static void main(String[] args) throws Exception { //load(Path.of("/home/aloubyansky/git/kogito-runtimes/springboot/bom")); - MavenProjectConfigurationLoader.load(Path.of("/home/aloubyansky/git/kogito-runtimes")); + MavenProjectConfigurationLoader.load(Path.of("/home/aloubyansky/git/debezium")); //generateUpdateRecipe(Path.of("/home/aloubyansky/git/camel-quarkus")); //load(Path.of("/home/aloubyansky/git/quarkus-copy")); //generateUpdateRecipe(Path.of("/home/aloubyansky/git/quarkus-todo-app"));