2016-04-12 4 views
3

解決済みの依存関係を取得するMavenプラグインを作成しています。単一のモジュールプロジェクト/ pomでは正常に動作しますが、複数のモジュールプロジェクトでは失敗します。Mavenプラグインのすべてのモジュール間で依存関係をどのように解決しますか?

ここでは、コードスニペット

@Mojo(
    name="scan", 
    aggregator = true, 
    defaultPhase = LifecyclePhase.COMPILE, 
    threadSafe = true, 
    requiresDependencyCollection = ResolutionScope.TEST, 
    requiresDependencyResolution = ResolutionScope.TEST, 
    requiresOnline = true 
) 
public class MyMojo extends AbstractMojo { 

    @Parameter(property = "project", required = true, readonly = true) 
    private MavenProject project; 

    @Parameter(property = "reactorProjects", required = true, readonly = true) 
    private List<MavenProject> reactorProjects; 


    @Override 
    public void execute() throws MojoExecutionException { 
    for(MavenProject p : reactorProjects) { 
     for(Artifact a : p.getArtifacts()) { 
     ...consolidate artifacts 
     } 
    } 
    } 
} 

は、上記のコードは、すべてのモジュール間ですべて解決の依存関係を統合しますが、それはいくつかの追加のものが含まれています。

ここでは、使用するサンプルプロジェクトを示します。あなたはモジュール/プロジェクトコアはコモンズに依存していることを、この

[INFO] ------------------------------------------------------------------------ 
[INFO] Building core 0.1-SNAPSHOT 
[INFO] ------------------------------------------------------------------------ 
[INFO] 
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ core --- 
[INFO] com.github:core:jar:0.1-SNAPSHOT 
[INFO] \- axis:axis:jar:1.4:compile 
[INFO] +- commons-logging:commons-logging:jar:1.0.4:runtime 
[INFO] \- commons-discovery:commons-discovery:jar:0.2:runtime 
[INFO]  \- (commons-logging:commons-logging:jar:1.0.3:runtime - omitted for conflict with 1.0.4) 
[INFO]                   
[INFO] ------------------------------------------------------------------------ 
[INFO] Building web 0.1-SNAPSHOT 
[INFO] ------------------------------------------------------------------------ 
[INFO] 
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ web --- 
[INFO] com.github:web:war:0.1-SNAPSHOT 
[INFO] +- commons-logging:commons-logging:jar:1.1.1:compile 
[INFO] \- com.github:core:jar:0.1-SNAPSHOT:compile 
[INFO] \- axis:axis:jar:1.4:compile 
[INFO]  +- (commons-logging:commons-logging:jar:1.0.4:runtime - omitted for conflict with 1.1.1) 
[INFO]  \- commons-discovery:commons-discovery:jar:0.2:runtime 
[INFO]   \- (commons-logging:commons-logging:jar:1.0.3:runtime - omitted for conflict with 1.1.1) 
[INFO] ------------------------------------------------------------------------ 

お知らせのような出力が表示され、

mvn dependency:tree -Dverbose -Dincludes=commons-logging 

を実行してくださいモジュール・プロジェクトのメインフォルダからthis github repo

をダウンロードしてくださいロギング1.0.4およびコモンズロギング1.0.3がありますが、競合のため1.0.3は省略され、1.0.4は解決されます。 これは、独自にコアを構築する場合は、コモンズロギング1.0.4のみを取得する必要があることを意味します。

module/project ウェブは、commons-loggingの競合するバージョンにも依存しますが、1.1.1に解決されています。

"mvn package"コマンドを使用して "プロジェクト全体"(modules-project)をビルドする場合は、modules-project/web/target/myweb/WEB-INF/libにすべての依存関係を解決し、コモンズロギング1.1.1のみを含みます。モジュール・プロジェクト、コア、およびウェブ:

はここで上記のコードでコード

に問題だ、reactorProjectsは3 MavenProjectのでインスタンス化されます。

modules-projectおよびwebの場合、commons-logging 1.1.1を解決して返します。しかし、コアのプロジェクトでは、commons-logging 1.0.4を解決して返します。

私はコモンズ・ログ1.1.1はビルドが生成されます依存であることを知っている私のプラグインのコードをしたい、としませコモンズ・ログ1.0.4

任意の考え?

+0

このプラグインの目的は何ですか?あなたは何をしたいですか? – khmarbaise

+0

"mvn package"が生成するすべての依存関係を取得したいだけです – kane

+0

