Skip to content

Commit 94995df

Browse files
committed
[MNG-8561] SourceRoot should be more lenient wrt duplicates
Add includes/excludes to the SourceKey
1 parent 10c1488 commit 94995df

File tree

2 files changed

+55
-50
lines changed

2 files changed

+55
-50
lines changed

impl/maven-core/src/main/java/org/apache/maven/project/MavenProject.java

Lines changed: 13 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.Objects;
3434
import java.util.Properties;
3535
import java.util.Set;
36+
import java.util.concurrent.CopyOnWriteArrayList;
3637
import java.util.function.Predicate;
3738
import java.util.stream.Stream;
3839

@@ -143,40 +144,10 @@ public class MavenProject implements Cloneable {
143144

144145
private List<MavenProject> collectedProjects;
145146

146-
/**
147-
* A tuple of {@link SourceRoot} properties for which we decide that no duplicated value should exist in a project.
148-
* The set of properties that we choose to put in this record may be modified in any future Maven version.
149-
* The intent is to detect some configuration errors.
150-
*/
151-
private record SourceKey(ProjectScope scope, Language language, Path directory) {
152-
/**
153-
* Converts this key into a source root.
154-
* Used for adding a new source when no other information is available.
155-
*
156-
* @return the source root for the properties of this key.
157-
*/
158-
SourceRoot createSource() {
159-
return new DefaultSourceRoot(scope, language, directory);
160-
}
161-
162-
/**
163-
* {@return an error message to report when a conflict is detected}.
164-
*
165-
* @param baseDir value of {@link #getBaseDirectory()}, in order to make the message shorter
166-
*/
167-
String conflictMessage(Path baseDir) {
168-
return "Directory " + baseDir.relativize(directory)
169-
+ " is specified twice for the scope \"" + scope.id()
170-
+ "\" and language \"" + language.id() + "\".";
171-
}
172-
}
173-
174147
/**
175148
* All sources of this project. The map includes main and test codes for all languages.
176-
* However, we put some restrictions on what information can be repeated.
177-
* Those restrictions are expressed in {@link SourceKey}.
178149
*/
179-
private HashMap<SourceKey, SourceRoot> sources = new LinkedHashMap<>(); // Need access to the `clone()` method.
150+
private List<SourceRoot> sources = new CopyOnWriteArrayList<>();
180151

181152
@Deprecated
182153
private ArtifactRepository releaseArtifactRepository;
@@ -358,11 +329,12 @@ public DependencyManagement getDependencyManagement() {
358329
* @since 4.0.0
359330
*/
360331
public void addSourceRoot(SourceRoot source) {
361-
var key = new SourceKey(source.scope(), source.language(), source.directory());
362-
SourceRoot current = sources.putIfAbsent(key, source);
363-
if (current != null && !current.equals(source)) {
364-
throw new IllegalArgumentException(key.conflictMessage(getBaseDirectory()));
332+
if (sources.contains(source)) {
333+
throw new IllegalArgumentException("Directory " + getBaseDirectory().relativize(source.directory())
334+
+ " is specified twice for the scope \"" + source.scope().id()
335+
+ "\" and language \"" + source.language().id() + "\".");
365336
}
337+
sources.add(source);
366338
}
367339

368340
/**
@@ -381,8 +353,7 @@ public void addSourceRoot(SourceRoot source) {
381353
*/
382354
public void addSourceRoot(ProjectScope scope, Language language, Path directory) {
383355
directory = getBaseDirectory().resolve(directory).normalize();
384-
var key = new SourceKey(scope, language, directory);
385-
sources.computeIfAbsent(key, SourceKey::createSource);
356+
addSourceRoot(new DefaultSourceRoot(scope, language, directory));
386357
}
387358

388359
/**
@@ -402,8 +373,7 @@ public void addSourceRoot(ProjectScope scope, Language language, String director
402373
directory = directory.trim();
403374
if (!directory.isBlank()) {
404375
Path path = getBaseDirectory().resolve(directory).normalize();
405-
var key = new SourceKey(scope, language, path);
406-
sources.computeIfAbsent(key, SourceKey::createSource);
376+
addSourceRoot(scope, language, path);
407377
}
408378
}
409379
}
@@ -432,7 +402,7 @@ public void addTestCompileSourceRoot(String path) {
432402
* @see #addSourceRoot(SourceRoot)
433403
*/
434404
public Collection<SourceRoot> getSourceRoots() {
435-
return Collections.unmodifiableCollection(sources.values());
405+
return Collections.unmodifiableCollection(sources);
436406
}
437407

438408
/**
@@ -449,7 +419,7 @@ public Collection<SourceRoot> getSourceRoots() {
449419
* @since 4.0.0
450420
*/
451421
public Stream<SourceRoot> getEnabledSourceRoots(ProjectScope scope, Language language) {
452-
Stream<SourceRoot> s = sources.values().stream().filter(SourceRoot::enabled);
422+
Stream<SourceRoot> s = sources.stream().filter(SourceRoot::enabled);
453423
if (scope != null) {
454424
s = s.filter((source) -> scope.equals(source.scope()));
455425
}
@@ -1249,7 +1219,7 @@ protected void setAttachedArtifacts(List<Artifact> attachedArtifacts) {
12491219
*/
12501220
@Deprecated
12511221
private void setSourceRootDirs(ProjectScope scope, Language language, List<String> roots) {
1252-
sources.values().removeIf((source) -> scope.equals(source.scope()) && language.equals(source.language()));
1222+
sources.removeIf((source) -> scope.equals(source.scope()) && language.equals(source.language()));
12531223
Path directory = getBaseDirectory();
12541224
for (String root : roots) {
12551225
addSourceRoot(new DefaultSourceRoot(scope, language, directory.resolve(root)));
@@ -1335,7 +1305,7 @@ private void deepCopy(MavenProject project) {
13351305
// This property is not handled like others as we don't use public API.
13361306
// The whole implementation of this `deepCopy` method may need revision,
13371307
// but it would be the topic for a separated commit.
1338-
sources = (HashMap<SourceKey, SourceRoot>) project.sources.clone();
1308+
sources = new CopyOnWriteArrayList<>(project.sources);
13391309

13401310
if (project.getModel() != null) {
13411311
setModel(project.getModel().clone());

impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSourceRoot.java

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,15 @@ public DefaultSourceRoot(final Path baseDir, ProjectScope scope, Resource resour
117117
}
118118

119119
/**
120-
* Creates a new instance for the given directory and scope. The language is assumed Java.
120+
* Creates a new instance for the given directory and scope.
121121
*
122122
* @param scope scope of source code (main or test)
123123
* @param language language of the source code
124124
* @param directory directory of the source code
125125
*/
126126
public DefaultSourceRoot(final ProjectScope scope, final Language language, final Path directory) {
127127
this.scope = Objects.requireNonNull(scope);
128-
this.language = language;
128+
this.language = Objects.requireNonNull(language);
129129
this.directory = Objects.requireNonNull(directory);
130130
includes = List.of();
131131
excludes = List.of();
@@ -136,6 +136,31 @@ public DefaultSourceRoot(final ProjectScope scope, final Language language, fina
136136
enabled = true;
137137
}
138138

139+
/**
140+
* Creates a new instance for the given directory and scope.
141+
*
142+
* @param scope scope of source code (main or test)
143+
* @param language language of the source code
144+
* @param directory directory of the source code
145+
*/
146+
public DefaultSourceRoot(
147+
final ProjectScope scope,
148+
final Language language,
149+
final Path directory,
150+
List<PathMatcher> includes,
151+
List<PathMatcher> excludes) {
152+
this.scope = Objects.requireNonNull(scope);
153+
this.language = language;
154+
this.directory = Objects.requireNonNull(directory);
155+
this.includes = includes != null ? List.copyOf(includes) : List.of();
156+
this.excludes = excludes != null ? List.copyOf(excludes) : List.of();
157+
moduleName = null;
158+
targetVersion = null;
159+
targetPath = null;
160+
stringFiltering = false;
161+
enabled = true;
162+
}
163+
139164
/**
140165
* {@return the given value as a trimmed non-blank string, or null otherwise}.
141166
*/
@@ -162,11 +187,21 @@ private static String nonBlank(String value) {
162187
private static List<PathMatcher> matchers(FileSystem fs, List<String> patterns) {
163188
final var matchers = new PathMatcher[patterns.size()];
164189
for (int i = 0; i < matchers.length; i++) {
165-
String pattern = patterns.get(i);
166-
if (pattern.indexOf(':') < 0) {
167-
pattern = "glob:" + pattern;
168-
}
169-
matchers[i] = fs.getPathMatcher(pattern);
190+
String rawPattern = patterns.get(i);
191+
String pattern = rawPattern.contains(":") ? rawPattern : "glob:" + rawPattern;
192+
matchers[i] = new PathMatcher() {
193+
final PathMatcher delegate = fs.getPathMatcher(pattern);
194+
195+
@Override
196+
public boolean matches(Path path) {
197+
return delegate.matches(path);
198+
}
199+
200+
@Override
201+
public String toString() {
202+
return pattern;
203+
}
204+
};
170205
}
171206
return List.of(matchers);
172207
}

0 commit comments

Comments
 (0)