Skip to content

Commit

Permalink
Use plexus to support classpath resources
Browse files Browse the repository at this point in the history
This is inspired by the PMD maven plugin
https://github.com/apache/maven-pmd-plugin/blob/4afad98d229a6764d2ebdd246c037d1645c7cbb9/src/main/java/org/apache/maven/plugins/pmd/PmdReport.java#L394

The aim is to support classpath configuration when using this plugin in parent aggregator projects where config is in a plugin dependency
  • Loading branch information
pwhittlesea committed May 2, 2024
1 parent ff8c143 commit 4a61d87
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 44 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@
<version>${gson.version}</version>
</dependency>

<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-resources</artifactId>
<version>1.3.0</version>
</dependency>

<!-- fix maven 3.9.2+ warnings:
Plugin should declare these Maven artifacts in `provided` scope: [org.apache.maven:maven-settings-builder:3.9.2, org.apache.maven:maven-builder-support:3.9.2, org.apache.maven:maven-artifact:3.9.2, org.apache.maven:maven-resolver-provider:3.9.2, org.apache.maven:maven-plugin-api:3.9.2, org.apache.maven:maven-core:3.9.2, org.apache.maven:maven-repository-metadata:3.9.2, org.apache.maven:maven-settings:3.9.2, org.apache.maven:maven-model-builder:3.9.2, org.apache.maven:maven-model:3.9.2]
-->
Expand Down
38 changes: 31 additions & 7 deletions src/main/java/biz/lermitage/oga/CheckMojo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ import biz.lermitage.oga.cfg.IgnoreList
import biz.lermitage.oga.util.DefinitionsTools
import biz.lermitage.oga.util.IOTools
import biz.lermitage.oga.util.IgnoreListTools
import org.apache.maven.execution.MavenSession
import org.apache.maven.plugin.AbstractMojo
import org.apache.maven.plugin.MojoExecutionException
import org.apache.maven.plugins.annotations.Component
import org.apache.maven.plugins.annotations.Mojo
import org.apache.maven.plugins.annotations.Parameter
import org.apache.maven.project.MavenProject
import org.codehaus.plexus.resource.ResourceManager
import org.codehaus.plexus.resource.loader.FileResourceLoader
import org.codehaus.plexus.util.xml.pull.XmlPullParserException
import java.io.File
import java.io.IOException
import java.net.URL
import java.util.Optional

/**
Expand Down Expand Up @@ -60,6 +62,12 @@ class CheckMojo : AbstractMojo() {
@Parameter(property = "project", readonly = true)
var project: MavenProject? = null

@Parameter(defaultValue = "\${session}", required = true, readonly = true)
private var session: MavenSession? = null

@Component
private val locator: ResourceManager? = null

/**
* Execute goal.
*/
Expand All @@ -72,22 +80,25 @@ class CheckMojo : AbstractMojo() {
return
}

setUpLocator(locator!!)

try {
val allDefinitions = mutableListOf(DefinitionsTools.loadDefinitionsFromUrl(ogDefinitionsUrl ?: DEFINITIONS_URL, log))
val allDefinitions = mutableListOf(DefinitionsTools.loadDefinitionsFromUrl(ogDefinitionsUrl ?: DEFINITIONS_URL, log, locator))
if (!ignoreUnofficialMigrations) {
allDefinitions += DefinitionsTools.loadDefinitionsFromUrl(ogUnofficialDefinitionsUrl ?: UNOFFICIAL_DEFINITIONS_URL, log)
allDefinitions += DefinitionsTools.loadDefinitionsFromUrl(ogUnofficialDefinitionsUrl ?: UNOFFICIAL_DEFINITIONS_URL, log, locator)
}

// Load additional definitions if defined
additionalDefinitionFiles!!.forEach { allDefinitions += DefinitionsTools.loadDefinitionsFromUrl(it, log) }
additionalDefinitionFiles!!.forEach { allDefinitions += DefinitionsTools.loadDefinitionsFromUrl(it, log, locator) }

var ignoreList = Optional.empty<IgnoreList>()
if (!ignoreListFile.isNullOrEmpty()) {
log.info("Loading ignore list from file $ignoreListFile")
ignoreList = Optional.of(IOTools.readIgnoreList(File(ignoreListFile)))
// TODO given that we now support loading a file from classpath, file and URL we could consolidate configuration to definitions and suppressions (like PMD/Checkstyle)
ignoreList = Optional.of(IOTools.readIgnoreList(ignoreListFile, locator, log))
} else if (!ignoreListUrl.isNullOrEmpty()) {
log.info("Loading ignore list from url $ignoreListUrl")
ignoreList = Optional.of(IOTools.readIgnoreList(URL(ignoreListUrl)))
ignoreList = Optional.of(IOTools.readIgnoreList(ignoreListUrl, locator, log))
}

val dependencies = DefinitionsTools.mapDependenciesToOgaDependencies(project!!.dependencies!!)
Expand Down Expand Up @@ -162,6 +173,19 @@ class CheckMojo : AbstractMojo() {
}
}

