Skip to content
This repository was archived by the owner on Sep 1, 2020. It is now read-only.

Commit 1ca2a12

Browse files
committed
Inlcude ASM as a dependency in sbt build
1 parent f7e1d7c commit 1ca2a12

File tree

1 file changed

+57
-9
lines changed

1 file changed

+57
-9
lines changed

build.sbt

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ val partestDep = withoutScalaLang("org.scala-lang.modules" %% "scala-partest" %
6161
val partestInterfaceDep = withoutScalaLang("org.scala-lang.modules" %% "scala-partest-interface" % "0.5.0")
6262
val junitDep = "junit" % "junit" % "4.11"
6363
val junitIntefaceDep = "com.novocode" % "junit-interface" % "0.11" % "test"
64+
val asmDep = "org.scala-lang.modules" % "scala-asm" % versionProps("scala-asm.version")
6465
val jlineDep = "jline" % "jline" % versionProps("jline.version")
6566
val antDep = "org.apache.ant" % "ant" % "1.9.4"
6667
val 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

184190
lazy val interactive = configureAsSubproject(project)
185191
.settings(disableDocsAndPublishingTasks: _*)
@@ -209,8 +215,6 @@ lazy val actors = configureAsSubproject(project)
209215

210216
lazy val forkjoin = configureAsForkOfJavaProject(project)
211217

212-
lazy val asm = configureAsForkOfJavaProject(project)
213-
214218
lazy 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

233237
lazy 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

251255
lazy 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

281285
lazy 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.
387435
def clearSourceAndResourceDirectories = Seq(Compile, Test).flatMap(config => inConfig(config)(Seq(

0 commit comments

Comments
 (0)