diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java index ebfb7b6753a51..b143884d7c467 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java @@ -33,11 +33,9 @@ public class LocalProject { private static class WorkspaceLoader { private final LocalWorkspace workspace = new LocalWorkspace(); - private final Map cachedModels = new HashMap<>(); + private final Map projectCache = new HashMap<>(); private final Path currentProjectPom; private Path workspaceRootPom; - // indicates whetehr the workspace root pom has been resolved or provided by the caller - private boolean workspaceRootResolved; private WorkspaceLoader(Path currentProjectPom) throws BootstrapMavenException { this.currentProjectPom = isPom(currentProjectPom) ? currentProjectPom @@ -56,119 +54,80 @@ private boolean isPom(Path p) { return false; } - private Model model(Path pomFile) throws BootstrapMavenException { - Model model = cachedModels.get(pomFile.getParent()); - if (model == null) { - model = loadAndCache(pomFile); + private LocalProject project(Path pomFile) throws BootstrapMavenException { + LocalProject project = projectCache.get(pomFile.getParent()); + if (project == null) { + project = loadAndCache(pomFile); } - return model; + return project; } - private Model loadAndCache(Path pomFile) throws BootstrapMavenException { - final Model model = readModel(pomFile); - cachedModels.put(pomFile.getParent(), model); - return model; + private LocalProject loadAndCache(Path pomFile) throws BootstrapMavenException { + final LocalProject project = new LocalProject(readModel(pomFile), workspace); + projectCache.put(pomFile.getParent(), project); + return project; } void setWorkspaceRootPom(Path rootPom) { this.workspaceRootPom = rootPom; } - private Path getWorkspaceRootPom() throws BootstrapMavenException { - return workspaceRootPom == null ? workspaceRootPom = resolveWorkspaceRootPom(false) : workspaceRootPom; - } - - private Path resolveWorkspaceRootPom(boolean stopAtCached) throws BootstrapMavenException { - Path rootPom = null; - Path projectPom = currentProjectPom; - Model model = model(projectPom); + private LocalProject loadCurrentProject(Path projectPom) throws BootstrapMavenException { + LocalProject currentProject = null; + LocalProject childProject = null; do { - rootPom = projectPom; - final Parent parent = model.getParent(); + final LocalProject project = loadProjectWithModules(projectPom, + childProject == null ? null : childProject.getDir().relativize(projectPom.getParent()).toString()); + if (childProject != null) { + project.modules.add(childProject); + } else { + currentProject = project; + } + + final Parent parent = project.getRawModel().getParent(); if (parent != null && parent.getRelativePath() != null && !parent.getRelativePath().isEmpty()) { - projectPom = projectPom.getParent().resolve(parent.getRelativePath()).normalize(); + projectPom = project.getDir().resolve(parent.getRelativePath()).normalize(); if (Files.isDirectory(projectPom)) { projectPom = projectPom.resolve(POM_XML); } } else { - final Path parentDir = projectPom.getParent().getParent(); + final Path parentDir = project.getDir().getParent(); if (parentDir == null) { break; } projectPom = parentDir.resolve(POM_XML); } - model = null; - if (Files.exists(projectPom)) { - model = cachedModels.get(projectPom.getParent()); - if (model == null) { - model = loadAndCache(projectPom); - } else { - // if the parent is not at the top of the FS tree, it might have already been parsed - model = null; - if (!stopAtCached) { - for (Map.Entry entry : cachedModels.entrySet()) { - // we are looking for the root dir of the workspace - if (rootPom.getNameCount() > entry.getKey().getNameCount()) { - rootPom = entry.getValue().getPomFile().toPath(); - } - } - // it is supposed to be the root pom - workspaceRootResolved = true; - } - } - } - } while (model != null); - return rootPom; + childProject = project; + } while (Files.exists(projectPom) && !projectCache.containsKey(projectPom.getParent())); + + return currentProject; } - LocalProject load() throws BootstrapMavenException { - final Path rootPom = getWorkspaceRootPom(); - load(null, rootPom); - if (workspace.getCurrentProject() == null) { - if (!currentProjectPom.equals(rootPom)) { - // if the root pom wasn't resolved but provided we are going to try to navigate - // to the very top pom that hasn't already been loaded - if (!workspaceRootResolved) { - final Path resolvedRootPom = resolveWorkspaceRootPom(true); - if (!rootPom.equals(resolvedRootPom)) { - load(null, resolvedRootPom); - } - } - // if the project still wasn't found, we load it directly - if (workspace.getCurrentProject() == null) { - load(null, currentProjectPom); + private LocalProject loadProjectWithModules(Path projectPom, String skipModule) throws BootstrapMavenException { + final LocalProject project = project(projectPom); + final List modules = project.getRawModel().getModules(); + if (!modules.isEmpty()) { + for (String module : modules) { + if (module.equals(skipModule)) { + continue; } - } - if (workspace.getCurrentProject() == null) { - throw new BootstrapMavenException( - "Failed to locate project " + currentProjectPom + " in the loaded workspace"); + project.modules.add(loadProjectWithModules(project.getDir().resolve(module).resolve(POM_XML), null)); } } - return workspace.getCurrentProject(); + return project; } - private void load(LocalProject parent, Path pom) throws BootstrapMavenException { - final Model model = model(pom); - final LocalProject project = new LocalProject(model, workspace); - if (parent != null) { - parent.modules.add(project); - } - try { - if (workspace.getCurrentProject() == null - && Files.isSameFile(currentProjectPom.getParent(), project.getDir())) { - workspace.setCurrentProject(project); - } - } catch (IOException e) { - throw new BootstrapMavenException("Failed to load current project", e); + LocalProject load() throws BootstrapMavenException { + final LocalProject currentProject = loadCurrentProject(currentProjectPom); + if (workspace != null) { + workspace.setCurrentProject(currentProject); } - final List modules = project.getRawModel().getModules(); - if (!modules.isEmpty()) { - for (String module : modules) { - load(project, project.getDir().resolve(module).resolve(POM_XML)); - } + if (workspaceRootPom != null && !projectCache.containsKey(workspaceRootPom.getParent())) { + loadCurrentProject(workspaceRootPom); } + return currentProject; } } @@ -255,7 +214,7 @@ private static Path locateCurrentProjectPom(Path path, boolean required) throws private final Model rawModel; private final String groupId; private final String artifactId; - private final String version; + private String version; private final Path dir; private final LocalWorkspace workspace; private final List modules = new ArrayList<>(0); @@ -270,25 +229,16 @@ private LocalProject(Model rawModel, LocalWorkspace workspace) throws BootstrapM final String rawVersion = ModelUtils.getRawVersion(rawModel); final boolean rawVersionIsUnresolved = ModelUtils.isUnresolvedVersion(rawVersion); - String resolvedVersion = rawVersionIsUnresolved ? ModelUtils.resolveVersion(rawVersion, rawModel) : rawVersion; + version = rawVersionIsUnresolved ? ModelUtils.resolveVersion(rawVersion, rawModel) : rawVersion; if (workspace != null) { workspace.addProject(this, rawModel.getPomFile().lastModified()); - if (rawVersionIsUnresolved) { - if (resolvedVersion == null) { - resolvedVersion = workspace.getResolvedVersion(); - if (resolvedVersion == null) { - throw UnresolvedVersionException.forGa(groupId, artifactId, rawVersion); - } - } else { - workspace.setResolvedVersion(resolvedVersion); - } + if (rawVersionIsUnresolved && version != null) { + workspace.setResolvedVersion(version); } - } else if (resolvedVersion == null) { + } else if (version == null && rawVersionIsUnresolved) { throw UnresolvedVersionException.forGa(groupId, artifactId, rawVersion); } - - this.version = resolvedVersion; } public LocalProject getLocalParent() { @@ -311,6 +261,15 @@ public String getArtifactId() { } public String getVersion() { + if (version != null) { + return version; + } + if (workspace != null) { + version = workspace.getResolvedVersion(); + } + if (version == null) { + throw UnresolvedVersionException.forGa(groupId, artifactId, ModelUtils.getRawVersion(rawModel)); + } return version; } diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/UnresolvedVersionException.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/UnresolvedVersionException.java index fd2213462c93f..cca4155fc5e8c 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/UnresolvedVersionException.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/UnresolvedVersionException.java @@ -1,13 +1,11 @@ package io.quarkus.bootstrap.resolver.maven.workspace; -import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; - /** * Thrown if a "Maven CI Friendly Versions" property in the version could not be resolved. * * @see Maven CI Friendly Versions (maven.apache.org) */ -public class UnresolvedVersionException extends BootstrapMavenException { +public class UnresolvedVersionException extends RuntimeException { private static final long serialVersionUID = 1L; diff --git a/independent-projects/bootstrap/maven-resolver/src/test/java/io/quarkus/bootstrap/workspace/test/LocalWorkspaceDiscoveryTest.java b/independent-projects/bootstrap/maven-resolver/src/test/java/io/quarkus/bootstrap/workspace/test/LocalWorkspaceDiscoveryTest.java index e5623297b80a0..c88e00fa7524e 100644 --- a/independent-projects/bootstrap/maven-resolver/src/test/java/io/quarkus/bootstrap/workspace/test/LocalWorkspaceDiscoveryTest.java +++ b/independent-projects/bootstrap/maven-resolver/src/test/java/io/quarkus/bootstrap/workspace/test/LocalWorkspaceDiscoveryTest.java @@ -108,7 +108,7 @@ public static void setup() throws Exception { @AfterEach public void restoreSystemProperties() { if (systemPropertiesBackup != null) { - System.setProperties(systemPropertiesBackup); + System.setProperties((Properties) systemPropertiesBackup.clone()); } } @@ -138,6 +138,26 @@ public void loadWorkspaceWithDirBreaks() throws Exception { assertEquals(4, ws.getProjects().size()); } + @Test + public void loadWorkspaceRootWithNoModules() throws Exception { + final URL projectUrl = Thread.currentThread().getContextClassLoader().getResource("workspace-root-no-module/root"); + assertNotNull(projectUrl); + final Path rootProjectDir = Paths.get(projectUrl.toURI()); + assertTrue(Files.exists(rootProjectDir)); + final Path nestedProjectDir = rootProjectDir.resolve("module1/module2"); + assertTrue(Files.exists(nestedProjectDir)); + + final LocalWorkspace ws = new BootstrapMavenContext(BootstrapMavenContext.config() + .setCurrentProject(nestedProjectDir.toString())) + .getWorkspace(); + + assertNotNull(ws.getProject("org.acme", "module3")); + assertNotNull(ws.getProject("org.acme", "module2")); + assertNotNull(ws.getProject("org.acme", "module1")); + assertNotNull(ws.getProject("org.acme", "root")); + assertEquals(4, ws.getProjects().size()); + } + @Test public void loadWorkspaceFromRootDirWithParentInChildDir() throws Exception { final URL projectUrl = Thread.currentThread().getContextClassLoader().getResource("workspace-parent-is-not-root-dir"); diff --git a/independent-projects/bootstrap/maven-resolver/src/test/resources/workspace-root-no-module/root/module1/module2/pom.xml b/independent-projects/bootstrap/maven-resolver/src/test/resources/workspace-root-no-module/root/module1/module2/pom.xml new file mode 100644 index 0000000000000..f742b96a6e503 --- /dev/null +++ b/independent-projects/bootstrap/maven-resolver/src/test/resources/workspace-root-no-module/root/module1/module2/pom.xml @@ -0,0 +1,13 @@ + + + 4.0.0 + + + org.acme + module1 + 1.0 + + + module2 + + diff --git a/independent-projects/bootstrap/maven-resolver/src/test/resources/workspace-root-no-module/root/module1/module3/pom.xml b/independent-projects/bootstrap/maven-resolver/src/test/resources/workspace-root-no-module/root/module1/module3/pom.xml new file mode 100644 index 0000000000000..c1e85e0aab72e --- /dev/null +++ b/independent-projects/bootstrap/maven-resolver/src/test/resources/workspace-root-no-module/root/module1/module3/pom.xml @@ -0,0 +1,13 @@ + + + 4.0.0 + + + org.acme + module1 + 1.0 + + + module3 + + diff --git a/independent-projects/bootstrap/maven-resolver/src/test/resources/workspace-root-no-module/root/module1/pom.xml b/independent-projects/bootstrap/maven-resolver/src/test/resources/workspace-root-no-module/root/module1/pom.xml new file mode 100644 index 0000000000000..b1a2a4c948d74 --- /dev/null +++ b/independent-projects/bootstrap/maven-resolver/src/test/resources/workspace-root-no-module/root/module1/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + + org.acme + root + 1.0 + + + module1 + pom + + module2 + module3 + + diff --git a/independent-projects/bootstrap/maven-resolver/src/test/resources/workspace-root-no-module/root/pom.xml b/independent-projects/bootstrap/maven-resolver/src/test/resources/workspace-root-no-module/root/pom.xml new file mode 100644 index 0000000000000..bdcc98967ff35 --- /dev/null +++ b/independent-projects/bootstrap/maven-resolver/src/test/resources/workspace-root-no-module/root/pom.xml @@ -0,0 +1,10 @@ + + + 4.0.0 + + org.acme + root + 1.0 + pom + +