build.sc
author Tomas Zeman <tomas@functionals.cz>
Tue, 11 May 2021 14:35:33 +0200
changeset 46 cd7815894e22
parent 44 ad85035e4d90
child 47 d7b69a5dcd37
permissions -rw-r--r--
Font-Awesome upgrade 5.15.1 -> 5.15.3

/*
 * REPL:
 *
 * ./mill --repl -w
 *
 * Generate Idea project:
 *
 * ./mill mill.scalalib.GenIdea/idea
 *
 */ 
import ammonite.ops._
import mill._
import mill.api.Loose
import mill.define.{Command, Input, Sources, Target}
import mill.scalajslib._
import mill.scalalib._
import mill.scalalib.publish._

import scala.language.postfixOps

object V {
  val fatags = "0.7-SNAPSHOT"
  val scala211 = "2.11.12"
  val scala212 = "2.12.12"
  val scala213 = "2.13.4"
  val scalaJs06 = "0.6.33"
  val scalaJs = "1.3.1"
  val scalatags = "0.9.2"
}

object D {
  val scalatags211 = ivy"com.lihaoyi::scalatags::0.6.8"
  val scalatags = ivy"com.lihaoyi::scalatags::${V.scalatags}"
}

def camelCase(s: String): String = {
  def inner(l: List[Char]): List[Char] = l match {
    case '-' :: '-' :: c :: rest => c.toUpper :: inner(rest)
    case '-' :: c :: rest => c.toUpper :: inner(rest)
    case c :: rest => c :: inner(rest)
    case Nil => Nil
  }
  inner(s toList) mkString ""
}

val compilerOptions = Seq(
  "-deprecation",                      // Emit warning and location for usages of deprecated APIs.
  "-encoding", "utf-8",                // Specify character encoding used by source files.
  "-explaintypes",                     // Explain type errors in more detail.
  "-feature",                          // Emit warning and location for usages of features that should be imported explicitly.
  "-language:higherKinds",             // Allow higher-kinded types
  "-language:implicitConversions",     // Allow definition of implicit functions called views
  "-language:reflectiveCalls",
  "-language:postfixOps",
  "-unchecked",                        // Enable additional warnings where generated code depends on assumptions.
  "-Xcheckinit",                       // Wrap field accessors to throw an exception on uninitialized access.
  "-target:jvm-1.8"
)

trait Common extends CrossSbtModule with PublishModule {

  override def artifactName = "fatags"

  def publishVersion: Target[String] = V.fatags

  def pomSettings: T[PomSettings] = PomSettings(
    description = "FontAwesome Scala DSL (tags)",
    organization = "cz.functionals",
    url = "https://hg.functionals.cz/fatags",
    licenses = Seq(License.`Apache-2.0`),
    versionControl = VersionControl(developerConnection = Some(
      "ssh://tzeman@hg.functionals.cz/repos/public/fatags")),
    developers = Seq(
      Developer("tzeman", "Tomas Zeman", "")
    )
  )

  override def scalacOptions: T[Seq[String]] = T{compilerOptions}

  def hgId: Input[String] = T.input {
    os.proc("hg", "id", "-i").call().out.text.trim
  }

  def hgNum: Input[String] = T.input {
    os.proc("hg", "id", "-n").call().out.text.trim
  }

  def hgTag: Input[Option[String]] = T.input {
    os.proc("hg", "id", "-t").call().out.text.trim.split(' ').headOption
  }

  override def ivyDeps: Target[Loose.Agg[Dep]] = T{
    if (scalaVersion() == V.scala211) Agg(D.scalatags211) else Agg(D.scalatags)
  }

  override def sources: Sources = T.sources{
    super.sources() :+ PathRef(millSourcePath / 'shared / 'src / 'main / 'scala)
  }

  // https://github.com/FortAwesome/Font-Awesome/raw/5.15.3/metadata/icons.json
  type IcoDef = (String, Set[String])
  def parseIcons: Target[List[IcoDef]] = T{
    ujson.read(os.read! pwd / "icons.json").obj.map(e => (e._1, e._2.obj("styles").arr.map(_.str).toSet)).toList
  }

