You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@maven.apache.org by Laird Nelson <lj...@gmail.com> on 2011/02/14 19:42:08 UTC

Topologically sorting dependencies?

Hello; I apologize if my terminology is off.  (I've never understood the
difference between a dependency and an artifact in the innards of Maven;
happy to be educated.)

I have to write a Maven plugin that, in order to work properly, needs a
topologically sorted list of resolved dependencies.

I was hoping that such a list existed somewhere that I could inject into my
plugin using the Javadoc tags.

Classpath order isn't really good enough; it is quite possible to explicitly
declare a dependency that might otherwise be transitively included; when you
do that, of course, the explicit declaration shows up "higher" in the
classpath than it would if it were included transitively.  No, I need to
sort the dependencies topologically, from least dependent to most dependent
(i.e. from the artifact with the least number of dependencies to the
artifact with the greatest number of dependencies).

What's the best way of accomplishing this?

Thanks,
Laird

Re: Topologically sorting dependencies?

Posted by Laird Nelson <lj...@gmail.com>.
I should also mention I can't guarantee the assertion statements, as there's
no documentation indicating, for example, whether Project.getArtifactMap
ever returns null.  I'm also supplying what I *think* is the proper key
format for the map, but can't be sure, as that isn't documented either.  I
ended up just looking at the source code and hoping that this key format is
not an internal detail of the class.

Best,
Laird

On Wed, Feb 16, 2011 at 10:11 AM, Laird Nelson <lj...@gmail.com> wrote:

> Well, here's how I did it.  It sure ain't pretty, but it works!
>
> Briefly, I grab the set of artifacts from a MavenProject.  Usually because
> I'm doing this from within a plugin whose dependency resolution has been set
> to "test", these artifacts are resolved already, which is convenient, and I
> don't bother to handle the case where they aren't already resolved.  Then I
> invoke MavenProjectBuilder#buildFromRepository() on each of them to get
> project information about each of them.  Now I have a list of
> MavenProjects.  I hand them to a new ProjectSorter, which does the
> topological sort I require, and keeps me blissfully ignorant of how exactly
> Maven does its reactor sorting.
>
> Finally, for each one, I grab its Artifact, and add it in order to the
> returned list.  I threw in an ArtifactFilter in case I want to weed out
> results.
>
> Hopefully this will be useful for other people in similar situations.  Even
> more hopefully someone will come along and ask pointedly why I went to all
> the trouble to rewrite the ArtifactWhosieWhatsit#sort() method, and I will
> reply because I didn't happen upon it.  :-)
>
> Best,
> Laird
>
> public static final List<Artifact> topologicallySort(final MavenProject
> project, MavenProjectBuilder builder, final ArtifactRepository
> localRepository, final ArtifactFilter filter) throws
> ProjectBuildingException, MissingProjectException,
> DuplicateProjectException, CycleDetectedException {
>     if (project == null) {
>       throw new IllegalArgumentException("project == null");
>     }
>     List<Artifact> returnValue = null;
>
>     @SuppressWarnings("unchecked")
>     final Set<Artifact> artifacts = (Set<Artifact>)project.getArtifacts();
>     if (artifacts != null) {
>       returnValue = new ArrayList<Artifact>();
>       if (!artifacts.isEmpty()) {
>         final List<MavenProject> projects = new ArrayList<MavenProject>();
>         projects.add(project);
>
>         if (builder == null) {
>           builder = new DefaultMavenProjectBuilder();
>         }
>
>         for (final Artifact artifact : artifacts) {
>           if (artifact != null) {
>             final MavenProject artifactProject =
> builder.buildFromRepository(artifact,
> project.getRemoteArtifactRepositories(), localRepository);
>             assert artifactProject != null;
>             projects.add(artifactProject);
>           }
>         }
>
>         final ProjectSorter sorter = new ProjectSorter(projects);
>         final List<MavenProject> sortedProjects =
> sorter.getSortedProjects();
>         assert sortedProjects != null;
>         assert sortedProjects.size() == projects.size();
>
>         final Map projectArtifactMap = project.getArtifactMap();
>         assert projectArtifactMap != null;
>
>         for (final MavenProject p : sortedProjects) {
>           if (p != null) {
>             final Artifact artifact = p.getArtifact();
>             if (artifact != null) {
>               final Artifact resolvedArtifact =
> (Artifact)projectArtifactMap.get(artifact.getGroupId() + ":" +
> artifact.getArtifactId());
>               if (resolvedArtifact != null && (filter == null ||
> filter.include(resolvedArtifact))) {
>                 returnValue.add(resolvedArtifact);
>               }
>             }
>           }
>         }
>
>       }
>     }
>
>     return returnValue;
>   }
>

Re: Topologically sorting dependencies?

Posted by Laird Nelson <lj...@gmail.com>.
Well, here's how I did it.  It sure ain't pretty, but it works!

Briefly, I grab the set of artifacts from a MavenProject.  Usually because
I'm doing this from within a plugin whose dependency resolution has been set
to "test", these artifacts are resolved already, which is convenient, and I
don't bother to handle the case where they aren't already resolved.  Then I
invoke MavenProjectBuilder#buildFromRepository() on each of them to get
project information about each of them.  Now I have a list of
MavenProjects.  I hand them to a new ProjectSorter, which does the
topological sort I require, and keeps me blissfully ignorant of how exactly
Maven does its reactor sorting.

Finally, for each one, I grab its Artifact, and add it in order to the
returned list.  I threw in an ArtifactFilter in case I want to weed out
results.

Hopefully this will be useful for other people in similar situations.  Even
more hopefully someone will come along and ask pointedly why I went to all
the trouble to rewrite the ArtifactWhosieWhatsit#sort() method, and I will
reply because I didn't happen upon it.  :-)

Best,
Laird

public static final List<Artifact> topologicallySort(final MavenProject
project, MavenProjectBuilder builder, final ArtifactRepository
localRepository, final ArtifactFilter filter) throws
ProjectBuildingException, MissingProjectException,
DuplicateProjectException, CycleDetectedException {
    if (project == null) {
      throw new IllegalArgumentException("project == null");
    }
    List<Artifact> returnValue = null;

    @SuppressWarnings("unchecked")
    final Set<Artifact> artifacts = (Set<Artifact>)project.getArtifacts();
    if (artifacts != null) {
      returnValue = new ArrayList<Artifact>();
      if (!artifacts.isEmpty()) {
        final List<MavenProject> projects = new ArrayList<MavenProject>();
        projects.add(project);

        if (builder == null) {
          builder = new DefaultMavenProjectBuilder();
        }

        for (final Artifact artifact : artifacts) {
          if (artifact != null) {
            final MavenProject artifactProject =
builder.buildFromRepository(artifact,
project.getRemoteArtifactRepositories(), localRepository);
            assert artifactProject != null;
            projects.add(artifactProject);
          }
        }

        final ProjectSorter sorter = new ProjectSorter(projects);
        final List<MavenProject> sortedProjects =
sorter.getSortedProjects();
        assert sortedProjects != null;
        assert sortedProjects.size() == projects.size();

        final Map projectArtifactMap = project.getArtifactMap();
        assert projectArtifactMap != null;

        for (final MavenProject p : sortedProjects) {
          if (p != null) {
            final Artifact artifact = p.getArtifact();
            if (artifact != null) {
              final Artifact resolvedArtifact =
(Artifact)projectArtifactMap.get(artifact.getGroupId() + ":" +
artifact.getArtifactId());
              if (resolvedArtifact != null && (filter == null ||
filter.include(resolvedArtifact))) {
                returnValue.add(resolvedArtifact);
              }
            }
          }
        }

      }
    }

    return returnValue;
  }

Re: Topologically sorting dependencies?

Posted by Laird Nelson <lj...@gmail.com>.
On Tue, Feb 15, 2011 at 8:22 AM, Ron Wheeler <rwheeler@artifact-software.com
> wrote:

> Doesn't your IDE do this already?
>

No, how could it?

Maybe I wasn't clear.

I am writing a Maven plugin.  For reasons I can go into if anyone cares, I
need to process some resolved dependencies in topological order.  That is, I
will be using this plugin to perform some operations on a Maven project that
uses it.  The Maven project will, of course, have dependencies.  However, if
I ask Maven for a list of those dependencies, they will be sorted in "Maven
order", not topological order.

