mirror of https://github.com/sbt/sbt.git
Add sbt-launcher
This commit is contained in:
parent
e5a6a609e3
commit
88f54cc356
14
build.sbt
14
build.sbt
|
|
@ -382,6 +382,19 @@ lazy val `sbt-shading` = project
|
||||||
libraryDependencies += "org.anarres.jarjar" % "jarjar-core" % "1.0.0"
|
libraryDependencies += "org.anarres.jarjar" % "jarjar-core" % "1.0.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
lazy val `sbt-launcher` = project
|
||||||
|
.dependsOn(cache)
|
||||||
|
.settings(commonSettings)
|
||||||
|
.settings(packAutoSettings)
|
||||||
|
.settings(
|
||||||
|
libraryDependencies ++= Seq(
|
||||||
|
"com.github.alexarchambault" %% "case-app" % "1.1.3",
|
||||||
|
"org.scala-sbt" % "launcher-interface" % "1.0.0",
|
||||||
|
"com.typesafe" % "config" % "1.3.1"
|
||||||
|
),
|
||||||
|
packExcludeArtifactTypes += "pom"
|
||||||
|
)
|
||||||
|
|
||||||
val http4sVersion = "0.8.6"
|
val http4sVersion = "0.8.6"
|
||||||
|
|
||||||
lazy val `http-server` = project
|
lazy val `http-server` = project
|
||||||
|
|
@ -426,6 +439,7 @@ lazy val `coursier` = project.in(file("."))
|
||||||
cli,
|
cli,
|
||||||
`sbt-coursier`,
|
`sbt-coursier`,
|
||||||
`sbt-shading`,
|
`sbt-shading`,
|
||||||
|
`sbt-launcher`,
|
||||||
web,
|
web,
|
||||||
doc,
|
doc,
|
||||||
`http-server`,
|
`http-server`,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
COURSIER_VERSION=1.0.0-SNAPSHOT
|
||||||
|
|
||||||
|
"$(dirname "$0")/../coursier" bootstrap \
|
||||||
|
"io.get-coursier:sbt-launcher_2.12:$COURSIER_VERSION" \
|
||||||
|
-i launcher \
|
||||||
|
-I launcher:org.scala-sbt:launcher-interface:1.0.0 \
|
||||||
|
-o csbt \
|
||||||
|
-J -Djline.shutdownhook=false
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package coursier.sbtlauncher
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
final case class AppConfiguration(
|
||||||
|
arguments: Array[String],
|
||||||
|
baseDirectory: File,
|
||||||
|
provider: xsbti.AppProvider
|
||||||
|
) extends xsbti.AppConfiguration
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package coursier.sbtlauncher
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
final case class AppProvider(
|
||||||
|
scalaProvider: xsbti.ScalaProvider,
|
||||||
|
id: xsbti.ApplicationID,
|
||||||
|
loader: ClassLoader,
|
||||||
|
mainClass: Class[_ <: xsbti.AppMain],
|
||||||
|
createMain: () => xsbti.AppMain,
|
||||||
|
mainClasspath: Array[File],
|
||||||
|
components: xsbti.ComponentProvider
|
||||||
|
) extends xsbti.AppProvider {
|
||||||
|
def entryPoint: Class[_] =
|
||||||
|
mainClass
|
||||||
|
def newMain(): xsbti.AppMain =
|
||||||
|
createMain()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
package coursier.sbtlauncher
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
final case class ApplicationID(
|
||||||
|
groupID: String,
|
||||||
|
name: String,
|
||||||
|
version: String,
|
||||||
|
mainClass: String,
|
||||||
|
mainComponents: Array[String],
|
||||||
|
crossVersioned: Boolean,
|
||||||
|
crossVersionedValue: xsbti.CrossValue,
|
||||||
|
classpathExtra: Array[File]
|
||||||
|
) extends xsbti.ApplicationID {
|
||||||
|
|
||||||
|
assert(crossVersioned == (crossVersionedValue != xsbti.CrossValue.Disabled))
|
||||||
|
|
||||||
|
def disableCrossVersion(scalaVersion: String): ApplicationID =
|
||||||
|
crossVersionedValue match {
|
||||||
|
case xsbti.CrossValue.Disabled =>
|
||||||
|
this
|
||||||
|
case xsbti.CrossValue.Binary =>
|
||||||
|
val scalaBinaryVersion = scalaVersion.split('.').take(2).mkString(".")
|
||||||
|
copy(
|
||||||
|
crossVersioned = false,
|
||||||
|
crossVersionedValue = xsbti.CrossValue.Disabled,
|
||||||
|
version = s"${version}_$scalaBinaryVersion"
|
||||||
|
)
|
||||||
|
case xsbti.CrossValue.Full =>
|
||||||
|
copy(
|
||||||
|
crossVersioned = false,
|
||||||
|
crossVersionedValue = xsbti.CrossValue.Disabled,
|
||||||
|
version = s"${version}_$scalaVersion"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ApplicationID {
|
||||||
|
def apply(id: xsbti.ApplicationID): ApplicationID =
|
||||||
|
id match {
|
||||||
|
case id0: ApplicationID => id0
|
||||||
|
case _ =>
|
||||||
|
ApplicationID(
|
||||||
|
id.groupID(),
|
||||||
|
id.name(),
|
||||||
|
id.version(),
|
||||||
|
id.mainClass(),
|
||||||
|
id.mainComponents(),
|
||||||
|
id.crossVersionedValue() != xsbti.CrossValue.Disabled,
|
||||||
|
id.crossVersionedValue(),
|
||||||
|
id.classpathExtra()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
package coursier.sbtlauncher
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.file.{Files, StandardCopyOption}
|
||||||
|
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
|
final class ComponentProvider(cacheDir: File) extends xsbti.ComponentProvider {
|
||||||
|
|
||||||
|
private val components0 = new mutable.HashMap[String, Array[File]]
|
||||||
|
|
||||||
|
def componentLocation(id: String): File =
|
||||||
|
new File(cacheDir, id)
|
||||||
|
|
||||||
|
def component(componentId: String): Array[File] = {
|
||||||
|
val res = components0.getOrElse[Array[File]](
|
||||||
|
componentId,
|
||||||
|
{
|
||||||
|
val dir = componentLocation(componentId)
|
||||||
|
if (dir.exists())
|
||||||
|
Option(dir.listFiles()).getOrElse(Array())
|
||||||
|
else
|
||||||
|
Array()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
private def clear(componentId: String): Unit = {
|
||||||
|
|
||||||
|
def deleteRecursively(f: File): Unit =
|
||||||
|
if (f.isFile)
|
||||||
|
f.delete()
|
||||||
|
else
|
||||||
|
Option(f.listFiles())
|
||||||
|
.getOrElse(Array())
|
||||||
|
.foreach(deleteRecursively)
|
||||||
|
|
||||||
|
val dir = componentLocation(componentId)
|
||||||
|
deleteRecursively(dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def copying(componentId: String, f: File): File = {
|
||||||
|
|
||||||
|
// TODO Use some locking mechanisms here
|
||||||
|
|
||||||
|
val dir = componentLocation(componentId)
|
||||||
|
dir.mkdirs()
|
||||||
|
val dest = new File(dir, f.getName)
|
||||||
|
Files.copy(f.toPath, dest.toPath, StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
dest
|
||||||
|
}
|
||||||
|
|
||||||
|
def defineComponentNoCopy(componentId: String, components: Array[File]): Unit = {
|
||||||
|
components0 += componentId -> components.distinct
|
||||||
|
}
|
||||||
|
def defineComponent(componentId: String, components: Array[File]): Unit = {
|
||||||
|
clear(componentId)
|
||||||
|
components0 += componentId -> components.distinct.map(copying(componentId, _))
|
||||||
|
}
|
||||||
|
def addToComponent(componentId: String, components: Array[File]): Boolean = {
|
||||||
|
val previousFiles = components0.getOrElse(componentId, Array.empty[File])
|
||||||
|
val newFiles = (previousFiles ++ components.distinct.map(copying(componentId, _))).distinct
|
||||||
|
components0 += componentId -> newFiles
|
||||||
|
newFiles.length != previousFiles.length
|
||||||
|
}
|
||||||
|
|
||||||
|
def lockFile: File = new File("/component-lock")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package coursier.sbtlauncher
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.util.concurrent.{Callable, ConcurrentHashMap}
|
||||||
|
|
||||||
|
case object DummyGlobalLock extends xsbti.GlobalLock {
|
||||||
|
|
||||||
|
private val locks = new ConcurrentHashMap[File, AnyRef]
|
||||||
|
|
||||||
|
def apply[T](lockFile: File, run: Callable[T]): T =
|
||||||
|
Option(lockFile) match {
|
||||||
|
case None => run.call()
|
||||||
|
case Some(lockFile0) =>
|
||||||
|
val lock0 = new AnyRef
|
||||||
|
val lock = Option(locks.putIfAbsent(lockFile0, lock0)).getOrElse(lock0)
|
||||||
|
|
||||||
|
lock.synchronized {
|
||||||
|
run.call()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,638 @@
|
||||||
|
package coursier.sbtlauncher
|
||||||
|
|
||||||
|
import java.io.{File, OutputStreamWriter}
|
||||||
|
import java.net.{URL, URLClassLoader}
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
import coursier.Cache.Logger
|
||||||
|
import coursier._
|
||||||
|
import coursier.ivy.IvyRepository
|
||||||
|
import coursier.maven.MavenSource
|
||||||
|
|
||||||
|
import scala.annotation.tailrec
|
||||||
|
import scalaz.{-\/, \/-}
|
||||||
|
import scalaz.concurrent.Task
|
||||||
|
|
||||||
|
class Launcher(
|
||||||
|
scalaVersion: String,
|
||||||
|
componentsCache: File,
|
||||||
|
val ivyHome: File
|
||||||
|
) extends xsbti.Launcher {
|
||||||
|
|
||||||
|
val componentProvider = new ComponentProvider(componentsCache)
|
||||||
|
|
||||||
|
lazy val baseLoader = {
|
||||||
|
|
||||||
|
@tailrec
|
||||||
|
def rootLoader(cl: ClassLoader): ClassLoader =
|
||||||
|
if (cl == null)
|
||||||
|
sys.error("Cannot find base loader")
|
||||||
|
else {
|
||||||
|
val isLauncherLoader =
|
||||||
|
try {
|
||||||
|
cl
|
||||||
|
.asInstanceOf[AnyRef { def getIsolationTargets: Array[String] }]
|
||||||
|
.getIsolationTargets
|
||||||
|
.contains("launcher")
|
||||||
|
} catch {
|
||||||
|
case _: Throwable => false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLauncherLoader)
|
||||||
|
cl
|
||||||
|
else
|
||||||
|
rootLoader(cl.getParent)
|
||||||
|
}
|
||||||
|
|
||||||
|
rootLoader(Thread.currentThread().getContextClassLoader)
|
||||||
|
}
|
||||||
|
|
||||||
|
val repositoryIdPrefix = "coursier-launcher-"
|
||||||
|
|
||||||
|
val repositories = Seq(
|
||||||
|
// mmh, ID "local" seems to be required for publishLocal to be fine if we're launching sbt
|
||||||
|
"local" -> Cache.ivy2Local,
|
||||||
|
s"${repositoryIdPrefix}central" -> MavenRepository("https://repo1.maven.org/maven2", sbtAttrStub = true),
|
||||||
|
s"${repositoryIdPrefix}typesafe-ivy-releases" -> IvyRepository.parse(
|
||||||
|
"https://repo.typesafe.com/typesafe/ivy-releases/[organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]"
|
||||||
|
).leftMap(sys.error).merge,
|
||||||
|
s"${repositoryIdPrefix}sbt-plugin-releases" -> IvyRepository.parse(
|
||||||
|
"https://repo.scala-sbt.org/scalasbt/sbt-plugin-releases/[organization]/[module](/scala_[scalaVersion])(/sbt_[sbtVersion])/[revision]/[type]s/[artifact](-[classifier]).[ext]"
|
||||||
|
).leftMap(sys.error).merge
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(!repositories.groupBy(_._1).exists(_._2.lengthCompare(1) > 0))
|
||||||
|
|
||||||
|
val cachePolicies = CachePolicy.default
|
||||||
|
|
||||||
|
def fetch(logger: Option[Logger]) = {
|
||||||
|
def helper(policy: CachePolicy) =
|
||||||
|
Cache.fetch(cachePolicy = policy, logger = logger)
|
||||||
|
|
||||||
|
val f = cachePolicies.map(helper)
|
||||||
|
|
||||||
|
Fetch.from(repositories.map(_._2), f.head, f.tail: _*)
|
||||||
|
}
|
||||||
|
|
||||||
|
val keepArtifactTypes = Set("jar", "bundle")
|
||||||
|
|
||||||
|
def tasks(res: Resolution, logger: Option[Logger], classifiersOpt: Option[Seq[String]] = None) = {
|
||||||
|
val a = classifiersOpt
|
||||||
|
.fold(res.dependencyArtifacts.map(_._2))(res.dependencyClassifiersArtifacts(_).map(_._2))
|
||||||
|
|
||||||
|
val keepArtifactTypes = classifiersOpt.fold(Set("jar", "bundle"))(c => c.map(c => MavenSource.classifierExtensionDefaultTypes.getOrElse((c, "jar"), ???)).toSet)
|
||||||
|
|
||||||
|
a.collect {
|
||||||
|
case artifact if keepArtifactTypes(artifact.`type`) =>
|
||||||
|
def file(policy: CachePolicy) = Cache.file(
|
||||||
|
artifact,
|
||||||
|
cachePolicy = policy,
|
||||||
|
logger = logger
|
||||||
|
)
|
||||||
|
|
||||||
|
(file(cachePolicies.head) /: cachePolicies.tail)(_ orElse file(_))
|
||||||
|
.run
|
||||||
|
.map(artifact.->)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def isOverrideRepositories = false // ???
|
||||||
|
|
||||||
|
def bootDirectory: File = ???
|
||||||
|
|
||||||
|
def getScala(version: String): xsbti.ScalaProvider =
|
||||||
|
getScala(version, "")
|
||||||
|
|
||||||
|
def getScala(version: String, reason: String): xsbti.ScalaProvider =
|
||||||
|
getScala(version, reason, "org.scala-lang")
|
||||||
|
|
||||||
|
def getScala(version: String, reason: String, scalaOrg: String): xsbti.ScalaProvider = {
|
||||||
|
|
||||||
|
val key = (version, scalaOrg)
|
||||||
|
|
||||||
|
Option(scalaProviderCache.get(key)).getOrElse {
|
||||||
|
val prov = getScala0(version, reason, scalaOrg)
|
||||||
|
val previous = Option(scalaProviderCache.putIfAbsent(key, prov))
|
||||||
|
previous.getOrElse(prov)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val scalaProviderCache = new ConcurrentHashMap[(String, String), xsbti.ScalaProvider]
|
||||||
|
|
||||||
|
private def getScala0(version: String, reason: String, scalaOrg: String): xsbti.ScalaProvider = {
|
||||||
|
|
||||||
|
val files = getScalaFiles(version, reason, scalaOrg)
|
||||||
|
|
||||||
|
val libraryJar = files.find(_.getName.startsWith("scala-library")).getOrElse {
|
||||||
|
throw new NoSuchElementException("scala-library JAR")
|
||||||
|
}
|
||||||
|
val compilerJar = files.find(_.getName.startsWith("scala-compiler")).getOrElse {
|
||||||
|
throw new NoSuchElementException("scala-compiler JAR")
|
||||||
|
}
|
||||||
|
|
||||||
|
val scalaLoader = new URLClassLoader(files.map(_.toURI.toURL).toArray, baseLoader)
|
||||||
|
|
||||||
|
ScalaProvider(
|
||||||
|
this,
|
||||||
|
version,
|
||||||
|
scalaLoader,
|
||||||
|
files.toArray,
|
||||||
|
libraryJar,
|
||||||
|
compilerJar,
|
||||||
|
id => app(id, id.version())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def getScalaFiles(version: String, reason: String, scalaOrg: String): Seq[File] = {
|
||||||
|
|
||||||
|
val initialRes = Resolution(
|
||||||
|
Set(
|
||||||
|
Dependency(Module(scalaOrg, "scala-library"), version),
|
||||||
|
Dependency(Module(scalaOrg, "scala-compiler"), version)
|
||||||
|
),
|
||||||
|
forceVersions = Map(
|
||||||
|
Module(scalaOrg, "scala-library") -> version,
|
||||||
|
Module(scalaOrg, "scala-compiler") -> version,
|
||||||
|
Module(scalaOrg, "scala-reflect") -> version
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val logger =
|
||||||
|
Some(new TermDisplay(
|
||||||
|
new OutputStreamWriter(System.err)
|
||||||
|
))
|
||||||
|
|
||||||
|
logger.foreach(_.init {
|
||||||
|
System.err.println(s"Resolving Scala $version (organization $scalaOrg)")
|
||||||
|
})
|
||||||
|
|
||||||
|
val res = initialRes.process.run(fetch(logger)).unsafePerformSync
|
||||||
|
|
||||||
|
logger.foreach { l =>
|
||||||
|
if (l.stopDidPrintSomething())
|
||||||
|
System.err.println(s"Resolved Scala $version (organization $scalaOrg)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.errors.nonEmpty) {
|
||||||
|
Console.err.println(s"Errors:\n${res.errors.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.conflicts.nonEmpty) {
|
||||||
|
Console.err.println(s"Conflicts:\n${res.conflicts.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res.isDone) {
|
||||||
|
Console.err.println("Did not converge")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val artifactLogger =
|
||||||
|
Some(new TermDisplay(
|
||||||
|
new OutputStreamWriter(System.err)
|
||||||
|
))
|
||||||
|
|
||||||
|
artifactLogger.foreach(_.init {
|
||||||
|
System.err.println(s"Fetching Scala $version artifacts (organization $scalaOrg)")
|
||||||
|
})
|
||||||
|
|
||||||
|
val results = Task.gatherUnordered(tasks(res, artifactLogger)).unsafePerformSync
|
||||||
|
|
||||||
|
artifactLogger.foreach { l =>
|
||||||
|
if (l.stopDidPrintSomething())
|
||||||
|
System.err.println(s"Fetched Scala $version artifacts (organization $scalaOrg)")
|
||||||
|
}
|
||||||
|
|
||||||
|
val errors = results.collect { case (a, -\/(err)) => (a, err) }
|
||||||
|
val files = results.collect { case (_, \/-(f)) => f }
|
||||||
|
|
||||||
|
if (errors.nonEmpty) {
|
||||||
|
Console.err.println(s"Error downloading artifacts:\n${errors.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
files
|
||||||
|
}
|
||||||
|
|
||||||
|
def topLoader: ClassLoader = baseLoader
|
||||||
|
|
||||||
|
def appRepositories: Array[xsbti.Repository] =
|
||||||
|
repositories.map {
|
||||||
|
case (id, m: MavenRepository) =>
|
||||||
|
Repository.Maven(id, new URL(m.root))
|
||||||
|
case (id, i: IvyRepository) =>
|
||||||
|
|
||||||
|
assert(i.metadataPatternOpt.forall(_ == i.pattern))
|
||||||
|
|
||||||
|
val (base, pat) = i.pattern.string.span(c => c != '[' && c != '$' && c != '(')
|
||||||
|
|
||||||
|
assert(base.nonEmpty, i.pattern.string)
|
||||||
|
|
||||||
|
Repository.Ivy(
|
||||||
|
id,
|
||||||
|
new URL(base),
|
||||||
|
pat,
|
||||||
|
pat,
|
||||||
|
mavenCompatible = false,
|
||||||
|
skipConsistencyCheck = true, // ???
|
||||||
|
descriptorOptional = true // ???
|
||||||
|
)
|
||||||
|
}.toArray
|
||||||
|
|
||||||
|
def ivyRepositories: Array[xsbti.Repository] =
|
||||||
|
appRepositories // ???
|
||||||
|
|
||||||
|
def globalLock = DummyGlobalLock
|
||||||
|
|
||||||
|
// See https://github.com/sbt/ivy/blob/2cf13e211b2cb31f0d3b317289dca70eca3362f6/src/java/org/apache/ivy/util/ChecksumHelper.java
|
||||||
|
def checksums: Array[String] = Array("sha1", "md5")
|
||||||
|
|
||||||
|
def app(id: xsbti.ApplicationID, version: String): xsbti.AppProvider =
|
||||||
|
app(ApplicationID(id).copy(version = version))
|
||||||
|
|
||||||
|
def app(id: xsbti.ApplicationID, extra: Dependency*): xsbti.AppProvider = {
|
||||||
|
|
||||||
|
val (scalaFiles, files) = appFiles(id, extra: _*)
|
||||||
|
|
||||||
|
val scalaLoader = new URLClassLoader(scalaFiles.map(_.toURI.toURL).toArray, baseLoader)
|
||||||
|
|
||||||
|
val libraryJar = scalaFiles.find(_.getName.startsWith("scala-library")).getOrElse {
|
||||||
|
throw new NoSuchElementException("scala-library JAR")
|
||||||
|
}
|
||||||
|
val compilerJar = scalaFiles.find(_.getName.startsWith("scala-compiler")).getOrElse {
|
||||||
|
throw new NoSuchElementException("scala-compiler JAR")
|
||||||
|
}
|
||||||
|
|
||||||
|
val scalaProvider = ScalaProvider(
|
||||||
|
this,
|
||||||
|
scalaVersion,
|
||||||
|
scalaLoader,
|
||||||
|
scalaFiles.toArray,
|
||||||
|
libraryJar,
|
||||||
|
compilerJar,
|
||||||
|
id => app(id, id.version())
|
||||||
|
)
|
||||||
|
|
||||||
|
val loader = new URLClassLoader(files.filterNot(scalaFiles.toSet).map(_.toURI.toURL).toArray, scalaLoader)
|
||||||
|
val mainClass0 = loader.loadClass(id.mainClass).asSubclass(classOf[xsbti.AppMain])
|
||||||
|
|
||||||
|
AppProvider(
|
||||||
|
scalaProvider,
|
||||||
|
id,
|
||||||
|
loader,
|
||||||
|
mainClass0,
|
||||||
|
() => mainClass0.newInstance(),
|
||||||
|
files.toArray,
|
||||||
|
componentProvider
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def appFiles(id: xsbti.ApplicationID, extra: Dependency*): (Seq[File], Seq[File]) = {
|
||||||
|
|
||||||
|
val id0 = ApplicationID(id).disableCrossVersion(scalaVersion)
|
||||||
|
|
||||||
|
val initialRes = Resolution(
|
||||||
|
Set(
|
||||||
|
Dependency(Module("org.scala-lang", "scala-library"), scalaVersion),
|
||||||
|
Dependency(Module("org.scala-lang", "scala-compiler"), scalaVersion),
|
||||||
|
Dependency(Module(id0.groupID, id0.name), id0.version)
|
||||||
|
) ++ extra,
|
||||||
|
forceVersions = Map(
|
||||||
|
Module("org.scala-lang", "scala-library") -> scalaVersion,
|
||||||
|
Module("org.scala-lang", "scala-compiler") -> scalaVersion,
|
||||||
|
Module("org.scala-lang", "scala-reflect") -> scalaVersion
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val logger =
|
||||||
|
Some(new TermDisplay(
|
||||||
|
new OutputStreamWriter(System.err)
|
||||||
|
))
|
||||||
|
|
||||||
|
val extraMsg =
|
||||||
|
if (extra.isEmpty)
|
||||||
|
""
|
||||||
|
else
|
||||||
|
s" (plus ${extra.length} dependencies)"
|
||||||
|
|
||||||
|
logger.foreach(_.init {
|
||||||
|
System.err.println(s"Resolving ${id0.groupID}:${id0.name}:${id0.version}$extraMsg")
|
||||||
|
})
|
||||||
|
|
||||||
|
val res = initialRes.process.run(fetch(logger)).unsafePerformSync
|
||||||
|
|
||||||
|
logger.foreach { l =>
|
||||||
|
if (l.stopDidPrintSomething())
|
||||||
|
System.err.println(s"Resolved ${id0.groupID}:${id0.name}:${id0.version}$extraMsg")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.errors.nonEmpty) {
|
||||||
|
Console.err.println(s"Errors:\n${res.errors.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.conflicts.nonEmpty) {
|
||||||
|
Console.err.println(s"Conflicts:\n${res.conflicts.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res.isDone) {
|
||||||
|
Console.err.println("Did not converge")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val artifactLogger =
|
||||||
|
Some(new TermDisplay(
|
||||||
|
new OutputStreamWriter(System.err)
|
||||||
|
))
|
||||||
|
|
||||||
|
artifactLogger.foreach(_.init {
|
||||||
|
System.err.println(s"Fetching ${id0.groupID}:${id0.name}:${id0.version} artifacts")
|
||||||
|
})
|
||||||
|
|
||||||
|
val results = Task.gatherUnordered(tasks(res, artifactLogger)).unsafePerformSync
|
||||||
|
|
||||||
|
artifactLogger.foreach { l =>
|
||||||
|
if (l.stopDidPrintSomething())
|
||||||
|
System.err.println(s"Fetched ${id0.groupID}:${id0.name}:${id0.version} artifacts")
|
||||||
|
}
|
||||||
|
|
||||||
|
val errors = results.collect { case (a, -\/(err)) => (a, err) }
|
||||||
|
val files = results.collect { case (_, \/-(f)) => f }
|
||||||
|
|
||||||
|
if (errors.nonEmpty) {
|
||||||
|
Console.err.println(s"Error downloading artifacts:\n${errors.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val scalaSubRes = res.subset(
|
||||||
|
Set(
|
||||||
|
Dependency(Module("org.scala-lang", "scala-library"), scalaVersion),
|
||||||
|
Dependency(Module("org.scala-lang", "scala-compiler"), scalaVersion)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val scalaArtifactLogger =
|
||||||
|
Some(new TermDisplay(
|
||||||
|
new OutputStreamWriter(System.err)
|
||||||
|
))
|
||||||
|
|
||||||
|
scalaArtifactLogger.foreach(_.init {
|
||||||
|
System.err.println(s"Fetching ${id0.groupID}:${id0.name}:${id0.version} Scala artifacts")
|
||||||
|
})
|
||||||
|
|
||||||
|
val scalaResults = Task.gatherUnordered(tasks(scalaSubRes, scalaArtifactLogger)).unsafePerformSync
|
||||||
|
|
||||||
|
scalaArtifactLogger.foreach { l =>
|
||||||
|
if (l.stopDidPrintSomething())
|
||||||
|
System.err.println(s"Fetched ${id0.groupID}:${id0.name}:${id0.version} Scala artifacts")
|
||||||
|
}
|
||||||
|
|
||||||
|
val scalaErrors = scalaResults.collect { case (a, -\/(err)) => (a, err) }
|
||||||
|
val scalaFiles = scalaResults.collect { case (_, \/-(f)) => f }
|
||||||
|
|
||||||
|
if (scalaErrors.nonEmpty) {
|
||||||
|
Console.err.println(s"Error downloading artifacts:\n${scalaErrors.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
(scalaFiles, files)
|
||||||
|
}
|
||||||
|
|
||||||
|
def registerScalaComponents(scalaVersion: String = scalaVersion): Unit = {
|
||||||
|
|
||||||
|
lazy val prov = getScala(scalaVersion)
|
||||||
|
lazy val jars = prov.jars()
|
||||||
|
|
||||||
|
lazy val libraryJar = jars.find(_.getName.startsWith("scala-library")).getOrElse {
|
||||||
|
throw new NoSuchElementException("scala-library JAR")
|
||||||
|
}
|
||||||
|
lazy val compilerJar = jars.find(_.getName.startsWith("scala-compiler")).getOrElse {
|
||||||
|
throw new NoSuchElementException("scala-compiler JAR")
|
||||||
|
}
|
||||||
|
lazy val reflectJar = jars.find(_.getName.startsWith("scala-reflect")).getOrElse {
|
||||||
|
throw new NoSuchElementException("scala-reflect JAR")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (componentProvider.component("library").isEmpty)
|
||||||
|
componentProvider.defineComponentNoCopy("library", Array(libraryJar))
|
||||||
|
if (componentProvider.component("compiler").isEmpty)
|
||||||
|
componentProvider.defineComponentNoCopy("compiler", Array(compilerJar))
|
||||||
|
if (componentProvider.component("reflect").isEmpty)
|
||||||
|
componentProvider.defineComponentNoCopy("reflect", Array(reflectJar))
|
||||||
|
}
|
||||||
|
|
||||||
|
def registerSbtInterfaceComponents(sbtVersion: String): Unit = {
|
||||||
|
|
||||||
|
lazy val (interfaceJar, _) = sbtInterfaceComponentFiles(sbtVersion)
|
||||||
|
lazy val compilerInterfaceSourceJar = sbtCompilerInterfaceSrcComponentFile(sbtVersion)
|
||||||
|
|
||||||
|
if (componentProvider.component("xsbti").isEmpty)
|
||||||
|
componentProvider.defineComponentNoCopy("xsbti", Array(interfaceJar))
|
||||||
|
if (componentProvider.component("compiler-interface").isEmpty)
|
||||||
|
componentProvider.defineComponentNoCopy("compiler-interface", Array(compilerInterfaceSourceJar))
|
||||||
|
if (componentProvider.component("compiler-interface-src").isEmpty)
|
||||||
|
componentProvider.defineComponentNoCopy("compiler-interface-src", Array(compilerInterfaceSourceJar))
|
||||||
|
}
|
||||||
|
|
||||||
|
private def sbtInterfaceComponentFiles(sbtVersion: String): (File, File) = {
|
||||||
|
|
||||||
|
lazy val res = {
|
||||||
|
|
||||||
|
val initialRes = Resolution(
|
||||||
|
Set(
|
||||||
|
Dependency(Module("org.scala-sbt", "interface"), sbtVersion, transitive = false)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val logger =
|
||||||
|
Some(new TermDisplay(
|
||||||
|
new OutputStreamWriter(System.err)
|
||||||
|
))
|
||||||
|
|
||||||
|
logger.foreach(_.init {
|
||||||
|
System.err.println(s"Resolving org.scala-sbt:interface:$sbtVersion")
|
||||||
|
})
|
||||||
|
|
||||||
|
val res = initialRes.process.run(fetch(logger)).unsafePerformSync
|
||||||
|
|
||||||
|
logger.foreach { l =>
|
||||||
|
if (l.stopDidPrintSomething())
|
||||||
|
System.err.println(s"Resolved org.scala-sbt:interface:$sbtVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.errors.nonEmpty) {
|
||||||
|
Console.err.println(s"Errors:\n${res.errors.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.conflicts.nonEmpty) {
|
||||||
|
Console.err.println(s"Conflicts:\n${res.conflicts.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res.isDone) {
|
||||||
|
Console.err.println("Did not converge")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy val interfaceJar = {
|
||||||
|
|
||||||
|
val artifactLogger =
|
||||||
|
Some(new TermDisplay(
|
||||||
|
new OutputStreamWriter(System.err)
|
||||||
|
))
|
||||||
|
|
||||||
|
artifactLogger.foreach(_.init {
|
||||||
|
System.err.println(s"Fetching org.scala-sbt:interface:$sbtVersion artifacts")
|
||||||
|
})
|
||||||
|
|
||||||
|
val results = Task.gatherUnordered(tasks(res, artifactLogger)).unsafePerformSync
|
||||||
|
|
||||||
|
artifactLogger.foreach { l =>
|
||||||
|
if (l.stopDidPrintSomething())
|
||||||
|
System.err.println(s"Fetched org.scala-sbt:interface:$sbtVersion artifacts")
|
||||||
|
}
|
||||||
|
|
||||||
|
val errors = results.collect { case (a, -\/(err)) => (a, err) }
|
||||||
|
val files = results.collect { case (_, \/-(f)) => f }
|
||||||
|
|
||||||
|
if (errors.nonEmpty) {
|
||||||
|
Console.err.println(s"Error downloading artifacts:\n${errors.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
files match {
|
||||||
|
case Nil =>
|
||||||
|
throw new NoSuchElementException(s"interface JAR for sbt $sbtVersion")
|
||||||
|
case List(jar) =>
|
||||||
|
jar
|
||||||
|
case _ =>
|
||||||
|
sys.error(s"Too many interface JAR for sbt $sbtVersion: ${files.mkString(", ")}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy val compilerInterfaceSourcesJar = {
|
||||||
|
|
||||||
|
val artifactLogger =
|
||||||
|
Some(new TermDisplay(
|
||||||
|
new OutputStreamWriter(System.err)
|
||||||
|
))
|
||||||
|
|
||||||
|
artifactLogger.foreach(_.init {
|
||||||
|
System.err.println(s"Fetching org.scala-sbt:interface:$sbtVersion source artifacts")
|
||||||
|
})
|
||||||
|
|
||||||
|
val results = Task.gatherUnordered(tasks(res, artifactLogger, Some(Seq("sources")))).unsafePerformSync
|
||||||
|
|
||||||
|
artifactLogger.foreach { l =>
|
||||||
|
if (l.stopDidPrintSomething())
|
||||||
|
System.err.println(s"Fetched org.scala-sbt:interface:$sbtVersion source artifacts")
|
||||||
|
}
|
||||||
|
|
||||||
|
val errors = results.collect { case (a, -\/(err)) => (a, err) }
|
||||||
|
val files = results.collect { case (_, \/-(f)) => f }
|
||||||
|
|
||||||
|
if (errors.nonEmpty) {
|
||||||
|
Console.err.println(s"Error downloading artifacts:\n${errors.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
files match {
|
||||||
|
case Nil =>
|
||||||
|
throw new NoSuchElementException(s"compiler-interface source JAR for sbt $sbtVersion")
|
||||||
|
case List(jar) =>
|
||||||
|
jar
|
||||||
|
case _ =>
|
||||||
|
sys.error(s"Too many compiler-interface source JAR for sbt $sbtVersion: ${files.mkString(", ")}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(interfaceJar, compilerInterfaceSourcesJar)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def sbtCompilerInterfaceSrcComponentFile(sbtVersion: String): File = {
|
||||||
|
|
||||||
|
val res = {
|
||||||
|
|
||||||
|
val initialRes = Resolution(
|
||||||
|
Set(
|
||||||
|
Dependency(Module("org.scala-sbt", "compiler-interface"), sbtVersion, transitive = false)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val logger =
|
||||||
|
Some(new TermDisplay(
|
||||||
|
new OutputStreamWriter(System.err)
|
||||||
|
))
|
||||||
|
|
||||||
|
logger.foreach(_.init {
|
||||||
|
System.err.println(s"Resolving org.scala-sbt:compiler-interface:$sbtVersion")
|
||||||
|
})
|
||||||
|
|
||||||
|
val res = initialRes.process.run(fetch(logger)).unsafePerformSync
|
||||||
|
|
||||||
|
logger.foreach { l =>
|
||||||
|
if (l.stopDidPrintSomething())
|
||||||
|
System.err.println(s"Resolved org.scala-sbt:compiler-interface:$sbtVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.errors.nonEmpty) {
|
||||||
|
Console.err.println(s"Errors:\n${res.errors.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.conflicts.nonEmpty) {
|
||||||
|
Console.err.println(s"Conflicts:\n${res.conflicts.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res.isDone) {
|
||||||
|
Console.err.println("Did not converge")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
val files = {
|
||||||
|
|
||||||
|
val artifactLogger =
|
||||||
|
Some(new TermDisplay(
|
||||||
|
new OutputStreamWriter(System.err)
|
||||||
|
))
|
||||||
|
|
||||||
|
artifactLogger.foreach(_.init {
|
||||||
|
System.err.println(s"Fetching org.scala-sbt:compiler-interface:$sbtVersion source artifacts")
|
||||||
|
})
|
||||||
|
|
||||||
|
val results = Task.gatherUnordered(
|
||||||
|
tasks(res, artifactLogger, None) ++
|
||||||
|
tasks(res, artifactLogger, Some(Seq("sources")))
|
||||||
|
).unsafePerformSync
|
||||||
|
|
||||||
|
artifactLogger.foreach { l =>
|
||||||
|
if (l.stopDidPrintSomething())
|
||||||
|
System.err.println(s"Fetched org.scala-sbt:compiler-interface:$sbtVersion source artifacts")
|
||||||
|
}
|
||||||
|
|
||||||
|
val errors = results.collect { case (a, -\/(err)) => (a, err) }
|
||||||
|
|
||||||
|
if (errors.nonEmpty) {
|
||||||
|
Console.err.println(s"Error downloading artifacts:\n${errors.map(" " + _).mkString("\n")}")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
results.collect { case (_, \/-(f)) => f }
|
||||||
|
}
|
||||||
|
|
||||||
|
files.find(f => f.getName == "compiler-interface-src.jar" || f.getName == "compiler-interface-sources.jar").getOrElse {
|
||||||
|
sys.error("compiler-interface-src not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
package coursier.sbtlauncher
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.nio.file.Files
|
||||||
|
|
||||||
|
import caseapp._
|
||||||
|
import com.typesafe.config.ConfigFactory
|
||||||
|
import coursier.Dependency
|
||||||
|
|
||||||
|
final case class MainApp(
|
||||||
|
@ExtraName("org")
|
||||||
|
organization: String,
|
||||||
|
name: String,
|
||||||
|
version: String,
|
||||||
|
scalaVersion: String,
|
||||||
|
sbtVersion: String,
|
||||||
|
mainClass: String,
|
||||||
|
mainComponents: List[String],
|
||||||
|
classpathExtra: List[String],
|
||||||
|
extra: List[String]
|
||||||
|
) extends App {
|
||||||
|
|
||||||
|
val sbtPropFile = new File(sys.props("user.dir") + "/sbt.properties")
|
||||||
|
val buildPropFile = new File(sys.props("user.dir") + "/project/build.properties")
|
||||||
|
|
||||||
|
val propFileOpt = Some(sbtPropFile).filter(_.exists())
|
||||||
|
.orElse(Some(buildPropFile).filter(_.exists()))
|
||||||
|
|
||||||
|
val (org0, name0, ver0, scalaVer0, extraDeps0, mainClass0, sbtVersion0) =
|
||||||
|
propFileOpt match {
|
||||||
|
case Some(propFile) =>
|
||||||
|
// can't get ConfigFactory.parseFile to work fine here
|
||||||
|
val conf = ConfigFactory.parseString(new String(Files.readAllBytes(propFile.toPath), StandardCharsets.UTF_8))
|
||||||
|
.withFallback(ConfigFactory.defaultReference(Thread.currentThread().getContextClassLoader))
|
||||||
|
.resolve()
|
||||||
|
val sbtConfig = SbtConfig.fromConfig(conf)
|
||||||
|
|
||||||
|
(sbtConfig.organization, sbtConfig.moduleName, sbtConfig.version, sbtConfig.scalaVersion, sbtConfig.dependencies, sbtConfig.mainClass, sbtConfig.version)
|
||||||
|
case None =>
|
||||||
|
require(scalaVersion.nonEmpty, "No scala version specified")
|
||||||
|
(organization, name, version, scalaVersion, Nil, mainClass, sbtVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
val (extraParseErrors, extraModuleVersions) = coursier.util.Parse.moduleVersions(extra, scalaVersion)
|
||||||
|
|
||||||
|
if (extraParseErrors.nonEmpty) {
|
||||||
|
???
|
||||||
|
}
|
||||||
|
|
||||||
|
val extraDeps = extraModuleVersions.map {
|
||||||
|
case (mod, ver) =>
|
||||||
|
Dependency(mod, ver)
|
||||||
|
}
|
||||||
|
|
||||||
|
val launcher = new Launcher(
|
||||||
|
scalaVer0,
|
||||||
|
// FIXME Add org & moduleName in this path
|
||||||
|
new File(s"${sys.props("user.dir")}/target/sbt-components/components_scala$scalaVer0${if (sbtVersion0.isEmpty) "" else "_sbt" + sbtVersion0}"),
|
||||||
|
new File(s"${sys.props("user.dir")}/target/ivy2")
|
||||||
|
)
|
||||||
|
|
||||||
|
launcher.registerScalaComponents()
|
||||||
|
|
||||||
|
if (sbtVersion0.nonEmpty)
|
||||||
|
launcher.registerSbtInterfaceComponents(sbtVersion0)
|
||||||
|
|
||||||
|
val appId = ApplicationID(
|
||||||
|
org0,
|
||||||
|
name0,
|
||||||
|
ver0,
|
||||||
|
mainClass0,
|
||||||
|
mainComponents.toArray,
|
||||||
|
crossVersioned = false,
|
||||||
|
xsbti.CrossValue.Disabled,
|
||||||
|
classpathExtra.map(new File(_)).toArray
|
||||||
|
)
|
||||||
|
|
||||||
|
val appProvider = launcher.app(appId, extraDeps0 ++ extraDeps: _*)
|
||||||
|
|
||||||
|
val appMain = appProvider.newMain()
|
||||||
|
|
||||||
|
val appConfig = AppConfiguration(
|
||||||
|
remainingArgs.toArray,
|
||||||
|
new File(sys.props("user.dir")),
|
||||||
|
appProvider
|
||||||
|
)
|
||||||
|
|
||||||
|
val thread = Thread.currentThread()
|
||||||
|
val previousLoader = thread.getContextClassLoader
|
||||||
|
|
||||||
|
val result =
|
||||||
|
try {
|
||||||
|
thread.setContextClassLoader(appProvider.loader())
|
||||||
|
appMain.run(appConfig)
|
||||||
|
} finally {
|
||||||
|
thread.setContextClassLoader(previousLoader)
|
||||||
|
}
|
||||||
|
|
||||||
|
result match {
|
||||||
|
case _: xsbti.Continue =>
|
||||||
|
case e: xsbti.Exit =>
|
||||||
|
sys.exit(e.code())
|
||||||
|
case _: xsbti.Reboot =>
|
||||||
|
sys.error("Not able to reboot yet")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object Main extends AppOf[MainApp]
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package coursier.sbtlauncher
|
||||||
|
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
object Repository {
|
||||||
|
|
||||||
|
final case class Maven(id: String, url: URL) extends xsbti.MavenRepository
|
||||||
|
|
||||||
|
final case class Ivy(
|
||||||
|
id: String,
|
||||||
|
url: URL,
|
||||||
|
ivyPattern: String,
|
||||||
|
artifactPattern: String,
|
||||||
|
mavenCompatible: Boolean,
|
||||||
|
skipConsistencyCheck: Boolean,
|
||||||
|
descriptorOptional: Boolean
|
||||||
|
) extends xsbti.IvyRepository
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
package coursier.sbtlauncher
|
||||||
|
|
||||||
|
import com.typesafe.config.Config
|
||||||
|
import coursier.Dependency
|
||||||
|
import coursier.util.Parse
|
||||||
|
|
||||||
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
|
final case class SbtConfig(
|
||||||
|
organization: String,
|
||||||
|
moduleName: String,
|
||||||
|
version: String,
|
||||||
|
scalaVersion: String,
|
||||||
|
mainClass: String,
|
||||||
|
dependencies: Seq[Dependency]
|
||||||
|
)
|
||||||
|
|
||||||
|
object SbtConfig {
|
||||||
|
|
||||||
|
def defaultOrganization = "org.scala-sbt"
|
||||||
|
def defaultModuleName = "sbt"
|
||||||
|
def defaultMainClass = "sbt.xMain"
|
||||||
|
|
||||||
|
def fromConfig(config: Config): SbtConfig = {
|
||||||
|
|
||||||
|
val version = config.getString("sbt.version")
|
||||||
|
|
||||||
|
val scalaVersion =
|
||||||
|
if (config.hasPath("scala.version"))
|
||||||
|
config.getString("scala.version")
|
||||||
|
else if (version.startsWith("0.13."))
|
||||||
|
"2.10.6"
|
||||||
|
else if (version.startsWith("1.0."))
|
||||||
|
"2.12.1"
|
||||||
|
else
|
||||||
|
throw new Exception(s"Don't know what Scala version should be used for sbt version '$version'")
|
||||||
|
|
||||||
|
val org =
|
||||||
|
if (config.hasPath("sbt.organization"))
|
||||||
|
config.getString("sbt.organization")
|
||||||
|
else
|
||||||
|
defaultOrganization
|
||||||
|
|
||||||
|
val name =
|
||||||
|
if (config.hasPath("sbt.module-name"))
|
||||||
|
config.getString("sbt.module-name")
|
||||||
|
else
|
||||||
|
defaultModuleName
|
||||||
|
|
||||||
|
val mainClass =
|
||||||
|
if (config.hasPath("sbt.main-class"))
|
||||||
|
config.getString("sbt.main-class")
|
||||||
|
else
|
||||||
|
defaultMainClass
|
||||||
|
|
||||||
|
val scalaBinaryVersion = scalaVersion.split('.').take(2).mkString(".")
|
||||||
|
val sbtBinaryVersion = version.split('.').take(2).mkString(".")
|
||||||
|
|
||||||
|
val rawPlugins =
|
||||||
|
if (config.hasPath("plugins"))
|
||||||
|
config.getStringList("plugins").asScala
|
||||||
|
else
|
||||||
|
Nil
|
||||||
|
|
||||||
|
val (pluginErrors, pluginsModuleVersions) = Parse.moduleVersions(rawPlugins, scalaVersion)
|
||||||
|
|
||||||
|
if (pluginErrors.nonEmpty) {
|
||||||
|
???
|
||||||
|
}
|
||||||
|
|
||||||
|
val pluginDependencies =
|
||||||
|
pluginsModuleVersions.map {
|
||||||
|
case (mod, ver) =>
|
||||||
|
Dependency(
|
||||||
|
mod.copy(
|
||||||
|
attributes = mod.attributes ++ Seq(
|
||||||
|
"scalaVersion" -> scalaBinaryVersion,
|
||||||
|
"sbtVersion" -> sbtBinaryVersion
|
||||||
|
)
|
||||||
|
),
|
||||||
|
ver
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val rawDeps =
|
||||||
|
if (config.hasPath("dependencies"))
|
||||||
|
config.getStringList("dependencies").asScala
|
||||||
|
else
|
||||||
|
Nil
|
||||||
|
|
||||||
|
val (depsErrors, depsModuleVersions) = Parse.moduleVersions(rawDeps, scalaVersion)
|
||||||
|
|
||||||
|
if (depsErrors.nonEmpty) {
|
||||||
|
???
|
||||||
|
}
|
||||||
|
|
||||||
|
val dependencies =
|
||||||
|
depsModuleVersions.map {
|
||||||
|
case (mod, ver) =>
|
||||||
|
Dependency(mod, ver)
|
||||||
|
}
|
||||||
|
|
||||||
|
SbtConfig(
|
||||||
|
org,
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
scalaVersion,
|
||||||
|
mainClass,
|
||||||
|
pluginDependencies ++ dependencies
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package coursier.sbtlauncher
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
final case class ScalaProvider(
|
||||||
|
launcher: xsbti.Launcher,
|
||||||
|
version: String,
|
||||||
|
loader: ClassLoader,
|
||||||
|
jars: Array[File],
|
||||||
|
libraryJar: File,
|
||||||
|
compilerJar: File,
|
||||||
|
createApp: xsbti.ApplicationID => xsbti.AppProvider
|
||||||
|
) extends xsbti.ScalaProvider {
|
||||||
|
def app(id: xsbti.ApplicationID): xsbti.AppProvider =
|
||||||
|
createApp(id)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
sbt.version=0.13.8
|
||||||
|
|
||||||
|
plugins = [
|
||||||
|
"io.get-coursier:sbt-coursier:1.0.0-M15-1"
|
||||||
|
"org.xerial.sbt:sbt-pack:0.8.2"
|
||||||
|
"org.scala-js:sbt-scalajs:0.6.14"
|
||||||
|
"com.jsuereth:sbt-pgp:1.0.0"
|
||||||
|
"org.scoverage:sbt-scoverage:1.4.0"
|
||||||
|
"org.tpolecat:tut-plugin:0.4.8"
|
||||||
|
"com.typesafe.sbt:sbt-proguard:0.2.2"
|
||||||
|
"com.typesafe:sbt-mima-plugin:0.1.13"
|
||||||
|
]
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
"org.scala-sbt:scripted-plugin:"${sbt.version}
|
||||||
|
]
|
||||||
Loading…
Reference in New Issue