简体   繁体   English

如何在gradle插件中添加自定义依赖关系处理程序?

[英]how to add custom dependency handler in a gradle plugin?

I would like to provide users of my gradle plugin a simple way to add all necessary dependencies. 我想为我的gradle插件用户提供一种添加所有必要依赖项的简单方法。 something like gradleApi() or localGroovy() . gradleApi()localGroovy()

I found out that both - gradleApi and localGroovy - are defined in DependencyHandler and implemented in DefaultDependencyHandler . 我发现gradleApi和localGroovy都是在DependencyHandler中定义的,并在DefaultDependencyHandler实现。 Can i provide a custom implementation of Dependencyhandler which extends DefaultDependencyHandler in my plugin? 我可以提供Dependencyhandler的自定义实现,它在我的插件中扩展了DefaultDependencyHandler吗? Or is there even a simplier way to achieve what i want? 或者是否有更简单的方法来实现我想要的?

thx in advance. thx提前。

One solution is to have the plugin install an extra method on the dependencies container: 一种解决方案是让插件在dependencies容器上安装额外的方法:

def jarDir = ...

project.dependencies.ext.pluginDeps = { 
    project.fileTree(jarDir) // filter file tree if necessary 
}

Users can then do: 用户可以这样做:

dependencies {
    compile pluginDeps()
}

