aboutsummaryrefslogblamecommitdiff
path: root/tools/gui/src/ProjectBuilder.scala
blob: ceba3762c3c04eb698afe186499600dac6a28fa8 (plain) (tree)




















































































































































                                                                                                                  
import java.io.File
import java.nio.file._

import Main.StringExtensionMethods

import scala.io.Source

class ProjectBuilder(
    name: String,
    defaultPackage: String,
    dependencyString: String,
    flagsString: String,
    location: File,
    scalaMajorVersion: String
) {

  private val newLine = System.lineSeparator()
  private val blankLine = newLine + newLine
  private val templateDir = System.getenv("CBT_HOME") / "tools" / "gui" / "resources" / "template-project"
  private val projectPath = location.getPath / name
  private val buildDir = projectPath / "build"
  private val mainDir = projectPath / "src" / "main" / "scala" / defaultPackage.split("\\.").reduce(_ / _)
  private val testDir = projectPath / "src" / "test" / "scala" / defaultPackage.split("\\.").reduce(_ / _)

  private val dependencies =
    if (dependencyString.isEmpty)
      ""
    else {
      def parseDependencies(input: String): Seq[Dependency] = {
        input.split(" ").map { x =>
          val xs = x.split("/")
          Dependency(xs(0), xs(1), xs(2))
        }
      }

      val list = parseDependencies(dependencyString)
      val str = list.map("      " ++ _.serialized).mkString(s",$newLine")
      s"""  override def dependencies = {
         |    super.dependencies ++ Resolver(mavenCentral).bind(
         |$str
         |    )
         |  }""".stripMargin
    }

  private val flags = {
    val map = flagsString.split(" ").map { x =>
      val Array(a, b) = x.split("/")
      (a, b)
    }.toMap
    Flags(map("readme") == "true", map("dotty") == "true", map("uberJar") == "true", map("wartremover") == "true")
  }

  private val plugins = {
    var content = ""
    if (flags.dotty)
      content += " with Dotty"
    if (flags.uberJar)
      content += " with UberJar"
    if (flags.wartremover)
      content += " with WartRemover"
    content
  }

  private val buildBuildDependencies = {
    var content = ""
    if (flags.uberJar)
      content += " :+ plugins.uberJar"
    if (flags.wartremover)
      content += " :+ plugins.wartremover"
    content
  }

  def build(): Unit = {
    new File(buildDir).mkdirs()
    new File(mainDir).mkdirs()
    new File(testDir).mkdirs()
    addBuild()
    if (buildBuildDependencies.nonEmpty)
      addBuildBuild()
    addMain()
    addReadme(flags)
  }

  private def writeTemplate(templatePath: String, targetPath: String, replacements: (String, String, String)*) = {
    var content = Source.fromFile(templatePath).mkString
    for (replacement <- replacements)
      if (replacement._1.nonEmpty)
        content = content.replace(replacement._3, replacement._2)
      else
        content = content.replace(replacement._3, "")
    write(new File(targetPath), content, StandardOpenOption.CREATE_NEW)
  }

  private def addBuild() =
    writeTemplate(
      templateDir / "build" / "build.scala",
      buildDir / "build.scala",
      (name, s"""  override def projectName = "$name"$blankLine""", "##projectName##"),
      (dependencyString, dependencies + blankLine, "##dependencies##"),
      (plugins, plugins, "##with##")
    )

  private def addBuildBuild() =
    writeTemplate(
      templateDir / "build" / "build" / "build.scala",
      buildDir / "build" / "build.scala",
      (buildBuildDependencies, buildBuildDependencies, "##plus##")
    )

  private def addMain() =
    writeTemplate(
      templateDir / "src" / "main" / "scala" / "Main.scala",
      mainDir / "Main.scala",
      (defaultPackage, s"package $defaultPackage$blankLine", "##package##")
    )

  private def addReadme(flags: Flags) = {
    if (flags.readme) {
      val content =
        if (name.nonEmpty)
          s"# $name$blankLine"
        else
          ""
      write(new File(projectPath / "readme.md"), content, StandardOpenOption.CREATE_NEW)
    }
  }

  private case class Dependency(group: String, artifact: String, version: String) {
    val nameVersion = """^(.+)_(\d+\.\d+)$""".r
    val (name, scalaVersion) = artifact match {
      case nameVersion(n, v) => (n, Some(v))
      case str => (str, None)
    }

    def serialized =
      if (scalaVersion.contains(scalaMajorVersion))
        s"""ScalaDependency("$group", "$name", "$version")"""
      else
        s"""MavenDependency("$group", "$artifact", "$version")"""
  }

  private def write(file: File, content: String, option: OpenOption) = {
    file.getParentFile.mkdirs()
    Files.write(file.toPath, content.getBytes, option)
  }

  private case class Flags(readme: Boolean, dotty: Boolean, uberJar: Boolean, wartremover: Boolean)

}