Программно разрешать зависимости Maven вне плагина - получить RepositorySystemSession и RepositorySystem
Может быть, это будет большая задача, чем я первоначально думал, но независимо от того, я пытаюсь загрузить MavenProject
из файла, а затем разрешить его зависимости. У меня есть код для обоих битов, но мне не хватает некоторых ссылок на объекты, которые мне нужны; в частности, мне нужно, чтобы получить экземпляры RepositorySystemSession
а также RepositorySystem
, Какие-нибудь советы?
Примечание: я пометил этот вопрос плагином maven, но это не плагин 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;
}
Я понимаю, что это может быть необычный запрос, может быть, я должен просто отказаться от того, что я пытался сделать, и обернуть это как плагин... но я просто хочу закончить то, что начал сейчас! Заранее спасибо.
7 ответов
Попробуйте 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
);
Я бы порекомендовал прочитать информацию об Aether lib, которая предназначена именно для таких целей.
Примечание: Эфир был ранее разработан в Sonatype, но с тех пор перешел в Eclipse.
Я только что нашел решение вашей проблемы:
/*******************************************************************************
* 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, чтобы найти артефакт в вашем локальном хранилище. Вам нужно будет изменить два параметра в основной функции: местоположение pom.xml вашего проекта и местоположение вашего локального репозитория.
Наслаждайтесь!:)
Попробуйте это (как видно из атер-демо):
...
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;
}
Есть хороший набор автономных примеров для Eclipses Aether API, который используется в последней версии Maven (3.1.1), и его можно найти здесь.
Примечание: Maven 3.1.X по-прежнему использует эфир 0.9.0.M2
(и последняя версия, которую мы использовали в примерах, 0.9.0.M3
). Таким образом, для запуска этих примеров в плагине Maven требуется версия M2, а отдельное приложение может использовать последнюю версию M3.
Это описано в разделе "Эфир / Настройка эфира" для RepositorySystem и в "Эфир / Создание сеанса системы репозитория" в вики eclipse.
Там нет тонны документации, но вы можете создать 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 );
}
Обратите внимание, что для этого требуются зависимости, подробно описанные в разделе "Получение эфира", в первую очередь maven-aether-provider
,
Когда у вас есть система репозитория, учебник продолжает создавать Repository System Session со следующим фабричным методом:
// 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;
}
- Примеры: https://maven.apache.org/resolver/xref/index.html
- Репо (включая примеры): https://github.com/apache/maven-resolver
- Maven Central: https://mvnrepository.com/artifact/org.apache.maven.resolver/maven-resolver
- Домашняя страница: https://maven.apache.org/resolver/index.html