Skip to content

Commit 71fb6d2

Browse files
committed
Make export to Json use BuildInfo
1 parent cb56b49 commit 71fb6d2

File tree

4 files changed

+64
-238
lines changed

4 files changed

+64
-238
lines changed

modules/cli/src/main/scala/scala/cli/exportCmd/JsonProject.scala

Lines changed: 32 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -9,43 +9,36 @@ import dependency.AnyDependency
99
import java.io.PrintStream
1010
import java.nio.charset.StandardCharsets
1111

12+
import scala.build.info.{BuildInfo, ExportDependencyFormat, ScopedBuildInfo}
1213
import scala.build.options.ConfigMonoid
1314
import scala.cli.util.SeqHelpers.*
1415
import scala.reflect.NameTransformer
1516
import scala.util.{Properties, Using}
1617

17-
final case class JsonProject(
18-
projectName: Option[String] = None,
19-
scalaVersion: Option[String] = None,
20-
platform: Option[String] = None,
21-
jvmVersion: Option[String] = None,
22-
scalaJsVersion: Option[String] = None,
23-
jsEsVersion: Option[String] = None,
24-
scalaNativeVersion: Option[String] = None,
25-
mainClass: Option[String] = None,
26-
scopes: Map[String, ScopedJsonProject] = Map.empty
27-
) extends Project {
28-
29-
def +(other: JsonProject): JsonProject =
30-
JsonProject.monoid.orElse(this, other)
18+
final case class JsonProject(buildInfo: BuildInfo) extends Project {
19+
def sorted = this.copy(
20+
buildInfo = buildInfo.copy(
21+
scopes = buildInfo.scopes.map { case (k, v) => k -> v.sorted }
22+
)
23+
)
3124

32-
def withScope(scopeName: String, scopedJsonProj: ScopedJsonProject): JsonProject =
33-
if (scopedJsonProj.sources.isEmpty)
34-
this
35-
else
36-
this.copy(
37-
scopes = this.scopes + (scopeName -> scopedJsonProj)
38-
)
25+
def withEmptyScopesRemoved = this.copy(
26+
buildInfo = buildInfo.copy(
27+
scopes = buildInfo.scopes.filter(_._2 != ScopedBuildInfo.empty)
28+
)
29+
)
3930

4031
def writeTo(dir: os.Path): Unit = {
4132
val config = WriterConfig.withIndentionStep(1)
4233

4334
Using(os.write.outputStream(dir / "export.json")) {
4435
outputStream =>
4536
writeToStream(
46-
this,
37+
sorted.withEmptyScopesRemoved.buildInfo,
4738
outputStream,
4839
config
40+
)(
41+
using JsonProject.jsonCodecBuildInfo
4942
)
5043
}
5144
}
@@ -54,83 +47,33 @@ final case class JsonProject(
5447
val config = WriterConfig.withIndentionStep(1)
5548

5649
writeToStream(
57-
this,
50+
sorted.withEmptyScopesRemoved.buildInfo,
5851
printStream,
5952
config
53+
)(
54+
using JsonProject.jsonCodecBuildInfo
6055
)
6156
}
6257
}
6358

64-
final case class ScopedJsonProject(
65-
sources: Seq[String] = Nil,
66-
scalacOptions: Seq[String] = Nil,
67-
scalaCompilerPlugins: Seq[ExportDependencyFormat] = Nil,
68-
dependencies: Seq[ExportDependencyFormat] = Nil,
69-
resolvers: Seq[String] = Nil,
70-
resourcesDirs: Seq[String] = Nil,
71-
customJarsDecls: Seq[String] = Nil
72-
) {
73-
74-
def +(other: ScopedJsonProject): ScopedJsonProject =
75-
ScopedJsonProject.monoid.orElse(this, other)
76-
77-
def sorted(using ord: Ordering[String]): ScopedJsonProject =
78-
ScopedJsonProject(
79-
this.sources.sorted,
80-
this.scalacOptions,
81-
this.scalaCompilerPlugins.sorted,
82-
this.dependencies.sorted,
83-
this.resolvers.sorted,
84-
this.resourcesDirs.sorted,
85-
this.customJarsDecls.sorted
86-
)
87-
}
88-
89-
object ScopedJsonProject {
90-
implicit val monoid: ConfigMonoid[ScopedJsonProject] = ConfigMonoid.derive
91-
implicit lazy val jsonCodec: JsonValueCodec[ScopedJsonProject] = JsonCodecMaker.make
59+
extension (s: ScopedBuildInfo) {
60+
def sorted(using ord: Ordering[String]) = s.copy(
61+
s.sources.sorted,
62+
s.scalacOptions.sorted,
63+
s.scalaCompilerPlugins.sorted(using JsonProject.ordering),
64+
s.dependencies.sorted(using JsonProject.ordering),
65+
s.resolvers.sorted,
66+
s.resourceDirs.sorted,
67+
s.customJarsDecls.sorted
68+
)
9269
}
9370

9471
object JsonProject {
95-
implicit val monoid: ConfigMonoid[JsonProject] = ConfigMonoid.derive
96-
implicit lazy val jsonCodec: JsonValueCodec[JsonProject] = JsonCodecMaker.make
97-
}
98-
99-
case class ExportDependencyFormat(groupId: String, artifactId: ArtifactId, version: String)
100-
101-
case class ArtifactId(name: String, fullName: String)
102-
103-
object ExportDependencyFormat {
104-
def apply(dep: Dependency): ExportDependencyFormat = {
105-
val scalaVersionStartIndex = dep.module.name.value.lastIndexOf('_')
106-
val shortDepName = if (scalaVersionStartIndex == -1)
107-
dep.module.name.value
108-
else
109-
dep.module.name.value.take(scalaVersionStartIndex)
110-
new ExportDependencyFormat(
111-
dep.module.organization.value,
112-
ArtifactId(shortDepName, dep.module.name.value),
113-
dep.version
114-
)
115-
}
116-
117-
def apply(
118-
dep: AnyDependency,
119-
scalaParamsOpt: Option[dependency.ScalaParameters]
120-
): ExportDependencyFormat = {
121-
import scala.build.internal.Util.*
122-
dep.toCs(scalaParamsOpt)
123-
.map(ExportDependencyFormat.apply)
124-
.getOrElse(
125-
ExportDependencyFormat(
126-
dep.module.organization,
127-
ArtifactId(dep.module.name, dep.module.name),
128-
dep.version
129-
)
130-
)
131-
}
72+
implicit lazy val jsonCodecBuildInfo: JsonValueCodec[BuildInfo] = JsonCodecMaker.make
73+
implicit lazy val jsonCodecScopedBuildInfo: JsonValueCodec[ScopedBuildInfo] = JsonCodecMaker.make
13274

13375
implicit val ordering: Ordering[ExportDependencyFormat] =
13476
Ordering.by(x => x.groupId + x.artifactId.fullName)
135-
implicit lazy val jsonCodec: JsonValueCodec[ExportDependencyFormat] = JsonCodecMaker.make
77+
implicit lazy val jsonCodecExportDependencyFormat: JsonValueCodec[ExportDependencyFormat] =
78+
JsonCodecMaker.make
13679
}

modules/cli/src/main/scala/scala/cli/exportCmd/JsonProjectDescriptor.scala

Lines changed: 14 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,10 @@ import java.nio.charset.StandardCharsets
1111
import java.nio.file.Path
1212

1313
import scala.build.errors.BuildException
14+
import scala.build.info.{BuildInfo, ScopedBuildInfo}
1415
import scala.build.internal.Constants
1516
import scala.build.internal.Runner.frameworkName
16-
import scala.build.options.{
17-
BuildOptions,
18-
JavaOptions,
19-
Platform,
20-
ScalaJsOptions,
21-
ScalaNativeOptions,
22-
Scope
23-
}
17+
import scala.build.options.{BuildOptions, Scope}
2418
import scala.build.testrunner.AsmTestRunner
2519
import scala.build.{Logger, Positioned, Sources}
2620
import scala.cli.util.SeqHelpers.*
@@ -31,136 +25,25 @@ final case class JsonProjectDescriptor(
3125
) extends ProjectDescriptor {
3226
private val charSet = StandardCharsets.UTF_8
3327

34-
private def scalaVersionSettings(options: BuildOptions): JsonProject = {
35-
val sv = options.scalaOptions.scalaVersion
36-
.flatMap(_.versionOpt)
37-
.getOrElse(Constants.defaultScalaVersion)
38-
39-
JsonProject(scalaVersion = Some(sv))
40-
}
41-
42-
private def scalaJsSettings(options: ScalaJsOptions): JsonProject = {
43-
44-
val scalaJsVersion = Some(options.version.getOrElse(Constants.scalaJsVersion))
45-
46-
JsonProject(
47-
platform = Some(Platform.JS.repr),
48-
scalaJsVersion = scalaJsVersion,
49-
jsEsVersion = options.esVersionStr
50-
)
51-
}
52-
53-
private def scalaNativeSettings(options: ScalaNativeOptions): JsonProject = {
54-
val scalaNativeVersion = Some(options.version.getOrElse(Constants.scalaNativeVersion))
55-
56-
JsonProject(
57-
platform = Some(Platform.Native.repr),
58-
scalaNativeVersion = scalaNativeVersion
59-
)
60-
}
61-
62-
private def jvmSettings(options: JavaOptions): JsonProject =
63-
JsonProject(
64-
platform = Some(Platform.JVM.repr),
65-
jvmVersion = options.jvmIdOpt.map(_.value)
66-
)
67-
68-
private def platformSettings(options: BuildOptions): JsonProject =
69-
options.scalaOptions.platform.map(_.value) match {
70-
case Some(Platform.JS) =>
71-
scalaJsSettings(options.scalaJsOptions)
72-
case Some(Platform.Native) =>
73-
scalaNativeSettings(options.scalaNativeOptions)
74-
case _ => jvmSettings(options.javaOptions)
75-
}
76-
77-
private def scalacOptionsSettings(options: BuildOptions): ScopedJsonProject =
78-
ScopedJsonProject(scalacOptions = options.scalaOptions.scalacOptions.toSeq.map(_.value.value))
79-
80-
private def sourcesSettings(sources: Sources): ScopedJsonProject =
81-
ScopedJsonProject(sources =
82-
ProjectDescriptor.sources(sources, charSet).map(_._1.toNIO.toString)
83-
)
84-
85-
private def scalaCompilerPlugins(options: BuildOptions): ScopedJsonProject =
86-
val compilerPlugins = options.scalaOptions.compilerPlugins.map(_.value)
87-
.map(ExportDependencyFormat(_, options.scalaParams.getOrElse(None)))
88-
89-
ScopedJsonProject(scalaCompilerPlugins = compilerPlugins)
90-
91-
private def dependencySettings(options: BuildOptions): ScopedJsonProject = {
92-
val directDeps = options.classPathOptions.extraDependencies.toSeq.map(_.value)
93-
.map(ExportDependencyFormat(_, options.scalaParams.getOrElse(None)))
94-
95-
ScopedJsonProject(dependencies = directDeps)
96-
}
97-
98-
private def repositorySettings(options: BuildOptions): ScopedJsonProject = {
99-
val resolvers = options.finalRepositories
100-
.getOrElse(Nil)
101-
.appended(Repositories.central)
102-
.appended(LocalRepositories.ivy2Local)
103-
.collect {
104-
case repo: MavenRepository => repo.root
105-
case repo: IvyRepository => s"ivy:${repo.pattern.string}"
106-
}
107-
.distinct
108-
109-
ScopedJsonProject(resolvers = resolvers)
110-
}
111-
112-
private def customResourcesSettings(options: BuildOptions): ScopedJsonProject =
113-
ScopedJsonProject(resourcesDirs = options.classPathOptions.resourcesDir.map(_.toNIO.toString))
114-
115-
private def customJarsSettings(options: BuildOptions): ScopedJsonProject = {
116-
117-
val customCompileOnlyJarsDecls =
118-
options.classPathOptions.extraCompileOnlyJars.map(_.toNIO.toString)
119-
120-
val customJarsDecls = options.classPathOptions.extraClassPath.map(_.toNIO.toString)
121-
122-
ScopedJsonProject(
123-
customJarsDecls = customCompileOnlyJarsDecls ++ customJarsDecls
124-
)
125-
}
126-
12728
def `export`(
12829
optionsMain: BuildOptions,
12930
optionsTest: BuildOptions,
13031
sourcesMain: Sources,
13132
sourcesTest: Sources
13233
): JsonProject = {
133-
val baseJsonProject = Seq(
134-
JsonProject(
135-
projectName = projectName,
136-
mainClass = optionsMain.mainClass
137-
),
138-
scalaVersionSettings(optionsMain),
139-
platformSettings(optionsMain)
140-
)
141-
.foldLeft(JsonProject())(_ + _)
34+
def getScopedBuildInfo(options: BuildOptions, sources: Sources) =
35+
val sourcePaths = sources.paths.map(_._1.toString)
36+
val inMemoryPaths = sources.inMemory.flatMap(_.originalPath.toSeq.map(_._2.toString))
14237

143-
val mainJsonProject = exportScope(optionsMain, sourcesMain)
144-
val testJsonProject = exportScope(optionsTest, sourcesTest)
38+
ScopedBuildInfo(options, sourcePaths ++ inMemoryPaths)
14539

146-
baseJsonProject
147-
.withScope(Scope.Main.name, mainJsonProject)
148-
.withScope(Scope.Test.name, testJsonProject)
149-
}
40+
val baseBuildInfo = BuildInfo(optionsMain)
15041

151-
def exportScope(
152-
options: BuildOptions,
153-
sources: Sources
154-
): ScopedJsonProject =
155-
Seq(
156-
scalaCompilerPlugins(options),
157-
scalacOptionsSettings(options),
158-
sourcesSettings(sources),
159-
dependencySettings(options),
160-
repositorySettings(options),
161-
customResourcesSettings(options),
162-
customJarsSettings(options)
163-
)
164-
.foldLeft(ScopedJsonProject())(_ + _)
165-
.sorted
42+
val mainBuildInfo = getScopedBuildInfo(optionsMain, sourcesMain)
43+
val testBuildInfo = getScopedBuildInfo(optionsTest, sourcesTest)
44+
45+
JsonProject(baseBuildInfo
46+
.withScope(Scope.Main.name, mainBuildInfo)
47+
.withScope(Scope.Test.name, testBuildInfo))
48+
}
16649
}

0 commit comments

Comments
 (0)