Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add supports for using Source Generator using Directives #3033

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion modules/build/src/main/scala/scala/build/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,8 @@ object Build {
if (options.useBuildServer.getOrElse(true)) None
else releaseFlag(options, compilerJvmVersionOpt, logger).map(_.toString)

val hardcodedSource = options.sourceGeneratorOptions.generatorConfig

val scalaCompilerParamsOpt = artifacts.scalaOpt match {
case Some(scalaArtifacts) =>
val params = value(options.scalaParams).getOrElse {
Expand Down Expand Up @@ -1009,7 +1011,8 @@ object Build {
resourceDirs = sources.resourceDirs,
scope = scope,
javaHomeOpt = Option(options.javaHomeLocation().value),
javacOptions = javacOptions
javacOptions = javacOptions,
generateSource = Option(sourceGeneratorConfig)
)
project
}
Expand Down
30 changes: 26 additions & 4 deletions modules/build/src/main/scala/scala/build/Project.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import coursier.core.Classifier

import java.io.ByteArrayOutputStream
import java.nio.charset.StandardCharsets
import java.nio.file.Path
import java.nio.file.{Path, Paths}
import java.util.Arrays

import scala.build.options.{ScalacOpt, Scope, ShadowingSeq}
import scala.build.options.{GeneratorConfig, ScalacOpt, Scope, ShadowingSeq}

final case class Project(
workspace: os.Path,
Expand All @@ -28,7 +28,8 @@ final case class Project(
resourceDirs: Seq[os.Path],
javaHomeOpt: Option[os.Path],
scope: Scope,
javacOptions: List[String]
javacOptions: List[String],
generateSource: Option[Seq[GeneratorConfig]]
) {

import Project._
Expand All @@ -50,6 +51,26 @@ final case class Project(
bridgeJars = scalaCompiler0.bridgeJarsOpt.map(_.map(_.toNIO).toList)
)
}

val sourceGenerator: Option[List[BloopConfig.SourceGenerator]] =
generateSource.map(configs =>
configs.map { config =>
val command0 = config.commandFilePath
val sourceGlobs0 = BloopConfig.SourcesGlobs(
Paths.get(config.inputDir),
None,
config.glob,
Nil
)

BloopConfig.SourceGenerator(
List(sourceGlobs0),
(config.outputPath / "source-generator-output").toNIO,
command0
)
}.toList
)

baseBloopProject(
projectName,
directory.toNIO,
Expand All @@ -65,7 +86,8 @@ final case class Project(
platform = Some(platform),
`scala` = scalaConfigOpt,
java = Some(BloopConfig.Java(javacOptions)),
resolution = resolution
resolution = resolution,
sourceGenerators = sourceGenerator
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ case class DirectivesPreprocessor(
)
}

for (vals <- unusedDirectives) println(s"preprocess- ${vals.toString} ${vals.key}")


val (optionsWithActualRequirements, optionsWithEmptyRequirements) =
buildOptionsWithTargetRequirements.global.partition(_.requirements.nonEmpty)
val summedOptionsWithNoRequirements =
Expand Down Expand Up @@ -137,6 +140,7 @@ case class DirectivesPreprocessor(
.toMap

val unused = directives.filter(d => !handlersMap.contains(d.key))
for (vals <- unused) println(s"${vals.toString} ${vals.key}")

val res = directives
.iterator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ object DirectivesPreprocessingUtils {
directives.ScalaJs.handler,
directives.ScalaNative.handler,
directives.ScalaVersion.handler,
directives.SourceGenerator.handler,
directives.Sources.handler,
directives.Tests.handler
).map(_.mapE(_.buildOptions))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ object DirectiveValueParser {
given DirectiveSingleValueParser[String] =
(key, value, scopePath, path) =>
value.asString.toRight {
println("do we get here?")
val pos = value.position(path)
new MalformedDirectiveError(
message =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package scala.build.preprocessing.directives

import scala.cli.commands.SpecificationLevel
import scala.build.directives.*
import scala.build.EitherCps.{either, value}
import scala.build.Ops.*
import scala.build.errors.{BuildException, CompositeBuildException}
import scala.build.options.{BuildOptions, SourceGeneratorOptions, GeneratorConfig}
import scala.build.options.GeneratorConfig
import scala.build.{Positioned, options}

@DirectiveUsage("//> using sourceGenerator", "`//> using sourceGenerator`")
@DirectiveDescription("Generate code using Source Generator")
@DirectiveLevel(SpecificationLevel.EXPERIMENTAL)
final case class SourceGenerator(
sourceGenerator: DirectiveValueParser.WithScopePath[List[Positioned[String]]] =
DirectiveValueParser.WithScopePath.empty(Nil)
) extends HasBuildOptions {
def buildOptions: Either[BuildException, BuildOptions] =
SourceGenerator.buildOptions(sourceGenerator)
}

object SourceGenerator {
val handler: DirectiveHandler[SourceGenerator] = DirectiveHandler.derive
def buildOptions(sourceGenerator: DirectiveValueParser.WithScopePath[List[Positioned[String]]])
: Either[BuildException, BuildOptions] = {
val sourceGenValue = sourceGenerator.value
sourceGenValue
.map(config => GeneratorConfig.parse(config, sourceGenerator.scopePath.subPath))
.sequence
.left.map(CompositeBuildException(_))
.map { configs =>
BuildOptions(sourceGeneratorOptions =
SourceGeneratorOptions(generatorConfig = configs)
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ final case class BuildOptions(
testOptions: TestOptions = TestOptions(),
notForBloopOptions: PostBuildOptions = PostBuildOptions(),
sourceGeneratorOptions: SourceGeneratorOptions = SourceGeneratorOptions(),
useBuildServer: Option[Boolean] = None
useBuildServer: Option[Boolean] = None,
) {

import BuildOptions.JavaHomeInfo
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package scala.build.options

import scala.build.Positioned
import scala.build.errors.{BuildException, MalformedInputError}

final case class GeneratorConfig(
inputDir: String,
glob: List[String],
commandFilePath: List[String],
outputPath: os.SubPath
)

object GeneratorConfig {

def parse(input: Positioned[String], output: os.SubPath): Either[BuildException, GeneratorConfig] =
input.value.split("\\|", 3) match {
case Array(inputDir, glob, commandFilePath) =>
val commandFileList = commandFilePath.split(" ").toList
Right(GeneratorConfig(inputDir, List(glob), commandFileList, output))
case _ =>
Left(
new MalformedInputError(
"sourceGenerator",
input.value,
"inputDir|glob|commandFilePath",
input.positions
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package scala.build.options
final case class SourceGeneratorOptions(
useBuildInfo: Option[Boolean] = None,
projectVersion: Option[String] = None,
computeVersion: Option[ComputeVersion] = None
computeVersion: Option[ComputeVersion] = None,
generatorConfig: Seq[GeneratorConfig] = Nil,
)

object SourceGeneratorOptions {
Expand Down
Loading