Skip to content

Commit

Permalink
Split Json into scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
MaciejG604 committed Feb 16, 2023
1 parent 8e200f3 commit 07048ab
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 167 deletions.
85 changes: 41 additions & 44 deletions modules/cli/src/main/scala/scala/cli/exportCmd/JsonProject.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,9 @@ final case class JsonProject(
scalaCompilerPlugins: Seq[String] = Nil,
scalaJsVersion: Option[String] = None,
scalaNativeVersion: Option[String] = None,
mainDeps: Seq[ExportDependencyFormat] = Nil,
testDeps: Seq[ExportDependencyFormat] = Nil,
mainSources: Seq[String] = Nil,
testSources: Seq[String] = Nil,
resolvers: Seq[ExportResolverFormat] = Nil,
extraDecls: Seq[String] = Nil,
resourcesDirs: Seq[String] = Nil,
mainClass: Option[String] = None
mainClass: Option[String] = None,
scopes: Seq[ScopedJsonProject] = Nil,
extraDecls: Seq[String] = Nil
) extends Project {

def +(other: JsonProject): JsonProject =
Expand All @@ -47,46 +42,48 @@ final case class JsonProject(
}
}

case class ExportResolverFormat(
name: String,
location: Option[String],
user: Option[String] = None,
password: Option[String] = None,
headers: Seq[(String, String)] = Nil
)
final case class ScopedJsonProject(
scopeName: Option[String] = None,
sources: Seq[String] = Nil,
dependencies: Seq[String] = Nil,
resolvers: Seq[String] = Nil,
resourcesDirs: Seq[String] = Nil,
extraDecls: Seq[String] = Nil
) extends Project {

object ExportResolverFormat {
implicit lazy val jsonCodec: JsonValueCodec[ExportResolverFormat] =
JsonCodecMaker.make(CodecMakerConfig
.withTransientNone(false)
.withTransientEmpty(false))
implicit lazy val StringSeqCodec: JsonValueCodec[Seq[String]] = JsonCodecMaker.make
}
def +(other: ScopedJsonProject): ScopedJsonProject =
ScopedJsonProject.monoid.orElse(this, other)

object JsonProject {
implicit val monoid: ConfigMonoid[JsonProject] = ConfigMonoid.derive
implicit lazy val jsonCodec: JsonValueCodec[JsonProject] = JsonCodecMaker.make
}

case class ExportDependencyFormat(groupId: String, artifactId: ArtifactId, version: String)
def writeTo(dir: os.Path): Unit = {
val config = WriterConfig.withIndentionStep(1)

case class ArtifactId(name: String, fullName: String)
Using(os.write.outputStream(dir / s"${scopeName.getOrElse("")}_export.json")) {
outputStream =>
writeToStream(
this,
outputStream,
config
)
}
}

object ExportDependencyFormat {
def apply(dep: Dependency): ExportDependencyFormat = {
val scalaVersionStartIndex = dep.module.name.value.lastIndexOf('_')
val shortDepName = if (scalaVersionStartIndex == -1)
dep.module.name.value
else
dep.module.name.value.take(scalaVersionStartIndex)
new ExportDependencyFormat(
dep.module.organization.value,
ArtifactId(shortDepName, dep.module.name.value),
dep.version
def sorted(using ord: Ordering[String]): ScopedJsonProject =
ScopedJsonProject(
this.scopeName,
this.sources.sorted,
this.dependencies.sorted,
this.resolvers.sorted,
this.resourcesDirs.sorted,
this.extraDecls.sorted
)
}
}

object ScopedJsonProject {
implicit val monoid: ConfigMonoid[ScopedJsonProject] = ConfigMonoid.derive
implicit lazy val jsonCodec: JsonValueCodec[ScopedJsonProject] = JsonCodecMaker.make
}

implicit val ordering: Ordering[ExportDependencyFormat] =
Ordering.by(x => x.groupId + x.artifactId.fullName)
implicit lazy val jsonCodec: JsonValueCodec[ExportDependencyFormat] = JsonCodecMaker.make
object JsonProject {
implicit val monoid: ConfigMonoid[JsonProject] = ConfigMonoid.derive
implicit lazy val jsonCodec: JsonValueCodec[JsonProject] = JsonCodecMaker.make
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import dependency.NoAttributes
import java.nio.charset.StandardCharsets
import java.nio.file.Path

import scala.build.errors.BuildException
import scala.build.internal.Constants
import scala.build.internal.Runner.frameworkName
import scala.build.options.{BuildOptions, Platform, ScalaJsOptions, ScalaNativeOptions, Scope}
Expand All @@ -23,27 +24,16 @@ final case class JsonProjectDescriptor(
) extends ProjectDescriptor {
private val charSet = StandardCharsets.UTF_8

private def sourcesSettings(mainSources: Sources, testSources: Sources): JsonProject = {
val mainSubPaths = ProjectDescriptor.sources(mainSources, charSet).map(_._1.toNIO.toString)
val testSubPaths = ProjectDescriptor.sources(testSources, charSet).map(_._1.toNIO.toString)
JsonProject(mainSources = mainSubPaths, testSources = testSubPaths)
}

private def scalaVersionSettings(options: BuildOptions): JsonProject = {
val sv = options.scalaOptions.scalaVersion
.flatMap(_.versionOpt) // FIXME If versionOpt is empty, the project is pure Java
.flatMap(_.versionOpt)
.getOrElse(Constants.defaultScalaVersion)

JsonProject(scalaVersion = Some(sv))
}

private def scalaCompilerPlugins(buildOptions: BuildOptions): JsonProject =
JsonProject(scalaCompilerPlugins =
buildOptions.scalaOptions.compilerPlugins.toSeq.map(_.value.render)
)

private def scalacOptionsSettings(buildOptions: BuildOptions): JsonProject =
JsonProject(scalacOptions = buildOptions.scalaOptions.scalacOptions.toSeq.map(_.value.value))
private def scalacOptionsSettings(options: BuildOptions): JsonProject =
JsonProject(scalacOptions = options.scalaOptions.scalacOptions.toSeq.map(_.value.value))

private def scalaJsSettings(options: ScalaJsOptions): JsonProject = {

Expand All @@ -65,121 +55,108 @@ final case class JsonProjectDescriptor(
JsonProject(scalaNativeVersion = scalaNativeVersion)
}

private def dependencySettings(
mainOptions: BuildOptions,
testOptions: BuildOptions
): JsonProject = {
def getExportDependencyFormat(
options: BuildOptions,
scope: Scope
): Seq[ExportDependencyFormat] = {
val artifacts = options.artifacts(Logger.nop, scope).toSeq

val allDeps = for {
artifact <- artifacts
detailedArtifact <- artifact.detailedArtifacts
exportDep = ExportDependencyFormat(detailedArtifact._1)
} yield exportDep

val directDeps = options.classPathOptions.extraDependencies.toSeq.map(_.value)

allDeps
.filter(exportDep =>
directDeps.exists(anyDep =>
anyDep.module.organization == exportDep.groupId &&
(anyDep.module.name == exportDep.artifactId.name
|| anyDep.module.name == exportDep.artifactId.name) &&
anyDep.version == exportDep.version
)
)
.distinct
.sorted
}

val mainDeps = getExportDependencyFormat(mainOptions, Scope.Main)
val testDeps = getExportDependencyFormat(testOptions, Scope.Test)

JsonProject(mainDeps = mainDeps, testDeps = testDeps)
private def platformSettings(options: BuildOptions): JsonProject = {
val platform = options.scalaOptions.platform.map(_.value.repr)
.orElse(Some(Platform.JVM.repr))

JsonProject(platform = platform)
}

private def sourcesSettings(sources: Sources): ScopedJsonProject =
ScopedJsonProject(sources =
ProjectDescriptor.sources(sources, charSet).map(_._1.toNIO.toString)
)

private def scalaCompilerPlugins(options: BuildOptions): ScopedJsonProject =
ScopedJsonProject(dependencies = options.scalaOptions.compilerPlugins.map(_.value.render))

private def dependencySettings(options: BuildOptions): ScopedJsonProject = {
val directDeps = options.classPathOptions.extraDependencies.toSeq
.map(_.value.render)

ScopedJsonProject(dependencies = directDeps)
}

private def repositorySettings(options: BuildOptions): JsonProject = {
private def repositorySettings(options: BuildOptions): ScopedJsonProject = {
val resolvers = options.finalRepositories
.getOrElse(Nil)
.appended(Repositories.central)
.appended(LocalRepositories.ivy2Local)
.collect {
case repo: MavenRepository =>
ExportResolverFormat(
name = "MavenRepository",
location = Some(repo.root)
) // TODO repo.authentication?
case repo: IvyRepository =>
ExportResolverFormat(
name = "IvyRepository",
location = repo.pattern.chunks.headOption.map(_.string)
) // TODO repo.authentication?
case repo: MavenRepository => repo.root
case repo: IvyRepository => s"ivy:${repo.pattern}"
}
.distinct
.sortBy(_.name)

JsonProject(resolvers = resolvers)
ScopedJsonProject(resolvers = resolvers)
}

private def customResourcesSettings(options: BuildOptions): JsonProject =
JsonProject(
resourcesDirs = options.classPathOptions.resourcesDir.map(_.toNIO.toString)
)
private def customResourcesSettings(options: BuildOptions): ScopedJsonProject =
ScopedJsonProject(resourcesDirs = options.classPathOptions.resourcesDir.map(_.toNIO.toString))

private def customJarsSettings(options: BuildOptions): JsonProject = {
private def customJarsSettings(options: BuildOptions): ScopedJsonProject = {

val customCompileOnlyJarsDecls =
options.classPathOptions.extraCompileOnlyJars.map(_.toNIO.toString)

val customJarsDecls = options.classPathOptions.extraClassPath.map(_.toNIO.toString)

JsonProject(
ScopedJsonProject(
extraDecls = customCompileOnlyJarsDecls ++ customJarsDecls
)
}

private def platformSettings(options: BuildOptions): JsonProject = {
val platform = options.scalaOptions.platform.map(_.value.repr)
.orElse(Some(Platform.JVM.repr))

JsonProject(platform = platform)
}

def `export`(
optionsMain: BuildOptions,
optionsTest: BuildOptions,
sourcesMain: Sources,
sourcesTest: Sources
): JsonProject = {
val mainJsonProject = exportScope(Scope.Main, optionsMain, sourcesMain)
val testJsonProject = exportScope(Scope.Test, optionsTest, sourcesTest)

// FIXME Put a sensible value in JsonProject.nameOpt
mainJsonProject + testJsonProject
}

def exportScope(
scope: Scope,
options: BuildOptions,
sources: Sources
): JsonProject = {
val baseSettings = JsonProject(
projectName = projectName,
mainClass = optionsMain.mainClass
mainClass = options.mainClass
)

val scopeSpecifics = Seq(
ScopedJsonProject(scopeName = Some(scope.name)),
scalaCompilerPlugins(options),
sourcesSettings(sources),
dependencySettings(options),
repositorySettings(options),
customResourcesSettings(options),
customJarsSettings(options)
)

val scopedJsonProject = scopeSpecifics.foldLeft(ScopedJsonProject())(_ + _)
.sorted

val settings = Seq(
baseSettings,
sourcesSettings(sourcesMain, sourcesTest),
scalaVersionSettings(optionsMain),
platformSettings(optionsMain),
scalacOptionsSettings(optionsMain),
scalaCompilerPlugins(optionsMain),
dependencySettings(optionsMain, optionsTest),
repositorySettings(optionsMain),
if (optionsMain.platform.value == Platform.JS) scalaJsSettings(optionsMain.scalaJsOptions)
else JsonProject(),
if (optionsMain.platform.value == Platform.Native)
scalaNativeSettings(optionsMain.scalaNativeOptions)
else JsonProject(),
customResourcesSettings(optionsMain),
customJarsSettings(optionsMain)
)
JsonProject(scopes = Seq(scopedJsonProject)),
scalaVersionSettings(options)
) ++
(if (scope == Scope.Main)
Seq(
platformSettings(options),
scalacOptionsSettings(options),
if (options.platform.value == Platform.JS)
scalaJsSettings(options.scalaJsOptions)
else if (options.platform.value == Platform.Native)
scalaNativeSettings(options.scalaNativeOptions)
else JsonProject()
)
else Nil)

settings.foldLeft(JsonProject())(_ + _)
}
Expand Down
Loading

0 comments on commit 07048ab

Please sign in to comment.