@@ -61,6 +61,7 @@ val partestDep = withoutScalaLang("org.scala-lang.modules" %% "scala-partest" %
6161val partestInterfaceDep = withoutScalaLang(" org.scala-lang.modules" %% " scala-partest-interface" % " 0.5.0" )
6262val junitDep = " junit" % " junit" % " 4.11"
6363val junitIntefaceDep = " com.novocode" % " junit-interface" % " 0.11" % " test"
64+ val asmDep = " org.scala-lang.modules" % " scala-asm" % versionProps(" scala-asm.version" )
6465val jlineDep = " jline" % " jline" % versionProps(" jline.version" )
6566val antDep = " org.apache.ant" % " ant" % " 1.9.4"
6667val scalacheckDep = withoutScalaLang(" org.scalacheck" %% " scalacheck" % " 1.11.4" )
@@ -169,17 +170,22 @@ lazy val compiler = configureAsSubproject(project)
169170 .settings(generatePropertiesFileSettings : _* )
170171 .settings(
171172 name := " scala-compiler" ,
172- libraryDependencies += antDep,
173+ libraryDependencies ++= Seq ( antDep, asmDep) ,
173174 // this a way to make sure that classes from interactive and scaladoc projects
174175 // end up in compiler jar (that's what Ant build does)
175176 // we need to use LocalProject references (with strings) to deal with mutual recursion
176177 mappings in Compile in packageBin :=
177178 (mappings in Compile in packageBin).value ++
179+ dependencyClasses(
180+ (externalDependencyClasspath in Compile ).value,
181+ modules = Set (asmDep),
182+ keep = " *.class" || " scala-asm.properties" ,
183+ streams.value.cacheDirectory) ++
178184 (mappings in Compile in packageBin in LocalProject (" interactive" )).value ++
179185 (mappings in Compile in packageBin in LocalProject (" scaladoc" )).value ++
180186 (mappings in Compile in packageBin in LocalProject (" repl" )).value,
181187 includeFilter in unmanagedResources in Compile := compilerIncludes)
182- .dependsOn(library, reflect, asm )
188+ .dependsOn(library, reflect)
183189
184190lazy val interactive = configureAsSubproject(project)
185191 .settings(disableDocsAndPublishingTasks : _* )
@@ -209,8 +215,6 @@ lazy val actors = configureAsSubproject(project)
209215
210216lazy val forkjoin = configureAsForkOfJavaProject(project)
211217
212- lazy val asm = configureAsForkOfJavaProject(project)
213-
214218lazy val partestExtras = configureAsSubproject(Project (" partest-extras" , file(" ." ) / " src" / " partest-extras" ))
215219 .dependsOn(repl)
216220 .settings(clearSourceAndResourceDirectories : _* )
@@ -231,9 +235,9 @@ lazy val junit = project.in(file("test") / "junit")
231235 )
232236
233237lazy val partestJavaAgent = (project in file(" ." ) / " src" / " partest-javaagent" ).
234- dependsOn(asm).
235238 settings(commonSettings : _* ).
236239 settings(
240+ libraryDependencies += asmDep,
237241 doc := file(" !!! NO DOCS !!!" ),
238242 publishLocal := {},
239243 publish := {},
@@ -249,13 +253,13 @@ lazy val partestJavaAgent = (project in file(".") / "src" / "partest-javaagent")
249253 )
250254
251255lazy val test = project.
252- dependsOn(compiler, interactive, actors, repl, scalap, partestExtras, partestJavaAgent, asm, scaladoc).
256+ dependsOn(compiler, interactive, actors, repl, scalap, partestExtras, partestJavaAgent, scaladoc).
253257 configs(IntegrationTest ).
254258 settings(disableDocsAndPublishingTasks : _* ).
255259 settings(commonSettings : _* ).
256260 settings(Defaults .itSettings: _* ).
257261 settings(
258- libraryDependencies ++= Seq (partestDep, scalaXmlDep, partestInterfaceDep, scalacheckDep),
262+ libraryDependencies ++= Seq (asmDep, partestDep, scalaXmlDep, partestInterfaceDep, scalacheckDep),
259263 unmanagedBase in Test := baseDirectory.value / " files" / " lib" ,
260264 unmanagedJars in Test <+= (unmanagedBase) (j => Attributed .blank(j)) map(identity),
261265 // no main sources
@@ -279,7 +283,7 @@ lazy val test = project.
279283 )
280284
281285lazy val root = (project in file(" ." )).
282- aggregate(library, forkjoin, reflect, compiler, asm, interactive, repl,
286+ aggregate(library, forkjoin, reflect, compiler, interactive, repl,
283287 scaladoc, scalap, actors, partestExtras, junit).settings(
284288 sources in Compile := Seq .empty,
285289 onLoadMessage := """ |*** Welcome to the sbt build definition for Scala! ***
@@ -310,7 +314,7 @@ def configureAsSubproject(project: Project): Project = {
310314
311315/**
312316 * Configuration for subprojects that are forks of some Java projects
313- * we depend on. At the moment there are just two: asm and forkjoin.
317+ * we depend on. At the moment there's just forkjoin.
314318 *
315319 * We do not publish artifacts for those projects but we package their
316320 * binaries in a jar of other project (compiler or library).
@@ -382,6 +386,50 @@ lazy val generateVersionPropertiesFileImpl: Def.Initialize[Task[File]] = Def.tas
382386 propFile
383387}
384388
389+ /**
390+ * Extract selected dependencies to the `cacheDirectory` and return a mapping for the content.
391+ * Heavily inspired by sbt-assembly (https://github.com/sbt/sbt-assembly/blob/0.13.0/src/main/scala/sbtassembly/Assembly.scala#L157)
392+ */
393+ def dependencyClasses (dependencies : Classpath , modules : Set [ModuleID ], keep : FileFilter , cacheDirectory : File ): Seq [(File , String )] = {
394+ val dependencyFiles : Seq [File ] = dependencies.map(_.data).toSeq
395+ val toInclude = dependencyFiles.filter(f => {
396+ val p = f.getCanonicalPath
397+ modules.exists(m => {
398+ // works for both .m2 (org/scala-lang/modules/scala-asm/5.0.3-scala-3/scala-asm-5.0.3-scala-3.jar)
399+ // and .ivy2 (org.scala-lang.modules/scala-asm/5.0.3-scala-3/bundles/scala-asm.jar)
400+ val nameParts = m.organization.split('.' ).toSet + m.name + m.revision
401+ nameParts.forall(p.contains)
402+ })
403+ })
404+ assert(toInclude.forall(sbt.classpath.ClasspathUtilities .isArchive), s " Expected JAR files as dependencies: $toInclude" )
405+
406+ val tempDir = cacheDirectory / " unpackedDependencies"
407+
408+ def sha1name (f : File ): String = bytesToSha1String(f.getCanonicalPath.getBytes(" UTF-8" ))
409+ def sha1content (f : File ): String = bytesToSha1String(IO .readBytes(f))
410+ def bytesToSha1String (bytes : Array [Byte ]): String = {
411+ val sha1 = java.security.MessageDigest .getInstance(" SHA-1" )
412+ val hash = sha1.digest(bytes)
413+ hash map {" %02x" .format(_)} mkString
414+ }
415+
416+ val jarDirs : Seq [File ] = for (jar <- toInclude) yield {
417+ val jarName = jar.getName
418+ val hash = sha1name(jar) + " _" + sha1content(jar)
419+ val jarNamePath = tempDir / (hash + " .jarName" )
420+ val dest = tempDir / hash
421+ if (! jarNamePath.exists || IO .read(jarNamePath) != jar.getCanonicalPath) {
422+ IO .delete(dest)
423+ dest.mkdir()
424+ IO .unzip(jar, dest)
425+ IO .write(jarNamePath, jar.getCanonicalPath, IO .utf8, append = false )
426+ }
427+ dest
428+ }
429+
430+ jarDirs.flatMap(dir => dir ** keep --- dir pair relativeTo(dir))
431+ }
432+
385433// Defining these settings is somewhat redundant as we also redefine settings that depend on them.
386434// However, IntelliJ's project import works better when these are set correctly.
387435def clearSourceAndResourceDirectories = Seq (Compile , Test ).flatMap(config => inConfig(config)(Seq (
0 commit comments