Fitnesse Maven Classpath插件无法解析远程依赖项 [英] Fitnesse Maven Classpath plugin cannot resolve remote dependencies

查看:105
本文介绍了Fitnesse Maven Classpath插件无法解析远程依赖项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Fitnesse Maven类路径插件,该插件允许Fitnesse使用以下命令解析类路径Maven存储库.

I am using the Fitnesse Maven classpath plugin that allows Fitnesse to resolve the classpath using the Maven repository.

该插件有效,但似乎无法解决存储在我的远程存储库中的依赖项.
如果快照在我的本地存储库中,但不在远程存储中,则可以解析快照.

The plugin works, but it does not seem to be able to resolve dependencies that are stored in my remote repository.
It can resolve a snapshot if it's in my local repository but not remotely.

如果我从Fitnessit外部运行mvn install,则找到依赖项没有问题,这表明我的settings.xml已正确设置.

If I run a mvn install (from outside Fitnesse) then it has no problems finding the dependencies so that suggests my settings.xml is set up correctly.

我已经调试了插件,但是很难准确指出为什么它无法解析远程快照.

I've debugged the plugin but am having difficulty pinpointing exactly why it cannot resolve the remote snapshots.

问题:如何更改它以使其能够解析快照?

Question: How can I change this to allow it to resolve snapshots?

添加更多详细信息

可以通过运行此单元测试轻松重现此内容:

This can easily be reproduced by running this unit test: MavenClasspathExtractorTest

此单元测试尝试解决commons-lang依赖性.

This unit test attempts to resolve the commons-lang dependency.

如果从本地存储库中删除此依赖项,则测试将失败,因为它似乎无法从远程存储库中检索.

If you remove this dependency from your local repository then the test fails as it does not seem to be able to retrieve from the remote repository.

如果将其放回本地存储库,它将再次通过.

If you put it back into your local repository it passes once again.

这是问题的症结所在.

潜在的解决方案

以下是使用jcabi-aether库的潜在解决方案,该库首先使用本地存储库,如果没有,将从远程存储库下载.这看起来很傻吗?它可以满足我的需求

The following is a potential solution using the jcabi-aether library that uses the local repository first, and if not there will download from the remote repository. Does this look fool-proof? It works for my needs

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.settings.Profile;
import org.apache.maven.settings.Repository;
import org.apache.maven.settings.Settings;
import org.apache.maven.settings.building.*;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.logging.console.ConsoleLoggerManager;
import org.sonatype.aether.artifact.Artifact;
import org.sonatype.aether.repository.RemoteRepository;
import org.sonatype.aether.util.artifact.DefaultArtifact;

import com.jcabi.aether.Aether;

/**
 * Utility class to extract classpath elements from Maven projects. Heavily based on code copied from Jenkin's Maven
 * support.
 */
public class MavenClasspathExtractor {
    public static final String userHome = System.getProperty( "user.home" );
    public static final File userMavenConfigurationHome = new File( userHome, ".m2" );
    public static final String envM2Home = System.getenv("M2_HOME");
    public final static String DEFAULT_SCOPE = "test";
    public static final File DEFAULT_USER_SETTINGS_FILE = new File( userMavenConfigurationHome, "settings.xml" );
    public static final File DEFAULT_GLOBAL_SETTINGS_FILE =
            new File( System.getProperty( "maven.home", envM2Home != null ? envM2Home : "" ), "conf/settings.xml" );

    private final Logger logger = new ConsoleLoggerManager().getLoggerForComponent("maven-classpath-plugin");

    // Ensure M2_HOME variable is handled in a way similar to the mvn executable (script). To the extend possible.
    static {
        String m2Home = System.getenv().get("M2_HOME");
        if (m2Home != null && System.getProperty("maven.home") == null) {
            System.setProperty("maven.home", m2Home);
        }
    }

    public List<String> extractClasspathEntries(File pomFile) throws MavenClasspathExtractionException {
        return extractClasspathEntries(pomFile, DEFAULT_SCOPE);
    }

    public List<String> extractClasspathEntries(File pomFile, String scope) throws MavenClasspathExtractionException {
        MavenXpp3Reader mavenReader;
        FileReader reader = null;
        try {
            mavenReader = new MavenXpp3Reader();
            reader = new FileReader(pomFile);
            Model model = mavenReader.read(reader);
            model.setPomFile(pomFile);

            Collection<RemoteRepository> remoteRepositories = getRemoteRepositories();
            File localRepo = new File( RepositorySystem.defaultUserLocalRepository.getAbsolutePath());
            MavenProject project = new MavenProject(model);

            Aether aether = new Aether(remoteRepositories, localRepo);
            Artifact root = new DefaultArtifact(project.getGroupId(), project.getArtifactId(), project.getPackaging(), project.getVersion());
            List<Artifact> artifacts = aether.resolve(root, scope);
            List<String> paths = new ArrayList<>();
            for(Artifact artifact : artifacts) {
                paths.add(artifact.getFile().getAbsolutePath());
            }
            return paths;

        } catch (Exception e) {
            throw new MavenClasspathExtractionException(e);
        } finally {
            if(reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    throw new MavenClasspathExtractionException(e);
                }
            }
        }
    }



    private Collection<RemoteRepository> getRemoteRepositories() throws SettingsBuildingException {
        SettingsBuildingRequest settingsBuildingRequest = new DefaultSettingsBuildingRequest();
        settingsBuildingRequest.setSystemProperties(System.getProperties());
        settingsBuildingRequest.setUserSettingsFile(DEFAULT_USER_SETTINGS_FILE);
        settingsBuildingRequest.setGlobalSettingsFile(DEFAULT_GLOBAL_SETTINGS_FILE);

        DefaultSettingsBuilderFactory mvnSettingBuilderFactory = new DefaultSettingsBuilderFactory();
        DefaultSettingsBuilder settingsBuilder =  mvnSettingBuilderFactory.newInstance();
        SettingsBuildingResult settingsBuildingResult = settingsBuilder.build(settingsBuildingRequest);

        Settings effectiveSettings = settingsBuildingResult.getEffectiveSettings();
        Map<String, Profile> profilesMap = effectiveSettings.getProfilesAsMap();
        Collection<RemoteRepository> remotes = new ArrayList<RemoteRepository>(20);
        for (String profileName : effectiveSettings.getActiveProfiles())
        {
            Profile profile = profilesMap.get(profileName);
            List<Repository> repositories = profile.getRepositories();
            for (Repository repo : repositories)
            {
                RemoteRepository remoteRepo
                        = new RemoteRepository(repo.getId(), "default", repo.getUrl());
                remotes.add(remoteRepo);
            }
        }
        return remotes;
    }
}

推荐答案

您看到的行为是该插件的预期行为:该插件的目的不是复制Maven为您下载依赖项的能力. 其目标是在使用Maven进行夹具开发时,通过Maven(即为夹具编写Java代码然后进行编译)使您在夹具开发过程中可以使用的依赖项也可用. 假设您使用Maven编译了Java源代码(因此将任何所需的依赖项下载到本地存储库中),并且现在您想要使用结果类(及其来自Wiki的依赖项). (这也是@ A_Di-Matteo所经历的.)

The behavior you see is the expected behavior of the plugin: the goal of this plugin is not to reproduce Maven's ability to download dependencies for you. Its goal is to make the dependencies that you have available to you during fixture development with Maven (i.e. writing Java code for fixtures and then compiling them) also available to the wiki when it uses your fixtures. It assumes you compiled your Java source using Maven (thus downloading any needed dependencies to your local repository) and you now want to use the resulting classes (and their dependencies from the wiki). (This is what @A_Di-Matteo also experienced.)

如果要使所有依赖项对不编译代码的人员可用,则应将依赖项复制到FitNesse安装并随Wiki一起分发.我知道获取所有依赖项并将它们放置在一个地方的最简单方法是使用maven-dependency-plugin的copy-dependencies目标.

if you want to make all dependencies available to people NOT compiling the code you should copy the dependencies to the FitNesse installation and distribute them with the wiki. The easiest way I know to get all dependencies and place them in one place is by using the maven-dependency-plugin's copy-dependencies goal.

在我的 FitNesse基线中,我使用Maven类路径插件来确保不在开发过程中必须手动更新Wiki的类路径.我将依赖项复制到单个目录中,并通过Wiki分发它们,以便人们可以使用固定装置执行/编写测试,而无需在其系统上编译或安装Maven(以创建独立的(不需要JDK或Maven的)Fitnesse环境").在我的根页面上,我结合了两种方法:

In my FitNesse baseline I use the Maven classpath plugin to ensure I don't have to update the wiki's classpath by hand during development. I copy the dependencies to a single directory and distribute them with the wiki so people can execute/write tests using the fixtures without compiling or having Maven on their system (to create 'a standalone (no JDK or Maven required) Fitnesse environment'). On my root page I combine both approaches:

The location when working standalone:
!path fixtures
!path fixtures/*.jar

When developing and changing the fixtures, we will work based on the pom.xml:
!pomFile ../pom.xml@compile

这篇关于Fitnesse Maven Classpath插件无法解析远程依赖项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