package mill package contrib.tut import coursier.MavenRepository import mill.scalalib._ import scala.util.matching.Regex /** * Tut is a documentation tool which compiles and evaluates Scala code in documentation files and provides various options for configuring how the results will be displayed in the compiled documentation. * * Extending this trait declares a Scala module which compiles markdown, HTML and `.txt` files in the `tut` folder of the module with Tut. * * By default the resulting documents are simply placed in the Mill build output folder but they can be placed elsewhere by overriding the [[mill.contrib.tut.TutModule#tutTargetDirectory]] task. * * For example: * * {{{ * // build.sc * import mill._, scalalib._, contrib.tut.__ * * object example extends TutModule { * def scalaVersion = "2.12.6" * def tutVersion = "0.6.7" * } * }}} * * This defines a project with the following layout: * * {{{ * build.sc * example/ * src/ * tut/ * resources/ * }}} * * In order to compile documentation we can execute the `tut` task in the module: * * {{{ * sh> mill example.tut * }}} */ trait TutModule extends ScalaModule { /** * This task determines where documentation files must be placed in order to be compiled with Tut. By default this is the `tut` folder at the root of the module. */ def tutSourceDirectory = T.sources { millSourcePath / 'tut } /** * A task which determines where the compiled documentation files will be placed. By default this is simply the Mill build's output folder for this task, * but this can be reconfigured so that documentation goes to the root of the module (e.g. `millSourcePath`) or to a dedicated folder (e.g. `millSourcePath / 'docs`) */ def tutTargetDirectory: T[os.Path] = T { T.ctx().dest } /** * A task which determines what classpath is used when compiling documentation. By default this is configured to use the same inputs as the [[mill.contrib.tut.TutModule#runClasspath]], * except for using [[mill.contrib.tut.TutModule#tutIvyDeps]] rather than the module's [[mill.contrib.tut.TutModule#runIvyDeps]]. */ def tutClasspath: T[Agg[PathRef]] = T { // Same as runClasspath but with tut added to ivyDeps from the start // This prevents duplicate, differently versioned copies of scala-library ending up on the classpath which can happen when resolving separately transitiveLocalClasspath() ++ resources() ++ localClasspath() ++ unmanagedClasspath() ++ tutIvyDeps() } /** * A task which determines the scalac plugins which will be used when compiling code examples with Tut. The default is to use the [[mill.contrib.tut.TutModule#scalacPluginIvyDeps]] for the module. */ def tutScalacPluginIvyDeps: T[Agg[Dep]] = scalacPluginIvyDeps() /** * A [[scala.util.matching.Regex]] task which will be used to determine which files should be compiled with tut. The default pattern is as follows: `.*\.(md|markdown|txt|htm|html)`. */ def tutNameFilter: T[Regex] = T { """.*\.(md|markdown|txt|htm|html)""".r } /** * The scalac options which will be used when compiling code examples with Tut. The default is to use the [[mill.contrib.tut.TutModule#scalacOptions]] for the module, * but filtering out options which are problematic in the REPL, e.g. `-Xfatal-warnings`, `-Ywarn-unused-imports`. */ def tutScalacOptions: T[Seq[String]] = scalacOptions().filterNot(Set( "-Ywarn-unused:imports", "-Ywarn-unused-import", "-Ywarn-dead-code", "-Xfatal-warnings" )) /** * The version of Tut to use. */ def tutVersion: T[String] /** * A task which determines how to fetch the Tut jar file and all of the dependencies required to compile documentation for the module and returns the resulting files. */ def tutIvyDeps: T[Agg[PathRef]] = T { Lib.resolveDependencies( repositories :+ MavenRepository(s"https://dl.bintray.com/tpolecat/maven"), Lib.depToDependency(_, scalaVersion()), compileIvyDeps() ++ transitiveIvyDeps() ++ Seq( ivy"org.tpolecat::tut-core:${tutVersion()}" ) ) } /** * A task which performs the dependency resolution for the scalac plugins to be used with Tut. */ def tutPluginJars: T[Agg[PathRef]] = resolveDeps(tutScalacPluginIvyDeps)() /** * Run Tut using the configuration specified in this module. The working directory used is the [[mill.contrib.tut.TutModule#millSourcePath]]. */ def tut: T[os.CommandResult] = T { val in = tutSourceDirectory().head.path.toIO.getAbsolutePath val out = tutTargetDirectory().toIO.getAbsolutePath val re = tutNameFilter() val opts = tutScalacOptions() val pOpts = tutPluginJars().map(pathRef => "-Xplugin:" + pathRef.path.toIO.getAbsolutePath) val tutArgs = List(in, out, re.pattern.toString) ++ opts ++ pOpts os.proc( 'java, "-cp", tutClasspath().map(_.path.toIO.getAbsolutePath).mkString(java.io.File.pathSeparator), "tut.TutMain", tutArgs ).call(millSourcePath) } }