From 244aa4cb0b7f9ae17cd98b6c04d91757c38f0399 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Wed, 4 Jan 2023 23:28:09 +0100 Subject: [PATCH] Domino: support for analyzing dependencies of a local Maven project by providing the project dir --- .../domino/ProjectDependencyConfig.java | 9 +++ .../domino/ProjectDependencyConfigImpl.java | 21 +++++ .../domino/ProjectDependencyResolver.java | 80 ++++++++++++++++++- .../domino/cli/BaseDepsToBuildCommand.java | 20 ++++- 4 files changed, 127 insertions(+), 3 deletions(-) diff --git a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfig.java b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfig.java index 3e76a0ac..acd3979b 100644 --- a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfig.java +++ b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfig.java @@ -10,6 +10,13 @@ public interface ProjectDependencyConfig { + /** + * Project directory + * + * @return project directory + */ + Path getProjectDir(); + /** * Project BOM * @@ -146,6 +153,8 @@ default void persist(Path p) throws IOException { interface Mutable extends ProjectDependencyConfig { + Mutable setProjectDir(Path projectDir); + Mutable setProjectBom(ArtifactCoords bom); Mutable setProjectArtifacts(Collection projectArtifacts); diff --git a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfigImpl.java b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfigImpl.java index 68a6e0a7..0ffa80e9 100644 --- a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfigImpl.java +++ b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfigImpl.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import io.quarkus.maven.dependency.ArtifactCoords; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -12,6 +13,7 @@ public class ProjectDependencyConfigImpl implements ProjectDependencyConfig { static final String WILDCARD = "*"; + private final Path projectDir; private final ArtifactCoords projectBom; private final Collection projectArtifacts; private final Collection includeArtifacts; @@ -34,6 +36,7 @@ public class ProjectDependencyConfigImpl implements ProjectDependencyConfig { private boolean includeAlreadyBuilt; private ProjectDependencyConfigImpl(ProjectDependencyConfig other) { + this.projectDir = other.getProjectDir(); projectBom = other.getProjectBom(); projectArtifacts = toUnmodifiableList(other.getProjectArtifacts()); includeArtifacts = toUnmodifiableList(other.getIncludeArtifacts()); @@ -56,6 +59,11 @@ private ProjectDependencyConfigImpl(ProjectDependencyConfig other) { warnOnResolutionErrors = other.isWarnOnResolutionErrors(); } + @Override + public Path getProjectDir() { + return projectDir; + } + @Override public ArtifactCoords getProjectBom() { return projectBom; @@ -158,6 +166,7 @@ public boolean isIncludeAlreadyBuilt() { static class Builder implements ProjectDependencyConfig.Mutable { + private Path projectDir; private ArtifactCoords projectBom; private Collection projectArtifacts = new ArrayList<>(); private Collection includeArtifacts = new ArrayList<>(); @@ -183,6 +192,7 @@ static class Builder implements ProjectDependencyConfig.Mutable { } Builder(ProjectDependencyConfig other) { + projectDir = other.getProjectDir(); projectBom = other.getProjectBom(); projectArtifacts.addAll(other.getProjectArtifacts()); includeArtifacts.addAll(other.getIncludeArtifacts()); @@ -205,6 +215,17 @@ static class Builder implements ProjectDependencyConfig.Mutable { includeAlreadyBuilt = other.isIncludeAlreadyBuilt(); } + @Override + public Path getProjectDir() { + return projectDir; + } + + @Override + public Mutable setProjectDir(Path projectDir) { + this.projectDir = projectDir; + return this; + } + @Override public ArtifactCoords getProjectBom() { return projectBom; diff --git a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyResolver.java b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyResolver.java index 563d79a8..27bab9dd 100644 --- a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyResolver.java +++ b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyResolver.java @@ -8,7 +8,10 @@ import io.quarkus.bom.decomposer.detector.PrefixedTagReleaseIdDetector; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject; +import io.quarkus.bootstrap.resolver.maven.workspace.LocalWorkspace; import io.quarkus.bootstrap.resolver.maven.workspace.ModelUtils; +import io.quarkus.bootstrap.util.IoUtils; import io.quarkus.devtools.messagewriter.MessageWriter; import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.maven.dependency.ArtifactKey; @@ -39,6 +42,8 @@ import org.apache.maven.model.DependencyManagement; import org.apache.maven.model.Model; import org.apache.maven.model.Parent; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.PluginExecution; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.collection.CollectRequest; @@ -103,7 +108,14 @@ public ProjectDependencyResolver build() { private MavenArtifactResolver getInitializedResolver() { if (resolver == null) { try { - return MavenArtifactResolver.builder().setWorkspaceDiscovery(false).build(); + if (depConfig == null || depConfig.getProjectDir() == null) { + return MavenArtifactResolver.builder().setWorkspaceDiscovery(false).build(); + } + return MavenArtifactResolver.builder() + .setCurrentProject(depConfig.getProjectDir().toString()) + .setEffectiveModelBuilder(true) + .setPreferPomsFromWorkspace(true) + .build(); } catch (BootstrapMavenException e) { throw new IllegalStateException("Failed to initialize the Maven artifact resolver", e); } @@ -379,6 +391,28 @@ private void removeProductizedDeps() { } protected Iterable getProjectArtifacts() { + if (config.getProjectDir() != null) { + final LocalWorkspace ws = resolver.getMavenContext().getWorkspace(); + final List createdDirs = new ArrayList<>(); + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + @Override + public void run() { + for (Path p : createdDirs) { + IoUtils.recursiveDelete(p); + } + } + })); + ws.getProjects().values().forEach(p -> ensureResolvable(p, createdDirs)); + final List result = new ArrayList<>(); + for (LocalProject project : ws.getProjects().values()) { + if (isPublished(project)) { + result.add(ArtifactCoords.of(project.getGroupId(), project.getArtifactId(), + ArtifactCoords.DEFAULT_CLASSIFIER, project.getRawModel().getPackaging(), project.getVersion())); + } + } + return result; + } + if (config.getProjectArtifacts().isEmpty()) { final List result = new ArrayList<>(); for (ArtifactCoords d : targetBomConstraints) { @@ -392,6 +426,50 @@ protected Iterable getProjectArtifacts() { return config.getProjectArtifacts(); } + private static boolean isPublished(LocalProject project) { + final Model model = project.getModelBuildingResult() == null ? project.getRawModel() + : project.getModelBuildingResult().getEffectiveModel(); + String skipStr = model.getProperties().getProperty("maven.install.skip"); + if (skipStr != null && Boolean.parseBoolean(skipStr)) { + return false; + } + skipStr = model.getProperties().getProperty("maven.deploy.skip"); + if (skipStr != null && Boolean.parseBoolean(skipStr)) { + return false; + } + if (model.getBuild() != null) { + for (Plugin plugin : model.getBuild().getPlugins()) { + if (plugin.getArtifactId().equals("maven-install-plugin") + || plugin.getArtifactId().equals("maven-deploy-plugin")) { + for (PluginExecution e : plugin.getExecutions()) { + if (e.getId().startsWith("default-") && e.getPhase().equals("none")) { + return false; + } + } + } + } + } + return true; + } + + private static void ensureResolvable(LocalProject project, List createdDirs) { + if (!project.getRawModel().getPackaging().equals(ArtifactCoords.TYPE_POM)) { + final Path classesDir = project.getClassesDir(); + if (!Files.exists(classesDir)) { + Path topDirToCreate = classesDir; + while (!Files.exists(topDirToCreate.getParent())) { + topDirToCreate = topDirToCreate.getParent(); + } + try { + Files.createDirectories(classesDir); + createdDirs.add(topDirToCreate); + } catch (IOException e) { + throw new RuntimeException("Failed to create " + classesDir, e); + } + } + } + } + private void processRootArtifact(List managedDeps, ArtifactCoords rootArtifact) { final DependencyNode root; diff --git a/domino/app/src/main/java/io/quarkus/domino/cli/BaseDepsToBuildCommand.java b/domino/app/src/main/java/io/quarkus/domino/cli/BaseDepsToBuildCommand.java index 54ba2bad..a04e1fc4 100644 --- a/domino/app/src/main/java/io/quarkus/domino/cli/BaseDepsToBuildCommand.java +++ b/domino/app/src/main/java/io/quarkus/domino/cli/BaseDepsToBuildCommand.java @@ -17,6 +17,9 @@ public abstract class BaseDepsToBuildCommand implements Callable { + @CommandLine.Option(names = { "--project-dir" }, description = "Project directory") + public File projectDir; + @CommandLine.Option(names = { "--bom" }, description = "BOM whose constraints should be used as top level artifacts to be built") public String bom; @@ -152,6 +155,13 @@ public Integer call() throws Exception { excludeKeys = Set.of(); } + if (projectDir != null) { + if (!projectDir.isDirectory()) { + throw new RuntimeException(projectDir + " is not a directory"); + } + config.setProjectDir(projectDir.toPath()); + } + config.setExcludeBomImports(excludeBomImports) .setExcludeGroupIds(excludeGroupIds) // TODO .setExcludeKeys(excludeKeys) @@ -176,7 +186,6 @@ public Integer call() throws Exception { if (exportTo != null) { config.persist(exportTo.toPath()); } else { - MavenArtifactResolver.builder().setWorkspaceDiscovery(false).build(); final ProjectDependencyResolver dependencyResolver = ProjectDependencyResolver.builder() .setLogOutputFile(outputFile == null ? null : outputFile.toPath()) .setAppendOutput(appendOutput) @@ -193,7 +202,14 @@ protected MavenArtifactResolver getArtifactResolver() { return artifactResolver; } try { - return artifactResolver = MavenArtifactResolver.builder().setWorkspaceDiscovery(false).build(); + if (projectDir == null) { + return artifactResolver = MavenArtifactResolver.builder().setWorkspaceDiscovery(false).build(); + } + return MavenArtifactResolver.builder() + .setCurrentProject(projectDir.getAbsolutePath()) + .setEffectiveModelBuilder(true) + .setPreferPomsFromWorkspace(true) + .build(); } catch (BootstrapMavenException e) { throw new RuntimeException("Failed to initialize Maven artifact resolver", e); }