private fun setUpLocator(locator: ResourceManager) {
val searchPaths = listOf(
// 0. The locator will read from classpath and URL locations
// 1. in the directory of the current project's pom file - note: extensions might replace the pom file on the fly
project!!.file.parentFile.absolutePath,
// 2. in the current project's directory
project!!.basedir.absolutePath,
// 3. in the base directory - that's the directory of the initial pom requested to build, e.g. the root of a multi-module build
session!!.request!!.baseDirectory
)
searchPaths.forEach { searchPath -> locator.addSearchPath(FileResourceLoader.ID, searchPath) }
}

companion object {
private const val GITHUB_PRJ_RAW_URL = "https://raw.githubusercontent.com/jonathanlermitage/oga-maven-plugin/master/"
private const val DEFINITIONS_URL = GITHUB_PRJ_RAW_URL + "uc/og-definitions.json"
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/biz/lermitage/oga/util/DefinitionsTools.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import biz.lermitage.oga.Dependency
import biz.lermitage.oga.DependencyType
import biz.lermitage.oga.cfg.Definitions
import org.apache.maven.plugin.logging.Log
import org.codehaus.plexus.resource.ResourceManager

/**
* Definitions tools.
Expand All @@ -12,9 +13,9 @@ import org.apache.maven.plugin.logging.Log
*/
object DefinitionsTools {

fun loadDefinitionsFromUrl(url: String, log: Log): Definitions {
fun loadDefinitionsFromUrl(url: String, log: Log, locator: ResourceManager): Definitions {
log.info("Loading definitions from $url")
val definitions = IOTools.readDefinitions(url)
val definitions = IOTools.readDefinitions(url, locator, log)

val nbDefinitions = definitions.migration?.size
var welcomeMsg = "Loaded $nbDefinitions definitions from '$url'"
Expand Down
60 changes: 25 additions & 35 deletions src/main/java/biz/lermitage/oga/util/IOTools.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import biz.lermitage.oga.cfg.Definitions
import biz.lermitage.oga.cfg.IgnoreList
import com.google.gson.GsonBuilder
import org.apache.commons.io.FileUtils
import java.io.BufferedReader
import org.apache.maven.plugin.MojoExecutionException
import org.apache.maven.plugin.logging.Log
import org.codehaus.plexus.resource.ResourceManager
import org.codehaus.plexus.resource.loader.FileResourceCreationException
import org.codehaus.plexus.resource.loader.ResourceNotFoundException
import java.io.File
import java.io.IOException
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL
import java.util.regex.Pattern
import java.nio.file.Files
import kotlin.io.path.pathString

/**
* IO tools.
Expand All @@ -22,45 +24,33 @@ object IOTools {
private val GSON = GsonBuilder().create()

@Throws(IOException::class)
fun readDefinitions(url: String): Definitions {
return readFromLocation(url, Definitions::class.java)
fun readDefinitions(location: String, locator: ResourceManager, log: Log): Definitions {
return readFromLocation(location, locator, log, Definitions::class.java)
}

@Throws(IOException::class)
fun readIgnoreList(url: URL): IgnoreList {
val ignoreListAsString = readContent(url)
return GSON.fromJson(ignoreListAsString, IgnoreList::class.java)
fun readIgnoreList(location: String, locator: ResourceManager, log: Log): IgnoreList {
return readFromLocation(location, locator, log, IgnoreList::class.java)
}

@Throws(IOException::class)
fun readIgnoreList(file: File): IgnoreList {
val ignoreListAsString = FileUtils.readFileToString(file, Charsets.UTF_8)
return GSON.fromJson(ignoreListAsString, IgnoreList::class.java)
}

@Throws(IOException::class)
private fun <T> readFromLocation(location: String, clazz: Class<T>): T {
val uriRx: Pattern = Pattern.compile("^https?:.*", Pattern.CASE_INSENSITIVE)
val asString = if (uriRx.matcher(location).matches()) {
readContent(URL(location))
} else {
FileUtils.readFileToString(File(location), Charsets.UTF_8)
}
private fun <T> readFromLocation(location: String, locator: ResourceManager, log: Log, clazz: Class<T>): T {
val file = locationToFile(location, locator, log)
val asString = FileUtils.readFileToString(file, Charsets.UTF_8)
return GSON.fromJson(asString, clazz)
}

@Throws(IOException::class)
private fun readContent(url: URL): String {
val content = StringBuilder()
val conn = url.openConnection() as HttpURLConnection
conn.requestMethod = "GET"
BufferedReader(InputStreamReader(conn.inputStream)).use { rd ->
var line: String? = rd.readLine()
while (line != null) {
content.append(line)
line = rd.readLine()
}
@Throws(MojoExecutionException::class)
private fun locationToFile(location: String, locator: ResourceManager, log: Log): File {
try {
val resolvedLocation = Files.createTempFile("oga-", ".json")
log.debug("Resolved file from '$location' to '$resolvedLocation'")
return locator.getResourceAsFile(location, resolvedLocation.pathString)
?: throw MojoExecutionException("Could not resolve $location")
} catch (e: ResourceNotFoundException) {
throw MojoExecutionException(e.message, e)
} catch (e: FileResourceCreationException) {
throw MojoExecutionException(e.message, e)
}
return content.toString()
}
}

0 comments on commit 4a61d87

Please sign in to comment.