From da5185ec7bf7f6bd157653b9d5f55a6b2a9f226d Mon Sep 17 00:00:00 2001 From: Juul Hobert Date: Fri, 9 Feb 2024 11:55:45 +0100 Subject: [PATCH] [MNG-7344] Copy with working importedFrom tree --- .../apache/maven/api/model/InputLocation.java | 19 +++++++ .../maven/api/model/InputLocationTracker.java | 2 + .../apache/maven/api/model/InputSource.java | 18 ++++++ .../model/building/DefaultModelBuilder.java | 10 +++- .../DefaultDependencyManagementImporter.java | 56 +++++++++++++++++-- src/mdo/model.vm | 27 ++++++++- 6 files changed, 122 insertions(+), 10 deletions(-) diff --git a/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocation.java b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocation.java index 28bd415366a8..930d697595f3 100644 --- a/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocation.java +++ b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocation.java @@ -32,12 +32,14 @@ public class InputLocation implements Serializable, InputLocationTracker { private final int columnNumber; private final InputSource source; private final Map locations; + private final InputLocation importedFrom; public InputLocation(InputSource source) { this.lineNumber = -1; this.columnNumber = -1; this.source = source; this.locations = Collections.singletonMap(0, this); + this.importedFrom = null; } public InputLocation(int lineNumber, int columnNumber) { @@ -54,6 +56,7 @@ public InputLocation(int lineNumber, int columnNumber, InputSource source, Objec this.source = source; this.locations = selfLocationKey != null ? Collections.singletonMap(selfLocationKey, this) : Collections.emptyMap(); + this.importedFrom = null; } public InputLocation(int lineNumber, int columnNumber, InputSource source, Map locations) { @@ -61,6 +64,15 @@ public InputLocation(int lineNumber, int columnNumber, InputSource source, Map getLocations() { return locations; } + /** + * Gets the input location that caused this model to be read. + */ + public InputLocation getImportedFrom() { + return importedFrom; + } + /** * Merges the {@code source} location into the {@code target} location. * diff --git a/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocationTracker.java b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocationTracker.java index ce4240e053b5..e38ad5c0642a 100644 --- a/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocationTracker.java +++ b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocationTracker.java @@ -20,4 +20,6 @@ public interface InputLocationTracker { InputLocation getLocation(Object field); + + InputLocation getImportedFrom(); } diff --git a/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputSource.java b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputSource.java index d5dc895fb7a2..003d013a8db1 100644 --- a/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputSource.java +++ b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputSource.java @@ -33,17 +33,27 @@ public class InputSource implements Serializable { private final String modelId; private final String location; private final List inputs; + private final InputLocation importedFrom; public InputSource(String modelId, String location) { this.modelId = modelId; this.location = location; this.inputs = null; + this.importedFrom = null; + } + + private InputSource(String modelId, String location, InputLocation importedFrom) { + this.modelId = modelId; + this.location = location; + this.inputs = null; + this.importedFrom = importedFrom; } public InputSource(Collection inputs) { this.modelId = null; this.location = null; this.inputs = ImmutableCollections.copy(inputs); + this.importedFrom = null; } /** @@ -64,6 +74,14 @@ public String getModelId() { return this.modelId; } + public InputLocation getImportedFrom() { + return importedFrom; + } + + public InputSource importedFrom(InputLocation importedFrom) { + return new InputSource(modelId, location, importedFrom); + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java index 7d832654a12e..87c6e882025b 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java @@ -1690,7 +1690,15 @@ private void importDependencyManagement( importMgmts = new ArrayList<>(); } - importMgmts.add(importMgmt.getDelegate()); + if (request.isLocationTracking()) { + // Keep track of why this DependencyManagement was imported. + importMgmts.add( + org.apache.maven.api.model.DependencyManagement.newBuilder(importMgmt.getDelegate(), true) + .importedFrom(dependency.getDelegate().getLocation("")) + .build()); + } else { + importMgmts.add(importMgmt.getDelegate()); + } } } diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java index 4456c541f5f9..0ee505ed5e25 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java @@ -21,13 +21,9 @@ import javax.inject.Named; import javax.inject.Singleton; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; -import org.apache.maven.api.model.Dependency; -import org.apache.maven.api.model.DependencyManagement; -import org.apache.maven.api.model.Model; +import org.apache.maven.api.model.*; import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.model.building.ModelProblemCollector; @@ -62,6 +58,11 @@ public Model importManagement( for (Dependency dependency : source.getDependencies()) { String key = dependency.getManagementKey(); dependencies.putIfAbsent(key, dependency); + + if (request.isLocationTracking()) { + Dependency updatedDependency = updateWithImportedFrom(dependency, source); + dependencies.put(key, updatedDependency); + } } } @@ -69,4 +70,47 @@ public Model importManagement( } return target; } + + static Dependency updateWithImportedFrom(Dependency dependency, DependencyManagement bom) { + // We are only interested in the InputSource, so the location of the element is sufficient + InputLocation dependencyLocation = dependency.getLocation(""); + InputLocation bomLocation = bom.getLocation(""); + + if (dependencyLocation == null || bomLocation == null) { + return dependency; + } + + InputSource dependencySource = dependencyLocation.getSource(); + InputSource bomSource = bomLocation.getSource(); + + // If the dependency and BOM have the same source, it means we found the root where the dependency is declared. + if (dependencySource == null + || bomSource == null + || Objects.equals(dependencySource.getModelId(), bomSource.getModelId())) { + return Dependency.newBuilder(dependency, true) + .importedFrom(bomLocation) + .build(); + } + + // TODO: determine function of the following code + while (dependencySource.getImportedFrom() != null) { + InputLocation importedFrom = dependencySource.getImportedFrom(); + + // Stop if the BOM is already in the list, no update necessary + if (Objects.equals(importedFrom.getSource().getModelId(), bomSource.getModelId())) { + return dependency; + } + + dependencySource = importedFrom.getSource(); + } + + // We modify the input location that is used for the whole file. + // This is likely correct because the POM hierarchy applies to the whole POM, not just one dependency. + // TODO What to do now?! + + // Create copy of bomLocation and set importedFrom with the value of dependency.getimportedFrom() + return Dependency.newBuilder(dependency, true) + .importedFrom(new InputLocation(bomLocation, dependency.getImportedFrom())) + .build(); + } } diff --git a/src/mdo/model.vm b/src/mdo/model.vm index 9f790bd583aa..f7c33acb0e69 100644 --- a/src/mdo/model.vm +++ b/src/mdo/model.vm @@ -130,6 +130,7 @@ public class ${class.name} #if ( ! $class.superClass ) /** Locations */ final Map locations; + final InputLocation importedFrom; #end #end @@ -151,7 +152,8 @@ public class ${class.name} $type $field.name${sep} #end #if ( $locationTracking ) - Map locations + Map locations, + InputLocation importedFrom #end ) { #if ( $class.superClass ) @@ -161,7 +163,8 @@ public class ${class.name} ${field.name}${sep} #end #if ( $locationTracking ) - locations + locations, + importedFrom #end ); #end @@ -179,6 +182,7 @@ public class ${class.name} #if ( $locationTracking ) #if ( ! $class.superClass ) this.locations = ImmutableCollections.copy(locations); + this.importedFrom = importedFrom; #end #end } @@ -244,6 +248,14 @@ public class ${class.name} return locations != null ? locations.get(key) : null; } + /** + * Gets the input location that caused this model to be read. + */ + public InputLocation getImportedFrom() + { + return importedFrom; + } + #end /** * Creates a new builder with this object as the basis. @@ -374,6 +386,7 @@ public class ${class.name} #end #if ( ! $class.superClass && $locationTracking ) Map locations; + InputLocation importedFrom; #end Builder(boolean withDefaults) { @@ -408,6 +421,7 @@ public class ${class.name} #end #if ( $locationTracking ) this.locations = base.locations; + this.importedFrom = base.importedFrom; #end } else { this.base = base; @@ -453,6 +467,12 @@ public class ${class.name} return this; } + @Nonnull + public Builder importedFrom(InputLocation importedFrom) { + this.importedFrom = importedFrom; + return this; + } + #end @Nonnull public ${class.name} build() { @@ -486,7 +506,8 @@ public class ${class.name} #end #end #if ( $locationTracking ) - locations + locations, + importedFrom #end ); }