Skip to content

Commit 80b7bb5

Browse files
committed
Add computing version for BuildInfo
1 parent 5cced0b commit 80b7bb5

File tree

25 files changed

+324
-135
lines changed

25 files changed

+324
-135
lines changed

modules/build/src/main/scala/scala/build/Build.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,10 +269,10 @@ object Build {
269269

270270
val scopedSources = value(crossSources.scopedSources(baseOptions))
271271

272-
val mainSources = scopedSources.sources(Scope.Main, baseOptions)
272+
val mainSources = value(scopedSources.sources(Scope.Main, baseOptions, allInputs.workspace))
273273
val mainOptions = mainSources.buildOptions
274274

275-
val testSources = scopedSources.sources(Scope.Test, baseOptions)
275+
val testSources = value(scopedSources.sources(Scope.Test, baseOptions, allInputs.workspace))
276276
val testOptions = testSources.buildOptions
277277

278278
val inputs0 = updateInputs(

modules/build/src/main/scala/scala/build/ScopedSources.scala

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package scala.build
22

3+
import scala.build.EitherCps.{either, value}
4+
import scala.build.errors.BuildException
35
import scala.build.info.{BuildInfo, ScopedBuildInfo}
46
import scala.build.options.{BuildOptions, HasScope, Scope}
57
import scala.build.preprocessing.ScriptPreprocessor
@@ -48,7 +50,11 @@ final case class ScopedSources(
4850
* @return
4951
* [[Sources]] instance that belong to specified scope
5052
*/
51-
def sources(scope: Scope, baseOptions: BuildOptions): Sources =
53+
def sources(
54+
scope: Scope,
55+
baseOptions: BuildOptions,
56+
workspace: os.Path
57+
): Either[BuildException, Sources] = either {
5258
val combinedOptions = combinedBuildOptions(scope, baseOptions)
5359

5460
val codeWrapper = ScriptPreprocessor.getScriptWrapper(combinedOptions)
@@ -60,12 +66,14 @@ final case class ScopedSources(
6066
val needsBuildInfo = combinedOptions.sourceGeneratorOptions.useBuildInfo.getOrElse(false)
6167

6268
val maybeBuildInfoSource = if (needsBuildInfo && scope == Scope.Main)
63-
Seq(Sources.InMemory(
64-
Left("build-info"),
65-
os.rel / "BuildInfo.scala",
66-
buildInfo(combinedOptions).generateContents(),
67-
None
68-
))
69+
Seq(
70+
Sources.InMemory(
71+
Left("build-info"),
72+
os.rel / "BuildInfo.scala",
73+
value(buildInfo(combinedOptions, workspace)).generateContents(),
74+
None
75+
)
76+
)
6977
else Nil
7078

7179
Sources(
@@ -75,6 +83,7 @@ final case class ScopedSources(
7583
resourceDirs.flatMap(_.valueFor(scope).toSeq),
7684
combinedOptions
7785
)
86+
}
7887

7988
/** Combine build options that had no requirements (console and using directives) or their
8089
* requirements have been resolved (e.g. target using directives) with build options that require
@@ -92,24 +101,25 @@ final case class ScopedSources(
92101
buildOptionsFor(scope)
93102
.foldRight(baseOptions)(_ orElse _)
94103

95-
def buildInfo(baseOptions: BuildOptions): BuildInfo = {
96-
def getScopedBuildInfo(scope: Scope): ScopedBuildInfo =
97-
val combinedOptions = combinedBuildOptions(scope, baseOptions)
98-
val sourcePaths = paths.flatMap(_.valueFor(scope).toSeq).map(_._1.toString)
99-
val inMemoryPaths =
100-
(inMemory.flatMap(_.valueFor(scope).toSeq).flatMap(_.originalPath.toOption) ++
101-
unwrappedScripts.flatMap(_.valueFor(scope).toSeq).flatMap(_.originalPath.toOption))
102-
.map(_._2.toString)
104+
def buildInfo(baseOptions: BuildOptions, workspace: os.Path): Either[BuildException, BuildInfo] =
105+
either {
106+
def getScopedBuildInfo(scope: Scope): ScopedBuildInfo =
107+
val combinedOptions = combinedBuildOptions(scope, baseOptions)
108+
val sourcePaths = paths.flatMap(_.valueFor(scope).toSeq).map(_._1.toString)
109+
val inMemoryPaths =
110+
(inMemory.flatMap(_.valueFor(scope).toSeq).flatMap(_.originalPath.toOption) ++
111+
unwrappedScripts.flatMap(_.valueFor(scope).toSeq).flatMap(_.originalPath.toOption))
112+
.map(_._2.toString)
103113

104-
ScopedBuildInfo(combinedOptions, sourcePaths ++ inMemoryPaths)
114+
ScopedBuildInfo(combinedOptions, sourcePaths ++ inMemoryPaths)
105115

106-
val baseBuildInfo = BuildInfo(combinedBuildOptions(Scope.Main, baseOptions))
116+
val baseBuildInfo = value(BuildInfo(combinedBuildOptions(Scope.Main, baseOptions), workspace))
107117

108-
val mainBuildInfo = getScopedBuildInfo(Scope.Main)
109-
val testBuildInfo = getScopedBuildInfo(Scope.Test)
118+
val mainBuildInfo = getScopedBuildInfo(Scope.Main)
119+
val testBuildInfo = getScopedBuildInfo(Scope.Test)
110120

111-
baseBuildInfo
112-
.withScope(Scope.Main.name, mainBuildInfo)
113-
.withScope(Scope.Test.name, testBuildInfo)
114-
}
121+
baseBuildInfo
122+
.withScope(Scope.Main.name, mainBuildInfo)
123+
.withScope(Scope.Test.name, testBuildInfo)
124+
}
115125
}

modules/build/src/main/scala/scala/build/bsp/BspImpl.scala

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,15 @@ final class BspImpl(
122122
if (verbosity >= 3)
123123
pprint.err.log(scopedSources)
124124

125-
val sourcesMain =
126-
scopedSources.sources(Scope.Main, sharedOptions)
127-
val sourcesTest =
128-
scopedSources.sources(Scope.Test, sharedOptions)
125+
val sourcesMain = value {
126+
scopedSources.sources(Scope.Main, sharedOptions, allInputs.workspace)
127+
.left.map((_, Scope.Main))
128+
}
129+
130+
val sourcesTest = value {
131+
scopedSources.sources(Scope.Test, sharedOptions, allInputs.workspace)
132+
.left.map((_, Scope.Test))
133+
}
129134

130135
if (verbosity >= 3)
131136
pprint.err.log(sourcesMain)

modules/build/src/main/scala/scala/build/preprocessing/directives/DirectivesPreprocessingUtils.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ object DirectivesPreprocessingUtils {
1313
val usingDirectiveHandlers: Seq[DirectiveHandler[BuildOptions]] =
1414
Seq[DirectiveHandler[_ <: HasBuildOptions]](
1515
directives.BuildInfo.handler,
16+
directives.ComputeVersion.handler,
1617
directives.Exclude.handler,
1718
directives.JavaHome.handler,
1819
directives.Jvm.handler,

modules/build/src/test/scala/scala/build/tests/ExcludeTests.scala

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class ExcludeTests extends munit.FunSuite {
8686
os.rel / "project.scala" ->
8787
s"""//> using exclude "Main.scala" """
8888
)
89-
testInputs.withInputs { (_, inputs) =>
89+
testInputs.withInputs { (root, inputs) =>
9090
val (crossSources, _) =
9191
CrossSources.forInputs(
9292
inputs,
@@ -96,7 +96,9 @@ class ExcludeTests extends munit.FunSuite {
9696
)(using ScalaCliInvokeData.dummy).orThrow
9797
val scopedSources = crossSources.scopedSources(BuildOptions())
9898
.orThrow
99-
val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions()))
99+
val sources =
100+
scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions()), root)
101+
.orThrow
100102

101103
expect(sources.paths.nonEmpty)
102104
expect(sources.paths.length == 2)
@@ -113,7 +115,7 @@ class ExcludeTests extends munit.FunSuite {
113115
os.rel / "project.scala" ->
114116
s"""//> using exclude "$${.}${File.separator}Main.scala" """
115117
)
116-
testInputs.withInputs { (_, inputs) =>
118+
testInputs.withInputs { (root, inputs) =>
117119
val (crossSources, _) =
118120
CrossSources.forInputs(
119121
inputs,
@@ -123,7 +125,9 @@ class ExcludeTests extends munit.FunSuite {
123125
)(using ScalaCliInvokeData.dummy).orThrow
124126
val scopedSources = crossSources.scopedSources(BuildOptions())
125127
.orThrow
126-
val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions()))
128+
val sources =
129+
scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions()), root)
130+
.orThrow
127131

128132
expect(sources.paths.nonEmpty)
129133
expect(sources.paths.length == 2)
@@ -140,7 +144,7 @@ class ExcludeTests extends munit.FunSuite {
140144
os.rel / "project.scala" ->
141145
"""//> using exclude "src/*.scala" """
142146
)
143-
testInputs.withInputs { (_, inputs) =>
147+
testInputs.withInputs { (root, inputs) =>
144148
val (crossSources, _) =
145149
CrossSources.forInputs(
146150
inputs,
@@ -150,7 +154,9 @@ class ExcludeTests extends munit.FunSuite {
150154
)(using ScalaCliInvokeData.dummy).orThrow
151155
val scopedSources = crossSources.scopedSources(BuildOptions())
152156
.orThrow
153-
val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions()))
157+
val sources =
158+
scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions()), root)
159+
.orThrow
154160

155161
expect(sources.paths.nonEmpty)
156162
expect(sources.paths.length == 2)
@@ -167,7 +173,7 @@ class ExcludeTests extends munit.FunSuite {
167173
os.rel / "project.scala" ->
168174
"""//> using exclude "src/*.scala" """
169175
)
170-
testInputs.withInputs { (_, inputs) =>
176+
testInputs.withInputs { (root, inputs) =>
171177
val (crossSources, _) =
172178
CrossSources.forInputs(
173179
inputs,
@@ -177,7 +183,9 @@ class ExcludeTests extends munit.FunSuite {
177183
)(using ScalaCliInvokeData.dummy).orThrow
178184
val scopedSources = crossSources.scopedSources(BuildOptions())
179185
.orThrow
180-
val sources = scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions()))
186+
val sources =
187+
scopedSources.sources(Scope.Main, crossSources.sharedOptions(BuildOptions()), root)
188+
.orThrow
181189

182190
expect(sources.paths.nonEmpty)
183191
expect(sources.paths.length == 2)

modules/build/src/test/scala/scala/build/tests/SourceGeneratorTests.scala

Lines changed: 79 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package scala.build.tests
33
import com.eed3si9n.expecty.Expecty.expect
44

55
import java.io.IOException
6+
import scala.Console.println
67
import scala.build.Ops.EitherThrowOps
78
import scala.build.errors.ToolkitDirectiveMissingVersionError
89
import scala.build.options.{
@@ -50,6 +51,27 @@ class SourceGeneratorTests extends munit.FunSuite {
5051
"ivy:file:.../.ivy2/local/"
5152
)
5253

54+
def initializeGit(
55+
cwd: os.Path,
56+
tag: String = "test-inputs",
57+
gitUserName: String = "testUser",
58+
gitUserEmail: String = "[email protected]"
59+
): Unit = {
60+
println(s"Initializing git in $cwd...")
61+
os.proc("git", "init").call(cwd = cwd)
62+
println(s"Setting git user.name to $gitUserName")
63+
os.proc("git", "config", "--local", "user.name", gitUserName).call(cwd = cwd)
64+
println(s"Setting git user.email to $gitUserEmail")
65+
os.proc("git", "config", "--local", "user.email", gitUserEmail).call(cwd = cwd)
66+
println(s"Adding $cwd to git...")
67+
os.proc("git", "add", ".").call(cwd = cwd)
68+
println(s"Doing an initial commit...")
69+
os.proc("git", "commit", "-m", "git init test inputs").call(cwd = cwd)
70+
println(s"Tagging as $tag...")
71+
os.proc("git", "tag", tag).call(cwd = cwd)
72+
println(s"Git initialized at $cwd")
73+
}
74+
5375
test(s"BuildInfo source generated") {
5476
val inputs = TestInputs(
5577
os.rel / "main.scala" ->
@@ -73,54 +95,61 @@ class SourceGeneratorTests extends munit.FunSuite {
7395
|""".stripMargin
7496
)
7597

76-
inputs.withBuild(baseOptions, buildThreads, bloopConfigOpt) {
77-
(root, _, maybeBuild) =>
78-
expect(maybeBuild.orThrow.success)
79-
val projectDir = os.list(root / ".scala-build").filter(
80-
_.baseName.startsWith(root.baseName + "_")
81-
)
82-
expect(projectDir.size == 1)
83-
val buildInfoPath = projectDir.head / "src_generated" / "main" / "BuildInfo.scala"
84-
expect(os.isFile(buildInfoPath))
98+
inputs.fromRoot { root =>
99+
initializeGit(root, "v1.0.0")
85100

86-
val buildInfoContent = os.read(buildInfoPath)
101+
inputs.copy(forceCwd = Some(root))
102+
.withBuild(baseOptions, buildThreads, bloopConfigOpt, skipCreatingSources = true) {
103+
(root, _, maybeBuild) =>
104+
expect(maybeBuild.orThrow.success)
105+
val projectDir = os.list(root / ".scala-build").filter(
106+
_.baseName.startsWith(root.baseName + "_")
107+
)
108+
expect(projectDir.size == 1)
109+
val buildInfoPath = projectDir.head / "src_generated" / "main" / "BuildInfo.scala"
110+
expect(os.isFile(buildInfoPath))
87111

88-
expect(normalizeResolvers(buildInfoContent) ==
89-
s"""package scala.cli.build
90-
|
91-
|object BuildInfo {
92-
| val scalaVersion = "3.2.2"
93-
| val platform = "JVM"
94-
| val jvmVersion = Some("11")
95-
| val scalaJsVersion = None
96-
| val jsEsVersion = None
97-
| val scalaNativeVersion = None
98-
| val mainClass = Some("Main")
99-
|
100-
|
101-
| object Main {
102-
| val sources = Seq("${root / "main.scala"}")
103-
| val scalacOptions = Seq("-Xasync")
104-
| val scalaCompilerPlugins = Seq("org.wartremover:wartremover_3.2.2:3.0.9")
105-
| val dependencies = Seq("com.lihaoyi:os-lib_3:0.9.1")
106-
| val resolvers = Seq("ivy:file:.../scala-cli-tests-extra-repo/local-repo/...", "https://repo1.maven.org/maven2", "ivy:file:.../.ivy2/local/")
107-
| val resourceDirs = Seq("${root / "resources"}")
108-
| val customJarsDecls = Seq("${root / "TEST1.jar"}", "${root / "TEST2.jar"}")
109-
| }
110-
|
111-
| object Test {
112-
| val sources = Nil
113-
| val scalacOptions = Nil
114-
| val scalaCompilerPlugins = Nil
115-
| val dependencies = Nil
116-
| val resolvers = Nil
117-
| val resourceDirs = Nil
118-
| val customJarsDecls = Nil
119-
| }
120-
|
121-
|}
122-
|""".stripMargin)
112+
val buildInfoContent = os.read(buildInfoPath)
113+
114+
expect(normalizeResolvers(buildInfoContent) ==
115+
s"""package scala.cli.build
116+
|
117+
|object BuildInfo {
118+
| val scalaVersion = "3.2.2"
119+
| val platform = "JVM"
120+
| val jvmVersion = Some("11")
121+
| val scalaJsVersion = None
122+
| val jsEsVersion = None
123+
| val scalaNativeVersion = None
124+
| val mainClass = Some("Main")
125+
| val projectVersion = Some("1.0.0")
126+
|
127+
|
128+
| object Main {
129+
| val sources = Seq("${root / "main.scala"}")
130+
| val scalacOptions = Seq("-Xasync")
131+
| val scalaCompilerPlugins = Seq("org.wartremover:wartremover_3.2.2:3.0.9")
132+
| val dependencies = Seq("com.lihaoyi:os-lib_3:0.9.1")
133+
| val resolvers = Seq("ivy:file:.../scala-cli-tests-extra-repo/local-repo/...", "https://repo1.maven.org/maven2", "ivy:file:.../.ivy2/local/")
134+
| val resourceDirs = Seq("${root / "resources"}")
135+
| val customJarsDecls = Seq("${root / "TEST1.jar"}", "${root / "TEST2.jar"}")
136+
| }
137+
|
138+
| object Test {
139+
| val sources = Nil
140+
| val scalacOptions = Nil
141+
| val scalaCompilerPlugins = Nil
142+
| val dependencies = Nil
143+
| val resolvers = Nil
144+
| val resourceDirs = Nil
145+
| val customJarsDecls = Nil
146+
| }
147+
|
148+
|}
149+
|""".stripMargin)
150+
}
123151
}
152+
124153
}
125154

126155
test(s"BuildInfo for native") {
@@ -171,6 +200,7 @@ class SourceGeneratorTests extends munit.FunSuite {
171200
| val jsEsVersion = None
172201
| val scalaNativeVersion = Some("0.4.6")
173202
| val mainClass = Some("Main")
203+
| val projectVersion = None
174204
|
175205
|
176206
| object Main {
@@ -212,6 +242,7 @@ class SourceGeneratorTests extends munit.FunSuite {
212242
|//> using platform scala-js
213243
|//> using jsVersion 1.13.1
214244
|//> using jsEsVersionStr es2015
245+
|//> using computeVersion "command:echo TestVersion"
215246
|
216247
|//> using buildInfo
217248
|
@@ -247,6 +278,7 @@ class SourceGeneratorTests extends munit.FunSuite {
247278
| val jsEsVersion = Some("es2015")
248279
| val scalaNativeVersion = None
249280
| val mainClass = Some("Main")
281+
| val projectVersion = Some("TestVersion")
250282
|
251283
|
252284
| object Main {
@@ -285,6 +317,7 @@ class SourceGeneratorTests extends munit.FunSuite {
285317
|//> using mainClass "Main"
286318
|//> using resourceDir ./resources
287319
|//> using jar TEST1.jar TEST2.jar
320+
|//> using computeVersion "command:echo TestVersion"
288321
|
289322
|//> using buildInfo
290323
|
@@ -320,6 +353,7 @@ class SourceGeneratorTests extends munit.FunSuite {
320353
| val jsEsVersion = None
321354
| val scalaNativeVersion = None
322355
| val mainClass = Some("Main")
356+
| val projectVersion = Some("TestVersion")
323357
|
324358
|
325359
| object Main {

0 commit comments

Comments
 (0)