Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sure all the project modules are loaded into workspace in case the root pom does not declare any #16138

Merged
merged 1 commit into from
Apr 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
}
}

Expand Down Expand Up @@ -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);
Expand All @@ -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() {
Expand All @@ -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;
}

Expand Down
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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}

Expand Down Expand Up @@ -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");
Expand Down
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>