すでにこのようなことができるmaven-assembly-pluginを使うべきです...依存関係を取得したいのとは別に、あなたはなぜそれらを必要としているのですか? – khmarbaise

答えて

4

実際にあなたの質問にはすべてのことがあります。以下のプラグインは、コンソール出力に反応器内のWARプロジェクトの成果物に印刷されます:これは何

@Mojo(name = "foo", aggregator = true, requiresDependencyResolution = ResolutionScope.TEST) 
public class MyMojo extends AbstractMojo { 

    @Parameter(defaultValue = "${project}", readonly = true, required = true) 
    private MavenProject project; 

    @Parameter(defaultValue = "${session}", readonly = true, required = true) 
    private MavenSession session; 

    @Parameter(property = "reactorProjects", required = true, readonly = true) 
    private List<MavenProject> reactorProjects; 

    public void execute() throws MojoExecutionException, MojoFailureException { 
     MavenProject packagedProject = getWarProject(reactorProjects); 
     for (Artifact artifact : packagedProject.getArtifacts()) { 
      getLog().info(artifact.toString()); 
     } 
    } 

    private MavenProject getWarProject(List<MavenProject> list) throws MojoExecutionException { 
     for (MavenProject project : list) { 
      if ("war".equals(project.getPackaging())) { 
       return project; 
      } 
     } 
     throw new MojoExecutionException("No WAR project found in the reactor"); 
    } 

} 

を、それが注入されたパラメータreactorProjectsで反応器内のすべてのプロジェクトを獲得することです。次に、それらのループのいずれかがそのパッケージを比較することによって"war"であるかを見つけるためにループする。見つかったら、getArtifacts()はそのプロジェクトの解決済みの成果物をすべて返します。それ作品を作る

魔法はMOJO定義でaggregator = trueです:

国旗このモジョ、すなわち集約モジュールとしてリストされているプロジェクトのセットでビルドマルチモジュールの方法でそれを実行します。 core POM

<plugin> 
    <groupId>sample.plugin</groupId> 
    <artifactId>test-maven-plugin</artifactId> 
    <version>1.0.0</version> 
    <executions> 
    <execution> 
     <id>test</id> 
     <phase>compile</phase> 
     <goals> 
     <goal>foo</goal> 
     </goals> 
    </execution> 
    </executions> 
</plugin> 

とあなたの例のプロジェクトを実行に追加すると

、これはコンソールに出力します。

[INFO] commons-logging:commons-logging:jar:1.1.1:compile 
[INFO] com.github:core:jar:0.1-SNAPSHOT:compile 
[INFO] axis:axis:jar:1.4:compile 
[INFO] org.apache.axis:axis-jaxrpc:jar:1.4:compile 
[INFO] org.apache.axis:axis-saaj:jar:1.4:compile 
[INFO] axis:axis-wsdl4j:jar:1.5.1:runtime 
[INFO] commons-discovery:commons-discovery:jar:0.2:runtime 

これは十分です。これで、私たちは前進し、例えば、解決された成果物を現在のビルド中のプロジェクトとパッケージ化されたプロジェクトと比較することができます。パッケージ化されたプロジェクトの成果物との現在のアーティファクトを比較して、唯一の同じグループ/アーティファクトIDが異なるバージョンのものを保持

printConflictingArtifacts(packagedProject.getArtifacts(), project.getArtifacts()); 

と呼ばれる、我々はメソッドを追加する場合

private void printConflictingArtifacts(Set<Artifact> packaged, Set<Artifact> current) { 
    for (Artifact a1 : current) { 
     for (Artifact a2 : packaged) { 
      if (a1.getGroupId().equals(a2.getGroupId()) && 
        a1.getArtifactId().equals(a2.getArtifactId()) && 
        !a1.getVersion().equals(a2.getVersion())) { 
       getLog().warn("Conflicting dependency: " + a2 + " will be packaged and found " + a1); 
      } 
     } 
    } 
} 

、我々あなたの例でコンソール出力で取得することができます:

[WARNING] Conflicting dependency: commons-logging:commons-logging:jar:1.1.1:compile will be packaged and found commons-logging:commons-logging:jar:1.0.4:runtime 

上記最終的な仮定パッケージングモジュールはWARモジュールでした。これをより一般的なものにして、モジュールのどれがターゲットモジュールであるかをユーザーに指定させることができます(つまり、実際の配信をパッケージ化します)。

はそのために、私たちは私たちのMOJO

@Parameter(property = "packagingArtifact") 
private String packagingArtifact; 

