This is an automated email from the ASF dual-hosted git repository.

slachiewicz pushed a commit to branch MDEP-648
in repository https://gitbox.apache.org/repos/asf/maven-dependency-plugin.git

commit 2220ad90dc89cdb19d95d9cf5abb1ebf851935f6
Author: Pim Moerenhout <[email protected]>
AuthorDate: Tue May 5 23:49:04 2020 +0200

    MDEP-648: Add location of listed repository.
---
 pom.xml                                            |   9 +
 .../invoker.properties                             |  37 +--
 src/it/projects/list-repositories-verbose/pom.xml  |  47 +++
 .../list-repositories-verbose/verify.groovy        |  26 ++
 .../projects/list-repositories/invoker.properties  |   1 +
 src/it/projects/list-repositories/verify.groovy    |  26 ++
 .../dependency/resolvers/ListRepositoriesMojo.java | 327 ++++++++++++++++++++-
 src/site/apt/usage.apt.vm                          |  11 +
 8 files changed, 457 insertions(+), 27 deletions(-)

diff --git a/pom.xml b/pom.xml
index 4687c93..929c38a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -86,6 +86,9 @@ under the License.
     <contributor>
       <name>Maarten Mulders</name>
     </contributor>
+    <contributor>
+      <name>Pim Moerenhout</name>
+    </contributor>
   </contributors>
 
   <properties>
@@ -340,6 +343,12 @@ under the License.
         </exclusion>
       </exclusions>
     </dependency>
+    <dependency>
+      <groupId>org.apache.maven.wagon</groupId>
+      <artifactId>wagon-http-lightweight</artifactId>
+      <version>3.4.0</version>
+      <scope>provided</scope>
+    </dependency>
 
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
diff --git a/src/it/projects/list-repositories/invoker.properties 
b/src/it/projects/list-repositories-verbose/invoker.properties
similarity index 97%
copy from src/it/projects/list-repositories/invoker.properties
copy to src/it/projects/list-repositories-verbose/invoker.properties
index 6973bb1..48fda22 100644
--- a/src/it/projects/list-repositories/invoker.properties
+++ b/src/it/projects/list-repositories-verbose/invoker.properties
@@ -1,18 +1,19 @@
-# 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 = 
${project.groupId}:${project.artifactId}:${project.version}:list-repositories
+# 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 = 
${project.groupId}:${project.artifactId}:${project.version}:list-repositories
+invoker.debug = true
\ No newline at end of file
diff --git a/src/it/projects/list-repositories-verbose/pom.xml 
b/src/it/projects/list-repositories-verbose/pom.xml
new file mode 100644
index 0000000..9082485
--- /dev/null
+++ b/src/it/projects/list-repositories-verbose/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.its.dependency</groupId>
+  <artifactId>test</artifactId>
+  <version>1.0-SNAPSHOT</version>
+
+  <name>Test</name>
+  <description>
+    Test dependency:list-repositories
+  </description>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-project</artifactId>
+      <version>2.0.6</version>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/src/it/projects/list-repositories-verbose/verify.groovy 
b/src/it/projects/list-repositories-verbose/verify.groovy
new file mode 100644
index 0000000..68bdb6a
--- /dev/null
+++ b/src/it/projects/list-repositories-verbose/verify.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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 file = new File( basedir, "build.log" );
+assert file.exists();
+
+String buildLog = file.getText( "UTF-8" );
+assert buildLog.contains( 'location: Maven settings (user/global)' );
+
+return true;
diff --git a/src/it/projects/list-repositories/invoker.properties 
b/src/it/projects/list-repositories/invoker.properties
index 6973bb1..e79fcff 100644
--- a/src/it/projects/list-repositories/invoker.properties
+++ b/src/it/projects/list-repositories/invoker.properties
@@ -16,3 +16,4 @@
 # under the License.
 
 invoker.goals = 
${project.groupId}:${project.artifactId}:${project.version}:list-repositories
+invoker.debug = false
\ No newline at end of file
diff --git a/src/it/projects/list-repositories/verify.groovy 
b/src/it/projects/list-repositories/verify.groovy
new file mode 100644
index 0000000..cb10938
--- /dev/null
+++ b/src/it/projects/list-repositories/verify.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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 file = new File( basedir, "build.log" );
+assert file.exists();
+
+String buildLog = file.getText( "UTF-8" );
+assert !buildLog.contains( 'location:' );
+
+return true;
diff --git 
a/src/main/java/org/apache/maven/plugins/dependency/resolvers/ListRepositoriesMojo.java
 
