创建自己的 Gradle Scala 插件

完成基本设置示例后,你可能会发现自己在每个 Scala Gradle 项目中都重复了大部分内容。闻起来像样板代码……

如果不使用 Gradle 提供的 Scala 插件 ,你可以应用自己的 Scala 插件,该插件将负责处理所有常见的构建逻辑,同时扩展已有的插件。

这个例子将把以前的构建逻辑转换为可重用的 Gradle 插件。

幸运的是,在 Gradle 中,你可以在 Gradle API 的帮助下轻松编写自定义插件,如文档中所述。作为实现语言,你可以使用 Scala 本身甚至 Java。但是,你可以在整个文档中找到的大多数示例都是用 Groovy 编写的。例如,如果你需要更多代码示例或想了解 Scala 插件背后的内容,可以查看 gradle github repo

编写插件

要求

自定义插件在应用于项目时将添加以下功能:

  • scalaVersion 属性对象,它将具有两个可覆盖的默认属性
    • major =“2.12”
    • minor =0
  • 应用于依赖项名称的 withScalaVersion 函数将添加 scala 主要版本以确保二进制兼容性(sbt %%运算符可能响铃,否则在继续之前转到此处
  • 创建必要目录树的 createDirs 任务,与前面的示例完全相同

实施指南

  1. 创建一个新的 gradle 项目并将以下内容添加到 build.gradle

    apply plugin: ‘scala’ apply plugin: ‘maven’

    repositories { mavenLocal() mavenCentral() }

    dependencies { compile gradleApi() compile “org.scala-lang:scala-library:2.12.0” }

备注

  • 插件实现是用 Scala 编写的,因此我们需要 Gradle Scala 插件
  • 为了使用其他项目的插件,使用 Gradle Maven 插件; 这增加了用于将项目 jar 保存到 Maven Local Repository 的 install 任务
  • compile gradleApi()gradle-api-<gradle_version>.jar 添加到类路径中
  1. 为插件实现创建一个新的 Scala 类
package com.btesila.gradle.plugins 
 
import org.gradle.api.{Plugin, Project}  
 
class ScalaCustomPlugin extends Plugin[Project] {
    override def apply(project: Project): Unit = {
        project.getPlugins.apply("scala")
    }
}

备注

  • 为了实现插件,只需扩展 Project 类型的 Plugin 特性并覆盖 apply 方法
  • 在 apply 方法中,你可以访问插件所应用的 Project 实例,你可以使用它来为其添加构建逻辑
  • 这个插件什么都不做,只是应用现有的 Gradle Scala 插件
  1. 添加 scalaVersion 对象属性

首先,我们创建一个 ScalaVersion 类,它将保存两个版本属性

class ScalaVersion {
  var major: String = "2.12"
  var minor: String = "0"
}

Gradle 插件的一个很酷的事实是,你始终可以添加或覆盖特定属性。插件通过连接到 gradle Project 实例的 ExtensionContainer 接收这种用户输入。有关详细信息,请查看信息。
通过在 apply 方法中添加以下内容,我们基本上是这样做的:

  • 如果项目中没有定义 scalaVersion 属性,我们添加一个默认值

  • 否则,我们将现有的一个作为 ScalaVersion 的实例,以进一步使用它

    var scalaVersion = new ScalaVersion if (!project.getExtensions.getExtraProperties.has(“scalaVersion”)) project.getExtensions.getExtraProperties.set(“scalaVersion”, scalaVersion) else scalaVersion = project.getExtensions.getExtraProperties.get(“scalaVersion”).asInstanceOf[ScalaVersion]

这相当于将以下内容写入应用插件的项目的构建文件:

ext {
    scalaVersion.major = "2.12"
    scalaVersion.minor = "0"

}
  1. 使用 scalaVersion 将 t​​ihuan20 库添加到项目依赖项中

    project.getDependencies.add(“compile”, s"org.scala-lang:scala-library:${scalaVersion.major}.${scalaVersion.minor}")

这相当于将以下内容写入应用插件的项目的构建文件:

compile "org.scala-lang:scala-library:2.12.0"
  1. 添加 withScalaVersion 功能

    val withScalaVersion = (lib: String) => { val libComp = lib.split(":") libComp.update(1, s"${libComp(1)}_${scalaVersion.major}") libComp.mkString(":") } project.getExtensions.getExtraProperties.set(“withScalaVersion”, withScalaVersion)

  2. 最后,创建 createDirs 任务并
    通过扩展 DefaultTask 将其添加到项目实现 Gradle 任务:

    class CreateDirs extends DefaultTask { @TaskAction def createDirs(): Unit = { val sourceSetContainer = this.getProject.getConvention.getPlugin(classOf[JavaPluginConvention]).getSourceSets

    sourceSetContainer forEach { sourceSet =>
      sourceSet.getAllSource.getSrcDirs.forEach(file => if (!file.getName.contains("java")) `file.mkdirs()`)
    }
    

    } }

注意SourceSetContainer 包含有关项目中存在的所有源目录的信息。Gradle Scala 插件的作用是将额外的源集添加到 Java 库中,如插件文档中所示

通过将此附加到 apply 方法,将 createDir 任务添加到项目中:

project.getTasks.create("createDirs", classOf[CreateDirs])

最后,你的 ScalaCustomPlugin 类应该是这样的:

class ScalaCustomPlugin extends Plugin[Project] {
  override def apply(project: Project): Unit = {
    project.getPlugins.apply("scala")

    var scalaVersion = new ScalaVersion
    if (!project.getExtensions.getExtraProperties.has("scalaVersion"))
      project.getExtensions.getExtraProperties.set("scalaVersion", scalaVersion)
    else
      scalaVersion = project.getExtensions.getExtraProperties.get("scalaVersion").asInstanceOf[ScalaVersion]

    project.getDependencies.add("compile", s"org.scala-lang:scala-library:${scalaVersion.major}.${scalaVersion.minor}")

    val withScalaVersion = (lib: String) => {
      val libComp = lib.split(":")
      libComp.update(1, s"${`libComp(1)`}_${scalaVersion.major}")
      libComp.mkString(":")
    }
    project.getExtensions.getExtraProperties.set("withScalaVersion", withScalaVersion)

    project.getTasks.create("createDirs", classOf[CreateDirs])
  }
}

将插件项目安装到本地 Maven 存储库

通过运行 tihuan 29
可以轻松完成此操作你可以通过访问本地存储库目录来检查安装,通常位于~/.m2/repository

Gradle 如何找到我们的新插件?

每个 Gradle 插件都有一个 id,用于 apply 语句。例如,通过将以下内容写入构建文件,它将转换为 Gradle 的触发器,以查找并应用 id 为 scala 的插件。

apply plugin: 'scala'

以同样的方式,我们希望以下列方式应用我们的新插件,

apply plugin: "com.btesila.scala.plugin"

这意味着我们的插件将具有 com.btesila.scala.plugin id。

要设置此 ID,请添加以下文件:

src / main / resources / META-INF / gradle-plugin / com.btesil.scala.plugin.properties

implementation-class=com.btesila.gradle.plugins.ScalaCustomPlugin

之后,再次运行 gradle install

使用插件

  1. 创建一个新的空 Gradle 项目,并将以下内容添加到构建文件中

    buildscript { repositories { mavenLocal() mavenCentral() }

    dependencies {
        //modify this path to match the installed plugin project in your local repository
        classpath 'com.btesila:working-with-gradle:1.0-SNAPSHOT'
    }
    

    }

    repositories { mavenLocal() mavenCentral() }

    apply plugin: “com.btesila.scala.plugin”

  2. 运行 gradle createDirs - 你现在应该生成所有源目录

  3. 通过将其添加到构建文件来覆盖 scala 版本:

    ext { scalaVersion.major = “2.11” scalaVersion.minor = “8”

    } println(project.ext.scalaVersion.major) println(project.ext.scalaVersion.minor)

  4. 添加与 Scala 版本二进制兼容的依赖库

    dependencies { compile withScalaVersion(“com.typesafe.scala-logging:scala-logging:3.5.0”) }

而已! 你现在可以在所有项目中使用此插件,而无需重复相同的旧样板。