このパラメータは、フォームgroupId:artifactIdのものであろうにパラメータを追加することができますし、ターゲット・モジュールの座標を表します。次に、getPackagingProjectというメソッドを追加して、それらの座標に関連付けられたMavenProjectを返すことができます。

core内部プラグインの構成は

<plugin> 
    <groupId>sample.plugin</groupId> 
    <artifactId>test-maven-plugin</artifactId> 
    <version>1.0.0</version> 
    <executions> 
     <execution> 
      <id>test</id> 
      <phase>compile</phase> 
      <goals> 
       <goal>foo</goal> 
      </goals> 
      <configuration> 
       <packagingArtifact>com.github:web</packagingArtifact> 
      </configuration> 
     </execution> 
    </executions> 
</plugin> 

なり、完全MOJOは次のようになります。これは、上記のアイデアを実現

@Mojo(name = "foo", aggregator = true, requiresDependencyResolution = ResolutionScope.TEST, defaultPhase = LifecyclePhase.COMPILE) 
public class MyMojo extends AbstractMojo { 

    @Parameter(defaultValue = "${project}", readonly = true, required = true) 
    private MavenProject project; 

    @Parameter(defaultValue = "${session}", readonly = true, required = true) 
    private MavenSession session; 

    @Parameter(property = "reactorProjects", required = true, readonly = true) 
    private List<MavenProject> reactorProjects; 

    @Parameter(property = "packagingArtifact") 
    private String packagingArtifact; 

    public void execute() throws MojoExecutionException, MojoFailureException { 
     MavenProject packagedProject = getPackagingProject(reactorProjects, packagingArtifact); 
     printConflictingArtifacts(packagedProject.getArtifacts(), project.getArtifacts()); 
    } 

    private void printConflictingArtifacts(Set<Artifact> packaged, Set<Artifact> current) { 
     for (Artifact a1 : current) { 
      for (Artifact a2 : packaged) { 
       if (a1.getGroupId().equals(a2.getGroupId()) && a1.getArtifactId().equals(a2.getArtifactId()) 
         && !a1.getVersion().equals(a2.getVersion())) { 
        getLog().warn("Conflicting dependency: " + a2 + " will be packaged and found " + a1); 
       } 
      } 
     } 
    } 

    private MavenProject getPackagingProject(List<MavenProject> list, String artifact) throws MojoExecutionException { 
     if (artifact == null) { 
      return getWarProject(list); 
     } 
     String[] tokens = artifact.split(":"); 
     for (MavenProject project : list) { 
      if (project.getGroupId().equals(tokens[0]) && project.getArtifactId().equals(tokens[1])) { 
       return project; 
      } 
     } 
     throw new MojoExecutionException("No " + artifact + " project found in the reactor"); 
    } 

    private MavenProject getWarProject(List<MavenProject> list) throws MojoExecutionException { 
     for (MavenProject project : list) { 
      if ("war".equals(project.getPackaging())) { 
       return project; 
      } 
     } 
     throw new MojoExecutionException("No WAR project found in the reactor"); 
    } 

} 

:ユーザーがターゲットモジュールに与えた場合、それを参考にしています。このパラメータが存在しない場合、デフォルトで原子炉内のWARを検出します。

+0

これは巧妙な解決策であり、私が挙げた特定の例ではうまくいくと思います。 (私はそれをupvoted)私の質問はどのように一般的なこのソリューションです。例えばすべてのマルチモジュールプロジェクトには、正確に1つの戦争が含まれていますか?私は戦争プロジェクトがなければ、これはうまくいかないと思いますが、戦争パッケージングがないマルチモジュールプロジェクトが何を意味するのかは分かりません。 – kane

+0

@kaneマルチモジュールプロジェクトは、必ずしも1つの戦争。問題は、どのモジュールが「パッケージ化」モジュールか「ターゲット」モジュールかを判断することになります。この場合、「戦争」パッケージングを有するモジュールによって決定される。しかし、より一般的なものにして、ターゲットモジュールを指定する構成要素を追加することは可能です。それを使って解決するつもりです。 – Tunaki

+0

私は原子炉について読んでいました。どうやら、それはモジュールが依存性に従って順番に構築されることを保証します。 reactorProjects命令を利用する一般的な解決策があるのだろうかと思います。つまり、最後のプロジェクトには解決された依存関係の完全なセットが常に含まれます。それは私たちの "ターゲット"モジュールですか? – kane

関連する問題