2016-05-03 162 views
1

我正在使用允許Fitnesse使用Maven存儲庫解析類路徑的Fitnesse Maven classpath pluginFitnesse Maven Classpath插件無法解析遠程依賴關係

該插件可以工作,但它似乎無法解決存儲在我的遠程存儲庫中的依賴關係。
它可以解決快照,如果它在我的本地存儲庫,但不是遠程。

如果我運行mvn install(來自Fitnesse外部),那麼找到依賴關係時沒有問題,因此建議我的settings.xml設置正確。

我調試了plugin,但我無法準確指出它爲什麼無法解析遠程快照。

問題:如何更改此設置以允許它解析快照?

編輯:添加更多詳細

這可以很容易地通過運行這個單元測試轉載:MavenClasspathExtractorTest

這個單元測試嘗試解決公地郎依賴。

如果您從本地存儲庫中刪除此依賴項,則測試將失敗,因爲它似乎無法從遠程存儲庫中檢索。

如果您將它放回本地存儲庫,它會再次通過。

這是問題的關鍵。

潛在的解決方案

下面是使用首先使用本地資源庫的jcabi-aether庫潛在的解決方案,如果不會有從遠程存儲庫下載。這看起來不錯嗎?它適合我的需求

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; 
    } 
} 
+0

您能否提供更多詳細信息?最重要的是,您實際使用的'pom.xml'文件(或相關/縮減的部分)? –

+0

在上面添加更多細節 – DJ180

回答

2

您看到的行爲是該插件的預期行爲:此插件的目標不是重現Maven爲您下載依賴關係的能力。 它的目標是在使用Maven進行燈具開發期間爲您提供的依賴關係(即編寫用於燈具的Java代碼,然後編譯它們),當wiki使用您的燈具時也可以使用它們。 它假定您使用Maven編譯Java源代碼(從而將任何所需的依賴項下載到本地資源庫),現在您想使用最終的類(以及它們從wiki中的依賴項)。 (這是@ A_Di-Matteo也經歷過的。)

如果你想讓所有人不需要編譯代碼,那麼你應該將依賴關係複製到FitNesse安裝中並將它們分發給wiki。我知道獲取所有依賴關係並將它們放在一個位置的最簡單方法是使用maven-dependency-plugin的copy-dependencies目標。

在我的FitNesse baseline中,我使用Maven classpath插件來確保在開發過程中不需要手動更新wiki的類路徑。我將依賴關係複製到一個單獨的目錄中,並將它們與wiki分發,這樣人們就可以在不編譯或在他們的系統上使用Maven的情況下使用fixtures執行/編寫測試(創建'獨立(不需要JDK或Maven)Fitnesse環境')。在我的根頁面上,我結合了兩種方法:

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 ../[email protected] 
+0

感謝您的解釋。理想情況下,我希望插件從Maven存儲庫下載依賴項,否則Fitnesse安裝會變得非常大,特別是如果您有多個Fitnesse項目。我現在正在編寫一些代碼,用於下載依賴關係並提供這些代碼 – DJ180

+0

我確認這是我猜測和重現的行爲:依賴關係必須已經存在於本地緩存中,否則它將無法工作。當pom被修改時,Eclipse實際上是爲我下載的,否則它應該是手動完成的(在測試pom中調用maven或使用本答案中提到的依賴插件)。 –

1

我能夠成功運行MavenClasspathExtractorTest,則:

  • 改變了commons-lang版本中通過測試中使用的pom.xml文件,更改爲2.0,不存在於我的Maven緩存:測試成功,在我的Maven緩存中依賴下載的propery
  • 本地刪除版本指定的pom.xml,2.6:測試成功,依賴關係下載了agai N到本地緩存

因此,您所遇到的行爲是不可重複的:它正確地從遠程倉庫獲取Maven依賴。

但是,確實無法獲取SNAPSHOT依賴關係(將它們添加到上面相同的pom.xml測試文件中)。以下警告顯示在我的IDE控制檯中:

[警告]無法將元數據/maven-metadata.xml從/轉移到nexus(http:/// nexus/content/groups/public /):No連接器可用於訪問存儲庫nexus(http:/// nexus/content/groups/public /)類型默認使用可用工廠

注意:我刪除了一些信息(url,依賴項名稱)。

這基本上是因爲項目pom.xml中缺少一些依賴關係,因此在運行時,嵌入式Maven無法找到任何有效工廠來從給定存儲庫傳輸依賴關係。

添加下面的依賴關係(項目,而不是測試之一)的POM固定的問題:

<dependency> 
    <groupId>org.eclipse.aether</groupId> 
    <artifactId>aether-connector-basic</artifactId> 
    <version>1.1.0</version> 
</dependency> 
<dependency> 
    <groupId>org.eclipse.aether</groupId> 
    <artifactId>aether-transport-wagon</artifactId> 
    <version>1.1.0</version> 
</dependency> 
<dependency> 
    <groupId>org.apache.maven.wagon</groupId> 
    <artifactId>wagon-http</artifactId> 
    <version>2.8</version> 
</dependency> 
<dependency> 
    <groupId>org.apache.maven.wagon</groupId> 
    <artifactId>wagon-provider-api</artifactId> 
    <version>2.8</version> 
</dependency> 

SNAPSHOT依賴然後取正常。

更新
以上是由IDE影響描述(在我的情況下的Eclipse),將其自動下載編輯測試POM依賴關係時的行爲。否則,依賴項應該已經存在於本地maven緩存中,以使測試成功執行。

+0

感謝您的回覆。不幸的是,在將這些依賴關係添加到主pom後,我仍然看到上面的相同錯誤。另外,我仍然無法解決我覺得很奇怪的遠程發佈的依賴關係。任何想法,爲什麼這是? – DJ180

+0

@ DJ180上面同樣的錯誤意味着'無法傳輸元數據'等錯誤? –

+0

是的,我得到了同樣的錯誤。我也很困惑你如何能夠解決遠程發佈的依賴關係 – DJ180