Skip to content

Commit

Permalink
Merge pull request #16138 from aloubyansky/workspace-loading
Browse files Browse the repository at this point in the history
Make sure all the project modules are loaded into workspace in case the root pom does not declare any
  • Loading branch information
gsmet authored Apr 1, 2021
2 parents 542cbfa + 5d974ba commit 00ae3e2
Showing 7 changed files with 133 additions and 103 deletions.
Original file line number Diff line number Diff line change
@@ -33,11 +33,9 @@ public class LocalProject {
private static class WorkspaceLoader {

private final LocalWorkspace workspace = new LocalWorkspace();
private final Map<Path, Model> cachedModels = new HashMap<>();
private final Map<Path, LocalProject> 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<Path, Model> 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<String> 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<String> 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<LocalProject> 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;
}

Original file line number Diff line number Diff line change
@@ -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 <a href="https://maven.apache.org/maven-ci-friendly.html">Maven CI Friendly Versions (maven.apache.org)</a>
*/
public class UnresolvedVersionException extends BootstrapMavenException {
public class UnresolvedVersionException extends RuntimeException {

private static final long serialVersionUID = 1L;

Original file line number Diff line number Diff line change
@@ -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");
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.acme</groupId>
<artifactId>module1</artifactId>
<version>1.0</version>
</parent>

<artifactId>module2</artifactId>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.acme</groupId>
<artifactId>module1</artifactId>
<version>1.0</version>
</parent>

<artifactId>module3</artifactId>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.acme</groupId>
<artifactId>root</artifactId>
<version>1.0</version>
</parent>

<artifactId>module1</artifactId>
<packaging>pom</packaging>
<modules>
<module>module2</module>
<module>module3</module>
</modules>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>

<groupId>org.acme</groupId>
<artifactId>root</artifactId>
<version>1.0</version>
<packaging>pom</packaging>

</project>

0 comments on commit 00ae3e2

Please sign in to comment.