From 4dbab72195c13cc63d20bbceaadb3d86d5c55b14 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 12 Jul 2022 15:11:07 +0200 Subject: [PATCH] [MINSTALL-177] Streamline the plugin (#32) Original plugin made hoops and loops, instead to perform what it needed to perform. Partly to blame this was unfinished state of MAT API (it was able to install project only). Installing project is needed in InstallMojo, but InstallFileMojo was forced to make hoops and loops due this, as it was passed one file (and maybe pomFile), and it was forced to create "fake" project, decorate and fake setup it with all whistle and bells, only to get it via MAT to resolver that would "decompose" it back into set of artifacts needing a deploy. So it went this file-artifact-project-artifact route, that made all the logic fragile and overly complicated. This PR completely reworks m-install-p making it (almost trivially) simple: it does what it needs to do, without any fuss, and does it in streamlined way: InstallMojo will create a list of artifacts out of project and pass it to repository system for deploy, while InstallFileMojo literally prepares just a deployment request, nothing more. No fuss, no magic, no fake project building etc. Note: the code in mojos may or may not need to be reusable, but definitely smells like some "Maven API-ish thing". Problems: InstallFileMojo implicitly implemented ID validation (thru fake project building), and it revealed the problem that Maven ID (groupId, artifactId) and version validation is deeply buried into maven-model-builder and is NOT reusable at all, hence a light copy of logic (rules for ID allowed characters and version forbidden characters) are copied over here. --- pom.xml | 35 +- .../invoker.properties | 18 + .../install-file-minstall-121-targz/pom.xml | 46 +++ .../install-file-minstall-121-targz/setup.bsh | 29 ++ .../test-0.1.pom | 35 ++ .../test-0.1.tar.gz | Bin 0 -> 345 bytes .../test.properties | 20 ++ .../verify.bsh | 52 +++ .../plugins/install/AbstractInstallMojo.java | 76 ----- .../plugins/install/InstallFileMojo.java | 308 ++++++++++-------- .../maven/plugins/install/InstallMojo.java | 121 +++++-- .../plugins/install/InstallFileMojoTest.java | 9 +- .../plugins/install/InstallMojoTest.java | 33 +- 13 files changed, 500 insertions(+), 282 deletions(-) create mode 100644 src/it/install-file-minstall-121-targz/invoker.properties create mode 100644 src/it/install-file-minstall-121-targz/pom.xml create mode 100644 src/it/install-file-minstall-121-targz/setup.bsh create mode 100644 src/it/install-file-minstall-121-targz/test-0.1.pom create mode 100644 src/it/install-file-minstall-121-targz/test-0.1.tar.gz create mode 100644 src/it/install-file-minstall-121-targz/test.properties create mode 100644 src/it/install-file-minstall-121-targz/verify.bsh delete mode 100644 src/main/java/org/apache/maven/plugins/install/AbstractInstallMojo.java diff --git a/pom.xml b/pom.xml index 7430747..e556d80 100644 --- a/pom.xml +++ b/pom.xml @@ -63,10 +63,10 @@ - 3.2.5 - 1.7.32 - 1.1.0 7 + 3.2.5 + 1.0.0.v20140518 + 1.7.5 2020-04-07T21:04:00Z @@ -97,9 +97,20 @@ provided - org.apache.maven.shared - maven-artifact-transfer - 0.13.1 + org.eclipse.aether + aether-api + ${aetherVersion} + provided + + + org.eclipse.aether + aether-util + ${aetherVersion} + compile + + + org.codehaus.plexus + plexus-utils @@ -145,18 +156,6 @@ ${slf4jVersion} test - - org.eclipse.aether - aether-api - ${aetherVersion} - test - - - org.eclipse.aether - aether-util - ${aetherVersion} - test - org.eclipse.aether aether-impl diff --git a/src/it/install-file-minstall-121-targz/invoker.properties b/src/it/install-file-minstall-121-targz/invoker.properties new file mode 100644 index 0000000..0413238 --- /dev/null +++ b/src/it/install-file-minstall-121-targz/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 = org.apache.maven.plugins:maven-install-plugin:${project.version}:install-file diff --git a/src/it/install-file-minstall-121-targz/pom.xml b/src/it/install-file-minstall-121-targz/pom.xml new file mode 100644 index 0000000..72009e3 --- /dev/null +++ b/src/it/install-file-minstall-121-targz/pom.xml @@ -0,0 +1,46 @@ + + + + + + 4.0.0 + + org.apache.maven.its.install.121 + test-targz + 1.0 + jar + + + Test to install a file via install:install-file using + packaging and expected having a different file extension. + + + + + + org.apache.maven.plugins + maven-install-plugin + @project.version@ + + + + + diff --git a/src/it/install-file-minstall-121-targz/setup.bsh b/src/it/install-file-minstall-121-targz/setup.bsh new file mode 100644 index 0000000..44849e7 --- /dev/null +++ b/src/it/install-file-minstall-121-targz/setup.bsh @@ -0,0 +1,29 @@ +/* + * 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.io.*; +import java.util.*; + +import org.codehaus.plexus.util.*; + +File file = new File( localRepositoryPath, "org/apache/maven/its/install/121/test-targz" ); +System.out.println( "Deleting " + file ); +FileUtils.deleteDirectory( file ); + +return true; diff --git a/src/it/install-file-minstall-121-targz/test-0.1.pom b/src/it/install-file-minstall-121-targz/test-0.1.pom new file mode 100644 index 0000000..fe478fe --- /dev/null +++ b/src/it/install-file-minstall-121-targz/test-0.1.pom @@ -0,0 +1,35 @@ + + + + + + 4.0.0 + + + org.apache.maven.its.install.121 + parent + 1.0 + + + + test-targz + + diff --git a/src/it/install-file-minstall-121-targz/test-0.1.tar.gz b/src/it/install-file-minstall-121-targz/test-0.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..226277c382b503bdef6c6df3250c49e7f3790a61 GIT binary patch literal 345 zcmWIWW@Zs#-~d9YP4g`okN_tG3xls~h@-BjpPT-_Qw$8u3<2Kk93T};P-Ou)HH!dM zz%~0i`gyv!28ZbRx_$ONbK1vSSMMUPx31Q?Gv_x48C)@b@U%$J%U8$K_hRWP7S0(j zC67qY(9U3){!H^nnwt1i@o=%}OP+~oS3FaFo%yNgV-X|RA;MFlZ@2@k0pS2|MkWyk vRDZx63GxRjfIAH2D|D^M#)5o-0JcCTTq}~F0=!w-K&qI4uog%k192Dt?J7l_ literal 0 HcmV?d00001 diff --git a/src/it/install-file-minstall-121-targz/test.properties b/src/it/install-file-minstall-121-targz/test.properties new file mode 100644 index 0000000..8485d14 --- /dev/null +++ b/src/it/install-file-minstall-121-targz/test.properties @@ -0,0 +1,20 @@ +# 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. + +file = test-0.1.tar.gz +pomFile = test-0.1.pom +packaging = war diff --git a/src/it/install-file-minstall-121-targz/verify.bsh b/src/it/install-file-minstall-121-targz/verify.bsh new file mode 100644 index 0000000..b3f31de --- /dev/null +++ b/src/it/install-file-minstall-121-targz/verify.bsh @@ -0,0 +1,52 @@ +/* + * 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.io.*; +import java.util.*; + +String[] paths = +{ + "org/apache/maven/its/install/121/test-targz/maven-metadata-local.xml", + "org/apache/maven/its/install/121/test-targz/1.0/test-targz-1.0.pom", + "org/apache/maven/its/install/121/test-targz/1.0/test-targz-1.0.tar.gz", +}; + +for ( String path : paths ) +{ + File file = new File( localRepositoryPath, path ); + System.out.println( "Checking for existence of " + file ); + if ( !file.isFile() ) + { + throw new FileNotFoundException( "Missing: " + file.getAbsolutePath() ); + } +} + +File file = new File( basedir, "test-0.1.pom" ); +if ( !file.isFile() ) +{ + throw new FileNotFoundException( "Missing: " + file.getAbsolutePath() ); +} + +File file = new File( basedir, "test-0.1.tar.gz" ); +if ( !file.isFile() ) +{ + throw new FileNotFoundException( "Missing: " + file.getAbsolutePath() ); +} + +return true; diff --git a/src/main/java/org/apache/maven/plugins/install/AbstractInstallMojo.java b/src/main/java/org/apache/maven/plugins/install/AbstractInstallMojo.java deleted file mode 100644 index 96d0f53..0000000 --- a/src/main/java/org/apache/maven/plugins/install/AbstractInstallMojo.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.apache.maven.plugins.install; - -/* - * 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.io.File; - -import org.apache.maven.artifact.Artifact; -import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugins.annotations.Component; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.project.ProjectBuildingRequest; -import org.apache.maven.project.artifact.ProjectArtifactMetadata; -import org.apache.maven.shared.transfer.repository.RepositoryManager; - -/** - * Common fields for installation mojos. - * - * @author Brett Porter - */ -public abstract class AbstractInstallMojo - extends AbstractMojo -{ - - @Component - protected RepositoryManager repositoryManager; - - @Parameter( defaultValue = "${session}", required = true, readonly = true ) - protected MavenSession session; - - /** - * Gets the path of the specified artifact within the local repository. Note that the returned path need not exist - * (yet). - * - * @param buildingRequest {@link ProjectBuildingRequest}. - * @param artifact The artifact whose local repo path should be determined, must not be null. - * @return The absolute path to the artifact when installed, never null. - */ - protected File getLocalRepoFile( ProjectBuildingRequest buildingRequest, Artifact artifact ) - { - String path = repositoryManager.getPathForLocalArtifact( buildingRequest, artifact ); - return new File( repositoryManager.getLocalRepositoryBasedir( buildingRequest ), path ); - } - - /** - * Gets the path of the specified artifact metadata within the local repository. Note that the returned path need - * not exist (yet). - * - * @param buildingRequest {@link ProjectBuildingRequest}. - * @param metadata The artifact metadata whose local repo path should be determined, must not be null. - * @return The absolute path to the artifact metadata when installed, never null. - */ - protected File getLocalRepoFile( ProjectBuildingRequest buildingRequest, ProjectArtifactMetadata metadata ) - { - String path = repositoryManager.getPathForLocalMetadata( buildingRequest, metadata ); - return new File( repositoryManager.getLocalRepositoryBasedir( buildingRequest ), path ); - } - -} diff --git a/src/main/java/org/apache/maven/plugins/install/InstallFileMojo.java b/src/main/java/org/apache/maven/plugins/install/InstallFileMojo.java index 32865b2..aab859f 100644 --- a/src/main/java/org/apache/maven/plugins/install/InstallFileMojo.java +++ b/src/main/java/org/apache/maven/plugins/install/InstallFileMojo.java @@ -21,46 +21,46 @@ import java.io.File; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; +import java.nio.file.Files; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.regex.Pattern; -import org.apache.maven.artifact.Artifact; -import org.apache.maven.artifact.handler.DefaultArtifactHandler; +import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Model; import org.apache.maven.model.Parent; -import org.apache.maven.model.building.ModelBuildingException; -import org.apache.maven.model.building.ModelSource; -import org.apache.maven.model.building.StringModelSource; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.apache.maven.model.io.xpp3.MavenXpp3Writer; +import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.project.DefaultProjectBuildingRequest; -import org.apache.maven.project.MavenProject; -import org.apache.maven.project.MavenProjectHelper; -import org.apache.maven.project.ProjectBuilder; -import org.apache.maven.project.ProjectBuildingException; -import org.apache.maven.project.ProjectBuildingRequest; -import org.apache.maven.project.artifact.ProjectArtifactMetadata; -import org.apache.maven.shared.transfer.project.install.ProjectInstaller; -import org.apache.maven.shared.transfer.project.install.ProjectInstallerRequest; -import org.apache.maven.shared.utils.Os; -import org.apache.maven.shared.utils.ReaderFactory; -import org.apache.maven.shared.utils.WriterFactory; -import org.apache.maven.shared.utils.io.IOUtil; import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.StringUtils; +import org.codehaus.plexus.util.xml.XmlStreamReader; +import org.codehaus.plexus.util.xml.XmlStreamWriter; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.eclipse.aether.DefaultRepositoryCache; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.ArtifactType; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.installation.InstallRequest; +import org.eclipse.aether.installation.InstallationException; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.LocalRepositoryManager; +import org.eclipse.aether.util.artifact.SubArtifact; /** * Installs a file in the local repository. @@ -69,8 +69,15 @@ */ @Mojo( name = "install-file", requiresProject = false, aggregator = true, threadSafe = true ) public class InstallFileMojo - extends AbstractInstallMojo + extends AbstractMojo { + private static final String LS = System.getProperty( "line.separator" ); + + @Component + private RepositorySystem repositorySystem; + + @Parameter( defaultValue = "${session}", required = true, readonly = true ) + private MavenSession session; /** * GroupId of the artifact to be installed. Retrieved from POM file if one is specified or extracted from @@ -158,31 +165,10 @@ public class InstallFileMojo @Parameter( property = "localRepositoryPath" ) private File localRepositoryPath; - /** - * Used for attaching the artifacts to install to the project. - */ - @Component - private MavenProjectHelper projectHelper; - - /** - * Used for creating the project to which the artifacts to install will be attached. - */ - @Component - private ProjectBuilder projectBuilder; - - /** - * Used to install the project created. - */ - @Component - private ProjectInstaller installer; - - /** - * @see org.apache.maven.plugin.Mojo#execute() - */ + @Override public void execute() throws MojoExecutionException, MojoFailureException { - if ( !file.exists() ) { String message = "The specified file '" + file.getPath() + "' does not exist"; @@ -190,16 +176,25 @@ public void execute() throw new MojoFailureException( message ); } - ProjectBuildingRequest buildingRequest = session.getProjectBuildingRequest(); - - // ---------------------------------------------------------------------- - // Override the default localRepository variable - // ---------------------------------------------------------------------- + RepositorySystemSession repositorySystemSession = session.getRepositorySession(); if ( localRepositoryPath != null ) { - buildingRequest = repositoryManager.setLocalRepositoryBasedir( buildingRequest, localRepositoryPath ); - - getLog().debug( "localRepoPath: " + repositoryManager.getLocalRepositoryBasedir( buildingRequest ) ); + // "clone" repository session and replace localRepository + DefaultRepositorySystemSession newSession = new DefaultRepositorySystemSession( + session.getRepositorySession() ); + // Clear cache, since we're using a new local repository + newSession.setCache( new DefaultRepositoryCache() ); + // keep same repositoryType + String contentType = newSession.getLocalRepository().getContentType(); + if ( "enhanced".equals( contentType ) ) + { + contentType = "default"; + } + LocalRepositoryManager localRepositoryManager = repositorySystem.newLocalRepositoryManager( newSession, + new LocalRepository( localRepositoryPath, contentType ) ); + newSession.setLocalRepositoryManager( localRepositoryManager ); + repositorySystemSession = newSession; + getLog().debug( "localRepoPath: " + localRepositoryManager.getRepository().getBasedir() ); } File temporaryPom = null; @@ -214,65 +209,63 @@ public void execute() pomFile = temporaryPom; } - MavenProject project = createMavenProject(); - - // We need to set a new ArtifactHandler otherwise - // the extension will be set to the packaging type - // which is sometimes wrong. - DefaultArtifactHandler ah = new DefaultArtifactHandler( packaging ); - ah.setExtension( FileUtils.getExtension( file.getName() ) ); - - project.getArtifact().setArtifactHandler( ah ); - Artifact artifact = project.getArtifact(); + if ( groupId == null || artifactId == null || version == null || packaging == null ) + { + throw new MojoExecutionException( "The artifact information is incomplete: 'groupId', 'artifactId', " + + "'version' and 'packaging' are required." ); + } - if ( file.equals( getLocalRepoFile( buildingRequest, artifact ) ) ) + if ( !isValidId( groupId ) + || !isValidId( artifactId ) + || !isValidVersion( version ) ) { - throw new MojoFailureException( "Cannot install artifact. " - + "Artifact is already in the local repository.\n\nFile in question is: " + file + "\n" ); + throw new MojoExecutionException( "The artifact information is not valid: uses invalid characters." ); } - if ( classifier == null ) + InstallRequest installRequest = new InstallRequest(); + + boolean isFilePom = classifier == null && "pom".equals( packaging ); + if ( !isFilePom ) { - artifact.setFile( file ); - if ( "pom".equals( packaging ) ) + ArtifactType artifactType = repositorySystemSession.getArtifactTypeRegistry().get( packaging ); + if ( artifactType != null + && StringUtils.isEmpty( classifier ) + && !StringUtils.isEmpty( artifactType.getClassifier() ) ) { - project.setFile( file ); + classifier = artifactType.getClassifier(); } } - else + Artifact mainArtifact = new DefaultArtifact( + groupId, + artifactId, + classifier, + isFilePom ? "pom" : getExtension( file ), + version + ).setFile( file ); + installRequest.addArtifact( mainArtifact ); + + File artifactLocalFile = getLocalRepositoryFile( session.getRepositorySession(), mainArtifact ); + File pomLocalFile = getPomLocalRepositoryFile( session.getRepositorySession(), mainArtifact ); + + if ( file.equals( artifactLocalFile ) ) { - projectHelper.attachArtifact( project, packaging, classifier, file ); + throw new MojoFailureException( "Cannot install artifact. " + + "Artifact is already in the local repository." + LS + LS + "File in question is: " + file + LS ); } if ( !"pom".equals( packaging ) ) { if ( pomFile != null ) { - if ( classifier == null ) - { - artifact.addMetadata( new ProjectArtifactMetadata( artifact, pomFile ) ); - } - else - { - project.setFile( pomFile ); - } + installRequest.addArtifact( new SubArtifact( mainArtifact, "", "pom", pomFile ) ); } else { - temporaryPom = generatePomFile(); - ProjectArtifactMetadata pomMetadata = new ProjectArtifactMetadata( artifact, temporaryPom ); - if ( Boolean.TRUE.equals( generatePom ) - || ( generatePom == null && !getLocalRepoFile( buildingRequest, pomMetadata ).exists() ) ) + if ( Boolean.TRUE.equals( generatePom ) || ( generatePom == null && !pomLocalFile.exists() ) ) { + temporaryPom = generatePomFile(); getLog().debug( "Installing generated POM" ); - if ( classifier == null ) - { - artifact.addMetadata( pomMetadata ); - } - else - { - project.setFile( temporaryPom ); - } + installRequest.addArtifact( new SubArtifact( mainArtifact, "", "pom", temporaryPom ) ); } else if ( generatePom == null ) { @@ -283,24 +276,19 @@ else if ( generatePom == null ) if ( sources != null ) { - projectHelper.attachArtifact( project, "jar", "sources", sources ); + installRequest.addArtifact( new SubArtifact( mainArtifact, "sources", "jar", sources ) ); } if ( javadoc != null ) { - projectHelper.attachArtifact( project, "jar", "javadoc", javadoc ); + installRequest.addArtifact( new SubArtifact( mainArtifact, "javadoc", "jar", javadoc ) ); } try { - // CHECKSTYLE_OFF: LineLength - ProjectInstallerRequest projectInstallerRequest = - new ProjectInstallerRequest().setProject( project ); - // CHECKSTYLE_ON: LineLength - - installer.install( buildingRequest, projectInstallerRequest ); + repositorySystem.install( repositorySystemSession, installRequest ); } - catch ( Exception e ) + catch ( InstallationException e ) { throw new MojoExecutionException( e.getMessage(), e ); } @@ -314,43 +302,6 @@ else if ( generatePom == null ) } } - /** - * Creates a Maven project in-memory from the user-supplied groupId, artifactId and version. When a classifier is - * supplied, the packaging must be POM because the project with only have attachments. This project serves as basis - * to attach the artifacts to install to. - * - * @return The created Maven project, never null. - * @throws MojoExecutionException When the model of the project could not be built. - * @throws MojoFailureException When building the project failed. - */ - private MavenProject createMavenProject() - throws MojoExecutionException, MojoFailureException - { - if ( groupId == null || artifactId == null || version == null || packaging == null ) - { - throw new MojoExecutionException( "The artifact information is incomplete: 'groupId', 'artifactId', " - + "'version' and 'packaging' are required." ); - } - ModelSource modelSource = new StringModelSource( "4.0.0" - + groupId + "" + artifactId + "" + version - + "" + ( classifier == null ? packaging : "pom" ) + "" ); - ProjectBuildingRequest pbr = new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() ); - pbr.setProcessPlugins( false ); - try - { - return projectBuilder.build( modelSource, pbr ).getProject(); - } - catch ( ProjectBuildingException e ) - { - if ( e.getCause() instanceof ModelBuildingException ) - { - throw new MojoExecutionException( "The artifact information is not valid:" + Os.LINE_SEP - + e.getCause().getMessage() ); - } - throw new MojoFailureException( "Unable to create the project.", e ); - } - } - private File readingPomFromJarFile() throws MojoExecutionException { @@ -387,7 +338,7 @@ private File readingPomFromJarFile() } pomFile = File.createTempFile( base, ".pom" ); - pomOutputStream = new FileOutputStream( pomFile ); + pomOutputStream = Files.newOutputStream( pomFile.toPath() ); IOUtil.copy( pomInputStream, pomOutputStream ); @@ -448,7 +399,7 @@ private Model readModel( File pomFile ) Reader reader = null; try { - reader = ReaderFactory.newXmlReader( pomFile ); + reader = new XmlStreamReader( pomFile ); final Model model = new MavenXpp3Reader().read( reader ); reader.close(); reader = null; @@ -545,7 +496,7 @@ private File generatePomFile() { File pomFile = File.createTempFile( "mvninstall", ".pom" ); - writer = WriterFactory.newXmlWriter( pomFile ); + writer = new XmlStreamWriter( pomFile ); new MavenXpp3Writer().write( writer, model ); writer.close(); writer = null; @@ -562,4 +513,85 @@ private File generatePomFile() } } + /** + * Gets the path of the specified artifact within the local repository. Note that the returned path need not exist + * (yet). + */ + private File getLocalRepositoryFile( RepositorySystemSession session, Artifact artifact ) + { + String path = session.getLocalRepositoryManager().getPathForLocalArtifact( artifact ); + return new File( session.getLocalRepository().getBasedir(), path ); + } + + /** + * Gets the path of the specified artifact POM within the local repository. Note that the returned path need + * not exist (yet). + */ + private File getPomLocalRepositoryFile( RepositorySystemSession session, Artifact artifact ) + { + SubArtifact pomArtifact = new SubArtifact( artifact, "", "pom" ); + String path = session.getLocalRepositoryManager().getPathForLocalArtifact( pomArtifact ); + return new File( session.getLocalRepository().getBasedir(), path ); + } + + // these below should be shared (duplicated in m-install-p, m-deploy-p) + + /** + * Specialization of {@link FileUtils#getExtension(String)} that honors various {@code tar.xxx} combinations. + */ + private String getExtension( final File file ) + { + String filename = file.getName(); + if ( filename.contains( ".tar." ) ) + { + return "tar." + FileUtils.getExtension( filename ); + } + else + { + return FileUtils.getExtension( filename ); + } + } + + /** + * Returns {@code true} if passed in string is "valid Maven ID" (groupId or artifactId). + */ + private boolean isValidId( String id ) + { + if ( id == null ) + { + return false; + } + for ( int i = 0; i < id.length(); i++ ) + { + char c = id.charAt( i ); + if ( !( c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' + || c >= '0' && c <= '9' || c == '-' || c == '_' || c == '.' ) ) + { + return false; + } + } + return true; + } + + private static final String ILLEGAL_VERSION_CHARS = "\\/:\"<>|?*[](){},"; + + /** + * Returns {@code true} if passed in string is "valid Maven (simple. non range, expression, etc) version". + */ + private boolean isValidVersion( String version ) + { + if ( version == null ) + { + return false; + } + for ( int i = version.length() - 1; i >= 0; i-- ) + { + if ( ILLEGAL_VERSION_CHARS.indexOf( version.charAt( i ) ) >= 0 ) + { + return false; + } + } + return true; + } + } diff --git a/src/main/java/org/apache/maven/plugins/install/InstallMojo.java b/src/main/java/org/apache/maven/plugins/install/InstallMojo.java index 8ea2f30..a6c694b 100644 --- a/src/main/java/org/apache/maven/plugins/install/InstallMojo.java +++ b/src/main/java/org/apache/maven/plugins/install/InstallMojo.java @@ -19,10 +19,13 @@ * under the License. */ -import java.io.IOException; +import java.io.File; import java.util.List; import java.util.Map; +import org.apache.maven.RepositoryUtils; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.descriptor.PluginDescriptor; @@ -31,10 +34,13 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; -import org.apache.maven.shared.transfer.artifact.install.ArtifactInstallerException; -import org.apache.maven.shared.transfer.project.NoFileAssignedException; -import org.apache.maven.shared.transfer.project.install.ProjectInstaller; -import org.apache.maven.shared.transfer.project.install.ProjectInstallerRequest; +import org.apache.maven.project.artifact.ProjectArtifact; +import org.apache.maven.project.artifact.ProjectArtifactMetadata; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.installation.InstallRequest; +import org.eclipse.aether.installation.InstallationException; +import org.eclipse.aether.util.artifact.SubArtifact; /** * Installs the project's main artifact, and any other artifacts attached by other plugins in the lifecycle, to the @@ -44,8 +50,14 @@ */ @Mojo( name = "install", defaultPhase = LifecyclePhase.INSTALL, threadSafe = true ) public class InstallMojo - extends AbstractInstallMojo + extends AbstractMojo { + @Component + private RepositorySystem repositorySystem; + + @Parameter( defaultValue = "${session}", required = true, readonly = true ) + private MavenSession session; + @Parameter( defaultValue = "${project}", readonly = true, required = true ) private MavenProject project; @@ -74,9 +86,6 @@ public class InstallMojo @Parameter( property = "maven.install.skip", defaultValue = "false" ) private boolean skip; - @Component - private ProjectInstaller installer; - private enum State { SKIPPED, INSTALLED, TO_BE_INSTALLED @@ -101,6 +110,7 @@ private boolean hasState( MavenProject project ) return pluginContext.containsKey( INSTALL_PROCESSED_MARKER ); } + @Override public void execute() throws MojoExecutionException, MojoFailureException { @@ -118,7 +128,8 @@ public void execute() } else { - getLog().info( "Deferring install for " + getProjectReferenceId( project ) + " at end" ); + getLog().info( "Deferring install for " + project.getGroupId() + + ":" + project.getArtifactId() + ":" + project.getVersion() + " at end" ); putState( State.TO_BE_INSTALLED ); } } @@ -136,11 +147,6 @@ public void execute() } } - private String getProjectReferenceId( MavenProject mavenProject ) - { - return mavenProject.getGroupId() + ":" + mavenProject.getArtifactId() + ":" + mavenProject.getVersion(); - } - private boolean allProjectsMarked() { for ( MavenProject reactorProject : reactorProjects ) @@ -153,31 +159,90 @@ private boolean allProjectsMarked() return true; } - private void installProject( MavenProject pir ) - throws MojoFailureException, MojoExecutionException + private void installProject( MavenProject project ) throws MojoExecutionException, MojoFailureException { try { - installer.install( session.getProjectBuildingRequest(), new ProjectInstallerRequest().setProject( pir ) ); + repositorySystem.install( session.getRepositorySession(), processProject( project ) ); } - catch ( IOException e ) + catch ( IllegalArgumentException e ) { - throw new MojoFailureException( "IOException", e ); + throw new MojoFailureException( e.getMessage(), e ); } - catch ( ArtifactInstallerException e ) + catch ( InstallationException e ) { - throw new MojoExecutionException( "ArtifactInstallerException", e ); + throw new MojoExecutionException( e.getMessage(), e ); } - catch ( NoFileAssignedException e ) + } + + /** + * Processes passed in {@link MavenProject} and produces {@link InstallRequest} out of it. + * + * @throws IllegalArgumentException if project is badly set up. + */ + private InstallRequest processProject( MavenProject project ) + { + InstallRequest request = new InstallRequest(); + org.apache.maven.artifact.Artifact mavenMainArtifact = project.getArtifact(); + String packaging = project.getPackaging(); + File pomFile = project.getFile(); + boolean isPomArtifact = "pom".equals( packaging ); + boolean pomArtifactAttached = false; + + if ( pomFile != null ) { - throw new MojoExecutionException( "NoFileAssignedException", e ); + request.addArtifact( RepositoryUtils.toArtifact( new ProjectArtifact( project ) ) ); + pomArtifactAttached = true; } - } + if ( !isPomArtifact ) + { + File file = mavenMainArtifact.getFile(); + if ( file != null && file.isFile() ) + { + Artifact mainArtifact = RepositoryUtils.toArtifact( mavenMainArtifact ); + request.addArtifact( mainArtifact ); - public void setSkip( boolean skip ) - { - this.skip = skip; + if ( !pomArtifactAttached ) + { + for ( Object metadata : mavenMainArtifact.getMetadataList() ) + { + if ( metadata instanceof ProjectArtifactMetadata ) + { + request.addArtifact( new SubArtifact( + mainArtifact, + "", + "pom" + ).setFile( ( (ProjectArtifactMetadata) metadata ).getFile() ) ); + pomArtifactAttached = true; + } + } + } + } + else if ( !project.getAttachedArtifacts().isEmpty() ) + { + throw new IllegalArgumentException( "The packaging plugin for this project did not assign " + + "a main file to the project but it has attachments. Change packaging to 'pom'." ); + } + else + { + throw new IllegalArgumentException( "The packaging for this project did not assign " + + "a file to the build artifact" ); + } + } + + if ( !pomArtifactAttached ) + { + throw new IllegalArgumentException( "The POM could not be attached" ); + } + + for ( org.apache.maven.artifact.Artifact attached : project.getAttachedArtifacts() ) + { + getLog().debug( "Attaching for install: " + attached.getId() ); + request.addArtifact( RepositoryUtils.toArtifact( attached ) ); + } + + return request; } } diff --git a/src/test/java/org/apache/maven/plugins/install/InstallFileMojoTest.java b/src/test/java/org/apache/maven/plugins/install/InstallFileMojoTest.java index bf040b1..c135d95 100644 --- a/src/test/java/org/apache/maven/plugins/install/InstallFileMojoTest.java +++ b/src/test/java/org/apache/maven/plugins/install/InstallFileMojoTest.java @@ -28,8 +28,8 @@ import org.apache.maven.plugin.testing.AbstractMojoTestCase; import org.apache.maven.project.DefaultProjectBuildingRequest; import org.apache.maven.project.ProjectBuildingRequest; -import org.apache.maven.shared.utils.ReaderFactory; -import org.apache.maven.shared.utils.io.FileUtils; +import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.xml.XmlStreamReader; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory; import org.eclipse.aether.repository.LocalRepository; @@ -159,7 +159,7 @@ public void testInstallFileWithGeneratePom() File installedPom = new File( getBasedir(), LOCAL_REPO + groupId + "/" + artifactId + "/" + version + "/" + artifactId + "-" + version + "." + "pom" ); - try ( Reader reader = ReaderFactory.newXmlReader( installedPom ) ) { + try ( Reader reader = new XmlStreamReader( installedPom ) ) { Model model = new MavenXpp3Reader().read( reader ); assertEquals( "4.0.0", model.getModelVersion() ); @@ -258,7 +258,7 @@ public void testInstallFile() assertTrue( installedArtifact.exists() ); - assertEquals( 5, FileUtils.getFiles( new File( LOCAL_REPO ), null, null ).size() ); + assertEquals( FileUtils.getFiles( new File( LOCAL_REPO ), null, null ).toString(), 5, FileUtils.getFiles( new File( LOCAL_REPO ), null, null ).size() ); } private void assignValuesForParameter( Object obj ) @@ -294,6 +294,7 @@ repositorySession, new LocalRepository( LOCAL_REPO ) ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest(); buildingRequest.setRepositorySession( repositorySession ); when( session.getProjectBuildingRequest() ).thenReturn( buildingRequest ); + when( session.getRepositorySession() ).thenReturn( repositorySession ); return session; } } diff --git a/src/test/java/org/apache/maven/plugins/install/InstallMojoTest.java b/src/test/java/org/apache/maven/plugins/install/InstallMojoTest.java index 1347e4b..57fe471 100644 --- a/src/test/java/org/apache/maven/plugins/install/InstallMojoTest.java +++ b/src/test/java/org/apache/maven/plugins/install/InstallMojoTest.java @@ -31,7 +31,9 @@ import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.metadata.ArtifactMetadata; import org.apache.maven.execution.MavenSession; +import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.plugin.testing.AbstractMojoTestCase; import org.apache.maven.plugins.install.stubs.AttachedArtifactStub0; @@ -39,9 +41,9 @@ import org.apache.maven.project.DefaultProjectBuildingRequest; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuildingRequest; -import org.apache.maven.shared.transfer.repository.RepositoryManager; -import org.apache.maven.shared.utils.io.FileUtils; +import org.codehaus.plexus.util.FileUtils; import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.NoLocalRepositoryManagerException; @@ -71,7 +73,7 @@ public void testInstallTestEnvironment() { File testPom = new File( getBasedir(), "target/test-classes/unit/basic-install-test/plugin-config.xml" ); - AbstractInstallMojo mojo = (AbstractInstallMojo) lookupMojo( "install", testPom ); + AbstractMojo mojo = (AbstractMojo) lookupMojo( "install", testPom ); assertNotNull( mojo ); } @@ -81,7 +83,7 @@ public void testBasicInstall() { File testPom = new File( getBasedir(), "target/test-classes/unit/basic-install-test/plugin-config.xml" ); - AbstractInstallMojo mojo = (AbstractInstallMojo) lookupMojo( "install", testPom ); + AbstractMojo mojo = (AbstractMojo) lookupMojo( "install", testPom ); assertNotNull( mojo ); @@ -118,7 +120,7 @@ public void testBasicInstallWithAttachedArtifacts() File testPom = new File( getBasedir(), "target/test-classes/unit/basic-install-test-with-attached-artifacts/" + "plugin-config.xml" ); - AbstractInstallMojo mojo = (AbstractInstallMojo) lookupMojo( "install", testPom ); + AbstractMojo mojo = (AbstractMojo) lookupMojo( "install", testPom ); assertNotNull( mojo ); @@ -159,7 +161,7 @@ public void testUpdateReleaseParamSetToTrue() { File testPom = new File( getBasedir(), "target/test-classes/unit/configured-install-test/plugin-config.xml" ); - AbstractInstallMojo mojo = (AbstractInstallMojo) lookupMojo( "install", testPom ); + AbstractMojo mojo = (AbstractMojo) lookupMojo( "install", testPom ); assertNotNull( mojo ); @@ -190,7 +192,7 @@ public void testInstallIfArtifactFileIsNull() { File testPom = new File( getBasedir(), "target/test-classes/unit/basic-install-test/plugin-config.xml" ); - AbstractInstallMojo mojo = (AbstractInstallMojo) lookupMojo( "install", testPom ); + AbstractMojo mojo = (AbstractMojo) lookupMojo( "install", testPom ); assertNotNull( mojo ); @@ -214,7 +216,7 @@ public void testInstallIfArtifactFileIsNull() fail( "Did not throw mojo execution exception" ); } - catch ( MojoExecutionException e ) + catch ( MojoFailureException e ) { //expected } @@ -228,7 +230,7 @@ public void testInstallIfPackagingIsPom() File testPom = new File( getBasedir(), "target/test-classes/unit/basic-install-test-packaging-pom/" + "plugin-config.xml" ); - AbstractInstallMojo mojo = (AbstractInstallMojo) lookupMojo( "install", testPom ); + AbstractMojo mojo = (AbstractMojo) lookupMojo( "install", testPom ); assertNotNull( mojo ); @@ -263,7 +265,7 @@ public void testBasicInstallAndCreate() { File testPom = new File( getBasedir(), "target/test-classes/unit/basic-install-checksum/plugin-config.xml" ); - AbstractInstallMojo mojo = (AbstractInstallMojo) lookupMojo( "install", testPom ); + AbstractMojo mojo = (AbstractMojo) lookupMojo( "install", testPom ); assertNotNull( mojo ); @@ -294,12 +296,7 @@ public void testBasicInstallAndCreate() } } - RepositoryManager repoManager = (RepositoryManager) getVariableValueFromObject( mojo, "repositoryManager" ); - - ProjectBuildingRequest pbr = mavenSession.getProjectBuildingRequest(); - - File pom = new File( repoManager.getLocalRepositoryBasedir( pbr ), - repoManager.getPathForLocalMetadata( pbr, metadata ) ); + File pom = new File( new File( LOCAL_REPO ), mavenSession.getRepositorySession().getLocalRepositoryManager().getPathForLocalArtifact( new DefaultArtifact( artifact.getGroupId(), artifact.getArtifactId(), "pom", artifact.getVersion() ) ) ); assertTrue( pom.exists() ); @@ -335,13 +332,12 @@ public void testSkip() setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() ); setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) ); setVariableValueToObject( mojo, "session", createMavenSession() ); + setVariableValueToObject( mojo, "skip", Boolean.TRUE ); artifact = (InstallArtifactStub) project.getArtifact(); artifact.setFile( file ); - mojo.setSkip( true ); - mojo.execute(); String groupId = dotToSlashReplacer( artifact.getGroupId() ); @@ -374,6 +370,7 @@ repositorySession, new LocalRepository( LOCAL_REPO ) ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest(); buildingRequest.setRepositorySession( repositorySession ); when( session.getProjectBuildingRequest() ).thenReturn( buildingRequest ); + when( session.getRepositorySession() ).thenReturn( repositorySession ); when( session.getPluginContext(any(PluginDescriptor.class), any(MavenProject.class))) .thenReturn( new ConcurrentHashMap() ); return session;