Skip to content

Commit

Permalink
Proper loading of 3rd party rulesets and reporters. (pinterest#577)
Browse files Browse the repository at this point in the history
Unblocks using them on on java 9+.

Signed-off-by: Yahor Berdnikau <egorr.berd@gmail.com>
  • Loading branch information
Tapchicoma authored and shashachu committed Sep 16, 2019
1 parent b63cd7f commit dd3a584
Showing 1 changed file with 48 additions and 52 deletions.
100 changes: 48 additions & 52 deletions ktlint/src/main/kotlin/com/pinterest/ktlint/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import com.pinterest.ktlint.internal.printHelpOrVersionUsage
import java.io.File
import java.io.IOException
import java.io.PrintStream
import java.net.URL
import java.net.URLClassLoader
import java.net.URLDecoder
import java.nio.file.Paths
Expand Down Expand Up @@ -223,9 +222,6 @@ class KtlintCommandLine {
}
val start = System.currentTimeMillis()

// load 3rd party ruleset(s) (if any)
if (rulesets.isNotEmpty()) loadJARs(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()) {
System.err.println("[ERROR] Cannot load custom ruleset!")
Expand All @@ -234,17 +230,9 @@ class KtlintCommandLine {
exitProcess(1)
}

// standard should go first
val ruleSetProviders =
ServiceLoader.load(RuleSetProvider::class.java)
.map { it.get().id to it }
.filter { (id) -> experimental || id != "experimental" }
.sortedBy { if (it.first == "standard") "\u0000${it.first}" else it.first }
if (debug) {
ruleSetProviders.forEach { System.err.println("[DEBUG] Discovered ruleset \"${it.first}\"") }
}
val ruleSetProviders = loadRulesets(rulesets)
val tripped = AtomicBoolean()
val reporter = loadReporter() { tripped.get() }
val reporter = loadReporter { tripped.get() }
data class LintErrorWithCorrectionInfo(val err: LintError, val corrected: Boolean)
val userData = listOfNotNull(
"android" to android.toString(),
Expand All @@ -262,7 +250,7 @@ class KtlintCommandLine {
formatFile(
fileName,
fileContent,
ruleSetProviders.map { it.second.get() },
ruleSetProviders.map { it.value.get() },
userData,
editorConfigPath,
debug
Expand All @@ -289,7 +277,7 @@ class KtlintCommandLine {
lintFile(
fileName,
fileContent,
ruleSetProviders.map { it.second.get() },
ruleSetProviders.map { it.value.get() },
userData,
editorConfigPath,
debug
Expand Down Expand Up @@ -363,20 +351,7 @@ class KtlintCommandLine {
)
}
.distinct()
val reporterLoader = ServiceLoader.load(ReporterProvider::class.java)
val reporterProviderById = reporterLoader.associateBy { it.id }
val missingReporters = tpls
.filter { !reporterProviderById.containsKey(it.id) }
.mapNotNull { it.artifact }
.distinct()
if (missingReporters.isNotEmpty()) {
loadJARs(missingReporters)
reporterLoader.reload()
reporterLoader.associateBy { it.id }
}
if (debug) {
reporterProviderById.forEach { (id) -> System.err.println("[DEBUG] Discovered reporter \"$id\"") }
}
val reporterProviderById = loadReporters(tpls.mapNotNull { it.artifact })
fun ReporterTemplate.toReporter(): Reporter {
val reporterProvider = reporterProviderById[id]
if (reporterProvider == null) {
Expand Down Expand Up @@ -478,22 +453,6 @@ class KtlintCommandLine {

private fun <T> List<T>.head(limit: Int) = if (limit == size) this else this.subList(0, limit)

// fixme: isn't going to work on JDK 9
private fun loadJARs(artifacts: List<String>) {
val jarUrls = artifacts
.map {
val artifactFile = File(expandTilde(it))
if (!artifactFile.exists()) {
System.err.println("Error: $it does not exist")
exitProcess(1)
}
artifactFile.toURI().toURL()
}

val classLoader = ClassLoader.getSystemClassLoader() as URLClassLoader
classLoader.addURLs(jarUrls)
}

private fun parseQuery(query: String) =
query.split("&")
.fold(LinkedHashMap<String, String>()) { map, s ->
Expand All @@ -508,12 +467,6 @@ class KtlintCommandLine {
map
}

private fun URLClassLoader.addURLs(url: Iterable<URL>) {
val method = URLClassLoader::class.java.getDeclaredMethod("addURL", 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 Expand Up @@ -578,4 +531,47 @@ class KtlintCommandLine {
producer.join()
}
}

private fun loadRulesets(externalRulesetsJarPaths: List<String>) = ServiceLoader
.load(
RuleSetProvider::class.java,
URLClassLoader(externalRulesetsJarPaths.toFilesURIList().toTypedArray())
)
.associateBy {
val key = it.get().id
// standard should go first
if (key == "standard") "\u0000$key" else key
}
.filterKeys { experimental || it != "experimental" }
.toSortedMap()
.also {
if (debug) {
it.forEach { entry ->
println("[DEBUG] Discovered ruleset with \"${entry.key}\" id.")
}
}
}

private fun loadReporters(externalReportersJarPaths: List<String>) = ServiceLoader
.load(
ReporterProvider::class.java,
URLClassLoader(externalReportersJarPaths.toFilesURIList().toTypedArray())
)
.associateBy { it.id }
.also {
if (debug) {
it.forEach { entry ->
println("[DEBUG] Discovered reporter with \"${entry.key}\" id.")
}
}
}

private fun List<String>.toFilesURIList() = map {
val jarFile = File(expandTilde(it))
if (!jarFile.exists()) {
println("Error: $it does not exist")
exitProcess(1)
}
jarFile.toURI().toURL()
}
}

0 comments on commit dd3a584

Please sign in to comment.