b/src/main/java/org/apache/maven/plugins/dependency/resolvers/ListRepositoriesMojo.java
index deed8d3..f2fb18f 100644
--- 
a/src/main/java/org/apache/maven/plugins/dependency/resolvers/ListRepositoriesMojo.java
+++ 
b/src/main/java/org/apache/maven/plugins/dependency/resolvers/ListRepositoriesMojo.java
@@ -19,15 +19,36 @@ package org.apache.maven.plugins.dependency.resolvers;
  * under the License.
  */
 
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.plugin.MojoExecutionException;
 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.plugins.annotations.ResolutionScope;
 import org.apache.maven.plugins.dependency.AbstractDependencyMojo;
-import org.apache.maven.shared.transfer.dependencies.collect.CollectorResult;
-import 
org.apache.maven.shared.transfer.dependencies.collect.DependencyCollector;
-import 
org.apache.maven.shared.transfer.dependencies.collect.DependencyCollectorException;
+import org.apache.maven.project.DefaultProjectBuildingRequest;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.settings.Mirror;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.shared.transfer.artifact.ArtifactCoordinate;
+import org.apache.maven.shared.transfer.artifact.DefaultArtifactCoordinate;
+import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolver;
+import org.apache.maven.shared.transfer.collection.CollectResult;
+import 
org.apache.maven.shared.transfer.collection.DependencyCollectionException;
+import org.apache.maven.shared.transfer.collection.DependencyCollector;
+import org.apache.maven.shared.transfer.graph.DependencyNode;
+import org.apache.maven.shared.transfer.graph.DependencyVisitor;
 
 /**
  * Goal that resolves all project dependencies and then lists the repositories 
used by the build and by the transitive
@@ -41,12 +62,46 @@ public class ListRepositoriesMojo
     extends AbstractDependencyMojo
 {
     /**
+     * Maven Project Builder component.
+     */
+    @Component
+    private ProjectBuilder projectBuilder;
+
+    /**
      * Dependency collector, needed to resolve dependencies.
      */
     @Component( role = DependencyCollector.class )
     private DependencyCollector dependencyCollector;
 
     /**
+     * Component used to resolve artifacts and download their files from 
remote repositories.
+     */
+    @Component
+    private ArtifactResolver artifactResolver;
+
+    /**
+     * The system settings for Maven. This is the instance resulting from
+     * merging global and user-level settings files.
+     */
+    @Parameter( defaultValue = "${settings}", readonly = true, required = true 
)
+    private Settings settings;
+
+    /**
+     * Remote repositories used for the project.
+     */
+    @Parameter( defaultValue = "${project.remoteArtifactRepositories}", 
required = true, readonly = true )
+    private List<ArtifactRepository> remoteRepositories;
+
+    /**
+     * Sets whether the plugin runs in verbose mode. As of plugin version 2.3, 
the default value is derived from Maven's
+     * global debug flag (compare command line switch <code>-X</code>). <br/>
+     *
+     * @since 3.1.2
+     */
+    @Parameter( property = "verbose" )
+    private boolean verbose;
+
+    /**
      * Displays a list of the repositories used by this build.
      *
      * @throws MojoExecutionException with a message if an error occurs.
@@ -55,22 +110,276 @@ public class ListRepositoriesMojo
     protected void doExecute()
         throws MojoExecutionException
     {
+
+        for ( ArtifactRepository artifactRepository : remoteRepositories )
+        {
+            verbose( "Maven remote repositories: " + repositoryAsString( 
artifactRepository ) );
+        }
+
+        final Set<ArtifactRepository> repositories = new HashSet<>();
+        final Set<Artifact> artifacts = new HashSet<>();
+
+        DependencyVisitor visitor = new DependencyVisitor()
+        {
+            @Override
+            public boolean visitEnter( DependencyNode dependencyNode )
+            {
+                repositories.addAll( dependencyNode.getRemoteRepositories() );
+                artifacts.add( dependencyNode.getArtifact() );
+                return true;
+            }
+
+            @Override
+            public boolean visitLeave( DependencyNode dependencyNode )
+            {
+                return true;
+            }
+        };
+
         try
         {
-            CollectorResult collectResult =
-                dependencyCollector.collectDependencies( 
session.getProjectBuildingRequest(), getProject().getModel() );
+            ProjectBuildingRequest projectBuildingRequest = 
session.getProjectBuildingRequest();
+
+            CollectResult collectResult =
+                dependencyCollector.collectDependencies( 
projectBuildingRequest, getProject().getModel() );
+
+            for ( Exception e : collectResult.getExceptions() )
+            {
+                throw new MojoExecutionException( "Collect dependencies 
failed", e );
+            }
+
+            collectResult.getRoot().accept( visitor );
+
+            verbose( "Artifacts used by the build of " + 
collectResult.getRoot().getArtifact() + ":" );
+            for ( Artifact artifact : artifacts )
+            {
+                verbose( " " + artifact.toString() );
+            }
 
             this.getLog().info( "Repositories used by this build:" );
+            for ( ArtifactRepository repo : repositories )
+            {
+                if ( isVerbose() )
+                {
+                    Set<String> locations = new HashSet<String>();
+                    for ( Mirror mirror : settings.getMirrors() )
+                    {
+                        if ( mirror.getId().equals( repo.getId() )
+                            && ( mirror.getUrl().equals( repo.getUrl() ) ) )
+                        {
+                            locations.add( "Maven settings (user/global)" );
+                        }
+                    }
+
+                    Artifact projectArtifact = getProject().getArtifact();
+                    MavenProject project = getMavenProject( ArtifactUtils.key( 
projectArtifact ) );
+                    traversePom( repo, projectArtifact, project, locations );
+
+                    for ( Artifact artifact : artifacts )
+                    {
+                        MavenProject artifactProject = getMavenProject( 
ArtifactUtils.key( artifact ) );
+                        traversePom( repo, artifact, artifactProject, 
locations );
+                    }
+                    writeRepository( repo, locations );
+                }
+                else
+                {
+                    this.getLog().info( repo.toString() );
+                }
+            }
+        }
+        catch ( DependencyCollectionException e )
+        {
+            throw new MojoExecutionException( "Unable to collect", e );
+        }
+    }
+
+    private void writeRepository( ArtifactRepository artifactRepository, 
Set<String> locations )
+    {
+        StringBuilder sb = new StringBuilder( 256 );
+        sb.append( artifactRepository.toString() );
+        for ( String location : locations )
+        {
+            sb.append( " location: " ).append( location ).append( 
System.lineSeparator() );
+        }
+        this.getLog().info( sb.toString() );
+    }
+
+    /**
+     * Parses the given String into GAV artifact coordinate information, 
adding the given type.
+     *
+     * @param artifactString should respect the format 
<code>groupId:artifactId[:version]</code>
+     * @param type The extension for the artifact, must not be 
<code>null</code>.
+     * @return the <code>Artifact</code> object for the 
<code>artifactString</code> parameter.
+     * @throws MojoExecutionException if the <code>artifactString</code> 
doesn't respect the format.
+     */
+    private ArtifactCoordinate getArtifactCoordinate( String artifactString, 
String type )
+        throws MojoExecutionException
+    {
+        if ( org.codehaus.plexus.util.StringUtils.isEmpty( artifactString ) )
+        {
+            throw new IllegalArgumentException( "artifact parameter could not 
be empty" );
+        }
+
+        String groupId; // required
+        String artifactId; // required
+        String version; // optional
+
+        String[] artifactParts = artifactString.split( ":" );
+        switch ( artifactParts.length )
+        {
+            case 2:
+                groupId = artifactParts[0];
+                artifactId = artifactParts[1];
+                version = Artifact.LATEST_VERSION;
+                break;
+            case 3:
+                groupId = artifactParts[0];
+                artifactId = artifactParts[1];
+                version = artifactParts[2];
+                break;
+            default:
+                throw new MojoExecutionException( "The artifact parameter '" + 
artifactString
+                    + "' should be conform to: " + 
"'groupId:artifactId[:version]'." );
+        }
+        return getArtifactCoordinate( groupId, artifactId, version, type );
+    }
+
+    private ArtifactCoordinate getArtifactCoordinate( String groupId, String 
artifactId, String version, String type )
+    {
+        DefaultArtifactCoordinate coordinate = new DefaultArtifactCoordinate();
+        coordinate.setGroupId( groupId );
+        coordinate.setArtifactId( artifactId );
+        coordinate.setVersion( version );
+        coordinate.setExtension( type );
+        return coordinate;
+    }
+
+    /**
+     * Retrieves the Maven Project associated with the given artifact String, 
in the form of
+     * <code>groupId:artifactId[:version]</code>. This resolves the POM 
artifact at those coordinates and then builds
+     * the Maven project from it.
+     *
+     * @param artifactString Coordinates of the Maven project to get.
+     * @return New Maven project.
+     * @throws MojoExecutionException If there was an error while getting the 
Maven project.
+     */
+    private MavenProject getMavenProject( String artifactString )
+        throws MojoExecutionException
+    {
+        ArtifactCoordinate coordinate = getArtifactCoordinate( artifactString, 
"pom" );
+        try
+        {
+            ProjectBuildingRequest pbr = new DefaultProjectBuildingRequest( 
session.getProjectBuildingRequest() );
+            pbr.setRemoteRepositories( remoteRepositories );
+            pbr.setProject( null );
+            pbr.setValidationLevel( 
ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
+            pbr.setResolveDependencies( false );
+            Artifact artifact = artifactResolver.resolveArtifact( pbr, 
coordinate ).getArtifact();
+            return projectBuilder.build( artifact.getFile(), pbr 
).getProject();
+        }
+        catch ( Exception e )
+        {
+            throw new MojoExecutionException( "Unable to get the POM for the 
artifact '" + artifactString
+                + "'. Verify the artifact parameter.", e );
+        }
+    }
+
+    private void traversePom( ArtifactRepository artifactRepository,
+                              Artifact artifact, MavenProject mavenProject, 
Set<String> locations )
+        throws MojoExecutionException
+    {
+        getLog().debug( "Looking for locations of repository " + 
repositoryAsString( artifactRepository )
+            + " for " + artifact );
+        if ( mavenProject != null )
+        {
+            for ( Repository repository : 
mavenProject.getOriginalModel().getRepositories() )
+            {
+                getLog().debug( "Found repository: " + repositoryAsString( 
repository )
+                    + " @ " + artifact + ":" + 
mavenProject.getOriginalModel().getPomFile() );
+                if ( isRepositoryEqual( repository, artifactRepository ) )
+                {
+                    locations.add( 
mavenProject.getModel().getPomFile().toString() );
+                }
+            }
+
+            traverseParentPom( artifactRepository, mavenProject, locations );
+        }
+        else
+        {
+            throw new MojoExecutionException( "No POM for the artifact '" + 
artifact + "'" );
+        }
+        return;
+    }
 
-            for ( ArtifactRepository repo : 
collectResult.getRemoteRepositories() )
+    private void traverseParentPom( ArtifactRepository artifactRepository,
+                                    MavenProject mavenProject, Set<String> 
locations )
+        throws MojoExecutionException
+    {
+        MavenProject parent = mavenProject.getParent();
+        if ( parent != null )
+        {
+            Model originalModel = parent.getOriginalModel();
+            if ( originalModel.getRepositories().size() != 0
+                || originalModel.getPluginRepositories().size() != 0 )
             {
-                this.getLog().info( repo.toString() );
+                String artifactKey =
+                    ArtifactUtils.key( parent.getGroupId(), 
parent.getArtifactId(), parent.getVersion() );
+                MavenProject parentPom = getMavenProject( artifactKey );
+
+                for ( Repository repository : originalModel.getRepositories() )
+                {
+                    getLog().debug( "Found parent repository " + 
repositoryAsString( repository )
+                        + " @ " + parentPom.getArtifact() + ":" + 
parentPom.getFile() );
+                    if ( isRepositoryEqual( repository, artifactRepository ) )
+                    {
+                        locations.add( parentPom.getFile().toString() );
+                    }
+                }
             }
+            traverseParentPom( artifactRepository, parent, locations );
         }
-        catch ( DependencyCollectorException e )
+        return;
+    }
+
+    private String repositoryAsString( Repository repository )
+    {
+        StringBuilder sb = new StringBuilder( 32 );
+        sb.append( repository.getId() );
+        sb.append( " (" );
+        sb.append( repository.getUrl() );
+        sb.append( ")" );
+        return sb.toString();
+    }
+
+    private String repositoryAsString( ArtifactRepository repository )
+    {
+        StringBuilder sb = new StringBuilder( 32 );
+        sb.append( repository.getId() );
+        sb.append( " (" );
+        sb.append( repository.getUrl() );
+        sb.append( ")" );
+        return sb.toString();
+    }
+
+    private boolean isVerbose()
+    {
+        return ( verbose || getLog().isDebugEnabled() );
+    }
+
+    private void verbose( String message )
+    {
+        if ( isVerbose() )
         {
-            throw new MojoExecutionException( "Unable to resolve artifacts", e 
);
+            getLog().info( message );
         }
     }
 
+    private boolean isRepositoryEqual( Repository repository, 
ArtifactRepository artifactRepository )
+    {
+        // TODO: Use org.apache.maven.RepositoryUtils in Maven or check also 
snapshots, etc.
+        return repository.getId().equals( artifactRepository.getId() )
+            && repository.getUrl().equals( artifactRepository.getUrl() );
+    }
+
 }
diff --git a/src/site/apt/usage.apt.vm b/src/site/apt/usage.apt.vm
index a67381c..9f912dc 100644
--- a/src/site/apt/usage.apt.vm
+++ b/src/site/apt/usage.apt.vm
@@ -685,6 +685,17 @@ mvn dependency:build-classpath -Dmdep.outputFile=cp.txt
   This goal is used to list all the repositories that this build depends upon. 
It will show repositories defined in your settings, 
   poms and declared in transitive dependency poms.
 
+  This goal can be executed from the command line:
+
++-----+
+mvn dependency:list-repositories
++-----+
+
+  Optionally, in verbose or debug mode it will display the location of the 
listed repository:
+
++-----+
+mvn dependency:list-repositories -Dverbose
++-----+
 
 * <<<dependency:get>>>
 

Reply via email to