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

Commit 5f268b3

Browse files
committed
Locate library/reflect/compiler via classloader
This is more precise than scanning the urls manually, and fits better with running partest from build tools, where we resolve the class path using maven/ivy. The main mode of running partest should be to let some other tool handle dependency resolution and setting up the classpath, and partest should just take that path, and work from there. Ideally, its only knowledge about the classpath is the holy trifecta (library/reflect/compiler). The core idea is to ask the loader for the code source of a representative class: ``` val classLoader = ScalaClassLoader fromURLs (testClassPath map (_.toURI.toURL)) val canaryClass = name match { case "library" => Class.forName("scala.Unit", false, classLoader) case "reflect" => Class.forName("scala.reflect.api.Symbols", false, classLoader) case "compiler" => Class.forName("scala.tools.nsc.Main", false, classLoader) } Path(canaryClass.getProtectionDomain.getCodeSource.getLocation.getPath) ```
1 parent 4eac034 commit 5f268b3

File tree

2 files changed

+32
-13
lines changed

2 files changed

+32
-13
lines changed

src/main/scala/scala/tools/partest/nest/FileManager.scala

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ object FileManager {
9898
else difflib.DiffUtils.generateUnifiedDiff(originalName, revisedName, original.asJava, diff, 1).asScala.mkString("\n")
9999
}
100100

101+
// only used by script-based partest, not recommended for anything else
101102
def classPathFromTrifecta(library: Path, reflect: Path, compiler: Path) = {
102103
val usingJars = library.getAbsolutePath endsWith ".jar"
103104
// basedir for jars or classfiles on core classpath
@@ -129,13 +130,33 @@ object FileManager {
129130
// find library/reflect/compiler jar or subdir under build/$stage/classes/
130131
// TODO: make more robust -- for now, only matching on prefix of jar file so it works for ivy/maven-resolved versioned jars
131132
// can we use the ClassLoader to find the jar/directory that contains a characteristic class file?
132-
def fromClassPath(name: String, testClassPath: List[Path]): Path = testClassPath find (f =>
133-
(f.extension == "jar" && f.getName.startsWith(s"scala-$name"))
134-
|| (f.absolutePathSegments endsWith Seq("classes", name))
135-
) getOrElse sys.error(s"Provided compilationPath does not contain a Scala $name element.\nLooked in: ${testClassPath.mkString(":")}")
133+
def fromClassPath(name: String, testClassPath: List[Path]): Path = {
134+
// the old approach:
135+
def fallback =
136+
testClassPath find (f =>
137+
(f.extension == "jar" && f.getName.startsWith(s"scala-$name"))
138+
|| (f.absolutePathSegments endsWith Seq("classes", name))
139+
) getOrElse sys.error(s"Provided compilationPath does not contain a Scala $name element.\nLooked in: ${testClassPath.mkString(":")}")
140+
141+
// more precise:
142+
try {
143+
val classLoader = ScalaClassLoader fromURLs (testClassPath map (_.toURI.toURL))
144+
val canaryClass =
145+
name match {
146+
case "library" => Class.forName("scala.Unit", false, classLoader)
147+
case "reflect" => Class.forName("scala.reflect.api.Symbols", false, classLoader)
148+
case "compiler" => Class.forName("scala.tools.nsc.Main", false, classLoader)
149+
}
150+
val path = Path(canaryClass.getProtectionDomain.getCodeSource.getLocation.getPath)
151+
if (path.extension == "jar" || path.absolutePathSegments.endsWith(Seq("classes", name))) path
152+
else fallback
153+
} catch {
154+
case everything: Exception => fallback
155+
}
156+
}
136157
}
137158

138-
class FileManager(val testClassPath: List[Path],
159+
class FileManager private (val testClassPath: List[Path],
139160
val libraryUnderTest: Path,
140161
val reflectUnderTest: Path,
141162
val compilerUnderTest: Path) {
@@ -146,24 +167,21 @@ class FileManager(val testClassPath: List[Path],
146167
FileManager.fromClassPath("compiler", testClassPath))
147168
}
148169

149-
def this(libraryUnderTest: Path, reflectUnderTest: Path, compilerUnderTest: Path) {
170+
protected[nest] def this(libraryUnderTest: Path, reflectUnderTest: Path, compilerUnderTest: Path) {
150171
this(FileManager.classPathFromTrifecta(libraryUnderTest, reflectUnderTest, compilerUnderTest), libraryUnderTest, reflectUnderTest, compilerUnderTest)
151172
}
152173

153-
def this(testClassPath: List[Path], trifecta: (Path, Path, Path)) {
174+
protected[nest] def this(testClassPath: List[Path], trifecta: (Path, Path, Path)) {
154175
this(testClassPath, trifecta._1, trifecta._2, trifecta._3)
155176
}
156177

157178
lazy val testClassLoader = ScalaClassLoader fromURLs (testClassPath map (_.toURI.toURL))
158179

159-
// basedir for jars or classfiles on core classpath
160-
lazy val baseDir = libraryUnderTest.parent
161-
162180
def distKind = {
163181
val p = libraryUnderTest.getAbsolutePath
164182
if (p endsWith "build/quick/classes/library") "quick"
165183
else if (p endsWith "build/pack/lib/scala-library.jar") "pack"
166-
else if (p endsWith "dists/latest/lib/scala-library.jar/") "latest"
184+
else if (p endsWith "dists/latest/lib/scala-library.jar") "latest"
167185
else "installed"
168186
}
169187
}

src/main/scala/scala/tools/partest/nest/Runner.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,8 @@ class SuiteRunner(
751751
PathSettings.testSourcePath = testSourcePath
752752

753753
def banner = {
754-
def relativize(path: String) = path.replace(fileManager.baseDir.toString, "$baseDir").replace(PathSettings.srcDir.toString, "$sourceDir")
754+
val baseDir = fileManager.compilerUnderTest.parent.toString
755+
def relativize(path: String) = path.replace(baseDir, "$baseDir").replace(PathSettings.srcDir.toString, "$sourceDir")
755756
val vmBin = javaHome + fileSeparator + "bin"
756757
val vmName = "%s (build %s, %s)".format(javaVmName, javaVmVersion, javaVmInfo)
757758

@@ -762,7 +763,7 @@ class SuiteRunner(
762763
|Java binaries in: $vmBin
763764
|Java runtime is: $vmName
764765
|Java options are: ${PartestDefaults.javaOpts}
765-
|baseDir: ${fileManager.baseDir}
766+
|baseDir: $baseDir
766767
|sourceDir: ${PathSettings.srcDir}
767768
""".stripMargin
768769
// |Available processors: ${Runtime.getRuntime().availableProcessors()}

0 commit comments

Comments
 (0)