【问题标题】:Programmatically resolving Maven dependencies outside of a plugin - get RepositorySystemSession and RepositorySystem以编程方式解决插件外部的 Maven 依赖项 - 获取 RepositorySystemSession 和 RepositorySystem
【发布时间】:2012-08-01 18:00:15
【问题描述】:

也许这将是一项比我最初想象的更大的任务,但无论如何,我正在尝试从文件加载MavenProject,然后解决其依赖关系。我有这两个位的代码,但是我缺少一些我需要的对象引用;具体来说,我需要获取RepositorySystemSessionRepositorySystem 的实例。有什么建议吗?

注意:我已经用 标记了这个问题,但这不是一个 Maven 插件。我很高兴授权 Maven 3(我想我已经拥有了..)

这是我目前的代码:

构造MavenProject

public static MavenProject loadProject(File pomFile) throws Exception
{
    MavenProject ret = null;
    MavenXpp3Reader mavenReader = new MavenXpp3Reader();

    if (pomFile != null && pomFile.exists())
    {
        FileReader reader = null;

        try
            {
            reader = new FileReader(pomFile);
            Model model = mavenReader.read(reader);
            model.setPomFile(pomFile);

            ret = new MavenProject(model);
        }
        finally
        {
            // Close reader
        }
    }

    return ret;
}

解决依赖关系:

public static List<Dependency> getArtifactsDependencies(MavenProject project, String dependencyType, String scope) throws Exception
{    
    DefaultArtifact pomArtifact = new DefaultArtifact(project.getId());

    RepositorySystemSession repoSession = null; // TODO
    RepositorySystem repoSystem = null; // TODO

    List<RemoteRepository> remoteRepos = project.getRemoteProjectRepositories();
    List<Dependency> ret = new ArrayList<Dependency>();

    Dependency dependency = new Dependency(pomArtifact, scope);

    CollectRequest collectRequest = new CollectRequest();
    collectRequest.setRoot(dependency);
    collectRequest.setRepositories(remoteRepos);

    DependencyNode node = repoSystem.collectDependencies(repoSession, collectRequest).getRoot();
    DependencyRequest projectDependencyRequest = new DependencyRequest(node, null);

    repoSystem.resolveDependencies(repoSession, projectDependencyRequest);

    PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
    node.accept(nlg);

    ret.addAll(nlg.getDependencies(true));

    return ret;
}

我意识到这可能是一个不寻常的请求,也许我应该放弃我正在尝试做的事情并将其包装为插件......但我只是想完成我现在开始的事情!提前致谢。

【问题讨论】:

标签: maven-plugin java maven maven-plugin aether


【解决方案1】:

我建议阅读有关Aether lib 的信息,这正是用于此类目的。

注意:Aether 之前是在 Sonatype 开发的,但后来转移到 Eclipse

【讨论】:

  • 感谢您的指点,尽管我仍然觉得文档有点轻...我现在可以根据文档获得RepositorySystem,但是使用所有相同的Maven创建RepositorySystemSession设置仍然有点棘手。我已经按照文档的建议检查了 maven.settings.building 包,但无济于事。理想情况下,我不想指定所有内容,我希望我的 pom.xml 文件(和 settings.xml)成为所有信息的来源。我认为我当前的问题是project.getRepositories() 为空。我会继续努力。谢谢。
  • 我建议看看这个:github.com/khmarbaise/pom-interpolator-test(它是从 Aether 示例增强的)。
  • 再次感谢,有用的代码位,但显然我只是使用示例中的代码 sn-ps 得到一个又一个异常。对于最经常在插件中运行的东西来说,这太麻烦了。如果以后有时间我会回来的,无论如何再次感谢。
  • 很抱歉,eclipse.org/aether 上的文档很差。几乎不存在。我们什么时候可以期待一份好的文档?
  • Aether 再次回到 Apache:projects.eclipse.org/comment/208#comment-208
【解决方案2】:

试试jcabi-aether,它是来自 Sonatype 的 Apache Aether 的包装器:

final File repo = this.session.getLocalRepository().getBasedir();
final Collection<Artifact> deps = new Aether(this.getProject(), repo).resolve(
  new DefaultArtifact("junit", "junit-dep", "", "jar", "4.10"),
  JavaScopes.RUNTIME
);

