All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.build.info.BuildInfo.scala Maven / Gradle / Ivy

package scala.build.info

import scala.build.EitherCps.{either, value}
import scala.build.errors.{BuildException, BuildInfoGenerationError}
import scala.build.info.BuildInfo.escapeBackslashes
import scala.build.internal.Constants
import scala.build.options.*

final case class BuildInfo(
  projectVersion: Option[String] = None,
  scalaVersion: Option[String] = None,
  platform: Option[String] = None,
  jvmVersion: Option[String] = None,
  scalaJsVersion: Option[String] = None,
  jsEsVersion: Option[String] = None,
  scalaNativeVersion: Option[String] = None,
  mainClass: Option[String] = None,
  scopes: Map[String, ScopedBuildInfo] = Map.empty
) {
  def +(other: BuildInfo): BuildInfo =
    BuildInfo.monoid.orElse(this, other)

  def withScope(scopeName: String, scopedBuildInfo: ScopedBuildInfo): BuildInfo =
    if (scopedBuildInfo.sources.isEmpty)
      this.copy(
        scopes = this.scopes + (scopeName -> ScopedBuildInfo.empty)
      )
    else
      this.copy(
        scopes = this.scopes + (scopeName -> scopedBuildInfo)
      )

  def generateContents(): String = {
    val nl     = System.lineSeparator()
    val indent = " " * 2
    val stringVals = Seq(
      "/** version of Scala used to compile this project */",
      s"val scalaVersion = \"${escapeBackslashes(scalaVersion.getOrElse(Constants.defaultScalaVersion))}\"",
      "/** target platform of this project, it can be \"JVM\" or \"JS\" or \"Native\" */",
      s"val platform = \"${escapeBackslashes(platform.getOrElse(Platform.JVM.repr))}\""
    )

    val optionVals = Seq(
      Seq(
        "/** version of JVM, if it's the target platform */",
        "val jvmVersion ="
      ) -> jvmVersion,
      Seq(
        "/** version of Scala.js, if it's the target platform */",
        "val scalaJsVersion ="
      ) -> scalaJsVersion,
      Seq(
        "/** Scala.js ECMA Script version, if Scala.js is the target platform */",
        "val jsEsVersion ="
      ) -> jsEsVersion,
      Seq(
        "/** version of Scala Native, if it's the target platform */",
        "val scalaNativeVersion ="
      ) -> scalaNativeVersion,
      Seq(
        "/** Main class specified for the project */",
        "val mainClass ="
      ) -> mainClass,
      Seq(
        "/** Project version */",
        "val projectVersion ="
      ) -> projectVersion
    ).flatMap { case (Seq(scaladoc, prefix), opt) =>
      Seq(
        scaladoc,
        opt.map(v => s"$prefix Some(\"${escapeBackslashes(v)}\")").getOrElse(s"$prefix None")
      )
    }

    val allVals = stringVals ++ optionVals

    val scopesContents =
      for ((scopeName, scopedBuildInfo) <- scopes)
        yield {
          val scopedBuildInfoVals = scopedBuildInfo.generateContentLines()
            .mkString(indent, nl + indent * 2, "")
          s"""$indent/** Information about the ${scopeName.capitalize} scope */
             |${indent}object ${scopeName.capitalize} {
             |$indent$scopedBuildInfoVals
             |$indent}""".stripMargin
        }

    s"""package scala.cli.build
       |
       |/** Information about the build gathered by Scala CLI */
       |object BuildInfo {
       |${allVals.mkString(indent, nl + indent, nl)}
       |${scopesContents.mkString(nl * 2)}
       |}
       |""".stripMargin
  }
}

object BuildInfo {
  def apply(
    options: BuildOptions,
    workspace: os.Path
  ): Either[BuildException, BuildInfo] = either[Exception] {
    Seq(
      BuildInfo(
        mainClass = options.mainClass,
        projectVersion = options.sourceGeneratorOptions.projectVersion.orElse(
          options.sourceGeneratorOptions.computeVersion
            .map(cv => value(cv.get(workspace)))
            .orElse(
              ComputeVersion.GitTag(os.rel, dynVer = false, positions = Nil).get(workspace).toOption
            )
        )
      ),
      scalaVersionSettings(options),
      platformSettings(options)
    )
      .reduceLeft(_ + _)
  }.left.map {
    case e: BuildException =>
      BuildInfoGenerationError(e.message, positions = e.positions, cause = e)
    case e => BuildInfoGenerationError(e.getMessage, Nil, e)
  }

  def escapeBackslashes(s: String): String =
    s.replace("\\", "\\\\")

  private def scalaVersionSettings(options: BuildOptions): BuildInfo = {
    val sv = options.scalaParams.toOption.flatten
      .map(_.scalaVersion)
      .orElse(options.scalaOptions.defaultScalaVersion)
      .getOrElse(Constants.defaultScalaVersion)

    BuildInfo(scalaVersion = Some(sv))
  }

  private def scalaJsSettings(options: ScalaJsOptions): BuildInfo = {

    val scalaJsVersion = Some(options.version.getOrElse(Constants.scalaJsVersion))

    BuildInfo(
      platform = Some(Platform.JS.repr),
      scalaJsVersion = scalaJsVersion,
      jsEsVersion = options.esVersionStr
    )
  }

  private def scalaNativeSettings(options: ScalaNativeOptions): BuildInfo =
    BuildInfo(
      platform = Some(Platform.Native.repr),
      scalaNativeVersion = Some(options.finalVersion)
    )

  private def jvmSettings(options: BuildOptions): BuildInfo =
    BuildInfo(
      platform = Some(Platform.JVM.repr),
      jvmVersion = options.javaOptions.jvmIdOpt.map(_.value)
        .orElse(Some(options.javaHome().value.version.toString))
    )

  private def platformSettings(options: BuildOptions): BuildInfo =
    options.scalaOptions.platform.map(_.value) match {
      case Some(Platform.JS) =>
        scalaJsSettings(options.scalaJsOptions)
      case Some(Platform.Native) =>
        scalaNativeSettings(options.scalaNativeOptions)
      case _ => jvmSettings(options)
    }

  implicit val monoid: ConfigMonoid[BuildInfo] = ConfigMonoid.derive
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy