From 0d363ab6e78d94604984d03c4ecf8758290351ca Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Wed, 29 Jul 2020 20:55:23 +0000 Subject: [PATCH 1/3] [MDEP-437] mdep.link=true creates symlink instead of physical copy Signed-off-by: Markus KARG --- .../copy-using-symlink/invoker.properties | 18 ++++++ src/it/projects/copy-using-symlink/pom.xml | 64 +++++++++++++++++++ src/it/projects/copy-using-symlink/verify.bsh | 38 +++++++++++ .../dependency/AbstractDependencyMojo.java | 33 ++++++++++ .../fromConfiguration/CopyMojo.java | 32 +++++++++- .../fromConfiguration/TestCopyMojo.java | 30 +++++++++ 6 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 src/it/projects/copy-using-symlink/invoker.properties create mode 100644 src/it/projects/copy-using-symlink/pom.xml create mode 100644 src/it/projects/copy-using-symlink/verify.bsh diff --git a/src/it/projects/copy-using-symlink/invoker.properties b/src/it/projects/copy-using-symlink/invoker.properties new file mode 100644 index 0000000000..6592030fb5 --- /dev/null +++ b/src/it/projects/copy-using-symlink/invoker.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +invoker.goals = clean process-sources -Dmdep.link=true diff --git a/src/it/projects/copy-using-symlink/pom.xml b/src/it/projects/copy-using-symlink/pom.xml new file mode 100644 index 0000000000..d683399b4d --- /dev/null +++ b/src/it/projects/copy-using-symlink/pom.xml @@ -0,0 +1,64 @@ + + + + + 4.0.0 + + org.apache.maven.its.dependency + test + 1.0-SNAPSHOT + + Test + + Test dependency:copy -Dmdep.link=true + + + + UTF-8 + + + + + + maven-dependency-plugin + @project.version@ + + + test + + copy + + + + + org.apache.maven + maven-model + 2.0.6 + + + + + + + + + diff --git a/src/it/projects/copy-using-symlink/verify.bsh b/src/it/projects/copy-using-symlink/verify.bsh new file mode 100644 index 0000000000..0cd89dcd9f --- /dev/null +++ b/src/it/projects/copy-using-symlink/verify.bsh @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.nio.file.*; + +Path libDir = basedir.toPath().resolve( "target/dependency" ); + +String[] expectedFiles = { + "maven-model-2.0.6.jar", +}; + +for ( String expectedFile : expectedFiles ) +{ + Path path = libDir.resolve( expectedFile ); + System.out.println( "Checking for existence of link " + path ); + if ( !Files.isSymbolicLink( path ) ) + { + throw new Exception( "Missing symlink " + path ); + } +} + +return true; diff --git a/src/main/java/org/apache/maven/plugins/dependency/AbstractDependencyMojo.java b/src/main/java/org/apache/maven/plugins/dependency/AbstractDependencyMojo.java index 07df9f631a..ec79e953aa 100644 --- a/src/main/java/org/apache/maven/plugins/dependency/AbstractDependencyMojo.java +++ b/src/main/java/org/apache/maven/plugins/dependency/AbstractDependencyMojo.java @@ -44,6 +44,7 @@ import org.codehaus.plexus.components.io.filemappers.FileMapper; import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector; import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.NioFiles; import org.codehaus.plexus.util.ReflectionUtils; import org.codehaus.plexus.util.StringUtils; @@ -196,6 +197,38 @@ protected void copyFile( File artifact, File destFile ) } } + /** + * Does the actual link of the file and logging. + * + * @param artifact represents the file to link to. + * @param destFile file name of destination link. + * @throws MojoExecutionException with a message if an error occurs. + */ + protected void linkFile( File artifact, File destFile ) + throws MojoExecutionException + { + try + { + getLog().info( "Linking " + + destFile + " to " + + ( this.outputAbsoluteArtifactFilename ? artifact.getAbsolutePath() : artifact.getName() ) ); + + if ( artifact.isDirectory() ) + { + // usual case is a future jar packaging, but there are special cases: classifier and other packaging + throw new MojoExecutionException( "Artifact has not been packaged yet. When used on reactor artifact, " + + "copy should be executed after packaging: see MDEP-187." ); + } + + // TODO Replace with FileUtils.linkFile(artifact, destFile); once https://github.com/codehaus-plexus/plexus-utils/pull/82 is merged + NioFiles.createSymbolicLink( destFile, artifact ); + } + catch ( IOException e ) + { + throw new MojoExecutionException( "Error linking " + destFile + " to artifact " + artifact, e ); + } + } + /** * @param artifact {@link Artifact} * @param location The location. diff --git a/src/main/java/org/apache/maven/plugins/dependency/fromConfiguration/CopyMojo.java b/src/main/java/org/apache/maven/plugins/dependency/fromConfiguration/CopyMojo.java index a2f2d359d9..32065f16d1 100644 --- a/src/main/java/org/apache/maven/plugins/dependency/fromConfiguration/CopyMojo.java +++ b/src/main/java/org/apache/maven/plugins/dependency/fromConfiguration/CopyMojo.java @@ -40,6 +40,13 @@ public class CopyMojo extends AbstractFromConfigurationMojo { + /** + * Link instead of copy + + * @since 3.1.3 + */ + @Parameter( property = "mdep.link", defaultValue = "false" ) + private boolean link = false; /** * Strip artifact version during copy @@ -132,7 +139,14 @@ protected void copyArtifact( ArtifactItem artifactItem ) { File destFile = new File( artifactItem.getOutputDirectory(), artifactItem.getDestFileName() ); - copyFile( artifactItem.getArtifact().getFile(), destFile ); + if ( this.isLink() ) + { + linkFile( artifactItem.getArtifact().getFile(), destFile ); + } + else + { + copyFile( artifactItem.getArtifact().getFile(), destFile ); + } } @Override @@ -145,6 +159,22 @@ protected ArtifactItemFilter getMarkedArtifactFilter( ArtifactItem item ) return destinationNameOverrideFilter; } + /** + * @return Returns whether to link instead of copy + */ + public boolean isLink() + { + return this.link; + } + + /** + * @param link Whether to link instead of copy. + */ + public void setLink( boolean link ) + { + this.link = link; + } + /** * @return Returns the stripVersion. */ diff --git a/src/test/java/org/apache/maven/plugins/dependency/fromConfiguration/TestCopyMojo.java b/src/test/java/org/apache/maven/plugins/dependency/fromConfiguration/TestCopyMojo.java index 52fa4e9c23..f060723ee1 100644 --- a/src/test/java/org/apache/maven/plugins/dependency/fromConfiguration/TestCopyMojo.java +++ b/src/test/java/org/apache/maven/plugins/dependency/fromConfiguration/TestCopyMojo.java @@ -21,6 +21,8 @@ import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -144,6 +146,20 @@ public void assertFileExists( ArtifactItem item, boolean exist ) assertEquals( exist, file.exists() ); } + public void assertFilesAreLinks( Collection items, boolean areLinks ) + { + for ( ArtifactItem item : items ) + { + assertFileIsLink( item, areLinks ); + } + } + + public void assertFileIsLink( ArtifactItem item, boolean isLink ) + { + Path path = item.getOutputDirectory().toPath().resolve( item.getDestFileName() ); + assertEquals( isLink, Files.isSymbolicLink( path ) ); + } + public void testMojoDefaults() { CopyMojo themojo = new CopyMojo(); @@ -233,6 +249,20 @@ public void testCopyToLocation() assertFilesExist( list, true ); } + public void testLink() + throws Exception + { + List list = stubFactory.getArtifactItems( stubFactory.getClassifiedArtifacts() ); + + mojo.setArtifactItems( createArtifactItemArtifacts( list ) ); + mojo.setLink( true ); + + mojo.execute(); + + assertFilesExist( list, true ); + assertFilesAreLinks( list, true ); + } + public void testCopyStripVersionSetInMojo() throws Exception { From 2006d951bd55e9dff7c20e7940929a4ae9be5b19 Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Fri, 28 Aug 2020 20:55:59 +0000 Subject: [PATCH 2/3] Using JUnit 4 for TestCopyMojo to enable Assumptions --- .../fromConfiguration/TestCopyMojo.java | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/apache/maven/plugins/dependency/fromConfiguration/TestCopyMojo.java b/src/test/java/org/apache/maven/plugins/dependency/fromConfiguration/TestCopyMojo.java index f060723ee1..769aeb662d 100644 --- a/src/test/java/org/apache/maven/plugins/dependency/fromConfiguration/TestCopyMojo.java +++ b/src/test/java/org/apache/maven/plugins/dependency/fromConfiguration/TestCopyMojo.java @@ -36,13 +36,19 @@ import org.apache.maven.plugins.dependency.AbstractDependencyMojoTestCase; import org.apache.maven.plugins.dependency.utils.DependencyUtil; import org.apache.maven.project.MavenProject; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +@RunWith(BlockJUnit4ClassRunner.class) public class TestCopyMojo extends AbstractDependencyMojoTestCase { private CopyMojo mojo; - protected void setUp() + @Before + public void setUp() throws Exception { super.setUp( "copy", false, false ); @@ -84,6 +90,7 @@ public void testSetArtifactWithoutPackaging() assertNull( item.getClassifier() ); } + @Test public void testSetArtifactWithoutClassifier() throws Exception { @@ -96,6 +103,7 @@ public void testSetArtifactWithoutClassifier() assertNull( item.getClassifier() ); } + @Test public void testSetArtifact() throws Exception { @@ -108,6 +116,7 @@ public void testSetArtifact() assertEquals( "e", item.getClassifier() ); } + @Test public void testGetArtifactItems() throws Exception { @@ -160,6 +169,7 @@ public void assertFileIsLink( ArtifactItem item, boolean isLink ) assertEquals( isLink, Files.isSymbolicLink( path ) ); } + @Test public void testMojoDefaults() { CopyMojo themojo = new CopyMojo(); @@ -169,6 +179,7 @@ public void testMojoDefaults() assertFalse( themojo.isStripClassifier() ); } + @Test public void testCopyFile() throws Exception { @@ -181,6 +192,7 @@ public void testCopyFile() assertFilesExist( list, true ); } + @Test public void testCopyFileWithBaseVersion() throws Exception { @@ -200,6 +212,7 @@ public void testCopyFileWithBaseVersion() assertFilesExist( list, true ); } + @Test public void testSkip() throws Exception { @@ -218,6 +231,7 @@ public void testSkip() } + @Test public void testCopyFileNoOverwrite() throws Exception { @@ -235,6 +249,7 @@ public void testCopyFileNoOverwrite() assertFilesExist( list, true ); } + @Test public void testCopyToLocation() throws Exception { @@ -249,6 +264,7 @@ public void testCopyToLocation() assertFilesExist( list, true ); } + @Test public void testLink() throws Exception { @@ -263,6 +279,7 @@ public void testLink() assertFilesAreLinks( list, true ); } + @Test public void testCopyStripVersionSetInMojo() throws Exception { @@ -280,6 +297,7 @@ public void testCopyStripVersionSetInMojo() assertFilesExist( list, true ); } + @Test public void testCopyStripClassifierSetInMojo() throws Exception { @@ -298,6 +316,7 @@ public void testCopyStripClassifierSetInMojo() assertFilesExist( list, true ); } + @Test public void testNonClassifierStrip() throws Exception { @@ -310,6 +329,7 @@ public void testNonClassifierStrip() assertFilesExist( list, true ); } + @Test public void testNonClassifierNoStrip() throws Exception { @@ -322,6 +342,7 @@ public void testNonClassifierNoStrip() assertFilesExist( list, true ); } + @Test public void testMissingVersionNotFound() throws Exception { @@ -370,6 +391,7 @@ public List getDependencyList( ArtifactItem item ) return list; } + @Test public void testMissingVersionFromDependencies() throws Exception { @@ -392,6 +414,7 @@ public void testMissingVersionFromDependencies() assertEquals( "2.0-SNAPSHOT", item.getVersion() ); } + @Test public void testMissingVersionFromDependenciesLooseMatch() throws Exception { @@ -423,6 +446,7 @@ public void testMissingVersionFromDependenciesLooseMatch() assertEquals( "2.1", item.getVersion() ); } + @Test public void testMissingVersionFromDependenciesWithClassifier() throws Exception { @@ -468,6 +492,7 @@ public List getDependencyMgtList( ArtifactItem item ) return list; } + @Test public void testMissingVersionFromDependencyMgt() throws Exception { @@ -501,6 +526,7 @@ public void testMissingVersionFromDependencyMgt() assertEquals( "3.0-SNAPSHOT", item.getVersion() ); } + @Test public void testMissingVersionFromDependencyMgtLooseMatch() throws Exception { @@ -541,6 +567,7 @@ public void testMissingVersionFromDependencyMgtLooseMatch() assertEquals( "3.1", item.getVersion() ); } + @Test public void testMissingVersionFromDependencyMgtWithClassifier() throws Exception { @@ -574,12 +601,14 @@ public void testMissingVersionFromDependencyMgtWithClassifier() assertEquals( "3.1", item.getVersion() ); } + @Test public void testArtifactNotFound() throws Exception { dotestArtifactExceptions( false, true ); } + @Test public void testArtifactResolutionException() throws Exception { @@ -612,6 +641,7 @@ public void dotestArtifactExceptions( boolean are, boolean anfe ) } } + @Test public void testNoArtifactItems() { try @@ -626,6 +656,7 @@ public void testNoArtifactItems() } + @Test public void testCopyDontOverWriteReleases() throws Exception { @@ -657,6 +688,7 @@ public void testCopyDontOverWriteReleases() assertEquals( time, copiedFile.lastModified() ); } + @Test public void testCopyDontOverWriteSnapshots() throws Exception { @@ -688,6 +720,7 @@ public void testCopyDontOverWriteSnapshots() assertEquals( time, copiedFile.lastModified() ); } + @Test public void testCopyOverWriteReleases() throws Exception { @@ -717,6 +750,7 @@ public void testCopyOverWriteReleases() assertEquals( 1000L, timeCopyNow ); } + @Test public void testCopyOverWriteSnapshot() throws Exception { @@ -747,6 +781,7 @@ public void testCopyOverWriteSnapshot() assertEquals( 1000L, timeCopyNow ); } + @Test public void testCopyOverWriteIfNewer() throws Exception { @@ -776,6 +811,7 @@ public void testCopyOverWriteIfNewer() assertTrue( time < copiedFile.lastModified() ); } + @Test public void testCopyFileWithOverideLocalRepo() throws Exception { From 60fc53164842a3fa0d3398013b319754e47d7baa Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Sun, 16 Aug 2020 15:55:52 +0200 Subject: [PATCH 3/3] Fail assumption when symlinks not supported --- .../fromConfiguration/TestCopyMojo.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/test/java/org/apache/maven/plugins/dependency/fromConfiguration/TestCopyMojo.java b/src/test/java/org/apache/maven/plugins/dependency/fromConfiguration/TestCopyMojo.java index 769aeb662d..6dd2884234 100644 --- a/src/test/java/org/apache/maven/plugins/dependency/fromConfiguration/TestCopyMojo.java +++ b/src/test/java/org/apache/maven/plugins/dependency/fromConfiguration/TestCopyMojo.java @@ -19,9 +19,12 @@ * under the License. */ +import static org.junit.Assume.assumeTrue; + import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.FileSystemException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; @@ -155,6 +158,27 @@ public void assertFileExists( ArtifactItem item, boolean exist ) assertEquals( exist, file.exists() ); } + private static final boolean supportsSymbolicLinks = supportsSymbolicLinks(); + + private static boolean supportsSymbolicLinks( ) + { + try { + Path target = Files.createTempFile( null, null ); + Path link = Files.createTempFile( null, null ); + Files.delete( link ); + try { + Files.createSymbolicLink( link, target ); + } catch ( FileSystemException e ) { + return false; + } + Files.delete( link ); + Files.delete( target ); + return true; + } catch ( IOException e ) { + throw new RuntimeException( e ); + } + } + public void assertFilesAreLinks( Collection items, boolean areLinks ) { for ( ArtifactItem item : items ) @@ -268,6 +292,8 @@ public void testCopyToLocation() public void testLink() throws Exception { + assumeTrue("supports symbolic links", supportsSymbolicLinks); + List list = stubFactory.getArtifactItems( stubFactory.getClassifiedArtifacts() ); mojo.setArtifactItems( createArtifactItemArtifacts( list ) );