summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.sbt53
-rw-r--r--project/JarJar.scala83
-rw-r--r--project/plugins.sbt4
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ILoop.scala2
4 files changed, 133 insertions, 9 deletions
diff --git a/build.sbt b/build.sbt
index 5dc8cad01d..1bb6962977 100644
--- a/build.sbt
+++ b/build.sbt
@@ -184,7 +184,7 @@ lazy val compiler = configureAsSubproject(project)
streams.value.cacheDirectory) ++
(mappings in Compile in packageBin in LocalProject("interactive")).value ++
(mappings in Compile in packageBin in LocalProject("scaladoc")).value ++
- (mappings in Compile in packageBin in LocalProject("repl")).value,
+ (mappings in Compile in packageBin in LocalProject("repl-jline-shaded")).value,
unmanagedResourceDirectories in Compile += (baseDirectory in ThisBuild).value / "src" / project.id,
includeFilter in unmanagedResources in Compile := compilerIncludes)
.dependsOn(library, reflect)
@@ -193,10 +193,8 @@ lazy val interactive = configureAsSubproject(project)
.settings(disableDocsAndPublishingTasks: _*)
.dependsOn(compiler)
-// TODO: SI-9339 embed shaded copy of jline & its interface (see #4563)
lazy val repl = configureAsSubproject(project)
.settings(
- libraryDependencies += jlineDep,
connectInput in run := true,
outputStrategy in run := Some(StdoutOutput),
run <<= (run in Compile).partialInput(" -usejavacp") // Automatically add this so that `repl/run` works without additional arguments.
@@ -204,6 +202,47 @@ lazy val repl = configureAsSubproject(project)
.settings(disableDocsAndPublishingTasks: _*)
.dependsOn(compiler, interactive)
+lazy val replJline = configureAsSubproject(Project("repl-jline", file(".") / "src" / "repl-jline"))
+ .settings(
+ libraryDependencies += jlineDep
+ )
+ .settings(disableDocsAndPublishingTasks: _*)
+ .dependsOn(repl)
+
+lazy val replJlineShaded = Project("repl-jline-shaded", file(".") / "target" / "repl-jline-shaded-src-dummy")
+ .settings(scalaSubprojectSettings: _*)
+ .settings(disableDocsAndPublishingTasks: _*)
+ .settings(
+ // There is nothing to compile for this project. Instead we use the compile task to create
+ // shaded versions of repl-jline and jline.jar. dist/mkBin puts all of quick/repl,
+ // quick/repl-jline and quick/repl-jline-shaded on the classpath for quick/bin scripts.
+ // This is different from the ant build where all parts are combined into quick/repl, but
+ // it is cleaner because it avoids circular dependencies.
+ compile in Compile <<= (compile in Compile).dependsOn(Def.task {
+ import java.util.jar._
+ import collection.JavaConverters._
+ val inputs: Iterator[JarJar.Entry] = {
+ val repljlineClasses = (products in Compile in replJline).value.flatMap(base => Path.allSubpaths(base).map(x => (base, x._1)))
+ val jlineJAR = (dependencyClasspath in Compile).value.find(_.get(moduleID.key) == Some(jlineDep)).get.data
+ val jarFile = new JarFile(jlineJAR)
+ val jarEntries = jarFile.entries.asScala.filterNot(_.isDirectory).map(entry => JarJar.JarEntryInput(jarFile, entry))
+ def compiledClasses = repljlineClasses.iterator.map { case (base, file) => JarJar.FileInput(base, file) }
+ (jarEntries ++ compiledClasses).filter(x => x.name.endsWith(".class") || x.name.endsWith(".properties") || x.name.startsWith("META-INF/native"))
+ }
+ //println(inputs.map(_.name).mkString("\n"))
+ import JarJar.JarJarConfig._
+ val config: Seq[JarJar.JarJarConfig] = Seq(
+ Rule("org.fusesource.**", "scala.tools.fusesource_embedded.@1"),
+ Rule("jline.**", "scala.tools.jline_embedded.@1"),
+ Rule("scala.tools.nsc.interpreter.jline.**", "scala.tools.nsc.interpreter.jline_embedded.@1"),
+ Keep("scala.tools.**")
+ )
+ val outdir = (classDirectory in Compile).value
+ JarJar(inputs, outdir, config)
+ })
+ )
+ .dependsOn(replJline)
+
lazy val scaladoc = configureAsSubproject(project)
.settings(
libraryDependencies ++= Seq(scalaXmlDep, scalaParserCombinatorsDep, partestDep)
@@ -224,7 +263,7 @@ lazy val actors = configureAsSubproject(project)
lazy val forkjoin = configureAsForkOfJavaProject(project)
lazy val partestExtras = configureAsSubproject(Project("partest-extras", file(".") / "src" / "partest-extras"))
- .dependsOn(repl)
+ .dependsOn(replJlineShaded)
.settings(clearSourceAndResourceDirectories: _*)
.settings(
libraryDependencies += partestDep,
@@ -261,7 +300,7 @@ lazy val partestJavaAgent = (project in file(".") / "src" / "partest-javaagent")
)
lazy val test = project.
- dependsOn(compiler, interactive, actors, repl, scalap, partestExtras, partestJavaAgent, scaladoc).
+ dependsOn(compiler, interactive, actors, replJlineShaded, scalap, partestExtras, partestJavaAgent, scaladoc).
configs(IntegrationTest).
settings(disableDocsAndPublishingTasks: _*).
settings(commonSettings: _*).
@@ -291,7 +330,7 @@ lazy val test = project.
)
lazy val root = (project in file(".")).
- aggregate(library, forkjoin, reflect, compiler, interactive, repl,
+ aggregate(library, forkjoin, reflect, compiler, interactive, repl, replJline, replJlineShaded,
scaladoc, scalap, actors, partestExtras, junit).settings(
sources in Compile := Seq.empty,
onLoadMessage := """|*** Welcome to the sbt build definition for Scala! ***
@@ -484,7 +523,7 @@ lazy val mkBinImpl: Def.Initialize[Task[Seq[File]]] = Def.task {
def mkBin(file: String, mainCls: String, classpath: Seq[Attributed[File]]): Seq[File] =
mkQuickBin(file, mainCls, classpath) ++ mkPackBin(file, mainCls)
- mkBin("scala" , "scala.tools.nsc.MainGenericRunner", (fullClasspath in Compile in repl).value) ++
+ mkBin("scala" , "scala.tools.nsc.MainGenericRunner", (fullClasspath in Compile in replJlineShaded).value) ++
mkBin("scalac" , "scala.tools.nsc.Main", (fullClasspath in Compile in compiler).value) ++
mkBin("fsc" , "scala.tools.nsc.CompileClient", (fullClasspath in Compile in compiler).value) ++
mkBin("scaladoc" , "scala.tools.nsc.ScalaDoc", (fullClasspath in Compile in scaladoc).value) ++
diff --git a/project/JarJar.scala b/project/JarJar.scala
new file mode 100644
index 0000000000..64281f23c1
--- /dev/null
+++ b/project/JarJar.scala
@@ -0,0 +1,83 @@
+import org.pantsbuild.jarjar
+import org.pantsbuild.jarjar._
+import org.pantsbuild.jarjar.util._
+import scala.collection.JavaConverters._
+import java.util.jar._
+import java.io._
+import sbt._
+
+object JarJar {
+ sealed abstract class JarJarConfig {
+ def toPatternElement: PatternElement
+ }
+ object JarJarConfig {
+ case class Rule(pattern: String, result: String) extends JarJarConfig {
+ def toPatternElement: PatternElement = {
+ val rule = new jarjar.Rule
+ rule.setPattern(pattern)
+ rule.setResult(result)
+ rule
+ }
+ }
+ case class Keep(pattern: String) extends JarJarConfig {
+ def toPatternElement: PatternElement = {
+ val keep = new jarjar.Keep
+ keep.setPattern(pattern)
+ keep
+ }
+ }
+ }
+
+ sealed abstract class Entry {
+ def name: String
+ def time: Long
+ def data: Array[Byte]
+ }
+
+ case class JarEntryInput(jarFile: JarFile, entry: JarEntry) extends Entry {
+ def name = entry.getName
+ def time = entry.getTime
+ def data = sbt.IO.readBytes(jarFile.getInputStream(entry))
+ }
+ case class FileInput(base: File, file: File) extends Entry {
+ def name = file.relativeTo(base).get.getPath
+ def time = file.lastModified
+ def data = sbt.IO.readBytes(file)
+ }
+
+ private def newMainProcessor(patterns: java.util.List[PatternElement], verbose: Boolean, skipManifest: Boolean): JarProcessor = {
+ val cls = Class.forName("org.pantsbuild.jarjar.MainProcessor")
+ val constructor = cls.getConstructor(classOf[java.util.List[_]], java.lang.Boolean.TYPE, java.lang.Boolean.TYPE)
+ constructor.setAccessible(true)
+ constructor.newInstance(patterns, Boolean.box(verbose), Boolean.box(skipManifest)).asInstanceOf[JarProcessor]
+ }
+
+ def apply(in: Iterator[Entry], outdir: File,
+ config: Seq[JarJarConfig], verbose: Boolean = false): Seq[File] = {
+ val patterns = config.map(_.toPatternElement).asJava
+ val processor: JarProcessor = newMainProcessor(patterns, verbose, false)
+ def process(e: Entry): Option[File] = {
+ val struct = new EntryStruct()
+ struct.name = e.name
+ struct.time = e.time
+ struct.data = e.data
+ if (processor.process(struct)) {
+ if (struct.name.endsWith("/")) None
+ else {
+ val f = outdir / struct.name
+ try {
+ f.getParentFile.mkdirs()
+ sbt.IO.write(f, struct.data)
+ } catch {
+ case ex: Exception =>
+ throw new IOException(s"Failed to write ${e.name} / ${f.getParentFile} / ${f.getParentFile.exists}", ex)
+ }
+ Some(f)
+ }
+ }
+ else None
+ }
+ in.flatMap(entry => process(entry)).toList
+
+ }
+}
diff --git a/project/plugins.sbt b/project/plugins.sbt
index dc266a8db1..862887d57f 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1 +1,3 @@
-libraryDependencies += "org.apache.commons" % "commons-lang3" % "3.3.2" \ No newline at end of file
+libraryDependencies += "org.apache.commons" % "commons-lang3" % "3.3.2"
+
+libraryDependencies += "org.pantsbuild" % "jarjar" % "1.6.0"
diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
index bf7c8551e5..adac438b37 100644
--- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
@@ -876,7 +876,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
if (settings.debug) {
val readerDiags = (readerClasses, readers).zipped map {
- case (cls, Failure(e)) => s" - $cls --> " + e.getStackTrace.mkString(e.toString+"\n\t", "\n\t","\n")
+ case (cls, Failure(e)) => s" - $cls --> \n\t" + scala.tools.nsc.util.stackTraceString(e) + "\n"
case (cls, Success(_)) => s" - $cls OK"
}
Console.println(s"All InteractiveReaders tried: ${readerDiags.mkString("\n","\n","\n")}")