From 7981691d604690631c2d17778f897bb4ddb0b0bb Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Wed, 19 Apr 2023 14:46:26 +0200 Subject: [PATCH 1/8] Support declaring test dependencies from the main scope --- .../main/scala/scala/build/CrossSources.scala | 32 +++-- .../preprocessing/DataPreprocessor.scala | 33 +++-- .../build/preprocessing/JarPreprocessor.scala | 14 +- .../preprocessing/JavaPreprocessor.scala | 36 +++-- .../preprocessing/MarkdownPreprocessor.scala | 3 +- .../preprocessing/PreprocessedSource.scala | 6 +- .../preprocessing/PreprocessingUtil.scala | 32 ++++- .../preprocessing/ScalaPreprocessor.scala | 133 +++++++++++++----- .../preprocessing/ScriptPreprocessor.scala | 25 ++-- .../scala/build/tests/DirectiveTests.scala | 33 ++++- .../scala/scala/build/tests/TestInputs.scala | 13 +- .../build/directives/HasBuildOptions.scala | 3 +- .../HasBuildOptionsWithRequirements.scala | 9 ++ .../preprocessing/directives/Dependency.scala | 51 +++++-- .../scala/cli/doc/GenerateReferenceDoc.scala | 18 ++- .../cli/integration/RunTestDefinitions.scala | 43 ++++++ .../scala/build/options/BuildOptions.scala | 11 ++ .../build/options/BuildRequirements.scala | 1 + website/docs/reference/directives.md | 6 +- .../reference/scala-command/directives.md | 6 +- 20 files changed, 382 insertions(+), 126 deletions(-) create mode 100644 modules/directives/src/main/scala/scala/build/directives/HasBuildOptionsWithRequirements.scala diff --git a/modules/build/src/main/scala/scala/build/CrossSources.scala b/modules/build/src/main/scala/scala/build/CrossSources.scala index 24eca705fd..828d68d129 100644 --- a/modules/build/src/main/scala/scala/build/CrossSources.scala +++ b/modules/build/src/main/scala/scala/build/CrossSources.scala @@ -155,17 +155,19 @@ object CrossSources { .left.map(CompositeBuildException(_)) .map(_.flatten) - val preprocessedInputFromArgs = value(preprocessSources(inputs.flattened())) + val preprocessedInputFromArgs: Seq[PreprocessedSource] = + value(preprocessSources(inputs.flattened())) val sourcesFromDirectives = preprocessedInputFromArgs .flatMap(_.options) .flatMap(_.internal.extraSourceFiles) .distinct - val inputsElemFromDirectives = + val inputsElemFromDirectives: Seq[SingleFile] = value(resolveInputsFromSources(sourcesFromDirectives, inputs.enableMarkdown)) - val preprocessedSourcesFromDirectives = value(preprocessSources(inputsElemFromDirectives)) - val allInputs = inputs.add(inputsElemFromDirectives) + val preprocessedSourcesFromDirectives: Seq[PreprocessedSource] = + value(preprocessSources(inputsElemFromDirectives)) + val allInputs = inputs.add(inputsElemFromDirectives) val preprocessedSources = (preprocessedInputFromArgs ++ preprocessedSourcesFromDirectives).distinct @@ -190,19 +192,19 @@ object CrossSources { else fromDirectives } - val buildOptions = for { - s <- preprocessedSources - opt <- s.options.toSeq - if opt != BuildOptions() + val buildOptions: Seq[WithBuildRequirements[BuildOptions]] = (for { + preprocessedSource <- preprocessedSources + opts <- preprocessedSource.options.toSeq + if opts != BuildOptions() } yield { - val baseReqs0 = baseReqs(s.scopePath) - WithBuildRequirements( - s.requirements.fold(baseReqs0)(_ orElse baseReqs0), - opt + val baseReqs0 = baseReqs(preprocessedSource.scopePath) + preprocessedSource.optionsWithTargetRequirements :+ WithBuildRequirements( + preprocessedSource.requirements.fold(baseReqs0)(_ orElse baseReqs0), + opts ) - } + }).flatten - val defaultMainClassOpt = for { + val defaultMainClassOpt: Option[String] = for { mainClassPath <- allInputs.defaultMainClassElement .map(s => ScopePath.fromPath(s.path).subPath) processedMainClass <- preprocessedSources.find(_.scopePath.subPath == mainClassPath) @@ -230,7 +232,7 @@ object CrossSources { ) -> m.directivesPositions } - val resourceDirs = allInputs.elements.collect { + val resourceDirs: Seq[WithBuildRequirements[os.Path]] = allInputs.elements.collect { case r: ResourceDirectory => WithBuildRequirements(BuildRequirements(), r.path) } ++ preprocessedSources.flatMap(_.options).flatMap(_.classPathOptions.resourcesDir).map( diff --git a/modules/build/src/main/scala/scala/build/preprocessing/DataPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/DataPreprocessor.scala index b8e9f1f4c1..72e12331a9 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/DataPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/DataPreprocessor.scala @@ -6,7 +6,13 @@ import scala.build.EitherCps.{either, value} import scala.build.Logger import scala.build.errors.BuildException import scala.build.input.{Inputs, SingleElement, VirtualData} -import scala.build.options.{BuildRequirements, SuppressWarningOptions} +import scala.build.options.{ + BuildOptions, + BuildRequirements, + SuppressWarningOptions, + WithBuildRequirements +} +import scala.build.preprocessing.DirectivesProcessor.DirectivesProcessorOutput import scala.build.preprocessing.PreprocessingUtil.optionsAndPositionsFromDirectives case object DataPreprocessor extends Preprocessor { @@ -21,7 +27,11 @@ case object DataPreprocessor extends Preprocessor { case file: VirtualData => val res = either { val content = new String(file.content, StandardCharsets.UTF_8) - val (updatedOptions, directivesPositions) = value { + val ( + updatedOptions: BuildOptions, + optsWithReqs: List[WithBuildRequirements[BuildOptions]], + directivesPositions: Option[DirectivesPositions] + ) = value { optionsAndPositionsFromDirectives( content, file.scopePath, @@ -35,15 +45,16 @@ case object DataPreprocessor extends Preprocessor { val inMemory = Seq( PreprocessedSource.InMemory( - Left(file.source), - file.subPath, - content, - 0, - Some(updatedOptions.global), - Some(BuildRequirements()), - Nil, - None, - file.scopePath, + originalPath = Left(file.source), + relPath = file.subPath, + code = content, + ignoreLen = 0, + options = Some(updatedOptions), + optionsWithTargetRequirements = optsWithReqs, + requirements = Some(BuildRequirements()), + scopedRequirements = Nil, + mainClassOpt = None, + scopePath = file.scopePath, directivesPositions ) ) diff --git a/modules/build/src/main/scala/scala/build/preprocessing/JarPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/JarPreprocessor.scala index 00df92e72e..83098b23b0 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/JarPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/JarPreprocessor.scala @@ -12,7 +12,6 @@ import scala.build.options.{ ClassPathOptions, SuppressWarningOptions } -import scala.build.preprocessing.PreprocessingUtil.optionsAndPositionsFromDirectives case object JarPreprocessor extends Preprocessor { def preprocess( @@ -30,12 +29,13 @@ case object JarPreprocessor extends Preprocessor { ) ) Seq(PreprocessedSource.OnDisk( - jar.path, - Some(buildOptions), - Some(BuildRequirements()), - Nil, - None, - None + path = jar.path, + options = Some(buildOptions), + optionsWithTargetRequirements = List.empty, + requirements = Some(BuildRequirements()), + scopedRequirements = Nil, + mainClassOpt = None, + directivesPositions = None )) }) case _ => diff --git a/modules/build/src/main/scala/scala/build/preprocessing/JavaPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/JavaPreprocessor.scala index 42360d7fa9..f83abd40b8 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/JavaPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/JavaPreprocessor.scala @@ -11,7 +11,13 @@ import scala.build.Logger import scala.build.errors.BuildException import scala.build.input.{Inputs, JavaFile, SingleElement, VirtualJavaFile} import scala.build.internal.JavaParserProxyMaker -import scala.build.options.{BuildRequirements, SuppressWarningOptions} +import scala.build.options.{ + BuildOptions, + BuildRequirements, + SuppressWarningOptions, + WithBuildRequirements +} +import scala.build.preprocessing.DirectivesProcessor.DirectivesProcessorOutput import scala.build.preprocessing.ExtractedDirectives.from import scala.build.preprocessing.PreprocessingUtil.optionsAndPositionsFromDirectives import scala.build.preprocessing.ScalaPreprocessor.* @@ -44,7 +50,11 @@ final case class JavaPreprocessor( case j: JavaFile => Some(either { val content = value(PreprocessingUtil.maybeRead(j.path)) val scopePath = ScopePath.fromPath(j.path) - val (updatedOptions, directivesPositions) = value { + val ( + updatedOptions: BuildOptions, + optsWithReqs: List[WithBuildRequirements[BuildOptions]], + directivesPositions: Option[DirectivesPositions] + ) = value { optionsAndPositionsFromDirectives( content, scopePath, @@ -56,12 +66,13 @@ final case class JavaPreprocessor( ) } Seq(PreprocessedSource.OnDisk( - j.path, - Some(updatedOptions.global), - Some(BuildRequirements()), - Nil, - None, - directivesPositions + path = j.path, + options = Some(updatedOptions), + optionsWithTargetRequirements = optsWithReqs, + requirements = Some(BuildRequirements()), + scopedRequirements = Nil, + mainClassOpt = None, + directivesPositions = directivesPositions )) }) case v: VirtualJavaFile => @@ -85,7 +96,11 @@ final case class JavaPreprocessor( } else v.subPath val content = new String(v.content, StandardCharsets.UTF_8) - val (updatedOptions, directivesPositions) = value { + val ( + updatedOptions: BuildOptions, + optsWithReqs: List[WithBuildRequirements[BuildOptions]], + directivesPositions: Option[DirectivesPositions] + ) = value { optionsAndPositionsFromDirectives( content, v.scopePath, @@ -101,7 +116,8 @@ final case class JavaPreprocessor( relPath = relPath, code = content, ignoreLen = 0, - options = Some(updatedOptions.global), + options = Some(updatedOptions), + optionsWithTargetRequirements = optsWithReqs, requirements = Some(BuildRequirements()), scopedRequirements = Nil, mainClassOpt = None, diff --git a/modules/build/src/main/scala/scala/build/preprocessing/MarkdownPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/MarkdownPreprocessor.scala index 24660f5fa0..05547b4624 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/MarkdownPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/MarkdownPreprocessor.scala @@ -88,7 +88,7 @@ case object MarkdownPreprocessor extends Preprocessor { allowRestrictedFeatures = allowRestrictedFeatures, suppressWarningOptions = suppressWarningOptions ) - }.getOrElse(ProcessingOutput(BuildRequirements(), Nil, BuildOptions(), None, None)) + }.getOrElse(ProcessingOutput.empty) val processedCode = processingOutput.updatedContent.getOrElse(wrappedMarkdown.code) PreprocessedSource.InMemory( originalPath = reportingPath.map(subPath -> _), @@ -96,6 +96,7 @@ case object MarkdownPreprocessor extends Preprocessor { processedCode, ignoreLen = 0, options = Some(processingOutput.opts), + optionsWithTargetRequirements = processingOutput.optsWithReqs, requirements = Some(processingOutput.globalReqs), processingOutput.scopedReqs, mainClassOpt = None, diff --git a/modules/build/src/main/scala/scala/build/preprocessing/PreprocessedSource.scala b/modules/build/src/main/scala/scala/build/preprocessing/PreprocessedSource.scala index 97daf650f0..b2d6c86554 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/PreprocessedSource.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/PreprocessedSource.scala @@ -1,9 +1,10 @@ package scala.build.preprocessing -import scala.build.options.{BuildOptions, BuildRequirements} +import scala.build.options.{BuildOptions, BuildRequirements, WithBuildRequirements} sealed abstract class PreprocessedSource extends Product with Serializable { def options: Option[BuildOptions] + def optionsWithTargetRequirements: List[WithBuildRequirements[BuildOptions]] def requirements: Option[BuildRequirements] def mainClassOpt: Option[String] @@ -17,6 +18,7 @@ object PreprocessedSource { final case class OnDisk( path: os.Path, options: Option[BuildOptions], + optionsWithTargetRequirements: List[WithBuildRequirements[BuildOptions]], requirements: Option[BuildRequirements], scopedRequirements: Seq[Scoped[BuildRequirements]], mainClassOpt: Option[String], @@ -31,6 +33,7 @@ object PreprocessedSource { code: String, ignoreLen: Int, options: Option[BuildOptions], + optionsWithTargetRequirements: List[WithBuildRequirements[BuildOptions]], requirements: Option[BuildRequirements], scopedRequirements: Seq[Scoped[BuildRequirements]], mainClassOpt: Option[String], @@ -42,6 +45,7 @@ object PreprocessedSource { } final case class NoSourceCode( options: Option[BuildOptions], + optionsWithTargetRequirements: List[WithBuildRequirements[BuildOptions]], requirements: Option[BuildRequirements], scopedRequirements: Seq[Scoped[BuildRequirements]], path: os.Path diff --git a/modules/build/src/main/scala/scala/build/preprocessing/PreprocessingUtil.scala b/modules/build/src/main/scala/scala/build/preprocessing/PreprocessingUtil.scala index 8de9a8c986..6f3de0a056 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/PreprocessingUtil.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/PreprocessingUtil.scala @@ -7,7 +7,7 @@ import java.nio.charset.StandardCharsets import scala.build.EitherCps.{either, value} import scala.build.Logger import scala.build.errors.{BuildException, FileNotFoundException} -import scala.build.options.{BuildOptions, SuppressWarningOptions} +import scala.build.options.{BuildOptions, SuppressWarningOptions, WithBuildRequirements} import scala.build.preprocessing.DirectivesProcessor.DirectivesProcessorOutput import scala.build.preprocessing.ExtractedDirectives.from import scala.build.preprocessing.ScalaPreprocessor.* @@ -30,7 +30,11 @@ object PreprocessingUtil { suppressWarningOptions: SuppressWarningOptions ): Either[ BuildException, - (DirectivesProcessorOutput[BuildOptions], Option[DirectivesPositions]) + ( + BuildOptions, + List[WithBuildRequirements[BuildOptions]], + Option[DirectivesPositions] + ) ] = either { val ExtractedDirectives(directives0, directivesPositions) = value(from( @@ -40,7 +44,7 @@ object PreprocessingUtil { scopePath, maybeRecoverOnError )) - val updatedOptions = value(DirectivesProcessor.process( + val updatedOptions: DirectivesProcessorOutput[BuildOptions] = value(DirectivesProcessor.process( directives0, usingDirectiveHandlers, path, @@ -49,6 +53,26 @@ object PreprocessingUtil { allowRestrictedFeatures, suppressWarningOptions )) - (updatedOptions, directivesPositions) + + val directives1 = updatedOptions.unused + val optionsWithReqs: DirectivesProcessorOutput[List[WithBuildRequirements[BuildOptions]]] = + value(DirectivesProcessor.process( + directives1, + usingDirectiveWithReqsHandlers, + path, + scopePath, + logger, + allowRestrictedFeatures, + suppressWarningOptions + )) + + val (optionsWithActualRequirements, optionsWithEmptyRequirements) = + optionsWithReqs.global.partition(_.requirements.nonEmpty) + val summedOptionsWithNoRequirements = + optionsWithEmptyRequirements + .map(_.value) + .foldLeft(updatedOptions.global)((acc, bo) => acc.orElse(bo)) + + (summedOptionsWithNoRequirements, optionsWithActualRequirements, directivesPositions) } } diff --git a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala index e3c205c314..01ae4da3e8 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala @@ -8,17 +8,16 @@ import java.nio.charset.StandardCharsets import scala.build.EitherCps.{either, value} import scala.build.Ops.* -import scala.build.directives.{HasBuildOptions, HasBuildRequirements} +import scala.build.directives.{ + HasBuildOptions, + HasBuildOptionsWithRequirements, + HasBuildRequirements +} import scala.build.errors.* import scala.build.input.{Inputs, ScalaFile, SingleElement, VirtualScalaFile} import scala.build.internal.Util -import scala.build.options.{ - BuildOptions, - BuildRequirements, - ClassPathOptions, - ShadowingSeq, - SuppressWarningOptions -} +import scala.build.options.* +import scala.build.preprocessing.DirectivesProcessor.DirectivesProcessorOutput import scala.build.preprocessing.directives import scala.build.preprocessing.directives.{DirectiveHandler, DirectiveUtil, ScopedDirective} import scala.build.{Logger, Position, Positioned} @@ -28,6 +27,7 @@ case object ScalaPreprocessor extends Preprocessor { private case class StrictDirectivesProcessingOutput( globalReqs: BuildRequirements, globalUsings: BuildOptions, + usingsWithReqs: List[WithBuildRequirements[BuildOptions]], scopedReqs: Seq[Scoped[BuildRequirements]], strippedContent: Option[String], directivesPositions: Option[DirectivesPositions] @@ -48,14 +48,25 @@ case object ScalaPreprocessor extends Preprocessor { globalReqs: BuildRequirements, scopedReqs: Seq[Scoped[BuildRequirements]], opts: BuildOptions, + optsWithReqs: List[WithBuildRequirements[BuildOptions]], updatedContent: Option[String], directivesPositions: Option[DirectivesPositions] ) + object ProcessingOutput { + def empty: ProcessingOutput = ProcessingOutput( + BuildRequirements(), + Nil, + BuildOptions(), + List.empty, + None, + None + ) + } + val usingDirectiveHandlers: Seq[DirectiveHandler[BuildOptions]] = Seq[DirectiveHandler[_ <: HasBuildOptions]]( directives.CustomJar.handler, - directives.Dependency.handler, directives.JavacOptions.handler, directives.JavaOptions.handler, directives.JavaProps.handler, @@ -80,6 +91,12 @@ case object ScalaPreprocessor extends Preprocessor { directives.Toolkit.handler ).map(_.mapE(_.buildOptions)) + val usingDirectiveWithReqsHandlers + : Seq[DirectiveHandler[List[WithBuildRequirements[BuildOptions]]]] = + Seq[DirectiveHandler[_ <: HasBuildOptionsWithRequirements]]( + directives.Dependency.handler + ).map(_.mapE(_.buildOptionsWithRequirements)) + val requireDirectiveHandlers: Seq[DirectiveHandler[BuildRequirements]] = Seq[DirectiveHandler[_ <: HasBuildRequirements]]( directives.RequirePlatform.handler, @@ -113,40 +130,44 @@ case object ScalaPreprocessor extends Preprocessor { ) ) match { case None => - PreprocessedSource.OnDisk(f.path, None, None, Nil, None, None) + PreprocessedSource.OnDisk(f.path, None, List.empty, None, Nil, None, None) case Some(ProcessingOutput( requirements, scopedRequirements, options, + optionsWithReqs, Some(updatedCode), directivesPositions )) => PreprocessedSource.InMemory( - Right((f.subPath, f.path)), - f.subPath, - updatedCode, - 0, - Some(options), - Some(requirements), - scopedRequirements, - None, - scopePath, - directivesPositions + originalPath = Right((f.subPath, f.path)), + relPath = f.subPath, + code = updatedCode, + ignoreLen = 0, + options = Some(options), + optionsWithTargetRequirements = optionsWithReqs, + requirements = Some(requirements), + scopedRequirements = scopedRequirements, + mainClassOpt = None, + scopePath = scopePath, + directivesPositions = directivesPositions ) case Some(ProcessingOutput( requirements, scopedRequirements, options, + optionsWithReqs, None, directivesPositions )) => PreprocessedSource.OnDisk( - f.path, - Some(options), - Some(requirements), - scopedRequirements, - None, - directivesPositions + path = f.path, + options = Some(options), + optionsWithTargetRequirements = optionsWithReqs, + requirements = Some(requirements), + scopedRequirements = scopedRequirements, + mainClassOpt = None, + directivesPositions = directivesPositions ) } Seq(source) @@ -160,7 +181,14 @@ case object ScalaPreprocessor extends Preprocessor { case v => os.sub / v.generatedSourceFileName } val content = new String(v.content, StandardCharsets.UTF_8) - val (requirements, scopedRequirements, options, updatedContentOpt, directivesPositions) = + val ( + requirements: BuildRequirements, + scopedRequirements: Seq[Scoped[BuildRequirements]], + options: BuildOptions, + optionsWithTargetRequirements: List[WithBuildRequirements[BuildOptions]], + updatedContentOpt: Option[String], + directivesPositions: Option[DirectivesPositions] + ) = value( process( content, @@ -172,15 +200,30 @@ case object ScalaPreprocessor extends Preprocessor { suppressWarningOptions ) ).map { - case ProcessingOutput(reqs, scopedReqs, opts, updatedContent, dirsPositions) => - (reqs, scopedReqs, opts, updatedContent, dirsPositions) - }.getOrElse((BuildRequirements(), Nil, BuildOptions(), None, None)) + case ProcessingOutput( + reqs, + scopedReqs, + opts, + optsWithReqs, + updatedContent, + dirsPositions + ) => + (reqs, scopedReqs, opts, optsWithReqs, updatedContent, dirsPositions) + }.getOrElse(( + BuildRequirements(), + Nil, + BuildOptions(), + List(WithBuildRequirements(BuildRequirements(), BuildOptions())), + None, + None + )) val s = PreprocessedSource.InMemory( originalPath = Left(v.source), relPath = relPath, updatedContentOpt.getOrElse(content), ignoreLen = 0, options = Some(options), + optionsWithTargetRequirements = optionsWithTargetRequirements, requirements = Some(requirements), scopedRequirements, mainClassOpt = None, @@ -259,6 +302,7 @@ case object ScalaPreprocessor extends Preprocessor { summedRequirements, scopedRequirements, summedOptions, + afterStrictUsing.usingsWithReqs, lastContentOpt, directivesPositions )) @@ -278,7 +322,7 @@ case object ScalaPreprocessor extends Preprocessor { val ExtractedDirectives(directives0, directivesPositions) = extractedDirectives - val updatedOptions = value { + val updatedOptions: DirectivesProcessorOutput[BuildOptions] = value { DirectivesProcessor.process( directives0, usingDirectiveHandlers, @@ -292,9 +336,24 @@ case object ScalaPreprocessor extends Preprocessor { val directives1 = updatedOptions.unused - val updatedRequirements = value { + val optionsWithTargetRequirements + : DirectivesProcessorOutput[List[WithBuildRequirements[BuildOptions]]] = value { DirectivesProcessor.process( directives1, + usingDirectiveWithReqsHandlers, + path, + cwd, + logger, + allowRestrictedFeatures, + suppressWarningOptions + ) + } + + val directives2 = optionsWithTargetRequirements.unused + + val updatedRequirements = value { + DirectivesProcessor.process( + directives2, requireDirectiveHandlers, path, cwd, @@ -306,12 +365,20 @@ case object ScalaPreprocessor extends Preprocessor { val unusedDirectives = updatedRequirements.unused + val (optionsWithActualRequirements, optionsWithEmptyRequirements) = + optionsWithTargetRequirements.global.partition(_.requirements.nonEmpty) + val summedOptionsWithNoRequirements = + optionsWithEmptyRequirements + .map(_.value) + .foldLeft(updatedOptions.global)((acc, bo) => acc.orElse(bo)) + value { unusedDirectives match { case Seq() => Right(StrictDirectivesProcessingOutput( updatedRequirements.global, - updatedOptions.global, + summedOptionsWithNoRequirements, + optionsWithActualRequirements, updatedRequirements.scoped, strippedContent = None, directivesPositions diff --git a/modules/build/src/main/scala/scala/build/preprocessing/ScriptPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/ScriptPreprocessor.scala index 414593dc4c..c725d8d110 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/ScriptPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/ScriptPreprocessor.scala @@ -86,7 +86,7 @@ object ScriptPreprocessor { val (pkg, wrapper) = AmmUtil.pathToPackageWrapper(subPath) - val processingOutput = + val processingOutput: ProcessingOutput = value(ScalaPreprocessor.process( contentIgnoredSheBangLines, reportingPath, @@ -96,7 +96,7 @@ object ScriptPreprocessor { allowRestrictedFeatures, suppressWarningOptions )) - .getOrElse(ProcessingOutput(BuildRequirements(), Nil, BuildOptions(), None, None)) + .getOrElse(ProcessingOutput.empty) val (code, topWrapperLen, _) = codeWrapper.wrapCode( pkg, @@ -109,16 +109,17 @@ object ScriptPreprocessor { val relPath = os.rel / (subPath / os.up) / s"${subPath.last.stripSuffix(".sc")}.scala" val file = PreprocessedSource.InMemory( - reportingPath.map((subPath, _)), - relPath, - code, - topWrapperLen, - Some(processingOutput.opts), - Some(processingOutput.globalReqs), - processingOutput.scopedReqs, - Some(CustomCodeWrapper.mainClassObject(Name(className)).backticked), - scopePath, - processingOutput.directivesPositions + originalPath = reportingPath.map((subPath, _)), + relPath = relPath, + code = code, + ignoreLen = topWrapperLen, + options = Some(processingOutput.opts), + optionsWithTargetRequirements = processingOutput.optsWithReqs, + requirements = Some(processingOutput.globalReqs), + scopedRequirements = processingOutput.scopedReqs, + mainClassOpt = Some(CustomCodeWrapper.mainClassObject(Name(className)).backticked), + scopePath = scopePath, + directivesPositions = processingOutput.directivesPositions ) List(file) } diff --git a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala index 71ea817f3f..315340487d 100644 --- a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala @@ -4,7 +4,7 @@ import com.eed3si9n.expecty.Expecty.expect import java.io.IOException import scala.build.{BuildThreads, Directories, LocalRepo, Position, Positioned} -import scala.build.options.{BuildOptions, InternalOptions, MaybeScalaVersion, ScalacOpt} +import scala.build.options.{BuildOptions, InternalOptions, MaybeScalaVersion, ScalacOpt, Scope} import scala.build.tests.util.BloopServer import build.Ops.EitherThrowOps import scala.build.Position @@ -106,6 +106,37 @@ class DirectiveTests extends munit.FunSuite { expect(toolkitDep.version == "latest.release") } } + for (scope <- Scope.all) + test(s"resolve test scope directives correctly when building for ${scope.name} scope") { + val inputs = TestInputs( + os.rel / "project.scala" -> + """//> using dep "com.lihaoyi::os-lib:0.9.1" + |//> using test.dep "org.scalameta::munit::0.7.29" + |""".stripMargin, + os.rel / "Tests.test.scala" -> + """class Tests extends munit.FunSuite { + | test("foo") { + | println("foo") + | } + |} + |""".stripMargin + ) + inputs.withBuild(baseOptions, buildThreads, bloopConfigOpt, scope = scope) { + (_, _, maybeBuild) => + val isTestScope = scope == Scope.Test + val build = maybeBuild.orThrow + val deps = build.options.classPathOptions.extraDependencies.toSeq.map(_.value) + expect(deps.nonEmpty) + val hasMainDeps = deps.exists(d => + d.organization == "com.lihaoyi" && d.name == "os-lib" && d.version == "0.9.1" + ) + val hasTestDeps = deps.exists(d => + d.organization == "org.scalameta" && d.name == "munit" && d.version == "0.7.29" + ) + expect(hasMainDeps) + expect(if isTestScope then hasTestDeps else !hasTestDeps) + } + } test("handling special syntax for path") { val filePath = os.rel / "src" / "simple.scala" diff --git a/modules/build/src/test/scala/scala/build/tests/TestInputs.scala b/modules/build/src/test/scala/scala/build/tests/TestInputs.scala index 36eb4184ff..40456993ec 100644 --- a/modules/build/src/test/scala/scala/build/tests/TestInputs.scala +++ b/modules/build/src/test/scala/scala/build/tests/TestInputs.scala @@ -3,13 +3,12 @@ package scala.build.tests import bloop.rifle.BloopRifleConfig import java.nio.charset.StandardCharsets - import scala.build.{Build, BuildThreads, Directories} import scala.build.compiler.{BloopCompilerMaker, SimpleScalaCompilerMaker} import scala.build.errors.BuildException import scala.build.input.{Inputs, ScalaCliInvokeData, SubCommand} import scala.build.internal.Util -import scala.build.options.BuildOptions +import scala.build.options.{BuildOptions, Scope} import scala.util.control.NonFatal import scala.util.Try @@ -73,7 +72,8 @@ final case class TestInputs( bloopConfigOpt: Option[BloopRifleConfig], fromDirectory: Boolean = false, buildTests: Boolean = true, - actionableDiagnostics: Boolean = false + actionableDiagnostics: Boolean = false, + scope: Scope = Scope.Main )(f: (os.Path, Inputs, Either[BuildException, Build]) => T): T = withCustomInputs(fromDirectory, None) { (root, inputs) => val compilerMaker = bloopConfigOpt match { @@ -82,7 +82,7 @@ final case class TestInputs( case None => SimpleScalaCompilerMaker("java", Nil) } - val res = + val builds = Build.build( inputs, options, @@ -94,7 +94,10 @@ final case class TestInputs( partial = None, actionableDiagnostics = Some(actionableDiagnostics) ) - f(root, inputs, res.map(_.main)) + val res = builds.map(_.get(scope).getOrElse { + sys.error(s"No ${scope.name} build found") + }) + f(root, inputs, res) } } diff --git a/modules/directives/src/main/scala/scala/build/directives/HasBuildOptions.scala b/modules/directives/src/main/scala/scala/build/directives/HasBuildOptions.scala index a9863626e3..c0c5c81cb1 100644 --- a/modules/directives/src/main/scala/scala/build/directives/HasBuildOptions.scala +++ b/modules/directives/src/main/scala/scala/build/directives/HasBuildOptions.scala @@ -1,9 +1,10 @@ package scala.build.directives import scala.build.errors.BuildException -import scala.build.options.BuildOptions +import scala.build.options.{BuildOptions, HasScope} import scala.build.preprocessing.ScopePath trait HasBuildOptions { def buildOptions: Either[BuildException, BuildOptions] + HasScope } diff --git a/modules/directives/src/main/scala/scala/build/directives/HasBuildOptionsWithRequirements.scala b/modules/directives/src/main/scala/scala/build/directives/HasBuildOptionsWithRequirements.scala new file mode 100644 index 0000000000..b36351d98f --- /dev/null +++ b/modules/directives/src/main/scala/scala/build/directives/HasBuildOptionsWithRequirements.scala @@ -0,0 +1,9 @@ +package scala.build.directives + +import scala.build.errors.BuildException +import scala.build.options.{BuildOptions, WithBuildRequirements} + +trait HasBuildOptionsWithRequirements { + def buildOptionsWithRequirements + : Either[BuildException, List[WithBuildRequirements[BuildOptions]]] +} diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Dependency.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Dependency.scala index e4faa0f284..ec147cdec7 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Dependency.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Dependency.scala @@ -1,18 +1,26 @@ package scala.build.preprocessing.directives + import dependency.AnyDependency import dependency.parser.DependencyParser import scala.build.EitherCps.{either, value} -import scala.build.Ops._ +import scala.build.Ops.* import scala.build.directives.* import scala.build.errors.{BuildException, CompositeBuildException, DependencyFormatError} -import scala.build.options.{BuildOptions, ClassPathOptions, ShadowingSeq} +import scala.build.options.{ + BuildOptions, + ClassPathOptions, + Scope, + ShadowingSeq, + WithBuildRequirements +} import scala.build.preprocessing.ScopePath import scala.build.{Logger, Positioned} import scala.cli.commands.SpecificationLevel -@DirectiveExamples("//> using dep \"org.scalatest::scalatest:3.2.10\"") -@DirectiveExamples("//> using dep \"org.scalameta::munit:0.7.29\"") +@DirectiveExamples("//> using dep \"com.lihaoyi::os-lib:0.9.1\"") +@DirectiveExamples("//> using test.dep \"org.scalatest::scalatest:3.2.10\"") +@DirectiveExamples("//> using test.dep \"org.scalameta::munit:0.7.29\"") @DirectiveExamples( "//> using dep \"tabby:tabby:0.2.3,url=https://github.com/bjornregnell/tabby/releases/download/v0.2.3/tabby_3-0.2.3.jar\"" ) @@ -23,15 +31,34 @@ import scala.cli.commands.SpecificationLevel @DirectiveDescription("Add dependencies") @DirectiveLevel(SpecificationLevel.MUST) final case class Dependency( - @DirectiveName("lib") - @DirectiveName("libs") + @DirectiveName("lib") // backwards compat + @DirectiveName("libs") // backwards compat @DirectiveName("dep") @DirectiveName("deps") @DirectiveName("dependencies") - dependency: List[Positioned[String]] = Nil -) extends HasBuildOptions { - def buildOptions: Either[BuildException, BuildOptions] = either { - val maybeDependencies = dependency + dependency: List[Positioned[String]] = Nil, + @DirectiveName("test.dep") + @DirectiveName("test.deps") + @DirectiveName("test.dependencies") + testDependency: List[Positioned[String]] = Nil +) extends HasBuildOptionsWithRequirements { + def buildOptionsWithRequirements + : Either[BuildException, List[WithBuildRequirements[BuildOptions]]] = + for { + globalBuildOptions <- Dependency.buildOptions(dependency) + testBuildOptions <- Dependency.buildOptions(testDependency) + } yield List( + globalBuildOptions.withEmptyRequirements, + testBuildOptions.withScopeRequirement(Scope.Test) + ) + +} + +object Dependency { + val handler: DirectiveHandler[Dependency] = DirectiveHandler.derive + + def buildOptions(deps: List[Positioned[String]]): Either[BuildException, BuildOptions] = either { + val maybeDependencies = deps .map { posStr => posStr .map { str => @@ -50,7 +77,3 @@ final case class Dependency( ) } } - -object Dependency { - val handler: DirectiveHandler[Dependency] = DirectiveHandler.derive -} diff --git a/modules/generate-reference-doc/src/main/scala/scala/cli/doc/GenerateReferenceDoc.scala b/modules/generate-reference-doc/src/main/scala/scala/cli/doc/GenerateReferenceDoc.scala index e1303dd2a0..3550d1e709 100644 --- a/modules/generate-reference-doc/src/main/scala/scala/cli/doc/GenerateReferenceDoc.scala +++ b/modules/generate-reference-doc/src/main/scala/scala/cli/doc/GenerateReferenceDoc.scala @@ -11,7 +11,7 @@ import shapeless.tag import java.nio.charset.StandardCharsets import java.util -import scala.build.options.{BuildOptions, BuildRequirements} +import scala.build.options.{BuildOptions, BuildRequirements, WithBuildRequirements} import scala.build.preprocessing.ScalaPreprocessor import scala.build.preprocessing.directives.DirectiveHandler import scala.cli.commands.{ScalaCommand, SpecificationLevel, tags} @@ -391,7 +391,9 @@ object GenerateReferenceDoc extends CaseApp[InternalDocOptions] { } private def usingContent( - usingHandlers: Seq[DirectiveHandler[BuildOptions]], + allUsingHandlers: Seq[ + DirectiveHandler[BuildOptions | List[WithBuildRequirements[BuildOptions]]] + ], requireHandlers: Seq[DirectiveHandler[BuildRequirements]], onlyRestricted: Boolean ): String = { @@ -444,7 +446,7 @@ object GenerateReferenceDoc extends CaseApp[InternalDocOptions] { ) SpecificationLevel.inSpecification.foreach { level => - val handlers = usingHandlers.filter(_.scalaSpecificationLevel == level) + val handlers = allUsingHandlers.filter(_.scalaSpecificationLevel == level) if (handlers.nonEmpty) { b.section(s"## ${level.md.capitalize} directives:") addHandlers(handlers) @@ -452,7 +454,7 @@ object GenerateReferenceDoc extends CaseApp[InternalDocOptions] { } val implHandlers = - usingHandlers.filter(_.scalaSpecificationLevel == SpecificationLevel.IMPLEMENTATION) + allUsingHandlers.filter(_.scalaSpecificationLevel == SpecificationLevel.IMPLEMENTATION) if (implHandlers.nonEmpty) { b.section("## Implementation-specific directices") @@ -464,7 +466,7 @@ object GenerateReferenceDoc extends CaseApp[InternalDocOptions] { } } else { - addHandlers(usingHandlers) + addHandlers(allUsingHandlers) b.append( """ @@ -504,13 +506,15 @@ object GenerateReferenceDoc extends CaseApp[InternalDocOptions] { val scalaOptionsReference = optionsReference(restrictedCommands, nameFormatter) + val allUsingDirectiveHandlers = + ScalaPreprocessor.usingDirectiveHandlers ++ ScalaPreprocessor.usingDirectiveWithReqsHandlers val allDirectivesContent = usingContent( - ScalaPreprocessor.usingDirectiveHandlers, + allUsingDirectiveHandlers, ScalaPreprocessor.requireDirectiveHandlers, onlyRestricted = false ) val restrictedDirectivesContent = usingContent( - ScalaPreprocessor.usingDirectiveHandlers.filterNot(_.isRestricted), + allUsingDirectiveHandlers.filterNot(_.isRestricted), ScalaPreprocessor.requireDirectiveHandlers.filterNot(_.isRestricted), onlyRestricted = true ) 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 c8ee14194b..324cca877b 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala @@ -1210,4 +1210,47 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String]) } } } + + test("declare test scope dependencies from main scope") { + val projectFile = "project.scala" + val invalidMainFile = "InvalidMain.scala" + val validMainFile = "ValidMain.scala" + val testFile = "Tests.test.scala" + TestInputs( + os.rel / projectFile -> + """//> using dep "com.lihaoyi::os-lib:0.9.1" + |//> using test.dep "org.scalameta::munit::0.7.29" + |//> using test.dep "com.lihaoyi::pprint:0.8.1" + |""".stripMargin, + os.rel / invalidMainFile -> + """object InvalidMain extends App { + | pprint.pprintln("Hello") + |} + |""".stripMargin, + os.rel / validMainFile -> + """object ValidMain extends App { + | println(os.pwd) + |} + |""".stripMargin, + os.rel / testFile -> + """class Tests extends munit.FunSuite { + | test("foo") { + | pprint.pprintln(os.pwd) + | } + |} + |""".stripMargin + ).fromRoot { root => + // running `invalidMainFile` should fail, as it's in the main scope and depends on test scope deps + val res1 = os.proc(TestUtil.cli, "run", projectFile, invalidMainFile) + .call(cwd = root, check = false) + expect(res1.exitCode == 1) + // running `validMainFile` should succeed, since it only depends on main scope deps + val res2 = os.proc(TestUtil.cli, "run", projectFile, validMainFile) + .call(cwd = root) + expect(res2.out.trim() == root.toString()) + // test scope should have access to both main and test deps + os.proc(TestUtil.cli, "test", projectFile, testFile) + .call(cwd = root, stderr = os.Pipe) + } + } } 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 edc56ce887..0cb0a8ff1c 100644 --- a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala @@ -21,6 +21,7 @@ import scala.build.internal.Constants.* import scala.build.internal.CsLoggerUtil.* import scala.build.internal.Regexes.scala3NightlyNicknameRegex import scala.build.internal.{Constants, OsLibc, StableScalaVersion} +import scala.build.options.BuildRequirements.ScopeRequirement import scala.build.options.validation.BuildOptionsRule import scala.build.{Artifacts, Logger, Os, Position, Positioned} import scala.collection.immutable.Seq @@ -486,6 +487,16 @@ final case class BuildOptions( lazy val interactive: Either[BuildException, Interactive] = internal.interactive.map(_()).getOrElse(Right(InteractiveNop)) + + def withBuildRequirements(buildRequirements: BuildRequirements) + : WithBuildRequirements[BuildOptions] = + WithBuildRequirements(buildRequirements, this) + + def withEmptyRequirements: WithBuildRequirements[BuildOptions] = + withBuildRequirements(BuildRequirements()) + + def withScopeRequirement(scope: Scope): WithBuildRequirements[BuildOptions] = + withBuildRequirements(BuildRequirements(scope = Some(ScopeRequirement(scope = scope)))) } object BuildOptions { diff --git a/modules/options/src/main/scala/scala/build/options/BuildRequirements.scala b/modules/options/src/main/scala/scala/build/options/BuildRequirements.scala index ba4f6d992e..4cda3a544f 100644 --- a/modules/options/src/main/scala/scala/build/options/BuildRequirements.scala +++ b/modules/options/src/main/scala/scala/build/options/BuildRequirements.scala @@ -22,6 +22,7 @@ final case class BuildRequirements( } def isEmpty: Boolean = this == BuildRequirements() + def nonEmpty: Boolean = !isEmpty def orElse(other: BuildRequirements): BuildRequirements = BuildRequirements.monoid.orElse(this, other) } diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index f0f3917c7f..e7689592c4 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -56,9 +56,11 @@ Add dependencies `//> using dep "`_org_`:`name`:`ver" #### Examples -`//> using dep "org.scalatest::scalatest:3.2.10"` +`//> using dep "com.lihaoyi::os-lib:0.9.1"` -`//> using dep "org.scalameta::munit:0.7.29"` +`//> using test.dep "org.scalatest::scalatest:3.2.10"` + +`//> using test.dep "org.scalameta::munit:0.7.29"` `//> using dep "tabby:tabby:0.2.3,url=https://github.com/bjornregnell/tabby/releases/download/v0.2.3/tabby_3-0.2.3.jar"` diff --git a/website/docs/reference/scala-command/directives.md b/website/docs/reference/scala-command/directives.md index 02ac998bd6..103a18e0c7 100644 --- a/website/docs/reference/scala-command/directives.md +++ b/website/docs/reference/scala-command/directives.md @@ -40,9 +40,11 @@ Add dependencies `//> using dep "`_org_`:`name`:`ver" #### Examples -`//> using dep "org.scalatest::scalatest:3.2.10"` +`//> using dep "com.lihaoyi::os-lib:0.9.1"` -`//> using dep "org.scalameta::munit:0.7.29"` +`//> using test.dep "org.scalatest::scalatest:3.2.10"` + +`//> using test.dep "org.scalameta::munit:0.7.29"` `//> using dep "tabby:tabby:0.2.3,url=https://github.com/bjornregnell/tabby/releases/download/v0.2.3/tabby_3-0.2.3.jar"` From 0d47092e5f089234f53e4d46f374b140b1a45044 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Thu, 20 Apr 2023 13:26:04 +0200 Subject: [PATCH 2/8] Support declaring test javacOptions from the main scope --- .../preprocessing/ScalaPreprocessor.scala | 4 +- .../scala/build/tests/DirectiveTests.scala | 74 +++++++++++-------- .../directives/JavacOptions.scala | 30 ++++---- website/docs/reference/directives.md | 2 + .../reference/scala-command/directives.md | 2 + 5 files changed, 66 insertions(+), 46 deletions(-) diff --git a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala index 01ae4da3e8..7f875cc0b2 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala @@ -67,7 +67,6 @@ case object ScalaPreprocessor extends Preprocessor { val usingDirectiveHandlers: Seq[DirectiveHandler[BuildOptions]] = Seq[DirectiveHandler[_ <: HasBuildOptions]]( directives.CustomJar.handler, - directives.JavacOptions.handler, directives.JavaOptions.handler, directives.JavaProps.handler, directives.JavaHome.handler, @@ -94,7 +93,8 @@ case object ScalaPreprocessor extends Preprocessor { val usingDirectiveWithReqsHandlers : Seq[DirectiveHandler[List[WithBuildRequirements[BuildOptions]]]] = Seq[DirectiveHandler[_ <: HasBuildOptionsWithRequirements]]( - directives.Dependency.handler + directives.Dependency.handler, + directives.JavacOptions.handler ).map(_.mapE(_.buildOptionsWithRequirements)) val requireDirectiveHandlers: Seq[DirectiveHandler[BuildRequirements]] = diff --git a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala index 315340487d..3c930f69fb 100644 --- a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala @@ -3,11 +3,10 @@ package scala.build.tests import com.eed3si9n.expecty.Expecty.expect import java.io.IOException -import scala.build.{BuildThreads, Directories, LocalRepo, Position, Positioned} +import scala.build.{Build, BuildThreads, Directories, LocalRepo, Position, Positioned} import scala.build.options.{BuildOptions, InternalOptions, MaybeScalaVersion, ScalacOpt, Scope} import scala.build.tests.util.BloopServer import build.Ops.EitherThrowOps -import scala.build.Position import dependency.AnyDependency class DirectiveTests extends munit.FunSuite { @@ -106,37 +105,50 @@ class DirectiveTests extends munit.FunSuite { expect(toolkitDep.version == "latest.release") } } - for (scope <- Scope.all) - test(s"resolve test scope directives correctly when building for ${scope.name} scope") { - val inputs = TestInputs( - os.rel / "project.scala" -> - """//> using dep "com.lihaoyi::os-lib:0.9.1" - |//> using test.dep "org.scalameta::munit::0.7.29" - |""".stripMargin, - os.rel / "Tests.test.scala" -> - """class Tests extends munit.FunSuite { - | test("foo") { - | println("foo") - | } - |} - |""".stripMargin - ) - inputs.withBuild(baseOptions, buildThreads, bloopConfigOpt, scope = scope) { - (_, _, maybeBuild) => - val isTestScope = scope == Scope.Test - val build = maybeBuild.orThrow - val deps = build.options.classPathOptions.extraDependencies.toSeq.map(_.value) - expect(deps.nonEmpty) - val hasMainDeps = deps.exists(d => - d.organization == "com.lihaoyi" && d.name == "os-lib" && d.version == "0.9.1" - ) - val hasTestDeps = deps.exists(d => - d.organization == "org.scalameta" && d.name == "munit" && d.version == "0.7.29" - ) - expect(hasMainDeps) - expect(if isTestScope then hasTestDeps else !hasTestDeps) + for (scope <- Scope.all) { + def withProjectFile[T](projectFileContent: String)(f: (Build, Boolean) => T): T = TestInputs( + os.rel / "project.scala" -> projectFileContent, + os.rel / "Tests.test.scala" -> + """class Tests extends munit.FunSuite { + | test("foo") { + | println("foo") + | } + |} + |""".stripMargin + ).withBuild(baseOptions, buildThreads, bloopConfigOpt, scope = scope) { (_, _, maybeBuild) => + f(maybeBuild.orThrow, scope == Scope.Test) + } + + test(s"resolve test scope dependencies correctly when building for ${scope.name} scope") { + withProjectFile(projectFileContent = """//> using dep "com.lihaoyi::os-lib:0.9.1" + |//> using test.dep "org.scalameta::munit::0.7.29" + |""".stripMargin) { (build, isTestScope) => + val deps = build.options.classPathOptions.extraDependencies.toSeq.map(_.value) + expect(deps.nonEmpty) + val hasMainDeps = deps.exists(d => + d.organization == "com.lihaoyi" && d.name == "os-lib" && d.version == "0.9.1" + ) + val hasTestDeps = deps.exists(d => + d.organization == "org.scalameta" && d.name == "munit" && d.version == "0.7.29" + ) + expect(hasMainDeps) + expect(if isTestScope then hasTestDeps else !hasTestDeps) } } + test(s"resolve test scope javacOpts correctly when building for ${scope.name} scope") { + withProjectFile(projectFileContent = + """//> using javacOpt "source", "1.8" + |//> using test.javacOpt "target", "1.8" + |//> using test.dep "org.scalameta::munit::0.7.29" + |""".stripMargin + ) { (build, isTestScope) => + val javacOpts = build.options.javaOptions.javacOptions.map(_.value) + expect(javacOpts.contains("source")) + val hasTestJavacOpts = javacOpts.contains("target") + expect(if isTestScope then hasTestJavacOpts else !hasTestJavacOpts) + } + } + } test("handling special syntax for path") { val filePath = os.rel / "src" / "simple.scala" diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/JavacOptions.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/JavacOptions.scala index 34b9b4bfe0..d0c62a109a 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/JavacOptions.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/JavacOptions.scala @@ -2,34 +2,38 @@ package scala.build.preprocessing.directives import scala.build.directives.* import scala.build.errors.BuildException -import scala.build.options.{BuildOptions, JavaOpt, ShadowingSeq} +import scala.build.options.{BuildOptions, JavaOpt, Scope, ShadowingSeq, WithBuildRequirements} +import scala.build.preprocessing.directives.JavacOptions.buildOptions import scala.build.{Logger, Positioned, options} import scala.cli.commands.SpecificationLevel @DirectiveGroupName("Javac options") @DirectiveExamples("//> using javacOpt \"source\", \"1.8\", \"target\", \"1.8\"") +@DirectiveExamples("//> using test.javacOpt \"source\", \"1.8\", \"target\", \"1.8\"") @DirectiveUsage( "//> using javacOpt _options_", "`//> using javacOpt `_options_" ) @DirectiveDescription("Add Javac options which will be passed when compiling sources.") @DirectiveLevel(SpecificationLevel.SHOULD) -// format: off final case class JavacOptions( @DirectiveName("javacOpt") - javacOptions: List[Positioned[String]] = Nil -) extends HasBuildOptions { - // format: on - def buildOptions: Either[BuildException, BuildOptions] = { - val buildOpt = BuildOptions( - javaOptions = options.JavaOptions( - javacOptions = javacOptions - ) - ) - Right(buildOpt) - } + javacOptions: List[Positioned[String]] = Nil, + @DirectiveName("test.javacOpt") + testJavacOptions: List[Positioned[String]] = Nil +) extends HasBuildOptionsWithRequirements { + + def buildOptionsWithRequirements + : Either[BuildException, List[WithBuildRequirements[BuildOptions]]] = + Right(List( + buildOptions(javacOptions).withEmptyRequirements, + buildOptions(testJavacOptions).withScopeRequirement(Scope.Test) + )) } object JavacOptions { val handler: DirectiveHandler[JavacOptions] = DirectiveHandler.derive + + def buildOptions(javacOptions: List[Positioned[String]]): BuildOptions = + BuildOptions(javaOptions = options.JavaOptions(javacOptions = javacOptions)) } diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index e7689592c4..99822e6aa9 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -114,6 +114,8 @@ Add Javac options which will be passed when compiling sources. #### Examples `//> using javacOpt "source", "1.8", "target", "1.8"` +`//> using test.javacOpt "source", "1.8", "target", "1.8"` + ### Main class Specify default main class diff --git a/website/docs/reference/scala-command/directives.md b/website/docs/reference/scala-command/directives.md index 103a18e0c7..3f8ea7e78a 100644 --- a/website/docs/reference/scala-command/directives.md +++ b/website/docs/reference/scala-command/directives.md @@ -146,6 +146,8 @@ Add Javac options which will be passed when compiling sources. #### Examples `//> using javacOpt "source", "1.8", "target", "1.8"` +`//> using test.javacOpt "source", "1.8", "target", "1.8"` + ### Platform Set the default platform to Scala.js or Scala Native From 4e4ffdbac8428f1bdb99daca5d515f3056d3bd27 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Thu, 20 Apr 2023 14:31:07 +0200 Subject: [PATCH 3/8] Support declaring test javaOptions from the main scope --- .../preprocessing/ScalaPreprocessor.scala | 2 +- .../scala/build/tests/DirectiveTests.scala | 13 ++++++++ .../directives/JavaOptions.scala | 30 +++++++++++-------- website/docs/reference/directives.md | 2 ++ .../reference/scala-command/directives.md | 2 ++ 5 files changed, 35 insertions(+), 14 deletions(-) diff --git a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala index 7f875cc0b2..478d82591d 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala @@ -67,7 +67,6 @@ case object ScalaPreprocessor extends Preprocessor { val usingDirectiveHandlers: Seq[DirectiveHandler[BuildOptions]] = Seq[DirectiveHandler[_ <: HasBuildOptions]]( directives.CustomJar.handler, - directives.JavaOptions.handler, directives.JavaProps.handler, directives.JavaHome.handler, directives.Jvm.handler, @@ -94,6 +93,7 @@ case object ScalaPreprocessor extends Preprocessor { : Seq[DirectiveHandler[List[WithBuildRequirements[BuildOptions]]]] = Seq[DirectiveHandler[_ <: HasBuildOptionsWithRequirements]]( directives.Dependency.handler, + directives.JavaOptions.handler, directives.JavacOptions.handler ).map(_.mapE(_.buildOptionsWithRequirements)) diff --git a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala index 3c930f69fb..a47acc1136 100644 --- a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala @@ -148,6 +148,19 @@ class DirectiveTests extends munit.FunSuite { expect(if isTestScope then hasTestJavacOpts else !hasTestJavacOpts) } } + test(s"resolve test scope javaOpts correctly when building for ${scope.name} scope") { + withProjectFile(projectFileContent = + """//> using javaOpt "-Xmx2g" + |//> using test.javaOpt "-Dsomething=a" + |//> using test.dep "org.scalameta::munit::0.7.29" + |""".stripMargin + ) { (build, isTestScope) => + val javaOpts = build.options.javaOptions.javaOpts.toSeq.map(_.value.value) + expect(javaOpts.contains("-Xmx2g")) + val hasTestJavaOpts = javaOpts.contains("-Dsomething=a") + expect(if isTestScope then hasTestJavaOpts else !hasTestJavaOpts) + } + } } test("handling special syntax for path") { diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/JavaOptions.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/JavaOptions.scala index b3097d4592..b7d8f2d15e 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/JavaOptions.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/JavaOptions.scala @@ -2,34 +2,38 @@ package scala.build.preprocessing.directives import scala.build.directives.* import scala.build.errors.BuildException -import scala.build.options.{BuildOptions, JavaOpt, ShadowingSeq} +import scala.build.options.{BuildOptions, JavaOpt, Scope, ShadowingSeq, WithBuildRequirements} +import scala.build.preprocessing.directives.JavaOptions.buildOptions import scala.build.{Logger, Positioned, options} import scala.cli.commands.SpecificationLevel @DirectiveGroupName("Java options") @DirectiveExamples("//> using javaOpt \"-Xmx2g\", \"-Dsomething=a\"") +@DirectiveExamples("//> using test.javaOpt \"-Dsomething=a\"") @DirectiveUsage( "//> using javaOpt _options_", "`//> using javaOpt `_options_" ) @DirectiveDescription("Add Java options which will be passed when running an application.") @DirectiveLevel(SpecificationLevel.MUST) -// format: off final case class JavaOptions( @DirectiveName("javaOpt") - javaOptions: List[Positioned[String]] = Nil -) extends HasBuildOptions { - // format: on - def buildOptions: Either[BuildException, BuildOptions] = { - val buildOpt = BuildOptions( - javaOptions = options.JavaOptions( - javaOpts = ShadowingSeq.from(javaOptions.map(_.map(JavaOpt(_)))) - ) - ) - Right(buildOpt) - } + javaOptions: List[Positioned[String]] = Nil, + @DirectiveName("test.javaOpt") + testJavaOptions: List[Positioned[String]] = Nil +) extends HasBuildOptionsWithRequirements { + def buildOptionsWithRequirements + : Either[BuildException, List[WithBuildRequirements[BuildOptions]]] = + Right(List( + buildOptions(javaOptions).withEmptyRequirements, + buildOptions(testJavaOptions).withScopeRequirement(Scope.Test) + )) } object JavaOptions { val handler: DirectiveHandler[JavaOptions] = DirectiveHandler.derive + def buildOptions(javaOptions: List[Positioned[String]]): BuildOptions = + BuildOptions(javaOptions = + options.JavaOptions(javaOpts = ShadowingSeq.from(javaOptions.map(_.map(JavaOpt(_))))) + ) } diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index 99822e6aa9..b30ff8708f 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -95,6 +95,8 @@ Add Java options which will be passed when running an application. #### Examples `//> using javaOpt "-Xmx2g", "-Dsomething=a"` +`//> using test.javaOpt "-Dsomething=a"` + ### Java properties Add Java properties diff --git a/website/docs/reference/scala-command/directives.md b/website/docs/reference/scala-command/directives.md index 3f8ea7e78a..8e4ca8c573 100644 --- a/website/docs/reference/scala-command/directives.md +++ b/website/docs/reference/scala-command/directives.md @@ -57,6 +57,8 @@ Add Java options which will be passed when running an application. #### Examples `//> using javaOpt "-Xmx2g", "-Dsomething=a"` +`//> using test.javaOpt "-Dsomething=a"` + ### Java properties Add Java properties From 7239d474375e6bdcf8653d7f3198a8fd5fcb06ab Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Thu, 20 Apr 2023 14:40:18 +0200 Subject: [PATCH 4/8] Support declaring test javaProps from the main scope --- .../preprocessing/ScalaPreprocessor.scala | 4 +-- .../scala/build/tests/DirectiveTests.scala | 13 +++++++ .../preprocessing/directives/JavaProps.scala | 34 ++++++++++++------- website/docs/reference/directives.md | 2 ++ .../reference/scala-command/directives.md | 2 ++ 5 files changed, 40 insertions(+), 15 deletions(-) diff --git a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala index 478d82591d..5e49871dfe 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala @@ -67,7 +67,6 @@ case object ScalaPreprocessor extends Preprocessor { val usingDirectiveHandlers: Seq[DirectiveHandler[BuildOptions]] = Seq[DirectiveHandler[_ <: HasBuildOptions]]( directives.CustomJar.handler, - directives.JavaProps.handler, directives.JavaHome.handler, directives.Jvm.handler, directives.MainClass.handler, @@ -94,7 +93,8 @@ case object ScalaPreprocessor extends Preprocessor { Seq[DirectiveHandler[_ <: HasBuildOptionsWithRequirements]]( directives.Dependency.handler, directives.JavaOptions.handler, - directives.JavacOptions.handler + directives.JavacOptions.handler, + directives.JavaProps.handler ).map(_.mapE(_.buildOptionsWithRequirements)) val requireDirectiveHandlers: Seq[DirectiveHandler[BuildRequirements]] = diff --git a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala index a47acc1136..66c8025be6 100644 --- a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala @@ -161,6 +161,19 @@ class DirectiveTests extends munit.FunSuite { expect(if isTestScope then hasTestJavaOpts else !hasTestJavaOpts) } } + test(s"resolve test scope javaProps correctly when building for ${scope.name} scope") { + withProjectFile(projectFileContent = + """//> using javaProp "foo=1" + |//> using test.javaProp "bar=2" + |//> using test.dep "org.scalameta::munit::0.7.29" + |""".stripMargin + ) { (build, isTestScope) => + val javaProps = build.options.javaOptions.javaOpts.toSeq.map(_.value.value) + expect(javaProps.contains("-Dfoo=1")) + val hasTestJavaProps = javaProps.contains("-Dbar=2") + expect(if isTestScope then hasTestJavaProps else !hasTestJavaProps) + } + } } test("handling special syntax for path") { diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/JavaProps.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/JavaProps.scala index 3622b67b51..befca8ab99 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/JavaProps.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/JavaProps.scala @@ -2,12 +2,14 @@ package scala.build.preprocessing.directives import scala.build.directives.* import scala.build.errors.BuildException -import scala.build.options.{BuildOptions, JavaOpt, ShadowingSeq} +import scala.build.options.{BuildOptions, JavaOpt, Scope, ShadowingSeq, WithBuildRequirements} +import scala.build.preprocessing.directives.JavaProps.buildOptions import scala.build.{Logger, Positioned, options} import scala.cli.commands.SpecificationLevel @DirectiveGroupName("Java properties") @DirectiveExamples("//> using javaProp \"foo1=bar\", \"foo2\"") +@DirectiveExamples("//> using test.javaProp \"foo3=bar\", \"foo4\"") @DirectiveUsage( "//> using javaProp _key=val_", """`//> using javaProp `_key=value_ @@ -15,14 +17,25 @@ import scala.cli.commands.SpecificationLevel ) @DirectiveDescription("Add Java properties") @DirectiveLevel(SpecificationLevel.MUST) -// format: off final case class JavaProps( @DirectiveName("javaProp") - javaProperty: List[Positioned[String]] = Nil -) extends HasBuildOptions { - // format: on - def buildOptions: Either[BuildException, BuildOptions] = { - val javaOpts = javaProperty.map { positioned => + javaProperty: List[Positioned[String]] = Nil, + @DirectiveName("test.javaProp") + testJavaProperty: List[Positioned[String]] = Nil +) extends HasBuildOptionsWithRequirements { + def buildOptionsWithRequirements + : Either[BuildException, List[WithBuildRequirements[BuildOptions]]] = + Right(List( + buildOptions(javaProperty).withEmptyRequirements, + buildOptions(testJavaProperty).withScopeRequirement(Scope.Test) + )) +} + +object JavaProps { + val handler: DirectiveHandler[JavaProps] = DirectiveHandler.derive + + def buildOptions(javaProperties: List[Positioned[String]]): BuildOptions = { + val javaOpts = javaProperties.map { positioned => positioned.map { v => v.split("=") match { case Array(k) => JavaOpt(s"-D$k") @@ -30,15 +43,10 @@ final case class JavaProps( } } } - val buildOpt = BuildOptions( + BuildOptions( javaOptions = options.JavaOptions( javaOpts = ShadowingSeq.from(javaOpts) ) ) - Right(buildOpt) } } - -object JavaProps { - val handler: DirectiveHandler[JavaProps] = DirectiveHandler.derive -} diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index b30ff8708f..26cbfa5f26 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -107,6 +107,8 @@ Add Java properties #### Examples `//> using javaProp "foo1=bar", "foo2"` +`//> using test.javaProp "foo3=bar", "foo4"` + ### Javac options Add Javac options which will be passed when compiling sources. diff --git a/website/docs/reference/scala-command/directives.md b/website/docs/reference/scala-command/directives.md index 8e4ca8c573..0479a32ff8 100644 --- a/website/docs/reference/scala-command/directives.md +++ b/website/docs/reference/scala-command/directives.md @@ -69,6 +69,8 @@ Add Java properties #### Examples `//> using javaProp "foo1=bar", "foo2"` +`//> using test.javaProp "foo3=bar", "foo4"` + ### Main class Specify default main class From 89bcea59d3f599e2c0f9c0cf68f36715a091f529 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Fri, 21 Apr 2023 12:32:30 +0200 Subject: [PATCH 5/8] Support declaring test resources dirs from the main scope --- .../preprocessing/ScalaPreprocessor.scala | 4 +- .../scala/build/tests/DirectiveTests.scala | 13 ++++++ .../preprocessing/directives/Resources.scala | 42 +++++++++++++------ website/docs/reference/directives.md | 2 + .../reference/scala-command/directives.md | 2 + 5 files changed, 48 insertions(+), 15 deletions(-) diff --git a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala index 5e49871dfe..bf3e12fefe 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala @@ -78,7 +78,6 @@ case object ScalaPreprocessor extends Preprocessor { directives.PublishContextual.CI.handler, directives.Python.handler, directives.Repository.handler, - directives.Resources.handler, directives.ScalacOptions.handler, directives.ScalaJs.handler, directives.ScalaNative.handler, @@ -94,7 +93,8 @@ case object ScalaPreprocessor extends Preprocessor { directives.Dependency.handler, directives.JavaOptions.handler, directives.JavacOptions.handler, - directives.JavaProps.handler + directives.JavaProps.handler, + directives.Resources.handler ).map(_.mapE(_.buildOptionsWithRequirements)) val requireDirectiveHandlers: Seq[DirectiveHandler[BuildRequirements]] = diff --git a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala index 66c8025be6..88922ac93d 100644 --- a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala @@ -174,6 +174,19 @@ class DirectiveTests extends munit.FunSuite { expect(if isTestScope then hasTestJavaProps else !hasTestJavaProps) } } + test(s"resolve test scope resourceDir correctly when building for ${scope.name} scope") { + withProjectFile(projectFileContent = + """//> using resourceDir "./mainResources" + |//> using test.resourceDir "./testResources" + |//> using test.dep "org.scalameta::munit::0.7.29" + |""".stripMargin + ) { (build, isTestScope) => + val resourcesDirs = build.options.classPathOptions.resourcesDir + expect(resourcesDirs.exists(_.last == "mainResources")) + val hasTestResources = resourcesDirs.exists(_.last == "testResources") + expect(if isTestScope then hasTestResources else !hasTestResources) + } + } } test("handling special syntax for path") { diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Resources.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Resources.scala index 9d7932dff2..2db75aa805 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Resources.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Resources.scala @@ -2,12 +2,21 @@ package scala.build.preprocessing.directives import scala.build.directives.* import scala.build.errors.BuildException -import scala.build.options.{BuildOptions, ClassPathOptions, JavaOpt, ShadowingSeq} +import scala.build.options.{ + BuildOptions, + ClassPathOptions, + JavaOpt, + Scope, + ShadowingSeq, + WithBuildRequirements +} +import scala.build.preprocessing.directives.Resources.buildOptions import scala.build.{Logger, Positioned, options} import scala.cli.commands.SpecificationLevel @DirectiveGroupName("Resource directories") @DirectiveExamples("//> using resourceDir \"./resources\"") +@DirectiveExamples("//> using test.resourceDir \"./resources\"") @DirectiveUsage( """//> using resourceDir _path_ | @@ -18,14 +27,26 @@ import scala.cli.commands.SpecificationLevel ) @DirectiveDescription("Manually add a resource directory to the class path") @DirectiveLevel(SpecificationLevel.SHOULD) -// format: off final case class Resources( @DirectiveName("resourceDir") - resourceDirs: DirectiveValueParser.WithScopePath[List[Positioned[String]]] = - DirectiveValueParser.WithScopePath.empty(Nil) -) extends HasBuildOptions { - // format: on - def buildOptions: Either[BuildException, BuildOptions] = { + resourceDirs: DirectiveValueParser.WithScopePath[List[Positioned[String]]] = + DirectiveValueParser.WithScopePath.empty(Nil), + @DirectiveName("test.resourceDir") + testResourceDirs: DirectiveValueParser.WithScopePath[List[Positioned[String]]] = + DirectiveValueParser.WithScopePath.empty(Nil) +) extends HasBuildOptionsWithRequirements { + def buildOptionsWithRequirements + : Either[BuildException, List[WithBuildRequirements[BuildOptions]]] = + Right(List( + buildOptions(resourceDirs).withEmptyRequirements, + buildOptions(testResourceDirs).withScopeRequirement(Scope.Test) + )) +} + +object Resources { + val handler: DirectiveHandler[Resources] = DirectiveHandler.derive + def buildOptions(resourceDirs: DirectiveValueParser.WithScopePath[List[Positioned[String]]]) + : BuildOptions = { val paths = resourceDirs.value.map(_.value) val (virtualRootOpt, rootOpt) = Directive.osRootResource(resourceDirs.scopePath) @@ -42,16 +63,11 @@ final case class Resources( } // warnIfNotExistsPath(paths0, logger) // this should be reported elsewhere (more from BuildOptions) - val buildOpt = BuildOptions( + BuildOptions( classPathOptions = ClassPathOptions( resourcesDir = paths0, resourcesVirtualDir = virtualPaths.toList.flatten ) ) - Right(buildOpt) } } - -object Resources { - val handler: DirectiveHandler[Resources] = DirectiveHandler.derive -} diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index 26cbfa5f26..606ae59e41 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -242,6 +242,8 @@ Manually add a resource directory to the class path #### Examples `//> using resourceDir "./resources"` +`//> using test.resourceDir "./resources"` + ### Scala Native options Add Scala Native options diff --git a/website/docs/reference/scala-command/directives.md b/website/docs/reference/scala-command/directives.md index 0479a32ff8..97a156fd08 100644 --- a/website/docs/reference/scala-command/directives.md +++ b/website/docs/reference/scala-command/directives.md @@ -187,6 +187,8 @@ Manually add a resource directory to the class path #### Examples `//> using resourceDir "./resources"` +`//> using test.resourceDir "./resources"` + ### Scala Native options Add Scala Native options From c8731f040c5c91dd02201c6a57a0f12047c7127f Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Fri, 21 Apr 2023 12:43:57 +0200 Subject: [PATCH 6/8] Support declaring test `scalac` options from the main scope --- .../preprocessing/ScalaPreprocessor.scala | 4 +- .../scala/build/tests/DirectiveTests.scala | 13 ++++++ .../directives/ScalacOptions.scala | 41 +++++++++++++------ website/docs/reference/directives.md | 2 + .../reference/scala-command/directives.md | 2 + 5 files changed, 47 insertions(+), 15 deletions(-) diff --git a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala index bf3e12fefe..fb75daa9ef 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala @@ -78,7 +78,6 @@ case object ScalaPreprocessor extends Preprocessor { directives.PublishContextual.CI.handler, directives.Python.handler, directives.Repository.handler, - directives.ScalacOptions.handler, directives.ScalaJs.handler, directives.ScalaNative.handler, directives.ScalaVersion.handler, @@ -94,7 +93,8 @@ case object ScalaPreprocessor extends Preprocessor { directives.JavaOptions.handler, directives.JavacOptions.handler, directives.JavaProps.handler, - directives.Resources.handler + directives.Resources.handler, + directives.ScalacOptions.handler ).map(_.mapE(_.buildOptionsWithRequirements)) val requireDirectiveHandlers: Seq[DirectiveHandler[BuildRequirements]] = diff --git a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala index 88922ac93d..2cb4f6846c 100644 --- a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala @@ -148,6 +148,19 @@ class DirectiveTests extends munit.FunSuite { expect(if isTestScope then hasTestJavacOpts else !hasTestJavacOpts) } } + test(s"resolve test scope scalac opts correctly when building for ${scope.name} scope") { + withProjectFile(projectFileContent = + """//> using option "--explain" + |//> using test.option "-deprecation" + |//> using test.dep "org.scalameta::munit::0.7.29" + |""".stripMargin + ) { (build, isTestScope) => + val scalacOpts = build.options.scalaOptions.scalacOptions.toSeq.map(_.value.value) + expect(scalacOpts.contains("--explain")) + val hasTestScalacOpts = scalacOpts.contains("-deprecation") + expect(if isTestScope then hasTestScalacOpts else !hasTestScalacOpts) + } + } test(s"resolve test scope javaOpts correctly when building for ${scope.name} scope") { withProjectFile(projectFileContent = """//> using javaOpt "-Xmx2g" diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalacOptions.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalacOptions.scala index d114134260..3d9f2fa1f7 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalacOptions.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalacOptions.scala @@ -2,12 +2,21 @@ package scala.build.preprocessing.directives import scala.build.directives.* import scala.build.errors.BuildException -import scala.build.options.{BuildOptions, ScalaOptions, ScalacOpt, ShadowingSeq} +import scala.build.options.{ + BuildOptions, + ScalaOptions, + ScalacOpt, + Scope, + ShadowingSeq, + WithBuildRequirements +} +import scala.build.preprocessing.directives.ScalacOptions.buildOptions import scala.build.{Logger, Positioned} import scala.cli.commands.SpecificationLevel @DirectiveGroupName("Compiler options") @DirectiveExamples("//> using option \"-Xasync\"") +@DirectiveExamples("//> using test.option \"-Xasync\"") @DirectiveExamples("//> using options \"-Xasync\", \"-Xfatal-warnings\"") @DirectiveUsage( "using option _option_ | using options _option1_ _option2_ …", @@ -17,22 +26,28 @@ import scala.cli.commands.SpecificationLevel ) @DirectiveDescription("Add Scala compiler options") @DirectiveLevel(SpecificationLevel.MUST) -// format: off final case class ScalacOptions( @DirectiveName("option") - options: List[Positioned[String]] = Nil -) extends HasBuildOptions { - // format: on - def buildOptions: Either[BuildException, BuildOptions] = { - val buildOpt = BuildOptions( - scalaOptions = ScalaOptions( - scalacOptions = ShadowingSeq.from(options.map(_.map(ScalacOpt(_)))) - ) - ) - Right(buildOpt) - } + options: List[Positioned[String]] = Nil, + @DirectiveName("test.option") + @DirectiveName("test.options") + @DirectiveName("test.scalacOptions") + testOptions: List[Positioned[String]] = Nil +) extends HasBuildOptionsWithRequirements { + def buildOptionsWithRequirements + : Either[BuildException, List[WithBuildRequirements[BuildOptions]]] = + Right(List( + buildOptions(options).withEmptyRequirements, + buildOptions(testOptions).withScopeRequirement(Scope.Test) + )) } object ScalacOptions { val handler: DirectiveHandler[ScalacOptions] = DirectiveHandler.derive + def buildOptions(options: List[Positioned[String]]): BuildOptions = + BuildOptions( + scalaOptions = ScalaOptions( + scalacOptions = ShadowingSeq.from(options.map(_.map(ScalacOpt(_)))) + ) + ) } diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index 606ae59e41..cf47f6a34d 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -16,6 +16,8 @@ Add Scala compiler options #### Examples `//> using option "-Xasync"` +`//> using test.option "-Xasync"` + `//> using options "-Xasync", "-Xfatal-warnings"` ### Compiler plugins diff --git a/website/docs/reference/scala-command/directives.md b/website/docs/reference/scala-command/directives.md index 97a156fd08..a4c7f7bdfa 100644 --- a/website/docs/reference/scala-command/directives.md +++ b/website/docs/reference/scala-command/directives.md @@ -22,6 +22,8 @@ Add Scala compiler options #### Examples `//> using option "-Xasync"` +`//> using test.option "-Xasync"` + `//> using options "-Xasync", "-Xfatal-warnings"` ### Compiler plugins From 52cdd98f15e6b051d0c32fe0e225400333e30a29 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Fri, 21 Apr 2023 15:18:50 +0200 Subject: [PATCH 7/8] Support declaring test `toolkit` from the main scope --- .../main/scala/scala/build/CrossSources.scala | 2 +- .../preprocessing/ScalaPreprocessor.scala | 9 ++-- .../scala/build/tests/DirectiveTests.scala | 13 ++++++ .../preprocessing/directives/Toolkit.scala | 44 +++++++++++++------ website/docs/reference/directives.md | 2 + .../reference/scala-command/directives.md | 2 + 6 files changed, 53 insertions(+), 19 deletions(-) diff --git a/modules/build/src/main/scala/scala/build/CrossSources.scala b/modules/build/src/main/scala/scala/build/CrossSources.scala index 828d68d129..f2a54ca24c 100644 --- a/modules/build/src/main/scala/scala/build/CrossSources.scala +++ b/modules/build/src/main/scala/scala/build/CrossSources.scala @@ -195,7 +195,7 @@ object CrossSources { val buildOptions: Seq[WithBuildRequirements[BuildOptions]] = (for { preprocessedSource <- preprocessedSources opts <- preprocessedSource.options.toSeq - if opts != BuildOptions() + if opts != BuildOptions() || preprocessedSource.optionsWithTargetRequirements.nonEmpty } yield { val baseReqs0 = baseReqs(preprocessedSource.scopePath) preprocessedSource.optionsWithTargetRequirements :+ WithBuildRequirements( diff --git a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala index fb75daa9ef..641742e359 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala @@ -35,7 +35,8 @@ case object ScalaPreprocessor extends Preprocessor { def isEmpty: Boolean = globalReqs == BuildRequirements.monoid.zero && globalUsings == BuildOptions.monoid.zero && scopedReqs.isEmpty && - strippedContent.isEmpty + strippedContent.isEmpty && + usingsWithReqs.isEmpty } private case class SpecialImportsProcessingOutput( @@ -82,8 +83,7 @@ case object ScalaPreprocessor extends Preprocessor { directives.ScalaNative.handler, directives.ScalaVersion.handler, directives.Sources.handler, - directives.Tests.handler, - directives.Toolkit.handler + directives.Tests.handler ).map(_.mapE(_.buildOptions)) val usingDirectiveWithReqsHandlers @@ -94,7 +94,8 @@ case object ScalaPreprocessor extends Preprocessor { directives.JavacOptions.handler, directives.JavaProps.handler, directives.Resources.handler, - directives.ScalacOptions.handler + directives.ScalacOptions.handler, + directives.Toolkit.handler ).map(_.mapE(_.buildOptionsWithRequirements)) val requireDirectiveHandlers: Seq[DirectiveHandler[BuildRequirements]] = diff --git a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala index 2cb4f6846c..2fd72ccc32 100644 --- a/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/DirectiveTests.scala @@ -200,6 +200,19 @@ class DirectiveTests extends munit.FunSuite { expect(if isTestScope then hasTestResources else !hasTestResources) } } + test(s"resolve test scope toolkit dependency correctly when building for ${scope.name} scope") { + withProjectFile( + projectFileContent = + s"""//> using test.toolkit "latest" + |""".stripMargin + ) { (build, isTestScope) => + val deps = build.options.classPathOptions.extraDependencies.toSeq.map(_.value) + if isTestScope then expect(deps.nonEmpty) + val hasToolkitDep = + deps.exists(d => d.organization == "org.scala-lang" && d.name == "toolkit") + expect(if isTestScope then hasToolkitDep else !hasToolkitDep) + } + } } test("handling special syntax for path") { diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala index 67122dd7e4..36119e1bca 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala @@ -8,34 +8,42 @@ import scala.build.EitherCps.{either, value} import scala.build.directives.* import scala.build.errors.BuildException import scala.build.internal.Constants -import scala.build.options.{BuildOptions, ClassPathOptions, JavaOpt, Scope, ShadowingSeq} +import scala.build.options.{ + BuildOptions, + ClassPathOptions, + JavaOpt, + Scope, + ShadowingSeq, + WithBuildRequirements +} +import scala.build.preprocessing.directives.Toolkit.buildOptions import scala.build.{Artifacts, Logger, Positioned, options} import scala.cli.commands.SpecificationLevel @DirectiveGroupName("Toolkit") @DirectiveExamples("//> using toolkit \"0.1.0\"") @DirectiveExamples("//> using toolkit \"latest\"") +@DirectiveExamples("//> using test.toolkit \"latest\"") @DirectiveUsage( "//> using toolkit _version_", "`//> using toolkit` _version_" ) @DirectiveDescription("Use a toolkit as dependency") @DirectiveLevel(SpecificationLevel.SHOULD) -// format: off final case class Toolkit( - toolkit: Option[Positioned[String]] = None -) extends HasBuildOptions { - // format: on - def buildOptions: Either[BuildException, BuildOptions] = { - val toolkitDep = - toolkit.toList.map(Toolkit.resolveDependency) - val buildOpt = BuildOptions( - classPathOptions = ClassPathOptions( - extraDependencies = ShadowingSeq.from(toolkitDep) + toolkit: Option[Positioned[String]] = None, + @DirectiveName("test.toolkit") + testToolkit: Option[Positioned[String]] = None +) extends HasBuildOptionsWithRequirements { + def buildOptionsWithRequirements + : Either[BuildException, List[WithBuildRequirements[BuildOptions]]] = + Right { + val mainBuildOpts = buildOptions(toolkit) + val testBuildOpts = buildOptions(testToolkit) + mainBuildOpts.toList.map(_.withEmptyRequirements) ++ testBuildOpts.toList.map( + _.withScopeRequirement(Scope.Test) ) - ) - Right(buildOpt) - } + } } object Toolkit { @@ -44,4 +52,12 @@ object Toolkit { dep"${Constants.toolkitOrganization}::${Constants.toolkitName}::$v,toolkit" ) val handler: DirectiveHandler[Toolkit] = DirectiveHandler.derive + + def buildOptions(toolkit: Option[Positioned[String]]): Option[BuildOptions] = toolkit.map { t => + BuildOptions( + classPathOptions = ClassPathOptions( + extraDependencies = ShadowingSeq.from(List(resolveDependency(t))) + ) + ) + } } diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index cf47f6a34d..09a319f85d 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -341,6 +341,8 @@ Use a toolkit as dependency `//> using toolkit "latest"` +`//> using test.toolkit "latest"` + ## target directives diff --git a/website/docs/reference/scala-command/directives.md b/website/docs/reference/scala-command/directives.md index a4c7f7bdfa..063c63bc59 100644 --- a/website/docs/reference/scala-command/directives.md +++ b/website/docs/reference/scala-command/directives.md @@ -271,3 +271,5 @@ Use a toolkit as dependency `//> using toolkit "latest"` +`//> using test.toolkit "latest"` + From c484b035b942bf20a87180a06f818974fa7b9085 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Mon, 24 Apr 2023 09:23:41 +0200 Subject: [PATCH 8/8] Support declaring test custom jars from the main scope --- .../preprocessing/ScalaPreprocessor.scala | 2 +- .../preprocessing/directives/CustomJar.scala | 36 +++++++-- .../cli/integration/RunTestDefinitions.scala | 74 +++++++++++++++++++ website/docs/reference/directives.md | 2 + .../reference/scala-command/directives.md | 2 + 5 files changed, 107 insertions(+), 9 deletions(-) diff --git a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala index 641742e359..a09f003a07 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala @@ -67,7 +67,6 @@ case object ScalaPreprocessor extends Preprocessor { val usingDirectiveHandlers: Seq[DirectiveHandler[BuildOptions]] = Seq[DirectiveHandler[_ <: HasBuildOptions]]( - directives.CustomJar.handler, directives.JavaHome.handler, directives.Jvm.handler, directives.MainClass.handler, @@ -89,6 +88,7 @@ case object ScalaPreprocessor extends Preprocessor { val usingDirectiveWithReqsHandlers : Seq[DirectiveHandler[List[WithBuildRequirements[BuildOptions]]]] = Seq[DirectiveHandler[_ <: HasBuildOptionsWithRequirements]]( + directives.CustomJar.handler, directives.Dependency.handler, directives.JavaOptions.handler, directives.JavacOptions.handler, diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/CustomJar.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/CustomJar.scala index 4ddcf2c631..a608184afc 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/CustomJar.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/CustomJar.scala @@ -1,9 +1,10 @@ package scala.build.preprocessing.directives -import scala.build.Ops._ +import scala.build.Ops.* import scala.build.directives.* import scala.build.errors.{BuildException, CompositeBuildException, WrongJarPathError} -import scala.build.options.{BuildOptions, ClassPathOptions} +import scala.build.options.{BuildOptions, ClassPathOptions, Scope, WithBuildRequirements} import scala.build.preprocessing.ScopePath +import scala.build.preprocessing.directives.CustomJar.buildOptions import scala.build.{Logger, Positioned} import scala.cli.commands.SpecificationLevel import scala.util.{Failure, Success, Try} @@ -11,6 +12,8 @@ import scala.util.{Failure, Success, Try} @DirectiveGroupName("Custom JAR") @DirectiveExamples( "//> using jar \"/Users/alexandre/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/chuusai/shapeless_2.13/2.3.7/shapeless_2.13-2.3.7.jar\"" +) @DirectiveExamples( + "//> using test.jar \"/Users/alexandre/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/chuusai/shapeless_2.13/2.3.7/shapeless_2.13-2.3.7.jar\"" ) @DirectiveUsage( "`//> using jar `_path_ | `//> using jars `_path1_, _path2_ …", @@ -23,9 +26,30 @@ import scala.util.{Failure, Success, Try} final case class CustomJar( @DirectiveName("jars") jar: DirectiveValueParser.WithScopePath[List[Positioned[String]]] = + DirectiveValueParser.WithScopePath.empty(Nil), + @DirectiveName("test.jar") + @DirectiveName("test.jars") + testJar: DirectiveValueParser.WithScopePath[List[Positioned[String]]] = DirectiveValueParser.WithScopePath.empty(Nil) -) extends HasBuildOptions { - def buildOptions: Either[BuildException, BuildOptions] = { +) extends HasBuildOptionsWithRequirements { + override def buildOptionsWithRequirements + : Either[BuildException, List[WithBuildRequirements[BuildOptions]]] = + Seq( + buildOptions(jar).map(_.withEmptyRequirements), + buildOptions(testJar).map(_.withScopeRequirement(Scope.Test)) + ) + .sequence + .left + .map(CompositeBuildException(_)) + .map(_.toList) + +} + +object CustomJar { + val handler: DirectiveHandler[CustomJar] = DirectiveHandler.derive + + def buildOptions(jar: DirectiveValueParser.WithScopePath[List[Positioned[String]]]) + : Either[BuildException, BuildOptions] = { val cwd = jar.scopePath jar.value .map { posPathStr => @@ -48,7 +72,3 @@ final case class CustomJar( } } } - -object CustomJar { - val handler: DirectiveHandler[CustomJar] = DirectiveHandler.derive -} 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 324cca877b..f9846f61e5 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala @@ -1253,4 +1253,78 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String]) .call(cwd = root, stderr = os.Pipe) } } + test("declare test scope custom jar from main scope") { + val projectFile = "project.scala" + val testMessageFile = "TestMessage.scala" + val mainMessageFile = "MainMessage.scala" + val validMainFile = "ValidMain.scala" + val invalidMainFile = "InvalidMain.scala" + val testFile = "Tests.test.scala" + val expectedMessage1 = "Hello" + val expectedMessage2 = " world!" + val jarPathsWithFiles @ Seq((mainMessageJar, _), (testMessageJar, _)) = + Seq( + os.rel / "MainMessage.jar" -> mainMessageFile, + os.rel / "TestMessage.jar" -> testMessageFile + ) + TestInputs( + os.rel / projectFile -> + s"""//> using jar "$mainMessageJar" + |//> using test.jar "$testMessageJar" + |//> using test.dep "org.scalameta::munit::0.7.29" + |""".stripMargin, + os.rel / mainMessageFile -> + """case class MainMessage(value: String) + |""".stripMargin, + os.rel / testMessageFile -> + """case class TestMessage(value: String) + |""".stripMargin, + os.rel / invalidMainFile -> + s"""object InvalidMain extends App { + | println(TestMessage("$expectedMessage1").value) + |} + |""".stripMargin, + os.rel / validMainFile -> + s"""object ValidMain extends App { + | println(MainMessage("$expectedMessage1").value) + |} + |""".stripMargin, + os.rel / testFile -> + s"""class Tests extends munit.FunSuite { + | val msg1 = MainMessage("$expectedMessage1").value + | val msg2 = TestMessage("$expectedMessage2").value + | val testName = msg1 + msg2 + | test(testName) { + | assert(1 + 1 == 2) + | } + |} + |""".stripMargin + ).fromRoot { root => + // package the MainMessage and TestMessage jars + for ((jarPath, sourcePath) <- jarPathsWithFiles) + os.proc( + TestUtil.cli, + "--power", + "package", + sourcePath, + "--library", + "-o", + jarPath, + extraOptions + ) + .call(cwd = root) + // running `invalidMainFile` should fail, as it's in the main scope and depends on the test scope jar + val res1 = os.proc(TestUtil.cli, "run", projectFile, invalidMainFile, extraOptions) + .call(cwd = root, check = false) + expect(res1.exitCode == 1) + // running `validMainFile` should succeed, since it only depends on the main scope jar + val res2 = os.proc(TestUtil.cli, "run", projectFile, validMainFile, extraOptions) + .call(cwd = root) + expect(res2.out.trim() == expectedMessage1) + // test scope should have access to both main and test deps + val res3 = os.proc(TestUtil.cli, "test", projectFile, testFile, extraOptions) + .call(cwd = root, stderr = os.Pipe) + expect(res3.out.trim().contains(s"$expectedMessage1$expectedMessage2")) + } + } } diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index 09a319f85d..711ae15147 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -40,6 +40,8 @@ Manually add JAR(s) to the class path #### Examples `//> using jar "/Users/alexandre/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/chuusai/shapeless_2.13/2.3.7/shapeless_2.13-2.3.7.jar"` +`//> using test.jar "/Users/alexandre/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/chuusai/shapeless_2.13/2.3.7/shapeless_2.13-2.3.7.jar"` + ### Custom sources Manually add sources to the project diff --git a/website/docs/reference/scala-command/directives.md b/website/docs/reference/scala-command/directives.md index 063c63bc59..49131d76c6 100644 --- a/website/docs/reference/scala-command/directives.md +++ b/website/docs/reference/scala-command/directives.md @@ -110,6 +110,8 @@ Manually add JAR(s) to the class path #### Examples `//> using jar "/Users/alexandre/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/chuusai/shapeless_2.13/2.3.7/shapeless_2.13-2.3.7.jar"` +`//> using test.jar "/Users/alexandre/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/chuusai/shapeless_2.13/2.3.7/shapeless_2.13-2.3.7.jar"` + ### Custom sources Manually add sources to the project