如果您不在 Maven 插件范围内:

final File repo = new File(System.getProperty("java.io.tmpdir"), "my-repo");
final MavenProject project = new MavenProject();
project.setRemoteArtifactRepositories(
  Arrays.asList(
    new RemoteRepository(
      "maven-central",
      "default",
      "http://repo1.maven.org/maven2/"
    )
  )
);
final Collection<Artifact> deps = new Aether(project, repo).resolve(
  new DefaultArtifact("junit", "junit-dep", "", "jar", "4.10"),
  JavaScopes.RUNTIME
);

【讨论】:

  • 感谢您的指点 - 库看起来确实很有趣,但我仍然没有RepositorySystemSession,除非我在插件执行中:(
【解决方案3】:

试试这个(从ather-demo可以看出):

...
LocalRepository localRepository = new LocalRepository("/path/to/local-repo");

RepositorySystem system = getRepositorySystemInstance();
RepositorySystemSession session = getRepositorySystemSessionInstance(system, localRepository);
....

public static RepositorySystem getRepositorySystemInstance()
{
    /**
     * Aether's components implement org.sonatype.aether.spi.locator.Service to ease manual wiring and using the
     * prepopulated DefaultServiceLocator, we only need to register the repository connector factories.
     */
    MavenServiceLocator locator = new MavenServiceLocator();
    locator.addService(RepositoryConnectorFactory.class, FileRepositoryConnectorFactory.class);
    locator.addService(RepositoryConnectorFactory.class, WagonRepositoryConnectorFactory.class);
    locator.setServices(WagonProvider.class, new ManualWagonProvider());

    return locator.getService(RepositorySystem.class);
}

private static RepositorySystemSession getRepositorySystemSessionInstance(RepositorySystem system,
                                                                          LocalRepository localRepo)
{
    MavenRepositorySystemSession session = new MavenRepositorySystemSession();

    session.setLocalRepositoryManager(system.newLocalRepositoryManager(localRepo));

    session.setTransferListener(new ConsoleTransferListener());
    session.setRepositoryListener(new ConsoleRepositoryListener());

    // Set this in order to generate dirty trees
    session.setDependencyGraphTransformer(null);

    return session;
}

【讨论】:

    【解决方案4】:

    我刚刚为你和我的问题想出了一个解决方案:

    /*******************************************************************************
     * Copyright (c) 2013 TerraFrame, Inc. All rights reserved. 
     * 
     * This file is part of Runway SDK(tm).
     * 
     * Runway SDK(tm) is free software: you can redistribute it and/or modify
     * it under the terms of the GNU Lesser General Public License as
     * published by the Free Software Foundation, either version 3 of the
     * License, or (at your option) any later version.
     * 
     * Runway SDK(tm) is distributed in the hope that it will be useful, but
     * WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU Lesser General Public License for more details.
     * 
     * You should have received a copy of the GNU Lesser General Public
     * License along with Runway SDK(tm).  If not, see <http://www.gnu.org/licenses/>.
     ******************************************************************************/
    
    package com.test.mavenaether;
    
    import java.io.File;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.Iterator;
    import java.util.List;
    
    import org.apache.maven.artifact.repository.ArtifactRepository;
    import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
    import org.apache.maven.artifact.repository.MavenArtifactRepository;
    import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
    import org.apache.maven.model.Model;
    import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
    import org.apache.maven.project.MavenProject;
    import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
    import org.sonatype.aether.artifact.Artifact;
    import org.sonatype.aether.resolution.DependencyResolutionException;
    import org.sonatype.aether.util.artifact.DefaultArtifact;
    import org.sonatype.aether.util.artifact.JavaScopes;
    
    import com.jcabi.aether.Aether;
    
    public class MavenAether
    {
      public static void main(String[] args) throws Exception
      {
        String classpath = getClasspathFromMavenProject(new File("/users/terraframe/documents/workspace/MavenSandbox/pom.xml"), new File("/users/terraframe/.m2/repository"));
        System.out.println("classpath = " + classpath);
      }
    
      public static String getClasspathFromMavenProject(File projectPom, File localRepoFolder) throws DependencyResolutionException, IOException, XmlPullParserException
      {
        MavenProject proj = loadProject(projectPom);
    
        proj.setRemoteArtifactRepositories(
            Arrays.asList(
                (ArtifactRepository) new MavenArtifactRepository(
                    "maven-central", "http://repo1.maven.org/maven2/", new DefaultRepositoryLayout(),
                    new ArtifactRepositoryPolicy(), new ArtifactRepositoryPolicy()
                )
            )
        );
    
        String classpath = "";
        Aether aether = new Aether(proj, localRepoFolder);
    
        List<org.apache.maven.model.Dependency> dependencies = proj.getDependencies();
        Iterator<org.apache.maven.model.Dependency> it = dependencies.iterator();
    
        while (it.hasNext()) {
          org.apache.maven.model.Dependency depend = it.next();
    
          final Collection<Artifact> deps = aether.resolve(
            new DefaultArtifact(depend.getGroupId(), depend.getArtifactId(), depend.getClassifier(), depend.getType(), depend.getVersion()),
            JavaScopes.RUNTIME
          );
    
          Iterator<Artifact> artIt = deps.iterator();
          while (artIt.hasNext()) {
            Artifact art = artIt.next();
            classpath = classpath + " " + art.getFile().getAbsolutePath();
          }
        }
    
        return classpath;
      }
    
      public static MavenProject loadProject(File pomFile) throws IOException, XmlPullParserException
      {
          MavenProject ret = null;
          MavenXpp3Reader mavenReader = new MavenXpp3Reader();
    
          if (pomFile != null && pomFile.exists())
          {
              FileReader reader = null;
    
              try
                  {
                  reader = new FileReader(pomFile);
                  Model model = mavenReader.read(reader);
                  model.setPomFile(pomFile);
    
                  ret = new MavenProject(model);
              }
              finally
              {
                reader.close();
              }
          }
    
          return ret;
      }
    }
    

    pom.xml:

    <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>com.test</groupId>
      <artifactId>MavenSandbox</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    
      <dependencies>
        <dependency>
          <groupId>com.jcabi</groupId>
          <artifactId>jcabi-aether</artifactId>
          <version>0.7.19</version>
        </dependency>
        <dependency>
          <groupId>org.apache.maven</groupId>
          <artifactId>maven-core</artifactId>
          <version>3.0.3</version>
        </dependency>
      </dependencies>
    </project>
    

    代码首先加载 Maven 项目(使用原始问题中提供的函数),然后使用 jcabi-aether 在本地存储库中查找工件。您将需要更改 main 函数中的两个参数:项目的 pom.xml 的位置和本地存储库的位置。

    享受吧! :)

    【讨论】:

      【解决方案5】:

      有一组很好的 Eclipses Aether API 独立示例,用于最新的 Maven (3.1.1),可以在 here 找到。

      注意:Maven 3.1.X 仍然使用 Aether 0.9.0.M2(我们在示例中使用的最新版本是 0.9.0.M3)。因此,要在 Maven 插件中运行这些示例,需要 M2 版本,而独立应用程序可以使用最新的 M3 版本。

      【讨论】:

        【解决方案6】:

        RepositorySystem 的 "Aether/Setting Aether Up" 和 eclipse wiki 的 "Aether/Creating a Repository System Session" 对此进行了介绍。

        文档并不多,但您可以按如下方式创建 RepositorySystem:

        // verbatim copy from the Setting Aether Up link
        private static RepositorySystem newRepositorySystem()
        {
            DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
            locator.addService( RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class );
            locator.addService( TransporterFactory.class, FileTransporterFactory.class );
            locator.addService( TransporterFactory.class, HttpTransporterFactory.class );
        
            return locator.getService( RepositorySystem.class );
        }
        

        请注意,这需要"Getting Aether" 中详述的依赖关系,尤其是maven-aether-provider

        当您拥有存储库系统后,教程继续使用以下工厂方法创建 RepositorySystemSession:

        // copied verbatim from "Creating a Repository System Session"
        private static RepositorySystemSession newSession( RepositorySystem system )
        {
            DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
        
            LocalRepository localRepo = new LocalRepository( "target/local-repo" );
            session.setLocalRepositoryManager( system.newLocalRepositoryManager( session, localRepo ) );
        
            return session;
        }
        

        【讨论】:

          猜你喜欢
          • 2016-03-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多