Skip to content

Commit 2ee9448

Browse files
committed
refactor(commands)!: Migrate VCS plugins to new plugin API
Relates to #9403. Signed-off-by: Sebastian Schuberth <[email protected]>
1 parent 494db9f commit 2ee9448

22 files changed

+113
-94
lines changed

cli/src/funTest/kotlin/AnalyzerFunTest.kt

+3-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ import org.ossreviewtoolkit.model.config.AnalyzerConfiguration
3636
import org.ossreviewtoolkit.model.config.PackageManagerConfiguration
3737
import org.ossreviewtoolkit.model.config.RepositoryConfiguration
3838
import org.ossreviewtoolkit.model.toYaml
39-
import org.ossreviewtoolkit.plugins.versioncontrolsystems.git.GitRepo
39+
import org.ossreviewtoolkit.plugins.api.PluginConfig
40+
import org.ossreviewtoolkit.plugins.versioncontrolsystems.git.GitRepoFactory
4041
import org.ossreviewtoolkit.utils.test.getAssetFile
4142
import org.ossreviewtoolkit.utils.test.matchExpectedResult
4243
import org.ossreviewtoolkit.utils.test.patchActualResult
@@ -53,7 +54,7 @@ class AnalyzerFunTest : WordSpec({
5354
)
5455
)
5556
val outputDir = tempdir().also {
56-
GitRepo.Factory().create().download(pkg, it)
57+
GitRepoFactory().create(PluginConfig()).download(pkg, it)
5758
}
5859

5960
val result = analyze(outputDir, packageManagers = emptySet()).toYaml()