This is, again, inside a plugin that I'm writing.  So I am not running Maven
here as an end user; I am interacting with Maven's API.

By "Maven order" what I mean is that in a Maven project if project A needs
project B, and also declares a dependency on project C, AND if project B
declares a dependency on project C, then ALTHOUGH project C is reachable
transitively from A (i.e. it doesn't NEED to declare C in its list of
dependencies), it will show up ahead of B in the list of artifacts that
Maven reports as the dependencies for project A.

I need to account for these situations in my plugin.  I need to
topologically sort that list instead, so that no matter how you have it
declared project C in such a case will always come last.  In case it
matters, my plugin doesn't have anything to do with classpaths (i.e. I'm not
re-implementing Maven's dependency resolution algorithm or anything silly
like that).  I am attempting to process well-known resources in the jar
files of other artifacts in topological order.

To my knowledge there is no API inside of Maven--the maven-dependency-plugin
included--that will take a list of Artifacts and sort them and their
transitive dependencies topologically, not according to the
classpath-building algorithm that Maven uses when sorting such dependencies
for Maven execution.

The closest thing I've found is ProjectSorter (
http://maven.apache.org/ref/3.0.2/maven-core/apidocs/org/apache/maven/project/ProjectSorter.html)
which topologically sorts a list of *projects*, but I would like to
accomplish the same thing with *Artifacts*.

Best,
Laird

Re: Topologically sorting dependencies?

Posted by Ron Wheeler <rw...@artifact-software.com>.
On 15/02/2011 7:56 AM, Laird Nelson wrote:
> On Tue, Feb 15, 2011 at 4:48 AM, Barrie Treloar<ba...@gmail.com>  wrote:
>
>> Is something like this
>> http://maven.apache.org/plugins/maven-dependency-plugin/
>> what you want?
>>
>> Try
>> mvn dependency:tree
>>
> That works fine for when I'm outputting dependencies to the screen (actually
> it doesn't; Maven no longer uses the same algorithm internally).
>
> I would like to feed this hypothetical API (which I'm coming to realize
> doesn't exist) a set of Artifacts, resolve them if necessary, though since
> I'm using it in a plugin resolution would have already occurred, and then
> receive back a sorted List of such Artifacts.
>
> Like ProjectSorter, but with Artifacts instead.
>
> L
>
Doesn't your IDE do this already?

Ron

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: Topologically sorting dependencies?

Posted by Laird Nelson <lj...@gmail.com>.
On Tue, Feb 15, 2011 at 4:48 AM, Barrie Treloar <ba...@gmail.com> wrote:

> Is something like this
> http://maven.apache.org/plugins/maven-dependency-plugin/
> what you want?
>
> Try
> mvn dependency:tree
>

That works fine for when I'm outputting dependencies to the screen (actually
it doesn't; Maven no longer uses the same algorithm internally).

I would like to feed this hypothetical API (which I'm coming to realize
doesn't exist) a set of Artifacts, resolve them if necessary, though since
I'm using it in a plugin resolution would have already occurred, and then
receive back a sorted List of such Artifacts.

Like ProjectSorter, but with Artifacts instead.

L

Re: Topologically sorting dependencies?

Posted by Barrie Treloar <ba...@gmail.com>.
On Tue, Feb 15, 2011 at 5:12 AM, Laird Nelson <lj...@gmail.com> wrote:

> Hello; I apologize if my terminology is off.  (I've never understood the
> difference between a dependency and an artifact in the innards of Maven;
> happy to be educated.)
>
> I have to write a Maven plugin that, in order to work properly, needs a
> topologically sorted list of resolved dependencies.
>
> I was hoping that such a list existed somewhere that I could inject into my
> plugin using the Javadoc tags.
>
> Classpath order isn't really good enough; it is quite possible to
> explicitly
> declare a dependency that might otherwise be transitively included; when
> you
> do that, of course, the explicit declaration shows up "higher" in the
> classpath than it would if it were included transitively.  No, I need to
> sort the dependencies topologically, from least dependent to most dependent
> (i.e. from the artifact with the least number of dependencies to the
> artifact with the greatest number of dependencies).
>
> What's the best way of accomplishing this?
>

Is something like this
http://maven.apache.org/plugins/maven-dependency-plugin/
what you want?

Try
mvn dependency:tree