ResolutionClassLoader (WIP)

This commit is contained in:
Alexandre Archambault 2015-12-30 01:34:43 +01:00
parent da98fbca2b
commit aa2a909fbd
2 changed files with 64 additions and 2 deletions

View File

@ -97,6 +97,9 @@ case class Launch(
@ExtraName("M")
@ExtraName("main")
mainClass: String,
@ExtraName("c")
@HelpMessage("Assume coursier is a dependency of the launched app, and share the coursier dependency of the launcher with it - allows the launched app to get the resolution that launched it via ResolutionClassLoader")
addCoursier: Boolean,
@Recurse
common: CommonOptions
) extends CoursierCommand {
@ -110,7 +113,29 @@ case class Launch(
}
}
val helper = new Helper(common, rawDependencies)
val extraForceVersions =
if (addCoursier)
???
else
Seq.empty[String]
val dontFilterOut =
if (addCoursier) {
val url = classOf[coursier.core.Resolution].getProtectionDomain.getCodeSource.getLocation
if (url.getProtocol == "file")
Seq(new File(url.getPath))
else {
Console.err.println(s"Cannot get the location of the JAR of coursier ($url not a file URL)")
sys.exit(255)
}
} else
Seq.empty[File]
val helper = new Helper(
common.copy(forceVersion = common.forceVersion ++ extraForceVersions),
rawDependencies
)
val files0 = helper.fetch(sources = false, javadoc = false)
@ -118,7 +143,7 @@ case class Launch(
files0.map(_.toURI.toURL).toArray,
new ClasspathFilter(
Thread.currentThread().getContextClassLoader,
Coursier.baseCp.map(new File(_)).toSet,
Coursier.baseCp.map(new File(_)).toSet -- dontFilterOut,
exclude = true
)
)

View File

@ -0,0 +1,37 @@
package coursier
import java.io.File
import java.net.URLClassLoader
import coursier.util.ClasspathFilter
class ResolutionClassLoader(
val resolution: Resolution,
val artifacts: Seq[(Dependency, Artifact, File)],
parent: ClassLoader
) extends URLClassLoader(
artifacts.map { case (_, _, f) => f.toURI.toURL }.toArray,
parent
) {
/**
* Filtered version of this `ClassLoader`, exposing only `dependencies` and their
* their transitive dependencies, and filtering out the other dependencies from
* `resolution` - for `ClassLoader` isolation.
*
* An application launched by `coursier launch -C` has `ResolutionClassLoader` set as its
* context `ClassLoader` (can be obtain with `Thread.currentThread().getContextClassLoader`).
* If it aims at doing `ClassLoader` isolation, exposing only a dependency `dep` to the isolated
* things, `filter(dep)` provides a `ClassLoader` that loaded `dep` and all its transitive
* dependencies through the same loader as the contextual one, but that "exposes" only
* `dep` and its transitive dependencies, nothing more.
*/
def filter(dependencies: Set[Dependency]): ClassLoader = {
val subRes = resolution.subset(dependencies)
val subArtifacts = subRes.dependencyArtifacts.map { case (_, a) => a }.toSet
val subFiles = artifacts.collect { case (_, a, f) if subArtifacts(a) => f }
new ClasspathFilter(this, subFiles.toSet, exclude = false)
}
}