Skip to content

Commit 1d3b2f7

Browse files
committed
wip
1 parent 0c3e845 commit 1d3b2f7

File tree

3 files changed

+77
-42
lines changed

3 files changed

+77
-42
lines changed

project/Build.scala

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,23 +1212,6 @@ object Build {
12121212
},
12131213
// Assembly configuration for shading
12141214
assembly / assemblyJarName := s"scala3-repl-shaded-${version.value}.jar",
1215-
assembly / mainClass := Some("scala.tools.repl.EmbeddedReplMain"),
1216-
// Shading rules: relocate specific packages to dotty.tools.repl.shaded, except scala.*, java.*, javax.*
1217-
// Keep org.jline unshaded (needs to access native terminal libraries)
1218-
assembly / assemblyShadeRules := Seq(
1219-
ShadeRule.rename("org.jline.**" -> "org.jline.@1").inAll,
1220-
ShadeRule.rename("dotty.**" -> "dotty.tools.repl.shaded.dotty.@1").inAll,
1221-
ShadeRule.rename("org.**" -> "dotty.tools.repl.shaded.org.@1").inAll,
1222-
ShadeRule.rename("com.**" -> "dotty.tools.repl.shaded.com.@1").inAll,
1223-
ShadeRule.rename("io.**" -> "dotty.tools.repl.shaded.io.@1").inAll,
1224-
ShadeRule.rename("coursier.**" -> "dotty.tools.repl.shaded.coursier.@1").inAll,
1225-
ShadeRule.rename("coursierapi.**" -> "dotty.tools.repl.shaded.coursierapi.@1").inAll,
1226-
ShadeRule.rename("dependency.**" -> "dotty.tools.repl.shaded.dependency.@1").inAll,
1227-
ShadeRule.rename("pprint.**" -> "dotty.tools.repl.shaded.pprint.@1").inAll,
1228-
ShadeRule.rename("fansi.**" -> "dotty.tools.repl.shaded.fansi.@1").inAll,
1229-
ShadeRule.rename("sourcecode.**" -> "dotty.tools.repl.shaded.sourcecode.@1").inAll,
1230-
ShadeRule.rename("xsbti.**" -> "dotty.tools.repl.shaded.xsbti.@1").inAll,
1231-
),
12321215
// Merge strategy for assembly
12331216
assembly / assemblyMergeStrategy := {
12341217
case PathList("META-INF", xs @ _*) => xs match {
@@ -1248,6 +1231,47 @@ object Build {
12481231
name.startsWith("scala-library") || name.startsWith("scala3-library") || name.startsWith("jline")
12491232
}
12501233
},
1234+
// Post-process assembly to physically move files into dotty/tools/repl/shaded/ subfolder
1235+
assembly := {
1236+
val originalJar = assembly.value
1237+
val log = streams.value.log
1238+
1239+
log.info(s"Post-processing assembly to relocate files into shaded subfolder...")
1240+
1241+
// Create a temporary directory for processing
1242+
val tmpDir = IO.createTemporaryDirectory
1243+
try {
1244+
IO.unzip(originalJar, tmpDir)
1245+
val shadedDir = tmpDir / "dotty" / "tools" / "repl" / "shaded"
1246+
IO.createDirectory(shadedDir)
1247+
1248+
(tmpDir ** "*").get.foreach { file =>
1249+
if (file.isFile) {
1250+
val relativePath = file.relativeTo(tmpDir).get.getPath
1251+
1252+
// Skip META-INF and scala/tools/repl files
1253+
val shouldMove = !relativePath.startsWith("META-INF") &&
1254+
!relativePath.startsWith("scala/tools/repl/") &&
1255+
!relativePath.startsWith("dotty/tools/repl/shaded/")
1256+
1257+
if (shouldMove) {
1258+
val newPath = shadedDir / relativePath
1259+
IO.createDirectory(newPath.getParentFile)
1260+
IO.move(file, newPath)
1261+
}
1262+
}
1263+
}
1264+
1265+
val filesToZip = (tmpDir ** "*").get.filter(_.isFile).map { f =>
1266+
(f, f.relativeTo(tmpDir).get.getPath)
1267+
}
1268+
IO.zip(filesToZip, originalJar, None)
1269+
1270+
log.info(s"Assembly post-processing complete")
1271+
} finally IO.delete(tmpDir)
1272+
1273+
originalJar
1274+
},
12511275
// Don't publish scala3-repl-shaded - it's an internal build artifact
12521276
publish / skip := true,
12531277
publishLocal / skip := true,

repl-embedded/src/scala/tools/repl/EmbeddedReplMain.scala

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,26 @@ class UnshadingClassLoader(parent: ClassLoader) extends ClassLoader(parent) {
1616

1717
private val SHADED_PREFIX = "dotty.tools.repl.shaded."
1818

19-
// Packages that were shaded
2019
private val SHADED_PACKAGES = Seq("dotty.", "org.", "com.", "io.", "coursier.", "coursierapi.", "dependency.", "pprint.", "fansi.", "sourcecode.", "xsbti.")
2120

22-
// Packages that are NOT shaded (even though they match SHADED_PACKAGES patterns)
2321
private val UNSHADED_PACKAGES = Seq("scala.", "scala.tools.repl.", "org.jline.")
2422

25-
override def loadClass(name: String, resolve: Boolean): Class[?] = {
26-
// Check if this is a class from a package we shaded (and not already in the shaded package)
27-
// Also exclude packages that are explicitly not shaded
28-
val shouldUnshade = SHADED_PACKAGES.exists(pkg => name.startsWith(pkg)) &&
29-
!name.startsWith(SHADED_PREFIX) &&
30-
!UNSHADED_PACKAGES.exists(pkg => name.startsWith(pkg))
23+
/** Check if a class/resource name should be loaded from the shaded location */
24+
private def shouldUnshade(name: String): Boolean = {
25+
SHADED_PACKAGES.exists(pkg => name.startsWith(pkg)) &&
26+
!name.startsWith(SHADED_PREFIX) &&
27+
!UNSHADED_PACKAGES.exists(pkg => name.startsWith(pkg)) ||
28+
name.startsWith("scala.tools.asm")
29+
}
3130

32-
if (shouldUnshade) {
31+
override def loadClass(name: String, resolve: Boolean): Class[?] = {
32+
if (shouldUnshade(name)) {
3333
val loaded = findLoadedClass(name)
3434
if (loaded != null) return loaded
3535

3636
try {
37-
val is = getParent.getResourceAsStream((SHADED_PREFIX + name).replace('.', '/') + ".class")
37+
val shadedPath = (SHADED_PREFIX + name).replace('.', '/') + ".class"
38+
val is = getParent.getResourceAsStream(shadedPath)
3839

3940
if (is != null) {
4041
try {
@@ -49,9 +50,20 @@ class UnshadingClassLoader(parent: ClassLoader) extends ClassLoader(parent) {
4950
}
5051
}
5152

52-
// For everything else (scala.* and already shaded classes), delegate to parent
5353
super.loadClass(name, resolve)
5454
}
55+
56+
override def getResourceAsStream(name: String): InputStream | Null = {
57+
val nameAsDots = name.replace('/', '.')
58+
59+
if (shouldUnshade(nameAsDots)) {
60+
val shadedPath = SHADED_PREFIX.replace('.', '/') + name
61+
val shadedStream = super.getResourceAsStream(shadedPath)
62+
if (shadedStream != null) return shadedStream
63+
}
64+
65+
super.getResourceAsStream(name)
66+
}
5567
}
5668

5769
/**
@@ -64,23 +76,22 @@ object EmbeddedReplMain {
6476
def main(args: Array[String]): Unit = {
6577
val argsWithClasspath =
6678
if (args.exists(arg => arg == "-classpath" || arg == "-cp")) args
67-
else Array("-classpath", System.getProperty("java.class.path")) ++ args
79+
else Array("-classpath", System.getProperty("java.class.path")) ++ args
6880

6981
val unshadingClassLoader = new UnshadingClassLoader(getClass.getClassLoader)
70-
try {
7182

72-
val replDriverClass = unshadingClassLoader.loadClass("dotty.tools.repl.ReplDriver")
73-
val constructor = replDriverClass.getConstructors().head
83+
val replDriverClass = unshadingClassLoader.loadClass("dotty.tools.repl.ReplDriver")
84+
val constructor = replDriverClass.getConstructors().head
85+
86+
// Create the ReplDriver instance with classpath argument
87+
val replDriver = constructor.newInstance(
88+
argsWithClasspath, // settings: Array[String] (now includes -classpath)
89+
System.out, // out: PrintStream
90+
Option(getClass.getClassLoader), // classLoader: Option[ClassLoader]
91+
"" // extraPredef: String
92+
)
7493

75-
// Create the ReplDriver instance with classpath argument
76-
val replDriver = constructor.newInstance(
77-
argsWithClasspath, // settings: Array[String] (now includes -classpath)
78-
System.out, // out: PrintStream
79-
Option(getClass.getClassLoader), // classLoader: Option[ClassLoader]
80-
"" // extraPredef: String
81-
)
94+
replDriverClass.getMethod("tryRunning").invoke(replDriver)
8295

83-
replDriverClass.getMethod("tryRunning").invoke(replDriver)
84-
}finally unshadingClassLoader.close
8596
}
8697
}

repl/src/dotty/tools/repl/AbstractFileClassLoader.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader, inter
9191
try
9292
val bytes = is.readAllBytes()
9393
defineClass(name, bytes, 0, bytes.length)
94-
finally is.close()
94+
finally Option(is).foreach(_.close())
9595

9696
case _ =>
9797
try findClass(name)

0 commit comments

Comments
 (0)