用于包装Maven工件存储库的Gradle自定义插件

时间:2017-05-24 15:59:16

标签: java maven gradle gradle-plugin

简介

我正在为Gradle编写一个自定义插件,允许用户将其构建生成的工件发布到公司Maven存储库。我希望用户能够使用标准maven-publish插件上传他们的工件,但是他们不知道存储库的详细信息,即身份验证。

用户可以运行本地版本,但不能向存储库发布任何内容。在构建服务器上运行时,相同的用户提供的构建脚本将能够发布。用户可以下载插件并在本地使用它,但它不起作用。它会失败或者做一个模拟的无操作上传到本地/虚拟仓库/无论如何,这现在并不重要。在构建服务器上运行时,插件只会“知道”并正常工作。

正如我所说,我希望用户使用标准maven-publish插件。对于用户的build.gradle:

我想要这样的东西
repositories {
    mavenCentral()
    Organization.mavenCorporate() /* this would be it */
}

Organization部分不是必需的,这就是我看到它如何与Gradle的项目扩展一起使用,这些扩展似乎目前比常规更受欢迎。)

当前状态

到目前为止,我已经能够在某种程度上使脚本的上述部分工作。当我运行使用我的插件的构建时,它会:

  • 在语法检查/编译时没有失败,所以我知道Gradle理解这段代码。
  • 在应用插件时打印一些信息,所以我知道Gradle确实在使用它。
  • 在构建脚本中执行println Organization.mavenCorporate().name时打印我的(当前硬编码的)存储库名称,因此我知道扩展正在运行。
  • 在构建脚本中执行println project.repositories[0].name时打印我的存储库名称,因此我知道项目知道存储库。该名称与上一个打印相同,并包含System.nanoTime(),以确保它不会生成两次。此外,如果我打印默认对象的toString()而不是其名称,则两个标识符都相同。

但是,当构建尝试解析实际依赖项时,它会失败并显示以下消息:

Execution failed for task ':myproject:compileJava'.
> Could not resolve all dependencies for configuration ':myproject:compileClasspath'.
   > Cannot resolve external dependency org.apache.logging.log4j:log4j-api:2.3 because no repositories are defined.
     Required by:
         project :myproject
    > Cannot resolve external dependency org.apache.logging.log4j:log4j-web:2.3 because no repositories are defined.
      Required by:
          project :myproject
[...]

困扰我的是'因为没有定义存储库'部分。我希望它会因为很多不同的原因而失败,但不是这个原因。当我添加另一个不包含所需依赖项的存储库时,它会因另一种错误而失败。

代码

我的插件是用Java编写的。我见过Gradle Plugin Portal的一个插件,其目的非常相似,但它是用Groovy编写的。它只是为project.repositories.metaClass添加了一些方法。我不知道Groovy,但这看起来像一个快速而肮脏的解决方案,以避免以适当的方式处理Gradle的API。

截至目前,我有以下内容:

  • 主要插件类:

    public class MyPlugin implements Plugin<Project> {
        @Override
        public void apply(Project project) {
            _printVersionInfo(project);
            // this allows the use of Organization methods as Gradle DSL
            project.getExtensions().create("Organization", Organization.class, project);
            // this should add the repo to project's RepositoryManager
            project.getRepositories().add(CustomRepository.getInstance(project));
        }
        [unrelated methods omitted]
    }
    
  • 自定义存储库类:

    public class CustomRepository implements MavenArtifactRepository {
        private static MavenArtifactRepository repo;    
        public static MavenArtifactRepository getInstance(Project project) {
            if (repo == null) {
                DefaultRepositoryHandler drh = (DefaultRepositoryHandler) project.getRepositories(); 
                repo = drh.maven(new CustomRepoAction());   
            }
            return repo;
        }
        [implemented methods from MavenArtifactRepository omitted for brevity; for debugging purposes, every method except getName() and getUrl() currently throws an UnsupportedOperationException]
    }
    
  • 扩展程序Organization。仅包含mavenCorporate() DSL方法,该方法返回使用与主插件类相同的MavenArtifactRepository调用获得的CustomRepository.getInstance(project)

  • 实现CustomRepoAction的{​​{1}}类。仅包含Action<MavenArtifactRepository>方法的实现,该方法设置作为参数传递的execute的名称和网址。

我正在使用Java 8和Gradle 3.4。作为用户,我对Gradle相对较新,并且不熟悉Java 7和8的新功能。

问题

<击> 我错过了什么吗?为什么Gradle不将MavenArtifactRepository返回的MavenRepositoryArtifact识别为存储库?我是否需要将存储库与项目,存储库处理程序或我不知道的任何类型的管理器对象绑定?

编辑:感谢@ lukegv的评论,现在我意识到我不能强制我的自定义DSL进入Organization.mavenCorporate()。我试过这样的事情:

DefaultRepositoryHandler

并且有效,将repositories { mavenCentral() maven Organization.mavenCorporateAction() /* instance of CustomRepoAction */ } 添加到项目的存储库中。但这并不能阻止用户访问存储库的内部,即密码。但是,MavenArtifactRepository不允许我添加RepositoryHandler.maven(Action<? super MavenArtifactRepository> action)的子类,我可以在其中控制此行为。

我是否需要实现MavenArtifactRepository并使其成为项目的默认存储库处理程序?如果没有实现我自己的自定义RepositoryHandler课程并且搞乱Gradle的内部结构,这是否可能?是否有一种清洁的方法来实现这一目标:

  

我希望用户能够使用标准Project插件   上传他们的工件,但没有他们知道存储库的   细节,即认证。

装饰,或任何暗示其他一切的默认行为变化很小或没有变化的东西?

0 个答案:

没有答案