  private def tpl(d: IcoDef): Set[String] = {
    val sym = d._1
    d._2.map {
      case "brands" =>  s"""  def ${camelCase(s"fab-$sym")}: FA = fab("$sym")"""
      case "solid" =>   s"""  def ${camelCase(s"fas-$sym")}: FA = fas("$sym")"""
      case "regular" => s"""  def ${camelCase(s"far-$sym")}: FA = far("$sym")"""
    }
  }

  override def generatedSources: Sources = T.sources{
    val d = T.ctx().dest
    val icons = parseIcons()
    write(d / "generated.scala",
      s"""
        |package fontawesome.generic
        |import scalatags.generic._
        |class GenericFA[Builder, Output <: FragT, FragT](
        |  val bun: Bundle[Builder, Output, FragT]) {
        |
        |  import bun.all._
        |
        |  val faStack: Modifier = cls := "fa-stack fa-lg"
        |
        |  implicit val bundle: Bundle[Builder, Output, FragT] = bun
        |  implicit def fa2mod(x: FA): Modifier = x()
        |
        |  private def fab(w: String): FA = FA(FaStyle.Brands, w)
        |  private def far(w: String): FA = FA(FaStyle.Regular, w)
        |  private def fas(w: String): FA = FA(FaStyle.Solid, w)
        |
        |${icons flatMap tpl mkString "\n"}
        |
        |}
      """.stripMargin)
    d
  }
}

class JvmModule(val crossScalaVersion: String) extends Common
class JsModule(val crossScalaVersion: String, crossJSVersion: String)
  extends ScalaJSModule with Common {

  override def scalaJSVersion: Target[String] = crossJSVersion

  override def millSourcePath = super.millSourcePath / os.up
}

object jvm extends Cross[JvmModule](V.scala211, V.scala212, V.scala213)
object js extends Cross[JsModule](
  V.scala211 -> V.scalaJs06,
  V.scala212 -> V.scalaJs06,
  V.scala212 -> V.scalaJs,
  V.scala213 -> V.scalaJs06,
  V.scala213 -> V.scalaJs
)

def compileAll(): Command[Unit] = T.command{
  jvm(V.scala213).compile()
  js(V.scala213, V.scalaJs).compile()
  js(V.scala213, V.scalaJs06).compile()
  jvm(V.scala212).compile()
  js(V.scala212, V.scalaJs).compile()
  js(V.scala212, V.scalaJs06).compile()
  jvm(V.scala211).compile()
  js(V.scala211, V.scalaJs06).compile()
  ()
}

def publishLocal(): Command[Unit] = T.command{
  jvm(V.scala213).publishLocal()()
  js(V.scala213, V.scalaJs).publishLocal()()
  js(V.scala213, V.scalaJs06).publishLocal()()
  jvm(V.scala212).publishLocal()()
  js(V.scala212, V.scalaJs).publishLocal()()
  js(V.scala212, V.scalaJs06).publishLocal()()
  jvm(V.scala211).publishLocal()()
  js(V.scala211, V.scalaJs06).publishLocal()()
}

def publishM2Local(p: os.Path): Command[Unit] = T.command{
  jvm(V.scala213).publishM2Local(p.toString)()
  js(V.scala213, V.scalaJs).publishM2Local(p.toString)()
  js(V.scala213, V.scalaJs06).publishM2Local(p.toString)()
  jvm(V.scala212).publishM2Local(p.toString)()
  js(V.scala212, V.scalaJs).publishM2Local(p.toString)()
  js(V.scala212, V.scalaJs06).publishM2Local(p.toString)()
  jvm(V.scala211).publishM2Local(p.toString)()
  js(V.scala211, V.scalaJs06).publishM2Local(p.toString)()
  ()
}

object example extends ScalaModule with ScalaJSModule {
  override def scalaVersion: Target[String] = T{V.scala213}
  override def scalaJSVersion: Target[String] = V.scalaJs

  override def scalacOptions: T[Seq[String]] = T{compilerOptions}

  override def moduleDeps: Seq[PublishModule] = Seq(js(V.scala213, V.scalaJs))

}

// vim: et ts=2 sw=2 syn=scala