Search code examples
sbtsbt-plugin

generate resources from an AutoPlugin in sbt


I have created the following plugin, like so many plugins before it...

/**
 * This plugin automatically generates a version number based on the configured
 * minor version and today's date and time.
 */
object DateVersionPlugin extends AutoPlugin {
  //override def trigger = allRequirements

  def dateFormat (fmt : String) =
    new java.text.SimpleDateFormat(fmt).format(
      new java.util.Date()
    )

  def versionNumber (majorVersion      : String,
                     versionTrimFront  : Int,
                     versionDateFormat : String) =
    "%s.%s".format(
      majorVersion, dateFormat(versionDateFormat).substring(versionTrimFront)
    )


  /**
   * Defines all settings/tasks that get automatically imported,
   * when the plugin is enabled
   */
  object autoImport {
    /**
     * The number of values to trim off the front of the date string.
     *
     * This is used to achieve a date string which doesn't include the
     * present millenium.  The century, a stretch, can be imagined as
     * conceivable - but few civilizations have lasted multiple millennia.
     */
    lazy val versionTrimFront    = settingKey[Int]("Number of characters to remove from front of date")

    /**
     * The format to use for generating the date-part of this version number.
     */
    lazy val versionDateFormat   = settingKey[String]("The date format to use for versions")

    /**
     * The major version to place at the front of the version number.
     */
    lazy val versionMajor        = settingKey[String]("The major version number, default 0")

    /**
     * The filename of the generated resource.
     */
    lazy val versionFilename     = settingKey[String]("The filename of the file to generate")

    /**
     * The name of the property to place in the version number.
     */
    lazy val versionPropertyName = settingKey[String]("The name of the property to store as version")

    /**
     * Generate a version.conf configuration file.
     *
     * This task generates a configuration file of the name specified in the
     * settings key.
     */
    lazy val generateVersionConf = taskKey[Seq[File]]("Generates a version.conf file.")
  }

  import autoImport._

  /**
   * Provide default settings
   */
  override def projectSettings: Seq[Setting[_]] = Seq(
    versionFilename     := "version.conf",
    versionPropertyName := "version",
    versionDateFormat   := "YY.D.HHmmss",
    versionTrimFront    := 0,
    versionMajor        := "0",

    (version in Global) := versionNumber(versionMajor.value,
      versionTrimFront.value, versionDateFormat.value),

    generateVersionConf <<=
      (resourceManaged in Compile, version, versionFilename, versionPropertyName, streams) map {
        (dir, v, filename, propertyName, s) =>
          val file = dir / filename

          val contents = propertyName + " = \"" + v.split("-").head + "\""

          s.log.info("Writing " + contents + " to " + file)

          IO.write(file, contents)

          Seq(file)
      },

    resourceGenerators in Compile += generateVersionConf.taskValue
  )
}

The generate-version-conf task behaves as desired, generating the file I'm looking for. The version setting is updated as expected by projects that use this plugin. But yet the following are not happening and I'm not clear why:

  1. The config file is not generated by compile.
  2. The config file is not packaged in the jar by package.
  3. The config file is not in the classpath when the run task is used.

Note I have also tried a dozen or so variations on this, and I have further tried:

  resourceGenerators in Compile <+= generateVersionConf

Which as I understand it should result in more or less the same behavior.

Inspecting the runtime attributes of this, I see some of the settings are applied successfully:

> inspect version
[info] Setting: java.lang.String = 0.15.338.160117
[info] Description:
[info]  The version/revision of the current module.
[info] Provided by:
[info]  */*:version
[info] Defined at:
[info]  (com.quantcast.sbt.version.DateVersionPlugin) DateVersionPlugin.scala:101
[info] Reverse dependencies:
[info]  *:isSnapshot
[info]  *:generateVersionConf
[info]  *:projectId
[info] Delegates:
[info]  *:version
[info]  {.}/*:version
[info]  */*:version
[info] Related:
[info]  */*:version

However, this is not true for compile:resourceGenerators, which shows that it still maintains the defaults.

> inspect compile:resourceGenerators
[info] Setting: scala.collection.Seq[sbt.Task[scala.collection.Seq[java.io.File]]] = List(Task(_))
[info] Description:
[info]  List of tasks that generate resources.
[info] Provided by:
[info]  {file:/home/scott/code/quantcast/play/sbt-date-version/sbt-test/}root/compile:resourceGenerators
[info] Defined at:
[info]  (sbt.Defaults) Defaults.scala:207
[info]  (sbt.Defaults) Defaults.scala:208
[info] Dependencies:
[info]  compile:discoveredSbtPlugins
[info]  compile:resourceManaged
[info] Reverse dependencies:
[info]  compile:managedResources
[info] Delegates:
[info]  compile:resourceGenerators
[info]  *:resourceGenerators
[info]  {.}/compile:resourceGenerators
[info]  {.}/*:resourceGenerators
[info]  */compile:resourceGenerators
[info]  */*:resourceGenerators
[info] Related:
[info]  test:resourceGenerators

My question is (now that I've continued to research this more), what could be keeping my changes to (generateResources in Compile) from being applied?


Solution

  • If this plugin needs to require the JvmPlugin. This is because the JvmPlugin defines the setting dependencies. Without it, apparently the compile:resourceGenerators setting is being overwritten by the defaults, redefining the set of resource generators to Nil and building from there.

    So the solution is to include the following line in the AutoPlugin definition.

      override def requires = plugins.JvmPlugin