downloader/build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ plugins {
2424

2525
dependencies {
2626
api(projects.model)
27+
api(projects.plugins.api)
2728

2829
implementation(projects.utils.ortUtils)
2930

downloader/src/main/kotlin/VersionControlSystem.kt

+25-21
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ import org.ossreviewtoolkit.model.Package
2929
import org.ossreviewtoolkit.model.VcsInfo
3030
import org.ossreviewtoolkit.model.VcsType
3131
import org.ossreviewtoolkit.model.config.LicenseFilePatterns
32-
import org.ossreviewtoolkit.model.config.PluginConfiguration
3332
import org.ossreviewtoolkit.model.orEmpty
33+
import org.ossreviewtoolkit.plugins.api.Plugin
34+
import org.ossreviewtoolkit.plugins.api.PluginConfig
3435
import org.ossreviewtoolkit.utils.common.CommandLineTool
3536
import org.ossreviewtoolkit.utils.common.collectMessages
3637
import org.ossreviewtoolkit.utils.common.uppercaseFirstChar
@@ -39,19 +40,22 @@ import org.ossreviewtoolkit.utils.ort.showStackTrace
3940

4041
import org.semver4j.Semver
4142

42-
abstract class VersionControlSystem {
43+
abstract class VersionControlSystem : Plugin {
4344
companion object {
45+
private fun getAllVcsByPriority(configs: Map<String, PluginConfig>) =
46+
ALL.map { (id, factory) ->
47+
val config = configs[id] ?: PluginConfig()
48+
factory.create(config)
49+
}.sortedByDescending {
50+
it.priority
51+
}
52+
4453
/**
4554
* Return the applicable VCS for the given [vcsType], or null if none is applicable.
4655
*/
47-
fun forType(vcsType: VcsType, configs: Map<String, PluginConfiguration> = emptyMap()) =
48-
ALL.values.filter { factory ->
49-
VcsType.forName(factory.type) == vcsType
50-
}.asSequence().map { factory ->
51-
val config = configs[factory.type]
52-
factory.create(options = config?.options.orEmpty(), secrets = emptyMap())
53-
}.find { vcs ->
54-
vcs.isAvailable()
56+
fun forType(vcsType: VcsType, configs: Map<String, PluginConfig> = emptyMap()) =
57+
getAllVcsByPriority(configs).find { vcs ->
58+
vcs.type == vcsType && vcs.isAvailable()
5559
}
5660

5761
/**
@@ -65,7 +69,7 @@ abstract class VersionControlSystem {
6569
* Return the applicable VCS for the given [vcsUrl], or null if none is applicable.
6670
*/
6771
@Synchronized
68-
fun forUrl(vcsUrl: String, configs: Map<String, PluginConfiguration> = emptyMap()) =
72+
fun forUrl(vcsUrl: String, configs: Map<String, PluginConfig> = emptyMap()) =
6973
// Do not use getOrPut() here as it cannot handle null values, also see
7074
// https://youtrack.jetbrains.com/issue/KT-21392.
7175
if (vcsUrl in urlToVcsMap) {
@@ -75,11 +79,8 @@ abstract class VersionControlSystem {
7579
when (val type = VcsHost.parseUrl(vcsUrl).type) {
7680
VcsType.UNKNOWN -> {
7781
// ...then eventually try to determine the type also dynamically.
78-
ALL.values.asSequence().map { factory ->
79-
val config = configs[factory.type]
80-
factory.create(options = config?.options.orEmpty(), secrets = emptyMap())
81-
}.find { vcs ->
82-
vcs.isAvailable() && vcs.isApplicableUrl(vcsUrl)
82+
getAllVcsByPriority(configs).find { vcs ->
83+
vcs.isApplicableUrl(vcsUrl) && vcs.isAvailable()
8384
}
8485
}
8586

@@ -99,16 +100,13 @@ abstract class VersionControlSystem {
99100
* Return the applicable VCS working tree for the given [vcsDirectory], or null if none is applicable.
100101
*/
101102
@Synchronized
102-
fun forDirectory(vcsDirectory: File, configs: Map<String, PluginConfiguration> = emptyMap()): WorkingTree? {
103+
fun forDirectory(vcsDirectory: File, configs: Map<String, PluginConfig> = emptyMap()): WorkingTree? {
103104
val absoluteVcsDirectory = vcsDirectory.absoluteFile
104105

105106
return if (absoluteVcsDirectory in dirToVcsMap) {
106107
dirToVcsMap[absoluteVcsDirectory]
107108
} else {
108-
ALL.values.asSequence().map { factory ->
109-
val config = configs[factory.type]
110-
factory.create(options = config?.options.orEmpty(), secrets = emptyMap())
111-
}.mapNotNull {
109+
getAllVcsByPriority(configs).mapNotNull {
112110
if (it is CommandLineTool && !it.isInPath()) {
113111
null
114112
} else {
@@ -168,6 +166,12 @@ abstract class VersionControlSystem {
168166
*/
169167
abstract val type: VcsType
170168

169+
/**
170+
* The [priority] defines the order in which VCS implementaions are to be used. A higher value means a higher
171+
* priority.
172+
*/
173+
abstract val priority: Int
174+
171175
/**
172176
* A list of symbolic names that point to the latest revision.
173177
*/

downloader/src/main/kotlin/VersionControlSystemFactory.kt

+5-16
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,17 @@
1919

2020
package org.ossreviewtoolkit.downloader
2121

22-
import java.util.ServiceLoader
23-
24-
import org.ossreviewtoolkit.utils.common.Plugin
25-
import org.ossreviewtoolkit.utils.common.TypedConfigurablePluginFactory
22+
import org.ossreviewtoolkit.plugins.api.PluginFactory
2623

2724
/**
28-
* An abstract class to be implemented by factories for [Version Control Systems][VersionControlSystem] for use with the
29-
* [ServiceLoader] mechanism. The [type] parameter denotes which VCS type is supported by this plugin, while the
30-
* [priority] parameter defines the order if more than one plugin supports the same VCS type.
25+
* A factory interface for creating [VersionControlSystem] instances.
3126
*/
32-
abstract class VersionControlSystemFactory<CONFIG>(override val type: String, val priority: Int) :
33-
TypedConfigurablePluginFactory<CONFIG, VersionControlSystem> {
27+
interface VersionControlSystemFactory : PluginFactory<VersionControlSystem> {
3428
companion object {
3529
/**
3630
* All [Version Control System factories][VersionControlSystemFactory] available in the classpath, associated by
37-
* their names, sorted by priority.
31+
* their ids.
3832
*/
39-
val ALL by lazy {
40-
Plugin.getAll<VersionControlSystemFactory<*>>()
41-
.toList()
42-
.sortedByDescending { (_, vcsFactory) -> vcsFactory.priority }
43-
.toMap()
44-
}
33+
val ALL by lazy { PluginFactory.getAll<VersionControlSystemFactory, VersionControlSystem>() }
4534
}
4635
}

downloader/src/test/kotlin/VersionControlSystemTest.kt

+4-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ import java.io.IOException
3232
import org.ossreviewtoolkit.model.Package
3333
import org.ossreviewtoolkit.model.VcsInfo
3434
import org.ossreviewtoolkit.model.VcsType
35-
import org.ossreviewtoolkit.plugins.versioncontrolsystems.git.Git
35+
import org.ossreviewtoolkit.plugins.api.PluginConfig
36+
import org.ossreviewtoolkit.plugins.versioncontrolsystems.git.GitFactory
3637

3738
class VersionControlSystemTest : WordSpec({
3839
val vcsRoot = File("..").absoluteFile.normalize()
@@ -85,7 +86,7 @@ class VersionControlSystemTest : WordSpec({
8586

8687
every { workingTree.guessRevisionName(any(), any()) } returns "v1.6.0"
8788

88-
Git.Factory().create()
89+
GitFactory().create(PluginConfig())
8990
.getRevisionCandidates(workingTree, pkg, allowMovingRevisions = true) shouldBeSuccess listOf(
9091
"v1.6.0"
9192
)
@@ -109,7 +110,7 @@ class VersionControlSystemTest : WordSpec({
109110
every { workingTree.listRemoteBranches() } returns listOf("main")
110111
every { workingTree.listRemoteTags() } returns emptyList()
111112

112-
Git.Factory().create()
113+
GitFactory().create(PluginConfig())
113114
.getRevisionCandidates(workingTree, pkg, allowMovingRevisions = true) shouldBeSuccess listOf(
114115
"master",
115116
"main"

plugins/version-control-systems/git/build.gradle.kts

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
plugins {
2121
// Apply precompiled plugins.
22-
id("ort-library-conventions")
22+
id("ort-plugin-conventions")
2323

2424
// Apply third-party plugins.
2525
alias(libs.plugins.kotlinSerialization)
@@ -43,6 +43,8 @@ dependencies {
4343
implementation(libs.kotlinx.serialization.core)
4444
implementation(libs.kotlinx.serialization.xml)
4545

46+
ksp(projects.downloader)
47+
4648
runtimeOnly(libs.jgit.ssh.apache.agent) {
4749
exclude(group = "org.apache.sshd", module = "sshd-sftp")
4850
.because("it is not required for cloning via SSH and causes issues with GraalVM native images")

plugins/version-control-systems/git/src/funTest/kotlin/GitDownloadFunTest.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import org.ossreviewtoolkit.model.Identifier
3232
import org.ossreviewtoolkit.model.Package
3333
import org.ossreviewtoolkit.model.VcsInfo
3434
import org.ossreviewtoolkit.model.VcsType
35+
import org.ossreviewtoolkit.plugins.api.PluginConfig
3536

3637
private const val PKG_VERSION = "0.4.1"
3738

@@ -43,7 +44,7 @@ private const val REPO_REV_FOR_VERSION = "371b23f37da064687518bace268d607a92ecbe
4344
private const val REPO_PATH_FOR_VERSION = "specs"
4445

4546
class GitDownloadFunTest : StringSpec() {
46-
private val git = Git.Factory().create()
47+
private val git = GitFactory().create(PluginConfig())
4748
private lateinit var outputDir: File
4849

4950
override suspend fun beforeTest(testCase: TestCase) {

plugins/version-control-systems/git/src/funTest/kotlin/GitFunTest.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import java.io.File
2929
import org.ossreviewtoolkit.downloader.WorkingTree
3030
import org.ossreviewtoolkit.model.VcsInfo
3131
import org.ossreviewtoolkit.model.VcsType
32+
import org.ossreviewtoolkit.plugins.api.PluginConfig
3233

3334
private val branches = mapOf(
3435
"main" to "6f09f276c4426c387c6663f54bbd45aea8d81dac",
@@ -44,7 +45,7 @@ private val tags = mapOf(
4445
)
4546

4647
class GitFunTest : WordSpec({
47-
val git = Git.Factory().create()
48+
val git = GitFactory().create(PluginConfig())
4849
val vcsInfo = VcsInfo(
4950
type = VcsType.GIT,
5051
url = "https://github.com/oss-review-toolkit/ort-test-data-git.git",

plugins/version-control-systems/git/src/funTest/kotlin/GitRepoDownloadFunTest.kt

+3-2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import org.ossreviewtoolkit.downloader.WorkingTree
3131
import org.ossreviewtoolkit.model.Package
3232
import org.ossreviewtoolkit.model.VcsInfo
3333
import org.ossreviewtoolkit.model.VcsType
34+
import org.ossreviewtoolkit.plugins.api.PluginConfig
3435

3536
private const val REPO_URL = "https://github.com/oss-review-toolkit/ort-test-data-git-repo?manifest=manifest.xml"
3637
private const val REPO_REV = "31588aa8f8555474e1c3c66a359ec99e4cd4b1fa"
@@ -44,7 +45,7 @@ class GitRepoDownloadFunTest : StringSpec() {
4445

4546
override suspend fun beforeSpec(spec: Spec) {
4647
outputDir = tempdir()
47-
workingTree = GitRepo().download(pkg, outputDir)
48+
workingTree = GitRepoFactory().create(PluginConfig()).download(pkg, outputDir)
4849
}
4950

5051
init {
@@ -99,7 +100,7 @@ class GitRepoDownloadFunTest : StringSpec() {
99100
"submodules/test-data-npm/long.js"
100101
).associateWith { VersionControlSystem.getPathInfo(outputDir.resolve(it)) }
101102

102-
val workingTree = GitRepo().getWorkingTree(outputDir)
103+
val workingTree = GitRepoFactory().create(PluginConfig()).getWorkingTree(outputDir)
103104
workingTree.getNested() shouldBe expectedSubmodules
104105
}
105106
}

plugins/version-control-systems/git/src/funTest/kotlin/GitWorkingTreeFunTest.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ import org.ossreviewtoolkit.downloader.VersionControlSystem
3232
import org.ossreviewtoolkit.downloader.WorkingTree
3333
import org.ossreviewtoolkit.model.VcsInfo
3434
import org.ossreviewtoolkit.model.VcsType
35+
import org.ossreviewtoolkit.plugins.api.PluginConfig
3536

3637
class GitWorkingTreeFunTest : StringSpec({
37-
val git = Git.Factory().create()
38+
val git = GitFactory().create(PluginConfig())
3839
val repoDir = tempdir()
3940
val vcsInfo = VcsInfo(
4041
type = VcsType.GIT,

plugins/version-control-systems/git/src/main/kotlin/Git.kt

+12-14
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ import org.ossreviewtoolkit.downloader.VersionControlSystemFactory
4949
import org.ossreviewtoolkit.downloader.WorkingTree
5050
import org.ossreviewtoolkit.model.VcsInfo
5151
import org.ossreviewtoolkit.model.VcsType
52+
import org.ossreviewtoolkit.plugins.api.OrtPlugin
53+
import org.ossreviewtoolkit.plugins.api.PluginDescriptor
5254
import org.ossreviewtoolkit.utils.common.CommandLineTool
53-
import org.ossreviewtoolkit.utils.common.Options
5455
import org.ossreviewtoolkit.utils.common.Os
5556
import org.ossreviewtoolkit.utils.common.collectMessages
5657
import org.ossreviewtoolkit.utils.common.safeMkdirs
@@ -61,8 +62,6 @@ import org.ossreviewtoolkit.utils.ort.showStackTrace
6162
import org.semver4j.RangesList
6263
import org.semver4j.RangesListFactory
6364

64-
const val DEFAULT_HISTORY_DEPTH = 50
65-
6665
// Replace prefixes of Git submodule repository URLs.
6766
private val REPOSITORY_URL_PREFIX_REPLACEMENTS = listOf(
6867
"git://" to "https://"
@@ -94,7 +93,15 @@ object GitCommand : CommandLineTool {
9493
* - *updateNestedSubmodules*: Whether nested submodules should be updated, or if only top-level submodules should be
9594
* considered. Defaults to true.
9695
*/
97-
class Git internal constructor(private val config: GitConfig) : VersionControlSystem() {
96+
@OrtPlugin(
97+
displayName = "Git",
98+
description = "A VCS implementation to interact with Git repositories.",
99+
factory = VersionControlSystemFactory::class
100+
)
101+
class Git(
102+
override val descriptor: PluginDescriptor,
103+
private val config: GitConfig
104+
) : VersionControlSystem() {
98105
companion object {
99106
init {
100107
// Make sure that JGit uses the exact same authentication information as ORT itself. This addresses
@@ -126,17 +133,8 @@ class Git internal constructor(private val config: GitConfig) : VersionControlSy
126133
}
127134
}
128135

129-
class Factory : VersionControlSystemFactory<GitConfig>(VcsType.GIT.toString(), 100) {
130-
override fun create(config: GitConfig) = Git(config)
131-
132-
override fun parseConfig(options: Options, secrets: Options) =
133-
GitConfig(
134-
historyDepth = options["historyDepth"]?.toIntOrNull() ?: DEFAULT_HISTORY_DEPTH,
135-
updateNestedSubmodules = options["updateNestedSubmodules"]?.toBooleanStrictOrNull() ?: true
136-
)
137-
}
138-
139136
override val type = VcsType.GIT
137+
override val priority = 100
140138
override val latestRevisionNames = listOf("HEAD", "@")
141139

142140
override fun getVersion() = GitCommand.getVersion()

plugins/version-control-systems/git/src/main/kotlin/GitConfig.kt

+9-1
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,18 @@
1919

2020
package org.ossreviewtoolkit.plugins.versioncontrolsystems.git
2121

22-
/** Git-specific [org.ossreviewtoolkit.downloader.VersionControlSystem] configuration. */
22+
import org.ossreviewtoolkit.downloader.VersionControlSystem
23+
import org.ossreviewtoolkit.plugins.api.OrtPluginOption
24+
25+
const val DEFAULT_HISTORY_DEPTH = 50
26+
27+
/** Git-specific [VersionControlSystem] configuration. */
2328
data class GitConfig(
2429
/** Depth of the commit history to fetch. */
30+
@OrtPluginOption(defaultValue = "$DEFAULT_HISTORY_DEPTH")
2531
val historyDepth: Int,
32+
2633
/** Whether nested submodules should be updated, or if only top-level submodules should be considered. */
34+
@OrtPluginOption(defaultValue = "true")
2735
val updateNestedSubmodules: Boolean
2836
)

plugins/version-control-systems/git/src/main/kotlin/GitRepo.kt

+13-8
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ import org.ossreviewtoolkit.downloader.WorkingTree
3838
import org.ossreviewtoolkit.model.VcsInfo
3939
import org.ossreviewtoolkit.model.VcsType
4040
import org.ossreviewtoolkit.model.utils.parseRepoManifestPath
41+
import org.ossreviewtoolkit.plugins.api.OrtPlugin
42+
import org.ossreviewtoolkit.plugins.api.PluginDescriptor
4143
import org.ossreviewtoolkit.utils.common.CommandLineTool
42-
import org.ossreviewtoolkit.utils.common.Options
4344
import org.ossreviewtoolkit.utils.common.Os
4445
import org.ossreviewtoolkit.utils.common.ProcessCapture
4546
import org.ossreviewtoolkit.utils.common.collectMessages
@@ -88,13 +89,17 @@ internal object GitRepoCommand : CommandLineTool {
8889
override fun displayName(): String = "GitRepo"
8990
}
9091

91-
class GitRepo internal constructor() : VersionControlSystem() {
92-
class Factory : VersionControlSystemFactory<Unit>(VcsType.GIT_REPO.toString(), 50) {
93-
override fun create(config: Unit) = GitRepo()
94-
override fun parseConfig(options: Options, secrets: Options) = Unit
95-
}
96-
92+
@OrtPlugin(
93+
displayName = "Git-Repo",
94+
description = "A VCS implementation to interact with Git-Repo repositories.",
95+
factory = VersionControlSystemFactory::class
96+
)
97+
class GitRepo(
98+
override val descriptor: PluginDescriptor,
99+
private val config: GitConfig
100+
) : VersionControlSystem() {
97101
override val type = VcsType.GIT_REPO
102+
override val priority = 50
98103
override val latestRevisionNames = listOf("HEAD", "@")
99104

100105
override fun getVersion() = GitRepoCommand.getVersion()
@@ -141,7 +146,7 @@ class GitRepo internal constructor() : VersionControlSystem() {
141146

142147
paths.forEach { path ->
143148
// Add the nested Repo project.
144-
val workingTree = Git.Factory().create().getWorkingTree(getRootPath().resolve(path))
149+
val workingTree = Git(GitFactory.descriptor, config).getWorkingTree(getRootPath().resolve(path))
145150
nested[path] = workingTree.getInfo()
146151

147152
// Add the Git submodules of the nested Repo project.

plugins/version-control-systems/git/src/main/resources/META-INF/services/org.ossreviewtoolkit.downloader.VersionControlSystemFactory

-2
This file was deleted.

0 commit comments

Comments
 (0)