diff --git a/modules/build/src/main/scala/scala/build/Build.scala b/modules/build/src/main/scala/scala/build/Build.scala index 7de5136a2f..e5b317590e 100644 --- a/modules/build/src/main/scala/scala/build/Build.scala +++ b/modules/build/src/main/scala/scala/build/Build.scala @@ -267,9 +267,7 @@ object Build { val baseOptions = overrideOptions.orElse(sharedOptions) - val wrappedScriptsSources = crossSources.withWrappedScripts(baseOptions) - - val scopedSources = value(wrappedScriptsSources.scopedSources(baseOptions)) + val scopedSources = value(crossSources.scopedSources(baseOptions)) val mainSources = scopedSources.sources(Scope.Main, baseOptions) val mainOptions = mainSources.buildOptions diff --git a/modules/build/src/main/scala/scala/build/CrossSources.scala b/modules/build/src/main/scala/scala/build/CrossSources.scala index fbef5c2bb7..78da7d1ca4 100644 --- a/modules/build/src/main/scala/scala/build/CrossSources.scala +++ b/modules/build/src/main/scala/scala/build/CrossSources.scala @@ -29,10 +29,8 @@ import scala.build.testrunner.DynamicTestRunner.globPattern import scala.util.Try import scala.util.chaining.* -/** CrossSources with unwrapped scripts, use [[withWrappedScripts]] to wrap them and obtain an - * instance of CrossSources - * - * See [[CrossSources]] for more information +/** Information gathered from preprocessing command inputs - sources (including unwrapped scripts) + * and build options from using directives * * @param paths * paths and realtive paths to sources on disk, wrapped in their build requirements @@ -45,7 +43,7 @@ import scala.util.chaining.* * @param unwrappedScripts * in memory script sources, their code must be wrapped before compiling */ -sealed class UnwrappedCrossSources( +final case class CrossSources( paths: Seq[WithBuildRequirements[(os.Path, os.RelPath)]], inMemory: Seq[WithBuildRequirements[Sources.InMemory]], defaultMainClass: Option[String], @@ -53,71 +51,18 @@ sealed class UnwrappedCrossSources( buildOptions: Seq[WithBuildRequirements[BuildOptions]], unwrappedScripts: Seq[WithBuildRequirements[Sources.UnwrappedScript]] ) { - - /** For all unwrapped script sources contained in this object wrap them according to provided - * BuildOptions - * - * @param buildOptions - * options used to choose the script wrapper - * @return - * CrossSources with all the scripts wrapped - */ - def withWrappedScripts(buildOptions: BuildOptions): CrossSources = { - val sharedOptions = this.sharedOptions(buildOptions) - val codeWrapper = ScriptPreprocessor.getScriptWrapper(sharedOptions) - - val wrappedScripts = unwrappedScripts.map { unwrapppedWithRequirements => - unwrapppedWithRequirements.map(_.wrap(codeWrapper)) - } - - CrossSources( - paths, - inMemory ++ wrappedScripts, - defaultMainClass, - resourceDirs, - this.buildOptions - ) - } - def sharedOptions(baseOptions: BuildOptions): BuildOptions = buildOptions .filter(_.requirements.isEmpty) .map(_.value) .foldLeft(baseOptions)(_ orElse _) - protected def needsScalaVersion = + private def needsScalaVersion = paths.exists(_.needsScalaVersion) || inMemory.exists(_.needsScalaVersion) || resourceDirs.exists(_.needsScalaVersion) || buildOptions.exists(_.needsScalaVersion) -} -/** Information gathered from preprocessing command inputs - sources and build options from using - * directives - * - * @param paths - * paths and realtive paths to sources on disk, wrapped in their build requirements - * @param inMemory - * in memory sources (e.g. snippets and wrapped scripts) wrapped in their build requirements - * @param defaultMainClass - * @param resourceDirs - * @param buildOptions - * build options from sources - */ -final case class CrossSources( - paths: Seq[WithBuildRequirements[(os.Path, os.RelPath)]], - inMemory: Seq[WithBuildRequirements[Sources.InMemory]], - defaultMainClass: Option[String], - resourceDirs: Seq[WithBuildRequirements[os.Path]], - buildOptions: Seq[WithBuildRequirements[BuildOptions]] -) extends UnwrappedCrossSources( - paths, - inMemory, - defaultMainClass, - resourceDirs, - buildOptions, - Nil - ) { def scopedSources(baseOptions: BuildOptions): Either[BuildException, ScopedSources] = either { val sharedOptions0 = sharedOptions(baseOptions) @@ -154,6 +99,9 @@ final case class CrossSources( .flatMap(_.withPlatform(platform.value).toSeq), buildOptions = buildOptions .filter(!_.requirements.isEmpty) + .flatMap(_.withScalaVersion(retainedScalaVersion).toSeq) + .flatMap(_.withPlatform(platform.value).toSeq), + unwrappedScripts = unwrappedScripts .flatMap(_.withScalaVersion(retainedScalaVersion).toSeq) .flatMap(_.withPlatform(platform.value).toSeq) ) @@ -171,6 +119,8 @@ final case class CrossSources( .flatMap(_.withPlatform(platform.value).toSeq), buildOptions = buildOptions .filter(!_.requirements.isEmpty) + .flatMap(_.withPlatform(platform.value).toSeq), + unwrappedScripts = unwrappedScripts .flatMap(_.withPlatform(platform.value).toSeq) ) } @@ -181,7 +131,8 @@ final case class CrossSources( crossSources0.inMemory.map(_.scopedValue(defaultScope)), defaultMainClass, crossSources0.resourceDirs.map(_.scopedValue(defaultScope)), - crossSources0.buildOptions.map(_.scopedValue(defaultScope)) + crossSources0.buildOptions.map(_.scopedValue(defaultScope)), + crossSources0.unwrappedScripts.map(_.scopedValue(defaultScope)) ) } } @@ -210,7 +161,7 @@ object CrossSources { suppressWarningOptions: SuppressWarningOptions, exclude: Seq[Positioned[String]] = Nil, maybeRecoverOnError: BuildException => Option[BuildException] = e => Some(e) - )(using ScalaCliInvokeData): Either[BuildException, (UnwrappedCrossSources, Inputs)] = either { + )(using ScalaCliInvokeData): Either[BuildException, (CrossSources, Inputs)] = either { def preprocessSources(elems: Seq[SingleElement]) : Either[BuildException, Seq[PreprocessedSource]] = @@ -401,7 +352,7 @@ object CrossSources { val inMemory = inMemoryWithDirectivePositions.map(_._1) val unwrappedScripts = unwrappedScriptsWithDirectivePositions.map(_._1) ( - UnwrappedCrossSources( + CrossSources( paths, inMemory, defaultMainClassOpt, diff --git a/modules/build/src/main/scala/scala/build/ScopedSources.scala b/modules/build/src/main/scala/scala/build/ScopedSources.scala index e83623044c..ff4adf2acb 100644 --- a/modules/build/src/main/scala/scala/build/ScopedSources.scala +++ b/modules/build/src/main/scala/scala/build/ScopedSources.scala @@ -1,13 +1,33 @@ package scala.build +import scala.build.info.{BuildInfo, ScopedBuildInfo} import scala.build.options.{BuildOptions, HasScope, Scope} +import scala.build.preprocessing.ScriptPreprocessor + +/** Information gathered from preprocessing command inputs - sources (including unwrapped scripts) + * and build options from using directives. Only scope requirements remain in this object after + * resolving them in [[CrossSources.scopedSources]] + * + * @param paths + * paths and relative paths to sources on disk with the scope they belong to + * @param inMemory + * in memory sources (e.g. snippets) with the scope they belong to + * @param defaultMainClass + * @param resourceDirs + * @param buildOptions + * build options sources with the scope they belong to + * @param unwrappedScripts + * in memory script sources with the scope they belong to, their code must be wrapped before + * compiling + */ final case class ScopedSources( paths: Seq[HasScope[(os.Path, os.RelPath)]], inMemory: Seq[HasScope[Sources.InMemory]], defaultMainClass: Option[String], resourceDirs: Seq[HasScope[os.Path]], - buildOptions: Seq[HasScope[BuildOptions]] + buildOptions: Seq[HasScope[BuildOptions]], + unwrappedScripts: Seq[HasScope[Sources.UnwrappedScript]] ) { def buildOptionsFor(scope: Scope): Seq[BuildOptions] = scope match { @@ -16,13 +36,80 @@ final case class ScopedSources( case _ => buildOptions.flatMap(_.valueFor(scope).toSeq) } + /** Resolve scope requirements and create a Sources instance + * @param scope + * scope to be resolved + * @param baseOptions + * options that have already been collected for this build, they should consist of: + * - options from the console + * - options from using directives from the sources + * - options from resolved using directives that had Scala version and platform requirements + * that fit the current build + * @return + * [[Sources]] instance that belong to specified scope + */ def sources(scope: Scope, baseOptions: BuildOptions): Sources = + val combinedOptions = combinedBuildOptions(scope, baseOptions) + + val codeWrapper = ScriptPreprocessor.getScriptWrapper(combinedOptions) + + val wrappedScripts = unwrappedScripts + .flatMap(_.valueFor(scope).toSeq) + .map(_.wrap(codeWrapper)) + + val needsBuildInfo = combinedOptions.sourceGeneratorOptions.useBuildInfo.getOrElse(false) + + val maybeBuildInfoSource = if (needsBuildInfo && scope == Scope.Main) + Seq(Sources.InMemory( + Left("build-info"), + os.rel / "BuildInfo.scala", + buildInfo(combinedOptions).generateContents(), + None + )) + else Nil + Sources( paths.flatMap(_.valueFor(scope).toSeq), - inMemory.flatMap(_.valueFor(scope).toSeq), + inMemory.flatMap(_.valueFor(scope).toSeq) ++ wrappedScripts ++ maybeBuildInfoSource, defaultMainClass, resourceDirs.flatMap(_.valueFor(scope).toSeq), - buildOptionsFor(scope) - .foldRight(baseOptions)(_ orElse _) + combinedOptions ) + + /** Combine build options that had no requirements (console and using directives) or their + * requirements have been resolved (e.g. target using directives) with build options that require + * the specified scope + * + * @param scope + * scope to be resolved + * @param baseOptions + * options that have already been collected for this build (had no requirements or they have + * been resolved) + * @return + * Combined BuildOptions, baseOptions' values take precedence + */ + def combinedBuildOptions(scope: Scope, baseOptions: BuildOptions): BuildOptions = + buildOptionsFor(scope) + .foldRight(baseOptions)(_ orElse _) + + def buildInfo(baseOptions: BuildOptions): BuildInfo = { + def getScopedBuildInfo(scope: Scope): ScopedBuildInfo = + val combinedOptions = combinedBuildOptions(scope, baseOptions) + val sourcePaths = paths.flatMap(_.valueFor(scope).toSeq).map(_._1.toString) + val inMemoryPaths = + (inMemory.flatMap(_.valueFor(scope).toSeq).flatMap(_.originalPath.toOption) ++ + unwrappedScripts.flatMap(_.valueFor(scope).toSeq).flatMap(_.originalPath.toOption)) + .map(_._2.toString) + + ScopedBuildInfo(combinedOptions, sourcePaths ++ inMemoryPaths) + + val baseBuildInfo = BuildInfo(combinedBuildOptions(Scope.Main, baseOptions)) + + val mainBuildInfo = getScopedBuildInfo(Scope.Main) + val testBuildInfo = getScopedBuildInfo(Scope.Test) + + baseBuildInfo + .withScope(Scope.Main.name, mainBuildInfo) + .withScope(Scope.Test.name, testBuildInfo) + } } diff --git a/modules/build/src/main/scala/scala/build/Sources.scala b/modules/build/src/main/scala/scala/build/Sources.scala index 7336e0e675..c9e05113f3 100644 --- a/modules/build/src/main/scala/scala/build/Sources.scala +++ b/modules/build/src/main/scala/scala/build/Sources.scala @@ -3,6 +3,7 @@ package scala.build import coursier.cache.ArchiveCache import coursier.util.Task +import scala.build.info.BuildInfo import scala.build.input.Inputs import scala.build.internal.{CodeWrapper, WrapperParams} import scala.build.options.{BuildOptions, Scope} @@ -28,6 +29,11 @@ final case class Sources( ) } + /** Write all in-memory sources to disk. + * + * @param generatedSrcRoot + * the root directory where the sources should be written + */ def generateSources(generatedSrcRoot: os.Path): Seq[GeneratedSource] = { val generated = for (inMemSource <- inMemory) yield { @@ -86,8 +92,6 @@ object Sources { /** The default preprocessor list. * - * @param codeWrapper - * used by the Scala script preprocessor to "wrap" user code * @param archiveCache * used from native launchers by the Java preprocessor, to download a java-class-name binary, * used to infer the class name of unnamed Java sources (like stdin) diff --git a/modules/build/src/main/scala/scala/build/bsp/BspImpl.scala b/modules/build/src/main/scala/scala/build/bsp/BspImpl.scala index 17857111b5..57d91a438a 100644 --- a/modules/build/src/main/scala/scala/build/bsp/BspImpl.scala +++ b/modules/build/src/main/scala/scala/build/bsp/BspImpl.scala @@ -111,14 +111,13 @@ final class BspImpl( ).left.map((_, Scope.Main)) } - val sharedOptions = crossSources.sharedOptions(buildOptions) - val wrappedScriptsSources = crossSources.withWrappedScripts(buildOptions) + val sharedOptions = crossSources.sharedOptions(buildOptions) if (verbosity >= 3) - pprint.err.log(wrappedScriptsSources) + pprint.err.log(crossSources) val scopedSources = - value(wrappedScriptsSources.scopedSources(buildOptions).left.map((_, Scope.Main))) + value(crossSources.scopedSources(buildOptions).left.map((_, Scope.Main))) if (verbosity >= 3) pprint.err.log(scopedSources) diff --git a/modules/build/src/main/scala/scala/build/bsp/BspServer.scala b/modules/build/src/main/scala/scala/build/bsp/BspServer.scala index 7052ff4660..3e5b5384e7 100644 --- a/modules/build/src/main/scala/scala/build/bsp/BspServer.scala +++ b/modules/build/src/main/scala/scala/build/bsp/BspServer.scala @@ -137,6 +137,19 @@ class BspServer( sourceItem.setUri(updatedUri) sourceItem.setGenerated(false) } + + // GeneratedSources not corresponding to files that exist on disk (unlike script wrappers) + val sourcesWithReportingPathString = generatedSources.values.flatMap(_.sources) + .filter(_.reportingPath.isLeft) + + for { + item <- res.getItems.asScala + if validTarget(item.getTarget) + sourceItem <- item.getSources.asScala + if sourcesWithReportingPathString.exists( + _.generated.toNIO.toUri.toASCIIString == sourceItem.getUri + ) + } sourceItem.setGenerated(true) } protected def forwardTo diff --git a/modules/build/src/main/scala/scala/build/preprocessing/directives/DirectivesPreprocessingUtils.scala b/modules/build/src/main/scala/scala/build/preprocessing/directives/DirectivesPreprocessingUtils.scala index 34b40f4106..a4ca4ee68c 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/directives/DirectivesPreprocessingUtils.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/directives/DirectivesPreprocessingUtils.scala @@ -12,6 +12,7 @@ import scala.build.preprocessing.directives object DirectivesPreprocessingUtils { val usingDirectiveHandlers: Seq[DirectiveHandler[BuildOptions]] = Seq[DirectiveHandler[_ <: HasBuildOptions]]( + directives.BuildInfo.handler, directives.Exclude.handler, directives.JavaHome.handler, directives.Jvm.handler, diff --git a/modules/build/src/test/scala/scala/build/tests/ExcludeTests.scala b/modules/build/src/test/scala/scala/build/tests/ExcludeTests.scala index 914e1fc62b..1ed6253bbc 100644 --- a/modules/build/src/test/scala/scala/build/tests/ExcludeTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/ExcludeTests.scala @@ -94,8 +94,7 @@ class ExcludeTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() )(using ScalaCliInvokeData.dummy).orThrow - val scopedSources = crossSources.withWrappedScripts(BuildOptions()) - .scopedSources(BuildOptions()) + val scopedSources = crossSources.scopedSources(BuildOptions()) .orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) @@ -122,8 +121,7 @@ class ExcludeTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() )(using ScalaCliInvokeData.dummy).orThrow - val scopedSources = crossSources.withWrappedScripts(BuildOptions()) - .scopedSources(BuildOptions()) + val scopedSources = crossSources.scopedSources(BuildOptions()) .orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) @@ -150,8 +148,7 @@ class ExcludeTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() )(using ScalaCliInvokeData.dummy).orThrow - val scopedSources = crossSources.withWrappedScripts(BuildOptions()) - .scopedSources(BuildOptions()) + val scopedSources = crossSources.scopedSources(BuildOptions()) .orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) @@ -178,8 +175,7 @@ class ExcludeTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() )(using ScalaCliInvokeData.dummy).orThrow - val scopedSources = crossSources.withWrappedScripts(BuildOptions()) - .scopedSources(BuildOptions()) + val scopedSources = crossSources.scopedSources(BuildOptions()) .orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) diff --git a/modules/build/src/test/scala/scala/build/tests/ScriptWrapperTests.scala b/modules/build/src/test/scala/scala/build/tests/ScriptWrapperTests.scala index 9adc77760e..62a2d0714c 100644 --- a/modules/build/src/test/scala/scala/build/tests/ScriptWrapperTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/ScriptWrapperTests.scala @@ -156,4 +156,50 @@ class ScriptWrapperTests extends munit.FunSuite { } } } + + for { + (targetDirective, enablingDirective) <- Seq( + ("target.scala 3.2.2", "scala 3.2.2"), + ("target.platform scala-native", "platform scala-native") + ) + } { + val inputs = TestInputs( + os.rel / "script1.sc" -> + s"""//> using dep "com.lihaoyi::os-lib:0.9.1" + |//> using $targetDirective + |//> using objectWrapper + | + |def main(args: String*): Unit = println("Hello") + |main() + |""".stripMargin, + os.rel / "script2.sc" -> + s"""//> using dep "com.lihaoyi::os-lib:0.9.1" + |//> using $enablingDirective + | + |println("Hello") + |""".stripMargin + ) + + test( + s"object wrapper with $targetDirective" + ) { + inputs.withBuild(baseOptions, buildThreads, bloopConfigOpt) { + (root, _, maybeBuild) => + expect(maybeBuild.orThrow.success) + val projectDir = os.list(root / ".scala-build").filter( + _.baseName.startsWith(root.baseName + "_") + ) + expect(projectDir.size == 1) + + expectObjectWrapper( + "script1", + projectDir.head / "src_generated" / "main" / "script1.scala" + ) + expectObjectWrapper( + "script2", + projectDir.head / "src_generated" / "main" / "script2.scala" + ) + } + } + } } diff --git a/modules/build/src/test/scala/scala/build/tests/SourceGeneratorTests.scala b/modules/build/src/test/scala/scala/build/tests/SourceGeneratorTests.scala new file mode 100644 index 0000000000..2d166fe081 --- /dev/null +++ b/modules/build/src/test/scala/scala/build/tests/SourceGeneratorTests.scala @@ -0,0 +1,349 @@ +package scala.build.tests + +import com.eed3si9n.expecty.Expecty.expect + +import java.io.IOException +import scala.build.Ops.EitherThrowOps +import scala.build.errors.ToolkitDirectiveMissingVersionError +import scala.build.options.{ + BuildOptions, + InternalOptions, + MaybeScalaVersion, + Platform, + ScalaOptions, + ScalacOpt, + Scope, + ScriptOptions +} +import scala.build.tests.util.BloopServer +import scala.build.{Build, BuildThreads, Directories, LocalRepo, Position, Positioned} + +class SourceGeneratorTests extends munit.FunSuite { + + val buildThreads = BuildThreads.create() + + def bloopConfigOpt = Some(BloopServer.bloopConfig) + + val extraRepoTmpDir = os.temp.dir(prefix = "scala-cli-tests-extra-repo-") + val directories = Directories.under(extraRepoTmpDir) + + override def afterAll(): Unit = { + TestInputs.tryRemoveAll(extraRepoTmpDir) + buildThreads.shutdown() + } + + val baseOptions = BuildOptions( + internal = InternalOptions( + localRepository = LocalRepo.localRepo(directories.localRepoDir), + keepDiagnostics = true + ) + ) + + private def normalizeResolvers(contents: String): String = + contents + .replaceAll( + "ivy:file:[^\"]*scala-cli-tests-extra-repo[^\"]*/local-repo[^\"]*", + "ivy:file:.../scala-cli-tests-extra-repo/local-repo/..." + ) + .replaceAll( + "ivy:file:[^\"]*\\.ivy2/local[^\"]*", + "ivy:file:.../.ivy2/local/" + ) + + test(s"BuildInfo source generated") { + val inputs = TestInputs( + os.rel / "main.scala" -> + """//> using dep com.lihaoyi::os-lib:0.9.1 + |//> using option -Xasync + |//> using plugin org.wartremover:::wartremover:3.0.9 + |//> using scala 3.2.2 + |//> using jvm 11 + |//> using mainClass Main + |//> using resourceDir ./resources + |//> using jar TEST1.jar TEST2.jar + | + |//> using buildInfo + | + |import scala.cli.build.BuildInfo + | + |object Main extends App { + | println(s"Scala version: ${BuildInfo.scalaVersion}") + | BuildInfo.Main.customJarsDecls.foreach(println) + |} + |""".stripMargin + ) + + inputs.withBuild(baseOptions, buildThreads, bloopConfigOpt) { + (root, _, maybeBuild) => + expect(maybeBuild.orThrow.success) + val projectDir = os.list(root / ".scala-build").filter( + _.baseName.startsWith(root.baseName + "_") + ) + expect(projectDir.size == 1) + val buildInfoPath = projectDir.head / "src_generated" / "main" / "BuildInfo.scala" + expect(os.isFile(buildInfoPath)) + + val buildInfoContent = os.read(buildInfoPath) + + expect(normalizeResolvers(buildInfoContent) == + s"""package scala.cli.build + | + |object BuildInfo { + | val scalaVersion = "3.2.2" + | val platform = "JVM" + | val jvmVersion = Some("11") + | val scalaJsVersion = None + | val jsEsVersion = None + | val scalaNativeVersion = None + | val mainClass = Some("Main") + | + | + | object Main { + | val sources = Seq("${root / "main.scala"}") + | val scalacOptions = Seq("-Xasync") + | val scalaCompilerPlugins = Seq("org.wartremover:wartremover_3.2.2:3.0.9") + | val dependencies = Seq("com.lihaoyi:os-lib_3:0.9.1") + | val resolvers = Seq("ivy:file:.../scala-cli-tests-extra-repo/local-repo/...", "https://repo1.maven.org/maven2", "ivy:file:.../.ivy2/local/") + | val resourceDirs = Seq("${root / "resources"}") + | val customJarsDecls = Seq("${root / "TEST1.jar"}", "${root / "TEST2.jar"}") + | } + | + | object Test { + | val sources = Nil + | val scalacOptions = Nil + | val scalaCompilerPlugins = Nil + | val dependencies = Nil + | val resolvers = Nil + | val resourceDirs = Nil + | val customJarsDecls = Nil + | } + | + |} + |""".stripMargin) + } + } + + test(s"BuildInfo for native") { + val inputs = TestInputs( + os.rel / "main.scala" -> + s"""//> using dep "com.lihaoyi::os-lib:0.9.1" + |//> using option "-Xasync" + |//> using plugin "org.wartremover:::wartremover:3.0.9" + |//> using scala 3.2.2 + |//> using jvm 11 + |//> using mainClass "Main" + |//> using resourceDir ./resources + |//> using jar TEST1.jar TEST2.jar + |//> using platform scala-native + |//> using nativeVersion 0.4.6 + | + |//> using buildInfo + | + |import scala.cli.build.BuildInfo + | + |object Main extends App { + | println(s"Scala version: $${BuildInfo.scalaVersion}") + | BuildInfo.Main.customJarsDecls.foreach(println) + |} + |""".stripMargin + ) + + inputs.withBuild(baseOptions, buildThreads, bloopConfigOpt) { + (root, _, maybeBuild) => + expect(maybeBuild.orThrow.success) + val projectDir = os.list(root / ".scala-build").filter( + _.baseName.startsWith(root.baseName + "_") + ) + expect(projectDir.size == 1) + val buildInfoPath = projectDir.head / "src_generated" / "main" / "BuildInfo.scala" + expect(os.isFile(buildInfoPath)) + + val buildInfoContent = os.read(buildInfoPath) + + expect(normalizeResolvers(buildInfoContent) == + s"""package scala.cli.build + | + |object BuildInfo { + | val scalaVersion = "3.2.2" + | val platform = "Native" + | val jvmVersion = None + | val scalaJsVersion = None + | val jsEsVersion = None + | val scalaNativeVersion = Some("0.4.6") + | val mainClass = Some("Main") + | + | + | object Main { + | val sources = Seq("${root / "main.scala"}") + | val scalacOptions = Seq("-Xasync") + | val scalaCompilerPlugins = Seq("org.wartremover:wartremover_3.2.2:3.0.9") + | val dependencies = Seq("com.lihaoyi:os-lib_3:0.9.1") + | val resolvers = Seq("ivy:file:.../scala-cli-tests-extra-repo/local-repo/...", "https://repo1.maven.org/maven2", "ivy:file:.../.ivy2/local/") + | val resourceDirs = Seq("${root / "resources"}") + | val customJarsDecls = Seq("${root / "TEST1.jar"}", "${root / "TEST2.jar"}") + | } + | + | object Test { + | val sources = Nil + | val scalacOptions = Nil + | val scalaCompilerPlugins = Nil + | val dependencies = Nil + | val resolvers = Nil + | val resourceDirs = Nil + | val customJarsDecls = Nil + | } + | + |} + |""".stripMargin) + } + } + + test(s"BuildInfo for js") { + val inputs = TestInputs( + os.rel / "main.scala" -> + s"""//> using dep "com.lihaoyi::os-lib:0.9.1" + |//> using option "-Xasync" + |//> using plugin "org.wartremover:::wartremover:3.0.9" + |//> using scala 3.2.2 + |//> using jvm 11 + |//> using mainClass "Main" + |//> using resourceDir ./resources + |//> using jar TEST1.jar TEST2.jar + |//> using platform scala-js + |//> using jsVersion 1.13.1 + |//> using jsEsVersionStr es2015 + | + |//> using buildInfo + | + |import scala.cli.build.BuildInfo + | + |object Main extends App { + | println(s"Scala version: $${BuildInfo.scalaVersion}") + | BuildInfo.Main.customJarsDecls.foreach(println) + |} + |""".stripMargin + ) + + inputs.withBuild(baseOptions, buildThreads, bloopConfigOpt) { + (root, _, maybeBuild) => + expect(maybeBuild.orThrow.success) + val projectDir = os.list(root / ".scala-build").filter( + _.baseName.startsWith(root.baseName + "_") + ) + expect(projectDir.size == 1) + val buildInfoPath = projectDir.head / "src_generated" / "main" / "BuildInfo.scala" + expect(os.isFile(buildInfoPath)) + + val buildInfoContent = os.read(buildInfoPath) + + expect(normalizeResolvers(buildInfoContent) == + s"""package scala.cli.build + | + |object BuildInfo { + | val scalaVersion = "3.2.2" + | val platform = "JS" + | val jvmVersion = None + | val scalaJsVersion = Some("1.13.1") + | val jsEsVersion = Some("es2015") + | val scalaNativeVersion = None + | val mainClass = Some("Main") + | + | + | object Main { + | val sources = Seq("${root / "main.scala"}") + | val scalacOptions = Seq("-Xasync") + | val scalaCompilerPlugins = Seq("org.wartremover:wartremover_3.2.2:3.0.9") + | val dependencies = Seq("com.lihaoyi:os-lib_3:0.9.1") + | val resolvers = Seq("ivy:file:.../scala-cli-tests-extra-repo/local-repo/...", "https://repo1.maven.org/maven2", "ivy:file:.../.ivy2/local/") + | val resourceDirs = Seq("${root / "resources"}") + | val customJarsDecls = Seq("${root / "TEST1.jar"}", "${root / "TEST2.jar"}") + | } + | + | object Test { + | val sources = Nil + | val scalacOptions = Nil + | val scalaCompilerPlugins = Nil + | val dependencies = Nil + | val resolvers = Nil + | val resourceDirs = Nil + | val customJarsDecls = Nil + | } + | + |} + |""".stripMargin) + } + } + + test(s"BuildInfo for Scala 2") { + val inputs = TestInputs( + os.rel / "main.scala" -> + s"""//> using dep "com.lihaoyi::os-lib:0.9.1" + |//> using option "-Xasync" + |//> using plugin "org.wartremover:::wartremover:3.0.9" + |//> using scala 2.13.6 + |//> using jvm 11 + |//> using mainClass "Main" + |//> using resourceDir ./resources + |//> using jar TEST1.jar TEST2.jar + | + |//> using buildInfo + | + |import scala.cli.build.BuildInfo + | + |object Main extends App { + | println(s"Scala version: $${BuildInfo.scalaVersion}") + | BuildInfo.Main.customJarsDecls.foreach(println) + |} + |""".stripMargin + ) + + inputs.withBuild(baseOptions, buildThreads, bloopConfigOpt) { + (root, _, maybeBuild) => + expect(maybeBuild.orThrow.success) + val projectDir = os.list(root / ".scala-build").filter( + _.baseName.startsWith(root.baseName + "_") + ) + expect(projectDir.size == 1) + val buildInfoPath = projectDir.head / "src_generated" / "main" / "BuildInfo.scala" + expect(os.isFile(buildInfoPath)) + + val buildInfoContent = os.read(buildInfoPath) + + expect(normalizeResolvers(buildInfoContent) == + s"""package scala.cli.build + | + |object BuildInfo { + | val scalaVersion = "2.13.6" + | val platform = "JVM" + | val jvmVersion = Some("11") + | val scalaJsVersion = None + | val jsEsVersion = None + | val scalaNativeVersion = None + | val mainClass = Some("Main") + | + | + | object Main { + | val sources = Seq("${root / "main.scala"}") + | val scalacOptions = Seq("-Xasync") + | val scalaCompilerPlugins = Seq("org.wartremover:wartremover_2.13.6:3.0.9") + | val dependencies = Seq("com.lihaoyi:os-lib_2.13:0.9.1") + | val resolvers = Seq("ivy:file:.../scala-cli-tests-extra-repo/local-repo/...", "https://repo1.maven.org/maven2", "ivy:file:.../.ivy2/local/") + | val resourceDirs = Seq("${root / "resources"}") + | val customJarsDecls = Seq("${root / "TEST1.jar"}", "${root / "TEST2.jar"}") + | } + | + | object Test { + | val sources = Nil + | val scalacOptions = Nil + | val scalaCompilerPlugins = Nil + | val dependencies = Nil + | val resolvers = Nil + | val resourceDirs = Nil + | val customJarsDecls = Nil + | } + | + |} + |""".stripMargin) + } + } +} diff --git a/modules/build/src/test/scala/scala/build/tests/SourcesTests.scala b/modules/build/src/test/scala/scala/build/tests/SourcesTests.scala index b881226403..98a7700b18 100644 --- a/modules/build/src/test/scala/scala/build/tests/SourcesTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/SourcesTests.scala @@ -6,7 +6,7 @@ import coursier.util.{Artifact, Task} import dependency.* import scala.build.Ops.* -import scala.build.{CrossSources, Position, Sources, UnwrappedCrossSources} +import scala.build.{CrossSources, Position, Sources} import scala.build.internal.ObjectCodeWrapper import scala.build.errors.{UsingDirectiveValueNumError, UsingDirectiveWrongValueTypeError} import scala.build.input.ScalaCliInvokeData @@ -62,10 +62,8 @@ class SourcesTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() ).orThrow - val wrappedCrossSources = - crossSources.withWrappedScripts(crossSources.sharedOptions(BuildOptions())) - val scopedSources = wrappedCrossSources.scopedSources(BuildOptions()).orThrow + val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) val obtainedDeps = sources.buildOptions.classPathOptions.extraDependencies.toSeq.toSeq.map( @@ -100,10 +98,8 @@ class SourcesTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() ).orThrow - val wrappedCrossSources = - crossSources.withWrappedScripts(crossSources.sharedOptions(BuildOptions())) - val scopedSources = wrappedCrossSources.scopedSources(BuildOptions()).orThrow + val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) expect( @@ -135,10 +131,8 @@ class SourcesTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() ).orThrow - val wrappedCrossSources = - crossSources.withWrappedScripts(crossSources.sharedOptions(BuildOptions())) - val scopedSources = wrappedCrossSources.scopedSources(BuildOptions()).orThrow + val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) expect( @@ -170,10 +164,8 @@ class SourcesTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() ).orThrow - val wrappedCrossSources = - crossSources.withWrappedScripts(crossSources.sharedOptions(BuildOptions())) - val scopedSources = wrappedCrossSources.scopedSources(BuildOptions()).orThrow + val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) expect(sources.buildOptions.classPathOptions.extraDependencies.toSeq.map(_.value).isEmpty) @@ -208,10 +200,8 @@ class SourcesTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() ).orThrow - val wrappedCrossSources = - crossSources.withWrappedScripts(crossSources.sharedOptions(BuildOptions())) - val scopedSources = wrappedCrossSources.scopedSources(BuildOptions()).orThrow + val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) expect( @@ -248,10 +238,8 @@ class SourcesTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() ).orThrow - val wrappedCrossSources = - crossSources.withWrappedScripts(crossSources.sharedOptions(BuildOptions())) - val scopedSources = wrappedCrossSources.scopedSources(BuildOptions()).orThrow + val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) expect( @@ -317,11 +305,10 @@ class SourcesTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() ).orThrow - val scriptWrappedSources = crossSources.withWrappedScripts(BuildOptions()) - val scopedSources = scriptWrappedSources.scopedSources(BuildOptions()).orThrow + val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow val sources = - scopedSources.sources(Scope.Main, scriptWrappedSources.sharedOptions(BuildOptions())) + scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) val parsedCodes: Seq[String] = sources.inMemory.map(_.generatedContent) @@ -353,10 +340,8 @@ class SourcesTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() ).orThrow - val wrappedCrossSources = - crossSources.withWrappedScripts(crossSources.sharedOptions(BuildOptions())) - val scopedSources = wrappedCrossSources.scopedSources(BuildOptions()).orThrow + val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) expect( @@ -392,10 +377,8 @@ class SourcesTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() ).orThrow - val wrappedCrossSources = - crossSources.withWrappedScripts(crossSources.sharedOptions(BuildOptions())) - val scopedSources = wrappedCrossSources.scopedSources(BuildOptions()).orThrow + val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) expect( @@ -422,10 +405,8 @@ class SourcesTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() ).orThrow - val wrappedCrossSources = - crossSources.withWrappedScripts(crossSources.sharedOptions(BuildOptions())) - val scopedSources = wrappedCrossSources.scopedSources(BuildOptions()).orThrow + val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) val javaOpts = sources.buildOptions.javaOptions.javaOpts.toSeq.sortBy(_.toString) @@ -463,10 +444,8 @@ class SourcesTests extends munit.FunSuite { TestLogger(), SuppressWarningOptions() ).orThrow - val wrappedCrossSources = - crossSources.withWrappedScripts(crossSources.sharedOptions(BuildOptions())) - val scopedSources = wrappedCrossSources.scopedSources(BuildOptions()).orThrow + val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions())) val jsOptions = sources.buildOptions.scalaJsOptions val jsConfig = jsOptions.linkerConfig(TestLogger()) @@ -565,8 +544,8 @@ class SourcesTests extends munit.FunSuite { SuppressWarningOptions() ) assert(crossSourcesResult.isRight) - val Right(CrossSources(onDiskSources, _, _, _, _)) = - crossSourcesResult.map(_._1.withWrappedScripts(BuildOptions())) + val Right(CrossSources(onDiskSources, _, _, _, _, _)) = + crossSourcesResult.map(_._1) val onDiskPaths = onDiskSources.map(_.value._1.last) expect(onDiskPaths == inputArgs) } diff --git a/modules/cli/src/main/scala/scala/cli/commands/dependencyupdate/DependencyUpdate.scala b/modules/cli/src/main/scala/scala/cli/commands/dependencyupdate/DependencyUpdate.scala index 3d757e64cf..7ee3bcd7fa 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/dependencyupdate/DependencyUpdate.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/dependencyupdate/DependencyUpdate.scala @@ -42,9 +42,8 @@ object DependencyUpdate extends ScalaCommand[DependencyUpdateOptions] { buildOptions.internal.exclude ).orExit(logger) - val sharedOptions = crossSources.sharedOptions(buildOptions) - val wrappedCrossOptions = crossSources.withWrappedScripts(sharedOptions) - val scopedSources = wrappedCrossOptions.scopedSources(buildOptions).orExit(logger) + val sharedOptions = crossSources.sharedOptions(buildOptions) + val scopedSources = crossSources.scopedSources(buildOptions).orExit(logger) def generateActionableUpdateDiagnostic(scope: Scope) : Seq[ActionableDependencyUpdateDiagnostic] = { diff --git a/modules/cli/src/main/scala/scala/cli/commands/export0/Export.scala b/modules/cli/src/main/scala/scala/cli/commands/export0/Export.scala index da664b72da..4762ae1e83 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/export0/Export.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/export0/Export.scala @@ -40,7 +40,7 @@ object Export extends ScalaCommand[ExportOptions] { logger.log("Preparing build") - val (crossSources: UnwrappedCrossSources, _) = value { + val (crossSources: CrossSources, _) = value { CrossSources.forInputs( inputs, Sources.defaultPreprocessors( @@ -54,11 +54,9 @@ object Export extends ScalaCommand[ExportOptions] { ) } - val wrappedScriptsSources = crossSources.withWrappedScripts(buildOptions) - - val scopedSources: ScopedSources = value(wrappedScriptsSources.scopedSources(buildOptions)) + val scopedSources: ScopedSources = value(crossSources.scopedSources(buildOptions)) val sources: Sources = - scopedSources.sources(scope, wrappedScriptsSources.sharedOptions(buildOptions)) + scopedSources.sources(scope, crossSources.sharedOptions(buildOptions)) if (verbosity >= 3) pprint.err.log(sources) diff --git a/modules/cli/src/main/scala/scala/cli/commands/publish/PublishSetup.scala b/modules/cli/src/main/scala/scala/cli/commands/publish/PublishSetup.scala index 9cf83b3ef6..1f931d16e3 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/publish/PublishSetup.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/publish/PublishSetup.scala @@ -93,10 +93,8 @@ object PublishSetup extends ScalaCommand[PublishSetupOptions] { ).orExit(logger) val crossSourcesSharedOptions = crossSources.sharedOptions(cliBuildOptions) - val wrappedCrossSources = crossSources.withWrappedScripts(crossSourcesSharedOptions) - val scopedSources = - wrappedCrossSources.scopedSources(crossSourcesSharedOptions).orExit(logger) - val sources = scopedSources.sources(Scope.Main, crossSourcesSharedOptions) + val scopedSources = crossSources.scopedSources(crossSourcesSharedOptions).orExit(logger) + val sources = scopedSources.sources(Scope.Main, crossSourcesSharedOptions) val pureJava = sources.hasJava && !sources.hasScala diff --git a/modules/cli/src/main/scala/scala/cli/commands/setupide/SetupIde.scala b/modules/cli/src/main/scala/scala/cli/commands/setupide/SetupIde.scala index eac5142cad..30ea42bd1e 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/setupide/SetupIde.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/setupide/SetupIde.scala @@ -44,10 +44,9 @@ object SetupIde extends ScalaCommand[SetupIdeOptions] { ) } - val sharedOptions = crossSources.sharedOptions(options) - val wrappedCrossOptions = crossSources.withWrappedScripts(sharedOptions) + val sharedOptions = crossSources.sharedOptions(options) - value(wrappedCrossOptions.scopedSources(options)) + value(crossSources.scopedSources(options)) .sources(Scope.Main, crossSources.sharedOptions(options)) .buildOptions } diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/HelpGroups.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/HelpGroups.scala index 27b48ff6fa..946ec2e31b 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/HelpGroups.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/HelpGroups.scala @@ -14,7 +14,7 @@ enum HelpGroup: NativeImage, Package, PGP, Publishing, RedHat, Repl, Run, Runner, - Scala, ScalaJs, ScalaNative, Secret, Signing, SuppressWarnings, + Scala, ScalaJs, ScalaNative, Secret, Signing, SuppressWarnings, SourceGenerator, Test, Uninstall, Update, Watch, Windows, @@ -28,6 +28,7 @@ enum HelpGroup: case ScalaJs => "Scala.js" case ScalaNative => "Scala Native" case SuppressWarnings => "Suppress warnings" + case SourceGenerator => "Source generator" case e => e.productPrefix enum HelpCommandGroup: diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala index 4ccfbd0404..534a6a9f77 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala @@ -35,6 +35,7 @@ import scala.cli.commands.shared.{ ScalaJsOptions, ScalaNativeOptions, SharedOptions, + SourceGeneratorOptions, SuppressWarningOptions } import scala.cli.commands.tags @@ -50,6 +51,8 @@ import scala.util.control.NonFatal // format: off final case class SharedOptions( + @Recurse + sourceGenerator: SourceGeneratorOptions = SourceGeneratorOptions(), @Recurse suppress: SuppressWarningOptions = SuppressWarningOptions(), @Recurse @@ -312,6 +315,9 @@ final case class SharedOptions( |The following jars were assumed to be source jars and will be treated as such: $assumedSourceJarsString""".stripMargin ) bo.BuildOptions( + sourceGeneratorOptions = bo.SourceGeneratorOptions( + useBuildInfo = sourceGenerator.useBuildInfo + ), suppressWarningOptions = bo.SuppressWarningOptions( suppressDirectivesInMultipleFilesWarning = getOptionOrFromConfig( diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/SourceGeneratorOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/SourceGeneratorOptions.scala new file mode 100644 index 0000000000..17e8292064 --- /dev/null +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/SourceGeneratorOptions.scala @@ -0,0 +1,20 @@ +package scala.cli.commands.shared + +import caseapp.* + +import scala.cli.commands.tags + +// format: off +final case class SourceGeneratorOptions( + @Group(HelpGroup.SourceGenerator.toString) + @Tag(tags.experimental) + @HelpMessage("Generate BuildInfo for project") + @Name("buildInfo") + useBuildInfo: Option[Boolean] = None, +) +// format: on + +object SourceGeneratorOptions { + implicit lazy val parser: Parser[SourceGeneratorOptions] = Parser.derive + implicit lazy val help: Help[SourceGeneratorOptions] = Help.derive +} diff --git a/modules/cli/src/main/scala/scala/cli/exportCmd/JsonProject.scala b/modules/cli/src/main/scala/scala/cli/exportCmd/JsonProject.scala index b4c8595184..7d8bf78757 100644 --- a/modules/cli/src/main/scala/scala/cli/exportCmd/JsonProject.scala +++ b/modules/cli/src/main/scala/scala/cli/exportCmd/JsonProject.scala @@ -9,33 +9,24 @@ import dependency.AnyDependency import java.io.PrintStream import java.nio.charset.StandardCharsets +import scala.build.info.{BuildInfo, ExportDependencyFormat, ScopedBuildInfo} import scala.build.options.ConfigMonoid import scala.cli.util.SeqHelpers.* import scala.reflect.NameTransformer import scala.util.{Properties, Using} -final case class JsonProject( - projectName: 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, ScopedJsonProject] = Map.empty -) extends Project { - - def +(other: JsonProject): JsonProject = - JsonProject.monoid.orElse(this, other) +final case class JsonProject(buildInfo: BuildInfo) extends Project { + def sorted = this.copy( + buildInfo = buildInfo.copy( + scopes = buildInfo.scopes.map { case (k, v) => k -> v.sorted } + ) + ) - def withScope(scopeName: String, scopedJsonProj: ScopedJsonProject): JsonProject = - if (scopedJsonProj.sources.isEmpty) - this - else - this.copy( - scopes = this.scopes + (scopeName -> scopedJsonProj) - ) + def withEmptyScopesRemoved = this.copy( + buildInfo = buildInfo.copy( + scopes = buildInfo.scopes.filter(_._2 != ScopedBuildInfo.empty) + ) + ) def writeTo(dir: os.Path): Unit = { val config = WriterConfig.withIndentionStep(1) @@ -43,9 +34,11 @@ final case class JsonProject( Using(os.write.outputStream(dir / "export.json")) { outputStream => writeToStream( - this, + sorted.withEmptyScopesRemoved.buildInfo, outputStream, config + )( + using JsonProject.jsonCodecBuildInfo ) } } @@ -54,85 +47,34 @@ final case class JsonProject( val config = WriterConfig.withIndentionStep(1) writeToStream( - this, + sorted.withEmptyScopesRemoved.buildInfo, printStream, config + )( + using JsonProject.jsonCodecBuildInfo ) } } -final case class ScopedJsonProject( - sources: Seq[String] = Nil, - scalacOptions: Seq[String] = Nil, - scalaCompilerPlugins: Seq[ExportDependencyFormat] = Nil, - dependencies: Seq[ExportDependencyFormat] = Nil, - compileOnlyDependencies: Seq[ExportDependencyFormat] = Nil, - resolvers: Seq[String] = Nil, - resourcesDirs: Seq[String] = Nil, - customJarsDecls: Seq[String] = Nil -) { - - def +(other: ScopedJsonProject): ScopedJsonProject = - ScopedJsonProject.monoid.orElse(this, other) - - def sorted(using ord: Ordering[String]): ScopedJsonProject = - ScopedJsonProject( - this.sources.sorted, - this.scalacOptions, - this.scalaCompilerPlugins.sorted, - this.dependencies.sorted, - this.compileOnlyDependencies.sorted, - this.resolvers.sorted, - this.resourcesDirs.sorted, - this.customJarsDecls.sorted - ) -} - -object ScopedJsonProject { - implicit val monoid: ConfigMonoid[ScopedJsonProject] = ConfigMonoid.derive - implicit lazy val jsonCodec: JsonValueCodec[ScopedJsonProject] = JsonCodecMaker.make +extension (s: ScopedBuildInfo) { + def sorted(using ord: Ordering[String]) = s.copy( + s.sources.sorted, + s.scalacOptions.sorted, + s.scalaCompilerPlugins.sorted(using JsonProject.ordering), + s.dependencies.sorted(using JsonProject.ordering), + s.compileOnlyDependencies.sorted(using JsonProject.ordering), + s.resolvers.sorted, + s.resourceDirs.sorted, + s.customJarsDecls.sorted + ) } object JsonProject { - implicit val monoid: ConfigMonoid[JsonProject] = ConfigMonoid.derive - implicit lazy val jsonCodec: JsonValueCodec[JsonProject] = JsonCodecMaker.make -} - -case class ExportDependencyFormat(groupId: String, artifactId: ArtifactId, version: String) - -case class ArtifactId(name: String, fullName: String) - -object ExportDependencyFormat { - def apply(dep: Dependency): ExportDependencyFormat = { - val scalaVersionStartIndex = dep.module.name.value.lastIndexOf('_') - val shortDepName = if (scalaVersionStartIndex == -1) - dep.module.name.value - else - dep.module.name.value.take(scalaVersionStartIndex) - new ExportDependencyFormat( - dep.module.organization.value, - ArtifactId(shortDepName, dep.module.name.value), - dep.version - ) - } - - def apply( - dep: AnyDependency, - scalaParamsOpt: Option[dependency.ScalaParameters] - ): ExportDependencyFormat = { - import scala.build.internal.Util.* - dep.toCs(scalaParamsOpt) - .map(ExportDependencyFormat.apply) - .getOrElse( - ExportDependencyFormat( - dep.module.organization, - ArtifactId(dep.module.name, dep.module.name), - dep.version - ) - ) - } + implicit lazy val jsonCodecBuildInfo: JsonValueCodec[BuildInfo] = JsonCodecMaker.make + implicit lazy val jsonCodecScopedBuildInfo: JsonValueCodec[ScopedBuildInfo] = JsonCodecMaker.make implicit val ordering: Ordering[ExportDependencyFormat] = Ordering.by(x => x.groupId + x.artifactId.fullName) - implicit lazy val jsonCodec: JsonValueCodec[ExportDependencyFormat] = JsonCodecMaker.make + implicit lazy val jsonCodecExportDependencyFormat: JsonValueCodec[ExportDependencyFormat] = + JsonCodecMaker.make } diff --git a/modules/cli/src/main/scala/scala/cli/exportCmd/JsonProjectDescriptor.scala b/modules/cli/src/main/scala/scala/cli/exportCmd/JsonProjectDescriptor.scala index ce149cb178..98cd8307f5 100644 --- a/modules/cli/src/main/scala/scala/cli/exportCmd/JsonProjectDescriptor.scala +++ b/modules/cli/src/main/scala/scala/cli/exportCmd/JsonProjectDescriptor.scala @@ -11,16 +11,10 @@ import java.nio.charset.StandardCharsets import java.nio.file.Path import scala.build.errors.BuildException +import scala.build.info.{BuildInfo, ScopedBuildInfo} import scala.build.internal.Constants import scala.build.internal.Runner.frameworkName -import scala.build.options.{ - BuildOptions, - JavaOptions, - Platform, - ScalaJsOptions, - ScalaNativeOptions, - Scope -} +import scala.build.options.{BuildOptions, Scope} import scala.build.testrunner.AsmTestRunner import scala.build.{Logger, Positioned, Sources} import scala.cli.util.SeqHelpers.* @@ -31,141 +25,25 @@ final case class JsonProjectDescriptor( ) extends ProjectDescriptor { private val charSet = StandardCharsets.UTF_8 - private def scalaVersionSettings(options: BuildOptions): JsonProject = { - val sv = options.scalaOptions.scalaVersion - .flatMap(_.versionOpt) - .getOrElse(Constants.defaultScalaVersion) - - JsonProject(scalaVersion = Some(sv)) - } - - private def scalaJsSettings(options: ScalaJsOptions): JsonProject = { - - val scalaJsVersion = Some(options.version.getOrElse(Constants.scalaJsVersion)) - - JsonProject( - platform = Some(Platform.JS.repr), - scalaJsVersion = scalaJsVersion, - jsEsVersion = options.esVersionStr - ) - } - - private def scalaNativeSettings(options: ScalaNativeOptions): JsonProject = { - val scalaNativeVersion = Some(options.version.getOrElse(Constants.scalaNativeVersion)) - - JsonProject( - platform = Some(Platform.Native.repr), - scalaNativeVersion = scalaNativeVersion - ) - } - - private def jvmSettings(options: JavaOptions): JsonProject = - JsonProject( - platform = Some(Platform.JVM.repr), - jvmVersion = options.jvmIdOpt.map(_.value) - ) - - private def platformSettings(options: BuildOptions): JsonProject = - options.scalaOptions.platform.map(_.value) match { - case Some(Platform.JS) => - scalaJsSettings(options.scalaJsOptions) - case Some(Platform.Native) => - scalaNativeSettings(options.scalaNativeOptions) - case _ => jvmSettings(options.javaOptions) - } - - private def scalacOptionsSettings(options: BuildOptions): ScopedJsonProject = - ScopedJsonProject(scalacOptions = options.scalaOptions.scalacOptions.toSeq.map(_.value.value)) - - private def sourcesSettings(sources: Sources): ScopedJsonProject = - ScopedJsonProject(sources = - ProjectDescriptor.sources(sources, charSet).map(_._1.toNIO.toString) - ) - - private def scalaCompilerPlugins(options: BuildOptions): ScopedJsonProject = - val compilerPlugins = options.scalaOptions.compilerPlugins.map(_.value) - .map(ExportDependencyFormat(_, options.scalaParams.getOrElse(None))) - - ScopedJsonProject(scalaCompilerPlugins = compilerPlugins) - - private def dependencySettings(options: BuildOptions): ScopedJsonProject = { - val directDeps = options.classPathOptions.extraDependencies.toSeq.map(_.value) - .map(ExportDependencyFormat(_, options.scalaParams.getOrElse(None))) - val compileDeps = options.classPathOptions.extraCompileOnlyDependencies.toSeq.map(_.value) - .map(ExportDependencyFormat(_, options.scalaParams.getOrElse(None))) - - ScopedJsonProject( - dependencies = directDeps, - compileOnlyDependencies = compileDeps - ) - } - - private def repositorySettings(options: BuildOptions): ScopedJsonProject = { - val resolvers = options.finalRepositories - .getOrElse(Nil) - .appended(Repositories.central) - .appended(LocalRepositories.ivy2Local) - .collect { - case repo: MavenRepository => repo.root - case repo: IvyRepository => s"ivy:${repo.pattern.string}" - } - .distinct - - ScopedJsonProject(resolvers = resolvers) - } - - private def customResourcesSettings(options: BuildOptions): ScopedJsonProject = - ScopedJsonProject(resourcesDirs = options.classPathOptions.resourcesDir.map(_.toNIO.toString)) - - private def customJarsSettings(options: BuildOptions): ScopedJsonProject = { - - val customCompileOnlyJarsDecls = - options.classPathOptions.extraCompileOnlyJars.map(_.toNIO.toString) - - val customJarsDecls = options.classPathOptions.extraClassPath.map(_.toNIO.toString) - - ScopedJsonProject( - customJarsDecls = customCompileOnlyJarsDecls ++ customJarsDecls - ) - } - def `export`( optionsMain: BuildOptions, optionsTest: BuildOptions, sourcesMain: Sources, sourcesTest: Sources ): JsonProject = { - val baseJsonProject = Seq( - JsonProject( - projectName = projectName, - mainClass = optionsMain.mainClass - ), - scalaVersionSettings(optionsMain), - platformSettings(optionsMain) - ) - .foldLeft(JsonProject())(_ + _) + def getScopedBuildInfo(options: BuildOptions, sources: Sources) = + val sourcePaths = sources.paths.map(_._1.toString) + val inMemoryPaths = sources.inMemory.flatMap(_.originalPath.toSeq.map(_._2.toString)) - val mainJsonProject = exportScope(optionsMain, sourcesMain) - val testJsonProject = exportScope(optionsTest, sourcesTest) + ScopedBuildInfo(options, sourcePaths ++ inMemoryPaths) - baseJsonProject - .withScope(Scope.Main.name, mainJsonProject) - .withScope(Scope.Test.name, testJsonProject) - } + val baseBuildInfo = BuildInfo(optionsMain) - def exportScope( - options: BuildOptions, - sources: Sources - ): ScopedJsonProject = - Seq( - scalaCompilerPlugins(options), - scalacOptionsSettings(options), - sourcesSettings(sources), - dependencySettings(options), - repositorySettings(options), - customResourcesSettings(options), - customJarsSettings(options) - ) - .foldLeft(ScopedJsonProject())(_ + _) - .sorted + val mainBuildInfo = getScopedBuildInfo(optionsMain, sourcesMain) + val testBuildInfo = getScopedBuildInfo(optionsTest, sourcesTest) + + JsonProject(baseBuildInfo + .withScope(Scope.Main.name, mainBuildInfo) + .withScope(Scope.Test.name, testBuildInfo)) + } } diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/BuildInfo.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/BuildInfo.scala new file mode 100644 index 0000000000..5c011441ec --- /dev/null +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/BuildInfo.scala @@ -0,0 +1,24 @@ +package scala.build.preprocessing.directives + +import scala.build.directives.* +import scala.build.errors.BuildException +import scala.build.options.{BuildOptions, SourceGeneratorOptions} +import scala.cli.commands.SpecificationLevel + +@DirectiveExamples("//> using buildInfo") +@DirectiveUsage("//> using buildInfo", "`//> using buildInfo") +@DirectiveDescription("Generate BuildInfo for project") +@DirectiveLevel(SpecificationLevel.RESTRICTED) +final case class BuildInfo( + buildInfo: Boolean = false +) extends HasBuildOptions { + def buildOptions: Either[BuildException, BuildOptions] = + val options = BuildOptions(sourceGeneratorOptions = + SourceGeneratorOptions(useBuildInfo = Some(buildInfo)) + ) + Right(options) +} + +object BuildInfo { + val handler: DirectiveHandler[BuildInfo] = DirectiveHandler.derive +} diff --git a/modules/integration/src/test/scala/scala/cli/integration/ExportJsonTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/ExportJsonTestDefinitions.scala index 457cee50d6..8fcf10d0fd 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/ExportJsonTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/ExportJsonTestDefinitions.scala @@ -19,6 +19,9 @@ abstract class ExportJsonTestDefinitions(val scalaVersionOpt: Option[String]) "ivy:file:.../.ivy2/local/" ) + private def withEscapedBackslashes(s: os.Path): String = + s.toString.replaceAll("\\\\", "\\\\\\\\") + test("export json") { val inputs = TestInputs( os.rel / "Main.scala" -> @@ -44,8 +47,9 @@ abstract class ExportJsonTestDefinitions(val scalaVersionOpt: Option[String]) |"platform":"JVM", |"jvmVersion":"adopt:11", |"scopes": [[ - | "main", { - | "sources": ["Main.scala"], + | "main", + | { + | "sources": ["${withEscapedBackslashes(root / "Main.scala")}"], | "dependencies": [ | { | "groupId":"com.lihaoyi", @@ -93,14 +97,6 @@ abstract class ExportJsonTestDefinitions(val scalaVersionOpt: Option[String]) .call(cwd = root) val jsonContents = readJson(exportJsonProc.out.text()) - .replaceAll( - "\"resourcesDirs\":\\[\"[^\"]*resources\"\\]", - "\"resourcesDirs\":[\"./resources\"]" - ) - .replaceAll( - "\"customJarsDecls\":\\[\"[^\"]*TEST.jar\"\\]", - "\"customJarsDecls\":[\"./TEST.jar\"]" - ) expect(jsonContents == s"""{ @@ -108,8 +104,9 @@ abstract class ExportJsonTestDefinitions(val scalaVersionOpt: Option[String]) |"platform":"Native", |"scalaNativeVersion":"${Constants.scalaNativeVersion}", |"scopes": [[ - | "main", { - | "sources": ["Main.scala"], + | "main", + | { + | "sources": ["${withEscapedBackslashes(root / "Main.scala")}"], | "scalacOptions":["-Xasync"], | "scalaCompilerPlugins": [ | { @@ -137,8 +134,9 @@ abstract class ExportJsonTestDefinitions(val scalaVersionOpt: Option[String]) | "ivy:file:.../.ivy2/local/" | ] | }], [ - | "test", { - | "sources":["unit.test.scala"], + | "test", + | { + | "sources":["${withEscapedBackslashes(root / "unit.test.scala")}"], | "scalacOptions":["-Xasync"], | "scalaCompilerPlugins": [ | { @@ -166,8 +164,8 @@ abstract class ExportJsonTestDefinitions(val scalaVersionOpt: Option[String]) | "ivy:file:.../scalacli/local-repo/...", | "ivy:file:.../.ivy2/local/" | ], - | "resourcesDirs":["./resources"], - | "customJarsDecls":["./TEST.jar"] + | "resourceDirs":["${withEscapedBackslashes(root / "resources")}"], + | "customJarsDecls":["${withEscapedBackslashes(root / "TEST.jar")}"] | } |]] |} @@ -216,8 +214,9 @@ abstract class ExportJsonTestDefinitions(val scalaVersionOpt: Option[String]) |"scalaJsVersion": "${Constants.scalaJsVersion}", |"jsEsVersion":"es2015", |"scopes": [[ - | "main", { - | "sources": ["Main.scala"], + | "main", + | { + | "sources": ["${withEscapedBackslashes(root / "Main.scala")}"], | "scalacOptions": ["-Xasync"], | "scalaCompilerPlugins": [ | { diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala index b96db163c2..2d25d2a1eb 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala @@ -1554,4 +1554,75 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String]) } } } + + test("BuildInfo fields should be reachable") { + val inputs = TestInputs( + os.rel / "Main.scala" -> + s"""//> using dep com.lihaoyi::os-lib:0.9.1 + |//> using option -Xasync + |//> using jvm 11 + |//> using mainClass Main + |//> using resourceDir ./resources + |//> using jar TEST1.jar TEST2.jar + | + |//> using buildInfo + | + |import scala.cli.build.BuildInfo + | + |object Main extends App { + | assert(BuildInfo.scalaVersion == "$actualScalaVersion") + | assert(BuildInfo.platform == "JVM") + | assert(BuildInfo.jvmVersion == Some("11")) + | assert(BuildInfo.scalaJsVersion == None) + | assert(BuildInfo.jsEsVersion == None) + | assert(BuildInfo.scalaNativeVersion == None) + | assert(BuildInfo.mainClass == Some("Main")) + | + | assert(BuildInfo.Main.sources.head.endsWith("Main.scala")) + | assert(BuildInfo.Main.scalacOptions == Seq("-Xasync")) + | assert(BuildInfo.Main.scalaCompilerPlugins.size == 0) + | assert(BuildInfo.Main.dependencies.size == 1) + | assert(BuildInfo.Main.dependencies.head.contains("com.lihaoyi:os-lib_")) + | assert(BuildInfo.Main.resolvers.size == 3) + | assert(BuildInfo.Main.resourceDirs.size == 1) + | assert(BuildInfo.Main.customJarsDecls.size == 2) + | + | assert(BuildInfo.Test.sources.head.endsWith("Test.scala")) + | assert(BuildInfo.Test.scalacOptions == Seq("-Xasync")) + | assert(BuildInfo.Test.scalaCompilerPlugins.size == 0) + | assert(BuildInfo.Test.dependencies.size == 2) + | assert(BuildInfo.Test.dependencies.exists(_.contains("com.lihaoyi:os-lib_"))) + | assert(BuildInfo.Test.dependencies.exists(_.contains("org.scalameta:munit"))) + | assert(BuildInfo.Test.resolvers.size == 3) + | assert(BuildInfo.Test.resourceDirs.size == 1) + | assert(BuildInfo.Test.customJarsDecls.size == 2) + |} + |""".stripMargin, + os.rel / "test" / "Test.scala" -> + """//> using dep org.scalameta::munit::0.7.29 + | + |class MyTests extends munit.FunSuite { + | test("foo") { + | assert(2 + 2 == 4) + | println("Hello from " + "tests") + | } + |} + |""".stripMargin + ) + + inputs.fromRoot { root => + val res = + os.proc(TestUtil.cli, "--power", extraOptions, ".").call(cwd = root) + val output = res.out.trim() + + val projectDir = os.list(root / ".scala-build").filter( + _.baseName.startsWith(root.baseName + "_") + ) + expect(projectDir.size == 1) + val buildInfoPath = projectDir.head / "src_generated" / "main" / "BuildInfo.scala" + expect(os.isFile(buildInfoPath)) + + expect(output == "") + } + } } diff --git a/modules/options/src/main/scala/scala/build/info/BuildInfo.scala b/modules/options/src/main/scala/scala/build/info/BuildInfo.scala new file mode 100644 index 0000000000..ddf8d4b041 --- /dev/null +++ b/modules/options/src/main/scala/scala/build/info/BuildInfo.scala @@ -0,0 +1,132 @@ +package scala.build.info + +import scala.build.info.BuildInfo.escapeBackslashes +import scala.build.internal.Constants +import scala.build.options.* + +final case class BuildInfo( + 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( + s"val scalaVersion = \"${escapeBackslashes(scalaVersion.getOrElse(Constants.defaultScalaVersion))}\"", + 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 + ).map { case (prefix, opt) => + 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}object ${scopeName.capitalize} { + |$indent$scopedBuildInfoVals + |$indent} + |""".stripMargin + } + + s"""package scala.cli.build + | + |object BuildInfo { + |${allVals.mkString(indent, nl + indent, nl)} + |${scopesContents.mkString(nl, nl, "")} + |} + |""".stripMargin + } +} + +object BuildInfo { + def apply( + options: BuildOptions + ): BuildInfo = + Seq( + BuildInfo( + mainClass = options.mainClass + ), + scalaVersionSettings(options), + platformSettings(options) + ) + .reduceLeft(_ + _) + + def escapeBackslashes(s: String): String = + s.replace("\\", "\\\\") + + private def scalaVersionSettings(options: BuildOptions): BuildInfo = { + val sv = options.scalaParams.toOption.flatten + .map(_.scalaVersion) + .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 = { + val scalaNativeVersion = Some(options.version.getOrElse(Constants.scalaNativeVersion)) + + BuildInfo( + platform = Some(Platform.Native.repr), + scalaNativeVersion = scalaNativeVersion + ) + } + + 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 +} diff --git a/modules/options/src/main/scala/scala/build/info/ScopedBuildInfo.scala b/modules/options/src/main/scala/scala/build/info/ScopedBuildInfo.scala new file mode 100644 index 0000000000..4ccb41dc7a --- /dev/null +++ b/modules/options/src/main/scala/scala/build/info/ScopedBuildInfo.scala @@ -0,0 +1,160 @@ +package scala.build.info + +import coursier.ivy.IvyRepository +import coursier.maven.MavenRepository +import coursier.{Dependency, LocalRepositories, Repositories} +import dependency.AnyDependency + +import java.nio.charset.StandardCharsets + +import scala.build.options.{BuildOptions, ConfigMonoid} +import scala.reflect.io.Path + +final case class ScopedBuildInfo( + sources: Seq[String] = Nil, + scalacOptions: Seq[String] = Nil, + scalaCompilerPlugins: Seq[ExportDependencyFormat] = Nil, + dependencies: Seq[ExportDependencyFormat] = Nil, + compileOnlyDependencies: Seq[ExportDependencyFormat] = Nil, + resolvers: Seq[String] = Nil, + resourceDirs: Seq[String] = Nil, + customJarsDecls: Seq[String] = Nil +) { + def +(other: ScopedBuildInfo): ScopedBuildInfo = + ScopedBuildInfo.monoid.orElse(this, other) + + 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) => + 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() + } +} + +object ScopedBuildInfo { + def empty: ScopedBuildInfo = ScopedBuildInfo() + + def apply(options: BuildOptions, sourcePaths: Seq[String]): ScopedBuildInfo = + Seq( + ScopedBuildInfo(sources = sourcePaths), + scalaCompilerPlugins(options), + scalacOptionsSettings(options), + dependencySettings(options), + repositorySettings(options), + customResourcesSettings(options), + customJarsSettings(options) + ) + .reduceLeft(_ + _) + + private def scalacOptionsSettings(options: BuildOptions): ScopedBuildInfo = + ScopedBuildInfo(scalacOptions = options.scalaOptions.scalacOptions.toSeq.map(_.value.value)) + + private def scalaCompilerPlugins(options: BuildOptions): ScopedBuildInfo = + val compilerPlugins = options.scalaOptions.compilerPlugins.map(_.value) + .map(ExportDependencyFormat(_, options.scalaParams.getOrElse(None))) + + ScopedBuildInfo(scalaCompilerPlugins = compilerPlugins) + + private def dependencySettings(options: BuildOptions): ScopedBuildInfo = { + val directDeps = options.classPathOptions.extraDependencies.toSeq.map(_.value) + .map(ExportDependencyFormat(_, options.scalaParams.getOrElse(None))) + val compileDeps = options.classPathOptions.extraCompileOnlyDependencies.toSeq.map(_.value) + .map(ExportDependencyFormat(_, options.scalaParams.getOrElse(None))) + + ScopedBuildInfo( + dependencies = directDeps, + compileOnlyDependencies = compileDeps + ) + } + + private def repositorySettings(options: BuildOptions): ScopedBuildInfo = { + val resolvers = options.finalRepositories + .getOrElse(Nil) + .appended(Repositories.central) + .appended(LocalRepositories.ivy2Local) + .collect { + case repo: MavenRepository => repo.root + case repo: IvyRepository => s"ivy:${repo.pattern.string}" + } + .distinct + + ScopedBuildInfo(resolvers = resolvers) + } + + private def customResourcesSettings(options: BuildOptions): ScopedBuildInfo = + ScopedBuildInfo(resourceDirs = options.classPathOptions.resourcesDir.map(_.toNIO.toString)) + + private def customJarsSettings(options: BuildOptions): ScopedBuildInfo = { + + val customCompileOnlyJarsDecls = + options.classPathOptions.extraCompileOnlyJars.map(_.toNIO.toString) + + val customJarsDecls = options.classPathOptions.extraClassPath.map(_.toNIO.toString) + + ScopedBuildInfo( + customJarsDecls = customCompileOnlyJarsDecls ++ customJarsDecls + ) + } + + private val charSet = StandardCharsets.UTF_8 + + implicit val monoid: ConfigMonoid[ScopedBuildInfo] = ConfigMonoid.derive +} + +final case class ExportDependencyFormat(groupId: String, artifactId: ArtifactId, version: String) { + override def toString(): String = { + val sb = new StringBuilder + sb.append(groupId) + sb.append(':') + sb.append(artifactId.fullName) + sb.append(':') + sb.append(version) + sb.toString() + } +} + +final case class ArtifactId(name: String, fullName: String) + +object ExportDependencyFormat { + def apply(dep: Dependency): ExportDependencyFormat = { + val scalaVersionStartIndex = dep.module.name.value.lastIndexOf('_') + val shortDepName = if (scalaVersionStartIndex == -1) + dep.module.name.value + else + dep.module.name.value.take(scalaVersionStartIndex) + new ExportDependencyFormat( + dep.module.organization.value, + ArtifactId(shortDepName, dep.module.name.value), + dep.version + ) + } + + def apply( + dep: AnyDependency, + scalaParamsOpt: Option[dependency.ScalaParameters] + ): ExportDependencyFormat = { + import scala.build.internal.Util.* + dep.toCs(scalaParamsOpt) + .map(ExportDependencyFormat.apply) + .getOrElse( + ExportDependencyFormat( + dep.module.organization, + ArtifactId(dep.module.name, dep.module.name), + dep.version + ) + ) + } +} diff --git a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala index d99eac975e..7ff5301186 100644 --- a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala @@ -41,7 +41,8 @@ final case class BuildOptions( internal: InternalOptions = InternalOptions(), mainClass: Option[String] = None, testOptions: TestOptions = TestOptions(), - notForBloopOptions: PostBuildOptions = PostBuildOptions() + notForBloopOptions: PostBuildOptions = PostBuildOptions(), + sourceGeneratorOptions: SourceGeneratorOptions = SourceGeneratorOptions() ) { import BuildOptions.JavaHomeInfo diff --git a/modules/options/src/main/scala/scala/build/options/SourceGeneratorOptions.scala b/modules/options/src/main/scala/scala/build/options/SourceGeneratorOptions.scala new file mode 100644 index 0000000000..19b52ee69e --- /dev/null +++ b/modules/options/src/main/scala/scala/build/options/SourceGeneratorOptions.scala @@ -0,0 +1,11 @@ +package scala.build.options + +final case class SourceGeneratorOptions( + useBuildInfo: Option[Boolean] = None +) + +object SourceGeneratorOptions { + /* Using HasHashData.nop here (SourceGeneratorOptions values are not used during compilation) */ + implicit val hasHashData: HasHashData[SourceGeneratorOptions] = HasHashData.nop + implicit val monoid: ConfigMonoid[SourceGeneratorOptions] = ConfigMonoid.derive +} diff --git a/website/docs/reference/cli-options.md b/website/docs/reference/cli-options.md index 49cb72c721..9f99ca7db7 100644 --- a/website/docs/reference/cli-options.md +++ b/website/docs/reference/cli-options.md @@ -1561,6 +1561,20 @@ Aliases: `--execute-md` [Internal] A synonym to --markdown-snippet, which defaults the sub-command to `run` when no sub-command is passed explicitly +## Source generator options + +Available in commands: + +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) + + + +### `--use-build-info` + +Aliases: `--build-info` + +Generate BuildInfo for project + ## Suppress warning options Available in commands: diff --git a/website/docs/reference/commands.md b/website/docs/reference/commands.md index d7685ea039..a8e076b23b 100644 --- a/website/docs/reference/commands.md +++ b/website/docs/reference/commands.md @@ -32,7 +32,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/compile -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [compile](./cli-options.md#compile-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [compile](./cli-options.md#compile-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## config @@ -78,7 +78,7 @@ Accepts option groups: [config](./cli-options.md#config-options), [coursier](./c Update dependency directives in the project -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [dependency update](./cli-options.md#dependency-update-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [dependency update](./cli-options.md#dependency-update-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) ## doc @@ -92,7 +92,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/doc -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [doc](./cli-options.md#doc-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [doc](./cli-options.md#doc-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) ## export @@ -114,7 +114,7 @@ The `export` sub-command is experimental. Please bear in mind that non-ideal user experience should be expected. If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team at https://github.com/VirtusLab/scala-cli -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [export](./cli-options.md#export-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [export](./cli-options.md#export-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) ## fmt @@ -131,7 +131,7 @@ All standard Scala CLI inputs are accepted, but only Scala sources will be forma For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/fmt -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fmt](./cli-options.md#fmt-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fmt](./cli-options.md#fmt-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) ## help @@ -183,7 +183,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/repl -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [repl](./cli-options.md#repl-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [repl](./cli-options.md#repl-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## package @@ -201,7 +201,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/package -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [package](./cli-options.md#package-options), [packager](./cli-options.md#packager-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [package](./cli-options.md#package-options), [packager](./cli-options.md#packager-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## publish @@ -228,7 +228,7 @@ The `publish` sub-command is experimental. Please bear in mind that non-ideal user experience should be expected. If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team at https://github.com/VirtusLab/scala-cli -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [publish](./cli-options.md#publish-options), [publish params](./cli-options.md#publish-params-options), [publish repository](./cli-options.md#publish-repository-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [publish](./cli-options.md#publish-options), [publish params](./cli-options.md#publish-params-options), [publish repository](./cli-options.md#publish-repository-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## publish local @@ -240,7 +240,7 @@ The `publish-local` sub-command is experimental. Please bear in mind that non-ideal user experience should be expected. If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team at https://github.com/VirtusLab/scala-cli -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [publish](./cli-options.md#publish-options), [publish params](./cli-options.md#publish-params-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [publish](./cli-options.md#publish-options), [publish params](./cli-options.md#publish-params-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## publish setup @@ -278,7 +278,7 @@ To pass arguments to the actual application, just add them after `--`, like: For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/run -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## github secret create @@ -325,7 +325,7 @@ Using directives can be defined in all supported input source file types. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/setup-ide -Accepts option groups: [bsp file](./cli-options.md#bsp-file-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [setup IDE](./cli-options.md#setup-ide-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [bsp file](./cli-options.md#bsp-file-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [setup IDE](./cli-options.md#setup-ide-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) ## shebang @@ -356,7 +356,7 @@ Using this, it is possible to conveniently set up Unix shebang scripts. For exam For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/shebang -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## test @@ -380,7 +380,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/test -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [test](./cli-options.md#test-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [test](./cli-options.md#test-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## uninstall @@ -483,7 +483,7 @@ It is normally supposed to be invoked by your IDE when a Scala CLI project is im Detailed documentation can be found on our website: https://scala-cli.virtuslab.org -Accepts option groups: [bsp](./cli-options.md#bsp-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [bsp](./cli-options.md#bsp-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) ### default-file diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index 32c87b39ec..1cf7bd1650 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -5,6 +5,15 @@ sidebar_position: 2 ## using directives +### BuildInfo + +Generate BuildInfo for project + +`//> using buildInfo + +#### Examples +`//> using buildInfo` + ### Compiler options Add Scala compiler options diff --git a/website/docs/reference/scala-command/commands.md b/website/docs/reference/scala-command/commands.md index 7db9415678..b9170a54e9 100644 --- a/website/docs/reference/scala-command/commands.md +++ b/website/docs/reference/scala-command/commands.md @@ -31,7 +31,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/compile -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [compile](./cli-options.md#compile-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [compile](./cli-options.md#compile-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ### config @@ -85,7 +85,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/doc -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [doc](./cli-options.md#doc-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [doc](./cli-options.md#doc-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) ### repl @@ -107,7 +107,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/repl -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [repl](./cli-options.md#repl-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [repl](./cli-options.md#repl-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ### run @@ -133,7 +133,7 @@ To pass arguments to the actual application, just add them after `--`, like: For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/run -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ### shebang @@ -164,7 +164,7 @@ Using this, it is possible to conveniently set up Unix shebang scripts. For exam For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/shebang -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## SHOULD have commands: @@ -183,7 +183,7 @@ All standard Scala CLI inputs are accepted, but only Scala sources will be forma For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/fmt -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fmt](./cli-options.md#fmt-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fmt](./cli-options.md#fmt-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) ### test @@ -207,7 +207,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/test -Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [test](./cli-options.md#test-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [test](./cli-options.md#test-options), [verbosity](./cli-options.md#verbosity-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ### version @@ -239,7 +239,7 @@ It is normally supposed to be invoked by your IDE when a Scala CLI project is im Detailed documentation can be found on our website: https://scala-cli.virtuslab.org -Accepts option groups: [bsp](./cli-options.md#bsp-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [bsp](./cli-options.md#bsp-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) ### clean @@ -291,7 +291,7 @@ Using directives can be defined in all supported input source file types. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/setup-ide -Accepts option groups: [bsp file](./cli-options.md#bsp-file-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [setup IDE](./cli-options.md#setup-ide-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [bsp file](./cli-options.md#bsp-file-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [setup IDE](./cli-options.md#setup-ide-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [workspace](./cli-options.md#workspace-options) ### uninstall