From 4fcf1f2184c6ba32b107ffde764afbeff0b9a9e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Efe=20G=C3=B6kdemir?= Date: Thu, 29 Oct 2026 23:23:14 +0300 Subject: [PATCH] [MDEP-976] - Fail on copy-dependencies destination collisions --- .../invoker.properties | 1 + .../verify.groovy | 12 +++---- .../CopyDependenciesMojo.java | 32 ++++++++++++------- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/it/projects/copy-dependencies-with-conflict/invoker.properties b/src/it/projects/copy-dependencies-with-conflict/invoker.properties index f50e476fd..1b8f29fae 100644 --- a/src/it/projects/copy-dependencies-with-conflict/invoker.properties +++ b/src/it/projects/copy-dependencies-with-conflict/invoker.properties @@ -16,3 +16,4 @@ # under the License. invoker.goals = clean process-sources +invoker.buildResult = failure diff --git a/src/it/projects/copy-dependencies-with-conflict/verify.groovy b/src/it/projects/copy-dependencies-with-conflict/verify.groovy index 5405439d7..5a5234a37 100644 --- a/src/it/projects/copy-dependencies-with-conflict/verify.groovy +++ b/src/it/projects/copy-dependencies-with-conflict/verify.groovy @@ -21,11 +21,11 @@ File file = new File( basedir, "build.log" ) assert file.exists() String buildLog = file.getText( "UTF-8" ) -assert buildLog.contains( '[WARNING] Overwriting ' ) -assert buildLog.contains( '[DEBUG] Copying artifact \'org.apache.maven.its.dependency.a:conflict:jar:1.0\'' ) -assert buildLog.contains( '[DEBUG] Copying artifact \'org.apache.maven.its.dependency.a:conflict:pom:1.0\'' ) -assert buildLog.contains( '[DEBUG] Copying artifact \'org.apache.maven.its.dependency.a:conflict:jar:1.0\'' ) -assert buildLog.contains( '[DEBUG] Copying artifact \'org.apache.maven.its.dependency.b:conflict:jar:1.0\'' ) -assert buildLog.contains( '[WARNING] Multiple files with the name conflict-1.0.jar in the dependency tree.' ) +assert buildLog.contains( 'Multiple artifacts map to the same destination file' ) +assert buildLog.contains( 'org.apache.maven.its.dependency.a:conflict' ) +assert buildLog.contains( 'org.apache.maven.its.dependency.b:conflict' ) + +File copiedFile = new File( basedir, 'target/it/copy-dep-test-2/conflict-1.0.jar' ) +assert !copiedFile.exists() return true diff --git a/src/main/java/org/apache/maven/plugins/dependency/fromDependencies/CopyDependenciesMojo.java b/src/main/java/org/apache/maven/plugins/dependency/fromDependencies/CopyDependenciesMojo.java index 162914fd9..0b612da31 100644 --- a/src/main/java/org/apache/maven/plugins/dependency/fromDependencies/CopyDependenciesMojo.java +++ b/src/main/java/org/apache/maven/plugins/dependency/fromDependencies/CopyDependenciesMojo.java @@ -54,8 +54,7 @@ /** * Goal that copies the files for a project's dependencies from the repository to a directory. * The default location to copy to is target/dependencies. - * Since all files are copied to the same directory by default, a dependency that - * has the same file name as another dependency will be overwritten. + * If dependencies map to the same destination file, the goal fails before copying to avoid overwriting an artifact. * * @author Brian Fox * @since 1.0 @@ -161,18 +160,29 @@ protected void doExecute() throws MojoExecutionException { Set artifacts = dss.getResolvedDependencies(); if (!useRepositoryLayout) { - Map copies = new HashMap<>(); + Map copies = new HashMap<>(); for (Artifact artifactItem : artifacts) { String destFileName = DependencyUtil.getFormattedFileName( artifactItem, stripVersion, prependGroupId, useBaseVersion, stripClassifier); - int numCopies = copies.getOrDefault(destFileName, 0); - copies.put(destFileName, numCopies + 1); - } - for (Map.Entry entry : copies.entrySet()) { - if (entry.getValue() > 1) { - getLog().warn("Multiple files with the name " + entry.getKey() + " in the dependency tree."); - getLog().warn( - "Not all JARs will be available. Consider using prependGroupId, useSubDirectoryPerArtifact, or useRepositoryLayout."); + File destDir = DependencyUtil.getFormattedOutputDirectory( + useSubDirectoryPerScope, + useSubDirectoryPerType, + useSubDirectoryPerArtifact, + useRepositoryLayout, + stripVersion, + stripType, + outputDirectory, + artifactItem); + File destFile = new File(destDir, destFileName) + .getAbsoluteFile() + .toPath() + .normalize() + .toFile(); + Artifact existingArtifact = copies.putIfAbsent(destFile, artifactItem); + if (existingArtifact != null) { + throw new MojoExecutionException("Multiple artifacts map to the same destination file '" + destFile + + "': " + existingArtifact.getId() + " and " + artifactItem.getId() + + ". Consider using prependGroupId, useSubDirectoryPerArtifact, or useRepositoryLayout."); } }