Программное разрешение зависимостей Maven вне плагина — get RepositorySystemSession и RepositorySystem

Возможно, это будет более сложная задача, чем я изначально думал, но, тем не менее, я пытаюсь загрузить MavenProject из файла, а затем разрешить его зависимости. У меня есть код для обоих битов, но мне не хватает некоторых ссылок на объекты, которые мне нужны; в частности, мне нужно получить экземпляры RepositorySystemSession и RepositorySystem. Какие-нибудь советы?

Примечание. Я пометил этот вопрос тегом maven-plugin, но это не плагин 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;
}

Я понимаю, что это может быть необычный запрос, может быть, мне следует просто отказаться от того, что я пытался сделать, и обернуть это как плагин... но я просто хочу закончить то, что начал сейчас! Заранее спасибо.


person Ed .    schedule 03.08.2012    source источник
comment
См. Примеры эфира   -  person Ondra Žižka    schedule 16.04.2016


Ответы (6)


Попробуйте jcabi-aether, который представляет собой оболочку для Apache Aether от Sonatype:

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
);
person yegor256    schedule 28.10.2012
comment
Спасибо за указатель - библиотека выглядит интересно, но у меня все еще нет RepositorySystemSession, если только я не нахожусь внутри выполнения плагина :( - person Ed .; 29.10.2012

Я бы рекомендовал прочитать информацию о Aether lib, которая как раз и предназначена для таких целей.

Примечание. Aether ранее разрабатывался в Sonatype, но с тех пор перешел в Eclipse.

person khmarbaise    schedule 03.08.2012
comment
Спасибо за указание, хотя я все еще чувствую, что документация немного светлая... Теперь я могу получить RepositorySystem на основе документации, но создание RepositorySystemSession со всеми теми же настройками Maven все еще оказывается немного сложным. Я проверил пакет maven.settings.building, как предлагает документация, но безрезультатно. В идеале я не хочу указывать все, я хочу, чтобы мой файл pom.xml (и settings.xml) был источником всей информации. Я думаю, что моя текущая проблема заключается в том, что project.getRepositories() равно нулю. Я буду продолжать попытки. Спасибо. - person Ed .; 06.08.2012
comment
Я бы посоветовал взглянуть на это: github.com/khmarbaise/pom-interpolator-test (он создан на основе примера Aether). - person khmarbaise; 06.08.2012
comment
Еще раз спасибо, полезные фрагменты кода, но, видимо, я просто получаю исключение за исключением, используя фрагменты кода из примера. Это слишком много хлопот для чего-то, что чаще всего запускается внутри плагина. Если у меня будет время позже, я вернусь к нему, спасибо еще раз в любом случае. - person Ed .; 06.08.2012
comment
Извините, но документация на eclipse.org/aether очень плохая. Почти не существует. Когда мы можем ожидать хорошую документацию? - person Robert Reiz; 11.08.2013
comment
Aether снова вернулся на Apache: projects.eclipse.org/comment/208#comment-208 - person Gustave; 19.12.2017

Я просто на скорую руку решил как вашу, так и мою проблему:

/*******************************************************************************
 * 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;
  }
}

пом.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 для поиска артефакта в вашем локальном репозитории. Вам нужно будет изменить два параметра в основной функции: расположение pom.xml вашего проекта и расположение вашего локального репозитория.

Наслаждаться! :)

person Ring    schedule 03.06.2013

Попробуйте это (как видно из атер-демо):

...
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;
}
person carlspring    schedule 23.05.2013

Существует хороший набор автономных примеров для Eclipses Aether API, который используется в последней версии Maven (3.1.1), и его можно найти здесь.

Примечание. Maven 3.1.X по-прежнему использует Aether 0.9.0.M2 (последняя версия, которую мы использовали в примерах, — 0.9.0.M3). Таким образом, для запуска этих примеров внутри плагина Maven требуется версия M2, а автономное приложение может использовать последнюю версию M3.

person Andrey Chaschev    schedule 30.09.2013

Это описано в "Aether/Настройка Aether Up" для RepositorySystem и в "Aether/Создание системного сеанса репозитория" в eclipse wiki.

Документации не так много, но вы можете создать 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 );
}

Обратите внимание, что для этого требуются зависимости, описанные в "Получение 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;
}
person Vogel612    schedule 03.08.2017