Skip to content

Document BuildInfo #2325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class SourceGeneratorTests extends munit.FunSuite {
)
)

private def normalizeResolvers(contents: String): String =
private def normalizeContents(contents: String): String =
contents
.replaceAll(
"ivy:file:[^\"]*scala-cli-tests-extra-repo[^\"]*/local-repo[^\"]*",
Expand All @@ -49,7 +49,9 @@ class SourceGeneratorTests extends munit.FunSuite {
.replaceAll(
"ivy:file:[^\"]*\\.ivy2/local[^\"]*",
"ivy:file:.../.ivy2/local/"
)
).linesWithSeparators
.filterNot(_.stripLeading().startsWith("/**"))
.mkString

def initializeGit(
cwd: os.Path,
Expand Down Expand Up @@ -111,7 +113,8 @@ class SourceGeneratorTests extends munit.FunSuite {

val buildInfoContent = os.read(buildInfoPath)

expect(normalizeResolvers(buildInfoContent) ==
assertNoDiff(
normalizeContents(buildInfoContent),
s"""package scala.cli.build
|
|object BuildInfo {
Expand All @@ -124,7 +127,6 @@ class SourceGeneratorTests extends munit.FunSuite {
| val mainClass = Some("Main")
| val projectVersion = Some("1.0.0")
|
|
| object Main {
| val sources = Seq("${root / "main.scala"}")
| val scalacOptions = Seq("-Xasync")
Expand All @@ -144,11 +146,11 @@ class SourceGeneratorTests extends munit.FunSuite {
| val resourceDirs = Nil
| val customJarsDecls = Nil
| }
|
|}
|""".stripMargin)
}
|""".stripMargin
)
}
}

}

Expand Down Expand Up @@ -189,7 +191,8 @@ class SourceGeneratorTests extends munit.FunSuite {

val buildInfoContent = os.read(buildInfoPath)

expect(normalizeResolvers(buildInfoContent) ==
assertNoDiff(
normalizeContents(buildInfoContent),
s"""package scala.cli.build
|
|object BuildInfo {
Expand All @@ -202,7 +205,6 @@ class SourceGeneratorTests extends munit.FunSuite {
| val mainClass = Some("Main")
| val projectVersion = None
|
|
| object Main {
| val sources = Seq("${root / "main.scala"}")
| val scalacOptions = Seq("-Xasync")
Expand All @@ -222,9 +224,9 @@ class SourceGeneratorTests extends munit.FunSuite {
| val resourceDirs = Nil
| val customJarsDecls = Nil
| }
|
|}
|""".stripMargin)
|""".stripMargin
)
}
}

Expand Down Expand Up @@ -267,7 +269,8 @@ class SourceGeneratorTests extends munit.FunSuite {

val buildInfoContent = os.read(buildInfoPath)

expect(normalizeResolvers(buildInfoContent) ==
assertNoDiff(
normalizeContents(buildInfoContent),
s"""package scala.cli.build
|
|object BuildInfo {
Expand All @@ -280,7 +283,6 @@ class SourceGeneratorTests extends munit.FunSuite {
| val mainClass = Some("Main")
| val projectVersion = Some("TestVersion")
|
|
| object Main {
| val sources = Seq("${root / "main.scala"}")
| val scalacOptions = Seq("-Xasync")
Expand All @@ -300,9 +302,9 @@ class SourceGeneratorTests extends munit.FunSuite {
| val resourceDirs = Nil
| val customJarsDecls = Nil
| }
|
|}
|""".stripMargin)
|""".stripMargin
)
}
}

Expand Down Expand Up @@ -342,7 +344,8 @@ class SourceGeneratorTests extends munit.FunSuite {

val buildInfoContent = os.read(buildInfoPath)

expect(normalizeResolvers(buildInfoContent) ==
assertNoDiff(
normalizeContents(buildInfoContent),
s"""package scala.cli.build
|
|object BuildInfo {
Expand All @@ -355,7 +358,6 @@ class SourceGeneratorTests extends munit.FunSuite {
| val mainClass = Some("Main")
| val projectVersion = Some("TestVersion")
|
|
| object Main {
| val sources = Seq("${root / "main.scala"}")
| val scalacOptions = Seq("-Xasync")
Expand All @@ -375,9 +377,9 @@ class SourceGeneratorTests extends munit.FunSuite {
| val resourceDirs = Nil
| val customJarsDecls = Nil
| }
|
|}
|""".stripMargin)
|""".stripMargin
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import shapeless.tag
import java.nio.charset.StandardCharsets
import java.util

import scala.build.info.{ArtifactId, BuildInfo, ExportDependencyFormat, ScopedBuildInfo}
import scala.build.options.{BuildOptions, BuildRequirements, WithBuildRequirements}
import scala.build.preprocessing.directives.DirectiveHandler
import scala.build.preprocessing.directives.DirectivesPreprocessingUtils.*
Expand Down Expand Up @@ -481,6 +482,100 @@ object GenerateReferenceDoc extends CaseApp[InternalDocOptions] {
b.toString
}

private def buildInfoContent: String = {
val b = new StringBuilder

b.section(
"""---
|title: BuildInfo
|sidebar_position: 6
|---""".stripMargin
)
b.section(
""":::caution
|BuildInfo is a restricted feature and requires setting the `--power` option to be used.
|You can pass it explicitly or set it globally by running:
|
| scala-cli config power true
|:::""".stripMargin
)

b.section(
"""During the building process Scala CLI collects information about the project's configuration,
|both from the console options and `using directives` found in the project's sources.
|You can access this information from your code using the `BuildInfo` object, that's automatically generated for your
|build on compile when that information changes.""".stripMargin
)

b.section(
"""To enable BuildInfo generation pass the `--build-info` option to Scala CLI or use a
|`//> using buildInfo` directive.""".stripMargin
)

b.section(
"""## Usage
|
|The generated BuildInfo object is available on the project's classpath. To access it you need to import it first.
|It is available in the package `scala.cli.build` so use
|```scala
|import scala.cli.build.BuildInfo
|```
|to import it.
|
|Below you can find an example instance of the BuildInfo object, with all fields explained.
|Some of the values have been shortened for readability.""".stripMargin
)

val osLibDep = ExportDependencyFormat("com.lihaoyi", ArtifactId("os-lib", "os-lib_3"), "0.9.1")
val toolkitDep =
ExportDependencyFormat("org.scala-lang", ArtifactId("toolkit", "toolkit_3"), "latest.release")

val mainScopedBuildInfo = ScopedBuildInfo(BuildOptions(), Seq(".../Main.scala")).copy(
scalacOptions = Seq("-Werror"),
scalaCompilerPlugins = Nil,
dependencies = Seq(osLibDep),
resolvers = Seq("https://repo1.maven.org/maven2", "ivy:file:..."),
resourceDirs = Seq(".../resources"),
customJarsDecls = Seq(".../AwesomeJar1.jar", ".../AwesomeJar2.jar")
)

val testScopedBuildInfo = ScopedBuildInfo(BuildOptions(), Seq(".../MyTests.scala")).copy(
scalacOptions = Seq("-Vdebug"),
scalaCompilerPlugins = Nil,
dependencies = Seq(toolkitDep),
resolvers = Seq("https://repo1.maven.org/maven2", "ivy:file:..."),
resourceDirs = Seq(".../test/resources"),
customJarsDecls = Nil
)

val generatedBuildInfo = BuildInfo(BuildOptions(), os.pwd) match {
case Right(bv) => bv
case Left(exception) =>
System.err.println(s"Failed to generate BuildInfo: ${exception.message}")
sys.exit(1)
}

val buildInfo = generatedBuildInfo.copy(
scalaVersion = Some("3.3.0"),
platform = Some("JVM"),
jvmVersion = Some("11"),
scalaJsVersion = None,
jsEsVersion = None,
scalaNativeVersion = None,
mainClass = Some("Main")
)
.withScope("main", mainScopedBuildInfo)
.withScope("test", testScopedBuildInfo)

b.section(
s"""```scala
|${buildInfo.generateContents().strip()}
|```""".stripMargin
)

b.mkString
}

def run(options: InternalDocOptions, args: RemainingArgs): Unit = {

val scalaCli = new ScalaCliCommands(
Expand Down Expand Up @@ -512,6 +607,7 @@ object GenerateReferenceDoc extends CaseApp[InternalDocOptions] {
requireDirectiveHandlers,
onlyRestricted = false
)

val restrictedDirectivesContent = usingContent(
allUsingDirectiveHandlers.filterNot(_.isRestricted),
requireDirectiveHandlers.filterNot(_.isRestricted),
Expand All @@ -524,6 +620,7 @@ object GenerateReferenceDoc extends CaseApp[InternalDocOptions] {
(os.rel / "cli-options.md") -> allCliOptionsContent,
(os.rel / "commands.md") -> allCommandsContent,
(os.rel / "directives.md") -> allDirectivesContent,
(os.rel / "build-info.md") -> buildInfoContent,
(os.rel / restrictedDocsDir / "cli-options.md") -> restrictedCliOptionsContent,
(os.rel / restrictedDocsDir / "commands.md") -> restrictedCommandsContent,
(os.rel / restrictedDocsDir / "directives.md") -> restrictedDirectivesContent,
Expand Down Expand Up @@ -551,6 +648,7 @@ object GenerateReferenceDoc extends CaseApp[InternalDocOptions] {
maybeWrite(options.outputPath / "cli-options.md", allCliOptionsContent)
maybeWrite(options.outputPath / "commands.md", allCommandsContent)
maybeWrite(options.outputPath / "directives.md", allDirectivesContent)
maybeWrite(options.outputPath / "build-info.md", buildInfoContent)

maybeWrite(
options.outputPath / restrictedDocsDir / "cli-options.md",
Expand Down
48 changes: 36 additions & 12 deletions modules/options/src/main/scala/scala/build/info/BuildInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,42 @@ final case class BuildInfo(
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(
"val jvmVersion =" -> jvmVersion,
"val scalaJsVersion =" -> scalaJsVersion,
"val jsEsVersion =" -> jsEsVersion,
"val scalaNativeVersion =" -> scalaNativeVersion,
"val mainClass =" -> mainClass,
"val projectVersion =" -> projectVersion
).map { case (prefix, opt) =>
opt.map(v => s"$prefix Some(\"${escapeBackslashes(v)}\")").getOrElse(s"$prefix None")
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
Expand All @@ -56,17 +79,18 @@ final case class BuildInfo(
yield {
val scopedBuildInfoVals = scopedBuildInfo.generateContentLines()
.mkString(indent, nl + indent * 2, "")
s"""${indent}object ${scopeName.capitalize} {
s"""$indent/** Information about the ${scopeName.capitalize} scope */
|${indent}object ${scopeName.capitalize} {
|$indent$scopedBuildInfoVals
|$indent}
|""".stripMargin
|$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, nl, "")}
|${scopesContents.mkString(nl * 2)}
|}
|""".stripMargin
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,27 @@ final case class ScopedBuildInfo(

def generateContentLines(): Seq[String] =
Seq(
s"val sources = " -> sources,
s"val scalacOptions = " -> scalacOptions,
s"val scalaCompilerPlugins = " -> scalaCompilerPlugins.map(_.toString()),
s"val dependencies = " -> dependencies.map(_.toString()),
s"val resolvers = " -> resolvers,
s"val resourceDirs = " -> resourceDirs,
s"val customJarsDecls = " -> customJarsDecls
).map { case (prefix, values) =>
Seq("/** sources found for the scope */", "val sources = ") -> sources,
Seq("/** scalac options for the scope */", "val scalacOptions = ") -> scalacOptions,
Seq(
"/** compiler plugins used in this scope */",
"val scalaCompilerPlugins = "
) -> scalaCompilerPlugins.map(_.toString()),
Seq("/** dependencies used in this scope */", "val dependencies = ") -> dependencies.map(
_.toString()
),
Seq("/** dependency resolvers used in this scope */", "val resolvers = ") -> resolvers,
Seq("/** resource directories used in this scope */", "val resourceDirs = ") -> resourceDirs,
Seq("/** custom jars added to this scope */", "val customJarsDecls = ") -> customJarsDecls
).flatMap { case (Seq(scaladoc, prefix), values) =>
val sb = new StringBuilder
sb.append(prefix)
if (values.isEmpty) sb.append("Nil")
else sb.append {
values.map(str => s"\"${BuildInfo.escapeBackslashes(str)}\"")
.mkString("Seq(", ", ", ")")
}
sb.toString()
Seq(scaladoc, sb.toString())
}
}

Expand Down
2 changes: 1 addition & 1 deletion website/docs/reference/bloop.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Interaction with Bloop server
sidebar_position: 6
sidebar_position: 10
---

# Interaction with Bloop server
Expand Down
Loading