SBT AutoPlugins教程

本教程将指导您完成编写自己的sbt插件的过程。 这样做有几个原因,而且非常简单:

  1. 将定制的构建步骤添加到您的持续集成过程中
  2. 为各种项目的不同环境提供默认设置

在开始之前,请确保在计算机上安装sbt ,并且可以通过命令行对其进行访问。 该代码可在github上找到 。 如果您是从第一次提交开始的,则可以在每次提交时逐步完成本教程。

设定

第一步是设置我们的插件项目。 在build.sbt中只有一个重要的设置,其余的取决于您。

sbtPlugin := true

这会将您的项目标记为sbt-plugin构建。 在本教程中,我使用的是sbt 0.13.7-M3,可让您根据需要编写build.sbt。 无需分隔线。 完整的build.sbt看起来像这样。

name := "awesome-os"
organization := "de.mukis"

scalaVersion in Global := "2.10.2"

sbtPlugin := true

// Settings to build a nice looking plugin site
site.settings
com.typesafe.sbt.SbtSite.SiteKeys.siteMappings <+= (baseDirectory) map { dir =>
  val nojekyll = dir / "src" / "site" / ".nojekyll"
  nojekyll -> ".nojekyll"
}
site.sphinxSupport()
site.includeScaladoc()

// enable github pages
ghpages.settings
git.remoteRepo := "git@github.com:muuki88/sbt-autoplugins-tutorial.git"

// Scripted - sbt plugin tests
scriptedSettings
scriptedLaunchOpts <+= version apply { v => "-Dproject.version="+v }

在此版本中使用的插件在project / plugins.sbt中配置。 没什么特别的。

外挂程式

现在,我们实现了插件的第一个工作版本和一个测试项目来进行尝试。 插件实际要做的是打印出很棒的操作系统。 稍后,我们将自定义此行为。

让我们看一下我们的插件代码。

import sbt._
import sbt.Keys.{ streams }

/**
 * This plugin helps you which operating systems are awesome
 */
object AwesomeOSPlugin extends AutoPlugin {

  /**
   * Defines all settings/tasks that get automatically imported,
   * when the plugin is enabled
   */
  object autoImport {
    lazy val awesomeOsPrint = TaskKey[Unit]("awesome-os-print", "Prints all awesome operating systems")
    lazy val awesomeOsList = SettingKey[Seq[String]]("awesome-os-list", "A list of awesome operating systems")
  }

  import autoImport._

  /**
   * Provide default settings
   */
  override lazy val projectSettings = Seq(
    awesomeOsList := Seq(
      "Ubuntu 12.04 LTS","Ubuntu 14.04 LTS","Debian Squeeze",
      "Fedora 20","CentOS 6",
      "Android 4.x",
      "Windows 2000","Windows XP","Windows 7","Windows 8.1",
      "MacOS Maverick","MacOS Yosemite",
      "iOS 6","iOS 7"
    ),
    awesomeOsPrint := {
      awesomeOsList.value foreach (os => streams.value.log.info(os))
    }
  )

}

就是这样。 我们定义了两个键。 AwesomeOsListSettingKey ,这意味着它是预先设置的,并且仅在某些人将其显式设置为另一个值或更改它时才会更改,例如

awesomeOsList += "Solaris"

awesomeOsPrint是一项任务,这意味着它在您每次调用时都会执行。

测试项目

让我们尝试一下插件。 为此,我们创建了一个测试项目,该项目对我们的os插件具有插件依赖性。 我们在插件项目的根目录下创建一个test-project目录。 在测试项目内部,我们添加一个build.sbt,其内容如下:

name := "test-project"
version := "1.0"

// enable our now plugin
enablePlugins(AwesomeOSPlugin)

但是,真正的技巧是在test-project / project / plugins.sbt内部完成的。 我们在父目录中创建对项目的引用:

// build root project
lazy val root = Project("plugins", file(".")) dependsOn(awesomeOS)

// depends on the awesomeOS project
lazy val awesomeOS = file("..").getAbsoluteFile.toURI

就这样。 在测试项目中运行sbt并打印出很棒的操作系统。

sbt awesomeOsPrint

如果您在插件代码中更改了某些内容,只需调用reload ,您的测试项目就会重新编译更改。

添加一个新任务并对其进行测试

接下来,我们添加一个将awesomeOsList存储在文件中的任务。 这是我们可以自动测试的。 测试sbt-plugins有点乏味,但是可以使用脚本化插件。

首先,我们在src / sbt-test内部创建一个文件夹 sbt-test内的目录可以视为将测试放入的类别。 我创建了一个全局文件夹,在其中放置了两个测试项目。 关键配置再次位于project / plugins.sbt中

addSbtPlugin("de.mukis" % "awesome-os" % sys.props("project.version"))

脚本化插件首先在本地对插件进行润饰,然后通过系统属性project.version将版本号传递给每个已启动的sbt测试版本。 我们之前在build.sbt中添加了此行为:

scriptedLaunchOpts <+= version apply { v => "-Dproject.version="+v }

每个测试项目都包含一个名为test的文件,该文件可以包含sbt命令和一些简单的check命令。 通常,您需要进行一些简单的检查,例如文件是否存在 ,并在测试项目中定义的任务中执行更复杂的工作。

我们第二次测试的测试文件如下所示。

# Create the another-os.txt file
> awesomeOsStore
$ exists target/another-os.txt
> check-os-list

检查操作系统列表任务测试项目的build.sbt内部定义(/src/sbt-test/global/store-custom-oslist/build.sbt。

enablePlugins(AwesomeOSPlugin)

name := "simple-test"

version := "0.1.0"

awesomeOsFileName := "another-os.txt"

// this is the scripted test
TaskKey[Unit]("check-os-list") := {
  val list = IO.read(target.value / awesomeOsFileName.value)
  assert(list contains "Ubuntu", "Ubuntu not present in awesome operating systems: " + list)
}

每个插件单独的操作系统

我们的下一个目标是自定义操作系统列表,以便用户可以选择他们最喜欢的系统。 为此,我们为每个操作系统类别生成一个配置范围 ,并为该范围中的设置生成一个插件。

在实际的插件中,您可以使用它来定义不同环境中的不同操作。 例如发展,分期或生产。 这是自动插件非常关键的一点,因为它允许您启用特定的插件以获得不同的构建风格和/或创建由不同的插件配置的不同的作用域。

第一步是创建三个新的自动插件: AwesomeWindowsPluginAwesomeMacPluginAwesomeLinuxPlugin 。 它们将以相同的方式工作:

  1. 将projectSettings的范围从AwesomeOSPlugin扩展到自定义定义的配置范围 ,并将其作为设置提供
  2. 覆盖自定义定义的配置范围内的特定设置/任务

AwesomeLinuxPlugin如下所示:

import sbt._

object AwesomeLinuxPlugin extends AutoPlugin{

  object autoImport {
    /** Custom configuration scope */
    lazy val Linux = config("awesomeLinux")
  }

  import AwesomeOSPlugin.autoImport._
  import autoImport._

  /** This plugin requires the AwesomeOSPlugin to be enabled */
  override def requires = AwesomeOSPlugin

  /** If all requirements are met, this plugin will automatically get enabled */
  override def trigger = allRequirements

  /**
   * 1. Use the AwesomeOSPlugin settings as default and scope them to Linux
   * 2. Override the default settings inside the Linux scope
   */
  override lazy val projectSettings = inConfig(Linux)(AwesomeOSPlugin.projectSettings) ++ settings

  /**
   * the linux specific settings
   */
  private lazy val settings: Seq[Setting[_]] = Seq(
    awesomeOsList in Linux := Seq(
      "Ubuntu 12.04 LTS",
      "Ubuntu 14.04 LTS",
      "Debian Squeeze",
      "Fedora 20",
      "CentOS 6",
      "Android 4.x"),
    // add awesome os to the general list
    awesomeOsList ++= (awesomeOsList in Linux).value
  )
}

其他插件的定义方式相同。 让我们尝试一下。 在测试项目中启动sbt。

sbt
awesomeOsPrint # will print all operating systems
awesomeWindows:awesomeOsPrint # will only print awesome windows os
awesomeMac:awesomeOsPrint # only mac
awesomeLinux:awesomeOsPrint # only linux

SBT已经提供了一些范围,例如CompileTest等。因此,只需要创建自己的范围。 大多数时候,您将使用已提供的插件,并在插件中自定义这些插件。

还有一张便条。 您可能想知道为什么全部启用了插件,而我们不必在测试项目中进行任何更改。 这是自动插件的另一个好处。 您可以指定require ,以定义插件和触发器之间的依赖关系,这些触发器指定何时应启用插件。

// what is required that this plugin can be enabled
<span class="k">override</span> <span class="k">def</span> <span class="nf">requires</span> <span class="o">=</span> <span class="n">AwesomeOSPlugin
</span>
// when should this plugin be enabled
<span class="k">override</span> <span class="k">def</span> <span class="nf">trigger</span> <span class="o">=</span> allRequirements

您的插件用户现在不必关心将插件放入build.sbt中的顺序,因为开发人员会预先定义需求,而sbt会尝试满足它们。

结论

SBT Autoplugins使插件用户和开发人员的生活更加轻松。 它稍微降低了sbt的陡峭学习曲线,并创建了更具可读性的buildfile。 对于sbt插件开发人员来说,迁移过程并不困难。 用sbt.AutoPlugin替换sbt.Plugin并创建一个autoImport字段。

翻译自: https://www.javacodegeeks.com/2014/11/sbt-autoplugins-tutorial.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值