Skip to content

Commit

Permalink
Create a new classloader instead of manipulating the system one
Browse files Browse the repository at this point in the history
  • Loading branch information
Markus Schwarz authored and jacquerie committed Jul 5, 2019
1 parent ba513d7 commit 90d98b0
Showing 1 changed file with 53 additions and 60 deletions.
113 changes: 53 additions & 60 deletions ktlint/src/main/kotlin/com/pinterest/ktlint/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.pinterest.ktlint.internal.printHelpOrVersionUsage
import java.io.File
import java.io.IOException
import java.io.PrintStream
import java.net.URLClassLoader
import java.net.URLDecoder
import java.nio.file.Paths
import java.util.ArrayList
Expand Down Expand Up @@ -252,9 +253,7 @@ class KtlintCommandLine {

// load 3rd party ruleset(s) (if any)
val dependencyResolver = lazy(LazyThreadSafetyMode.NONE) { buildDependencyResolver() }
if (!rulesets.isEmpty()) {
loadJARs(dependencyResolver, rulesets)
}
val rulesetClassLoader = getServiceClassloader(dependencyResolver, rulesets)

// Detect custom rulesets that have not been moved to the new package
if (ServiceLoader.load(com.github.shyiko.ktlint.core.RuleSetProvider::class.java).any()) {
Expand All @@ -266,7 +265,7 @@ class KtlintCommandLine {

// standard should go first
val ruleSetProviders =
ServiceLoader.load(RuleSetProvider::class.java)
ServiceLoader.load(RuleSetProvider::class.java, rulesetClassLoader)
.map { it.get().id to it }
.filter { (id) -> experimental || id != "experimental" }
.sortedBy { if (it.first == "standard") "\u0000${it.first}" else it.first }
Expand Down Expand Up @@ -385,9 +384,8 @@ class KtlintCommandLine {
val reporterProviderById = reporterLoader.associate { it.id to it }.let { map ->
val missingReporters = tpls.filter { !map.containsKey(it.id) }.mapNotNull { it.artifact }.distinct()
if (!missingReporters.isEmpty()) {
loadJARs(dependencyResolver, missingReporters)
reporterLoader.reload()
reporterLoader.associate { it.id to it }
val reporterClassloader = getServiceClassloader(dependencyResolver, missingReporters)
ServiceLoader.load(ReporterProvider::class.java, reporterClassloader).associate { it.id to it }
} else map
}
if (debug) {
Expand Down Expand Up @@ -545,54 +543,55 @@ class KtlintCommandLine {
return dependencyResolver
}

// fixme: isn't going to work on JDK 9
private fun loadJARs(dependencyResolver: Lazy<MavenDependencyResolver>, artifacts: List<String>) {
(ClassLoader.getSystemClassLoader() as java.net.URLClassLoader)
.addURLs(
artifacts.flatMap { artifact ->
if (debug) {
System.err.println("[DEBUG] Resolving $artifact")
}
val result = try {
dependencyResolver.value.resolve(DefaultArtifact(artifact)).map { it.toURI().toURL() }
} catch (e: IllegalArgumentException) {
val file = File(expandTilde(artifact))
if (!file.exists()) {
System.err.println("Error: $artifact does not exist")
exitProcess(1)
}
listOf(file.toURI().toURL())
} catch (e: RepositoryException) {
if (debug) {
e.printStackTrace()
}
System.err.println("Error: $artifact wasn't found")
exitProcess(1)
}
if (debug) {
result.forEach { url -> System.err.println("[DEBUG] Loading $url") }
}
if (!skipClasspathCheck) {
if (result.any { it.toString().substringAfterLast("/").startsWith("ktlint-core-") }) {
System.err.println(
"\"$artifact\" appears to have a runtime/compile dependency on \"ktlint-core\".\n" +
"Please inform the author that \"com.pinterest:ktlint*\" should be marked " +
"compileOnly (Gradle) / provided (Maven).\n" +
"(to suppress this warning use --skip-classpath-check)"
)
}
if (result.any { it.toString().substringAfterLast("/").startsWith("kotlin-stdlib-") }) {
System.err.println(
"\"$artifact\" appears to have a runtime/compile dependency on \"kotlin-stdlib\".\n" +
"Please inform the author that \"org.jetbrains.kotlin:kotlin-stdlib*\" should be marked " +
"compileOnly (Gradle) / provided (Maven).\n" +
"(to suppress this warning use --skip-classpath-check)"
)
}
}
result
private fun getServiceClassloader(dependencyResolver: Lazy<MavenDependencyResolver>, artifacts: List<String>): ClassLoader {
val parentClassloader = KtlintCommandLine::class.java.classLoader
if (artifacts.isEmpty()) {
return parentClassloader
}
val artifactUrls = artifacts.flatMap { artifact ->
if (debug) {
System.err.println("[DEBUG] Resolving $artifact")
}
val result = try {
dependencyResolver.value.resolve(DefaultArtifact(artifact)).map { it.toURI().toURL() }
} catch (e: IllegalArgumentException) {
val file = File(expandTilde(artifact))
if (!file.exists()) {
System.err.println("Error: $artifact does not exist")
exitProcess(1)
}
)
listOf(file.toURI().toURL())
} catch (e: RepositoryException) {
if (debug) {
e.printStackTrace()
}
System.err.println("Error: $artifact wasn't found")
exitProcess(1)
}
if (debug) {
result.forEach { url -> System.err.println("[DEBUG] Loading $url") }
}
if (!skipClasspathCheck) {
if (result.any { it.toString().substringAfterLast("/").startsWith("ktlint-core-") }) {
System.err.println(
"\"$artifact\" appears to have a runtime/compile dependency on \"ktlint-core\".\n" +
"Please inform the author that \"com.github.shyiko:ktlint*\" should be marked " +
"compileOnly (Gradle) / provided (Maven).\n" +
"(to suppress this warning use --skip-classpath-check)"
)
}
if (result.any { it.toString().substringAfterLast("/").startsWith("kotlin-stdlib-") }) {
System.err.println(
"\"$artifact\" appears to have a runtime/compile dependency on \"kotlin-stdlib\".\n" +
"Please inform the author that \"org.jetbrains.kotlin:kotlin-stdlib*\" should be marked " +
"compileOnly (Gradle) / provided (Maven).\n" +
"(to suppress this warning use --skip-classpath-check)"
)
}
}
result
}
return URLClassLoader(artifactUrls.toTypedArray(), parentClassloader)
}

private fun parseQuery(query: String) =
Expand All @@ -609,12 +608,6 @@ class KtlintCommandLine {
map
}

private fun java.net.URLClassLoader.addURLs(url: Iterable<java.net.URL>) {
val method = java.net.URLClassLoader::class.java.getDeclaredMethod("addURL", java.net.URL::class.java)
method.isAccessible = true
url.forEach { method.invoke(this, it) }
}

private fun File.mkdirsOrFail() {
if (!mkdirs() && !isDirectory) {
throw IOException("Unable to create \"${this}\" directory")
Expand Down

0 comments on commit 90d98b0

Please sign in to comment.