Extra properties/methods are normally meant to be used by build scripts only (because they aren't backed by a model that can be discovered and reasoned about), but in this particular case (and as of Gradle 2.1) I can't think of a clearly better solution. 额外的属性/方法通常仅用于构建脚本(因为它们不受可以被发现和推理的模型的支持),但在这种特殊情况下(以及Gradle 2.1)我无法思考一个明显更好的解决方案。

PS: Keep in mind that for file (rather than repository) based dependencies, no version conflict resolution will occur. PS:请记住,对于基于文件(而不是存储库)的依赖项,不会发生版本冲突解决。

See if this helps to some extent. 看看这在某种程度上是否有帮助。 Let's say you create a custom plugin / class and consume it's artifact that in Gradle (within GRADLE_HOME/init.d/common.gradle file level). 假设您创建了一个自定义插件/类并使用它在Gradle中的工件(在GRADLE_HOME / init.d / common.gradle文件级别内)。

Custom plugin project's java/groovy file will look like 自定义插件项目的java / groovy文件看起来像

// Your custom plugin class file will look like
// Your custom plugin's source code will reside at: com.mycustom.plugin.gradle under src/main/java folder tree. 
package com.mycustom.plugin.gradle
import org.gradle.api.*
import org.gradle.api.file.*

import java.io.File;

public class myCustomFileUtil {
    /**
     * Default constructor
     */
   public myCustomFileUtil() {
   }

   /**
    * Read file returning list of lines. Double slash (//) at start of line
    * defines a comment.
    * @param fileName File to read.
    * @return List of lines.
    */
    public static List readIntoList( String fileName ) {
      def fname = new File( fileName )
        def listFinal = []
        def listLines = fname.readLines()
        listLines.each { it ->
            def str = it.trim();
            if( str.length() > 0 ) {
                if( ! str.startsWith( "//" ) ) listFinal.add( str );
            }
      }
        return listFinal
    }
}

In build.gradle 在build.gradle中

// The following funcationality is coming from a custom plugin that you'll write which will read a text file and create a list.
// It'll also ignore any lines that start with "//"
import com.mycustom.plugin.gradle.myCustomFileUtil

sourceSets {

   //if you have any
   //main
   //test
   //acceptanceTest
   //etc

}

// Read dependency lists from external files
List depListCompile = myCustomFileUtil.readIntoList( "$projectDir/dep-compile.txt" )
List depListTest = myCustomFileUtil.readIntoList( "$projectDir/dep-testArtifacts.txt" )
List depListWar = myCustomFileUtil.readIntoList( "$projectDir/dep-war.txt" )
List depListJibx = myCustomFileUtil.readIntoList( "$projectDir/dep-jibx.txt" )
List depListSomeOperationINeed = myCustomFileUtil.readIntoList( "$projectDir/dep-someoperationineed.txt" )


// Define dependencies
dependencies {
   // Compilation
   compile  depListCompile

   // If dependencies already exist on the local folder / in some workspace
   compile  fileTree(srcDir: "somefolder/whichcontain/myjar", include: "*.jar")
   compile  fileTree(srcDir: "/path/xx/yy/somefolder/whichcontain/myotherartifacts", include: "*.[zw]*")
   compile  fileTree(srcDir: "C:/zzz/somefolder/whichcontain", include: "myotherartifacts/*.[pj]*")

   // Unit Tests
   testCompile depListTest

   // Acceptance tests
   // Everything from compile and testCompile targets
   acceptanceTestCompile configurations.compile
   acceptanceTestCompile configurations.testCompile

   // Output of compiling "main" files
   acceptanceTestCompile sourceSets.main.output

   // Additional dependencies from war and others
   acceptanceTestCompile depListTest, depListWar

   // All configuration files
   acceptanceTestRuntime files( 'conf' )
}
// ... and more code here to do other operations

In dep-compile.txt you can have entries like 在dep-compile.txt中,你可以有像这样的条目

com.mycompany.project:oneofmycompanyartifact1:1.1.1
com.mycompany.project:oneofmycompanyartifact2:1.0.1@zip

httpunit:httpunit:1.6
jibx:jibx-bind:0.10.3.3
jibx:jibx-extras:0.10.3.3
jibx:jibx-run:0.10.3.3

cactus:cactus:1.7.2
selenium:selenium:0.9.2

Similarly, in dep-testArtifacts.txt, you can have the following entries (and create similar dep-XXXX files per Gradle phases/functionality you want: compile, test, war, doingSomeOperation etc). 类似地,在dep-testArtifacts.txt中,您可以拥有以下条目(并根据所需的Gradle阶段/功能创建类似的dep-XXXX文件:compile,test,war,doingSomeOperation等)。

cactus:cactus:1.7.2
jackson-all:jackson-all:1.9.9
jibx:jibx-bind:0.10.3.3
jibx:jibx-extras:0.10.3.3
jibx:jibx-run:0.10.3.3
//junit:junit:4.10
junit:junit:4.11
mockito-all:mockito-all:1.9.5

I found another way to do this. 我发现了另一种方法。 You can rely on the convention mechanism to do it. 您可以依靠约定机制来执行此操作。 First define a convention class: 首先定义一个约定类:

class CustomDepsPluginConvention {
    // here you can return anything which configuration methods in the
    // `dependencies` block would accept, e.g. a string or a map
    fun customDependency(): Map<String, String> {
        return mapOf(
            "group" to "com.whatever",
            "name" to "whatever",
            "version" to "1.2.3"
        )
    }
}

Then you add this convention object to the project in the plugin apply() method: 然后在插件apply()方法中将此约定对象添加到项目中:

open class CustomDepsPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        // the identifier of the convention object does not matter,
        // as long as it is unique
        project.convention.plugins["customDeps"] = CustomDepsPluginConvention()
    }
}

After you apply this plugin, the convention object will be added to the project object, exposing all its methods and properties on the project object and thus making them available directly in the build script: 应用此插件后,约定对象将添加到项目对象中,在项目对象上公开其所有方法和属性,从而使它们直接在构建脚本中可用:

apply plugin: CustomDepsPlugin

dependencies {
    compile customDependency()
}

This approach is arguably cleaner; 这种方法可以说更清洁; the only potential downside of it is that convention objects are kind of "deprecated" and are not recommended to be used. 唯一可能的缺点是,约定对象有点“弃用”,不建议使用。 Also, it may cause issues with the Kotlin DSL (as far as I remember, convention objects are not really supported by Kotlin DSL); 此外,它可能会导致Kotlin DSL出现问题(据我记得,Kotlin DSL并不真正支持常规对象); if you want to support Kotlin DSL, though, you can expose these dependency-generating functions as importable top-level functions and import them to your build script. 但是,如果要支持Kotlin DSL,可以将这些依赖关系生成函数公开为可导入的顶级函数,并将它们导入到构建脚本中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM