Skip to content

Commit c542022

Browse files
committed
feat(analyzer)!: Migrate package managers to new plugin API
As part of this refactoring the `analzyerConfig` argument is moved from the constructor to the `beforeResolution` and `resolveDependencies` functions. This was not done in a separate commit because it would have required a lot of code changes that would have been removed again as part of the migration. Resolves #9403. Signed-off-by: Martin Nonnenmacher <[email protected]>
1 parent ad41e5f commit c542022

File tree

130 files changed

+1233
-1048
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+1233
-1048
lines changed

analyzer/build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ plugins {
2727

2828
dependencies {
2929
api(projects.model)
30+
api(projects.plugins.api)
3031

3132
implementation(projects.downloader)
3233
implementation(projects.utils.configUtils)

analyzer/src/funTest/kotlin/PackageManagerFunTest.kt

+42-42
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ import io.kotest.matchers.should
3232

3333
import java.io.File
3434

35-
import org.ossreviewtoolkit.model.config.AnalyzerConfiguration
3635
import org.ossreviewtoolkit.model.config.Excludes
3736
import org.ossreviewtoolkit.model.config.PathExclude
3837
import org.ossreviewtoolkit.model.config.PathExcludeReason
38+
import org.ossreviewtoolkit.plugins.api.PluginConfig
3939

4040
class PackageManagerFunTest : WordSpec({
4141
val definitionFiles = listOf(
@@ -73,7 +73,7 @@ class PackageManagerFunTest : WordSpec({
7373
)
7474

7575
val projectDir = tempdir()
76-
val packageManagers = PackageManagerFactory.ALL.values.map { it.create(AnalyzerConfiguration()) }
76+
val packageManagers = PackageManagerFactory.ALL.values.map { it.create(PluginConfig()) }
7777

7878
beforeSpec {
7979
definitionFiles.writeFiles(projectDir)
@@ -85,75 +85,75 @@ class PackageManagerFunTest : WordSpec({
8585

8686
// The test project contains at least one file per package manager, so the result should also contain an
8787
// entry for each package manager.
88-
managedFiles.keys.map { it.managerName } shouldContainExactlyInAnyOrder
89-
PackageManagerFactory.ALL.values.map { it.type }.filterNot { it == "Unmanaged" }
88+
managedFiles.keys.map { it.descriptor.id } shouldContainExactlyInAnyOrder
89+
PackageManagerFactory.ALL.values.map { it.descriptor.id }.filterNot { it == "Unmanaged" }
9090

91-
val managedFilesByName = managedFiles.groupByName(projectDir)
91+
val managedFilesById = managedFiles.groupById(projectDir)
9292

9393
assertSoftly {
94-
managedFilesByName["Bazel"] should containExactly("bazel/MODULE.bazel")
95-
managedFilesByName["Bower"] should containExactly("bower/bower.json")
96-
managedFilesByName["Bundler"] should containExactly("bundler/Gemfile")
97-
managedFilesByName["Cargo"] should containExactly("cargo/Cargo.toml")
98-
managedFilesByName["Carthage"] should containExactly("carthage/Cartfile.resolved")
99-
managedFilesByName["CocoaPods"] should containExactly("cocoapods/Podfile")
100-
managedFilesByName["Composer"] should containExactly("composer/composer.json")
101-
managedFilesByName["Conan"] should containExactlyInAnyOrder(
94+
managedFilesById["Bazel"] should containExactly("bazel/MODULE.bazel")
95+
managedFilesById["Bower"] should containExactly("bower/bower.json")
96+
managedFilesById["Bundler"] should containExactly("bundler/Gemfile")
97+
managedFilesById["Cargo"] should containExactly("cargo/Cargo.toml")
98+
managedFilesById["Carthage"] should containExactly("carthage/Cartfile.resolved")
99+
managedFilesById["CocoaPods"] should containExactly("cocoapods/Podfile")
100+
managedFilesById["Composer"] should containExactly("composer/composer.json")
101+
managedFilesById["Conan"] should containExactlyInAnyOrder(
102102
"conan-py/conanfile.py",
103103
"conan-txt/conanfile.txt"
104104
)
105-
managedFilesByName["GoMod"] should containExactly("gomod/go.mod")
106-
managedFilesByName["GradleInspector"] should containExactlyInAnyOrder(
105+
managedFilesById["GoMod"] should containExactly("gomod/go.mod")
106+
managedFilesById["GradleInspector"] should containExactlyInAnyOrder(
107107
"gradle-groovy/build.gradle",
108108
"gradle-kotlin/build.gradle.kts"
109109
)
110-
managedFilesByName["Maven"] should containExactly("maven/pom.xml")
111-
managedFilesByName["NPM"] should containExactly("npm-pnpm-and-yarn/package.json")
112-
managedFilesByName["NuGet"] should containExactlyInAnyOrder(
110+
managedFilesById["Maven"] should containExactly("maven/pom.xml")
111+
managedFilesById["NPM"] should containExactly("npm-pnpm-and-yarn/package.json")
112+
managedFilesById["NuGet"] should containExactlyInAnyOrder(
113113
"dotnet/test.csproj",
114114
"nuget/packages.config"
115115
)
116-
managedFilesByName["PIP"] should containExactlyInAnyOrder(
116+
managedFilesById["PIP"] should containExactlyInAnyOrder(
117117
"pip-requirements/requirements.txt",
118118
"pip-setup/setup.py"
119119
)
120-
managedFilesByName["Pipenv"] should containExactly("pipenv/Pipfile.lock")
121-
managedFilesByName["PNPM"] should containExactly("npm-pnpm-and-yarn/package.json")
122-
managedFilesByName["Poetry"] should containExactly("poetry/poetry.lock")
123-
managedFilesByName["Pub"] should containExactly("pub/pubspec.yaml")
124-
managedFilesByName["SBT"] should containExactly("sbt/build.sbt")
125-
managedFilesByName["SpdxDocumentFile"] should containExactlyInAnyOrder(
120+
managedFilesById["Pipenv"] should containExactly("pipenv/Pipfile.lock")
121+
managedFilesById["PNPM"] should containExactly("npm-pnpm-and-yarn/package.json")
122+
managedFilesById["Poetry"] should containExactly("poetry/poetry.lock")
123+
managedFilesById["Pub"] should containExactly("pub/pubspec.yaml")
124+
managedFilesById["SBT"] should containExactly("sbt/build.sbt")
125+
managedFilesById["SpdxDocumentFile"] should containExactlyInAnyOrder(
126126
"spdx-package/package.spdx.yml",
127127
"spdx-project/project.spdx.yml"
128128
)
129-
managedFilesByName["SwiftPM"] should containExactlyInAnyOrder(
129+
managedFilesById["SwiftPM"] should containExactlyInAnyOrder(
130130
"spm-app/Package.resolved",
131131
"spm-lib/Package.swift"
132132
)
133-
managedFilesByName["Stack"] should containExactly("stack/stack.yaml")
134-
managedFilesByName["Yarn"] should containExactly("npm-pnpm-and-yarn/package.json")
133+
managedFilesById["Stack"] should containExactly("stack/stack.yaml")
134+
managedFilesById["Yarn"] should containExactly("npm-pnpm-and-yarn/package.json")
135135
}
136136
}
137137

138138
"find only files for active package managers" {
139139
val managedFiles = PackageManager.findManagedFiles(
140140
projectDir,
141-
packageManagers.filter { it.managerName in listOf("GradleInspector", "PIP", "SBT") }
141+
packageManagers.filter { it.descriptor.id in setOf("GradleInspector", "PIP", "SBT") }
142142
)
143143

144144
managedFiles shouldHaveSize 3
145145

146-
val managedFilesByName = managedFiles.groupByName(projectDir)
146+
val managedFilesById = managedFiles.groupById(projectDir)
147147

148-
managedFilesByName["GradleInspector"] should containExactlyInAnyOrder(
148+
managedFilesById["GradleInspector"] should containExactlyInAnyOrder(
149149
"gradle-groovy/build.gradle",
150150
"gradle-kotlin/build.gradle.kts"
151151
)
152-
managedFilesByName["PIP"] should containExactlyInAnyOrder(
152+
managedFilesById["PIP"] should containExactlyInAnyOrder(
153153
"pip-requirements/requirements.txt",
154154
"pip-setup/setup.py"
155155
)
156-
managedFilesByName["SBT"] should containExactly("sbt/build.sbt")
156+
managedFilesById["SBT"] should containExactly("sbt/build.sbt")
157157
}
158158

159159
"find no files if no package managers are active" {
@@ -172,25 +172,25 @@ class PackageManagerFunTest : WordSpec({
172172
val pathExclude = PathExclude("$tempDir**", PathExcludeReason.TEST_OF)
173173
val excludes = Excludes(paths = listOf(pathExclude))
174174

175-
val managedFilesByName = PackageManager.findManagedFiles(rootDir, packageManagers, excludes = excludes)
176-
.groupByName(rootDir)
175+
val managedFilesById = PackageManager.findManagedFiles(rootDir, packageManagers, excludes = excludes)
176+
.groupById(rootDir)
177177

178-
managedFilesByName["GradleInspector"] should containExactlyInAnyOrder(
178+
managedFilesById["GradleInspector"] should containExactlyInAnyOrder(
179179
"gradle-groovy/build.gradle",
180180
"gradle-kotlin/build.gradle.kts"
181181
)
182-
managedFilesByName["Maven"] should containExactly("maven/pom.xml")
183-
managedFilesByName["SBT"] should containExactly("sbt/build.sbt")
182+
managedFilesById["Maven"] should containExactly("maven/pom.xml")
183+
managedFilesById["SBT"] should containExactly("sbt/build.sbt")
184184
}
185185

186186
"handle specific excluded definition files" {
187187
val pathExclude = PathExclude("gradle-groovy/build.gradle", PathExcludeReason.OTHER)
188188
val excludes = Excludes(paths = listOf(pathExclude))
189189

190190
val managedFiles = PackageManager.findManagedFiles(projectDir, packageManagers, excludes = excludes)
191-
val managedFilesByName = managedFiles.groupByName(projectDir)
191+
val managedFilesById = managedFiles.groupById(projectDir)
192192

193-
managedFilesByName["GradleInspector"] should containExactly(
193+
managedFilesById["GradleInspector"] should containExactly(
194194
"gradle-kotlin/build.gradle.kts"
195195
)
196196
}
@@ -208,9 +208,9 @@ class PackageManagerFunTest : WordSpec({
208208
* package managers can be easily accessed. The keys in expected and actual maps of definition files are different
209209
* instances of package manager factories. So to compare values use the package manager types as keys instead.
210210
*/
211-
private fun ManagedProjectFiles.groupByName(projectDir: File) =
211+
private fun ManagedProjectFiles.groupById(projectDir: File) =
212212
map { (manager, files) ->
213-
manager.managerName to files.map { it.relativeTo(projectDir).invariantSeparatorsPath }
213+
manager.descriptor.id to files.map { it.relativeTo(projectDir).invariantSeparatorsPath }
214214
}.toMap()
215215

216216
/**

analyzer/src/main/kotlin/Analyzer.kt

+31-21
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import org.ossreviewtoolkit.model.config.Excludes
4646
import org.ossreviewtoolkit.model.config.RepositoryConfiguration
4747
import org.ossreviewtoolkit.model.orEmpty
4848
import org.ossreviewtoolkit.model.toYaml
49+
import org.ossreviewtoolkit.plugins.api.PluginConfig
4950
import org.ossreviewtoolkit.plugins.packagecurationproviders.api.PackageCurationProvider
5051
import org.ossreviewtoolkit.utils.common.CommandLineTool
5152
import org.ossreviewtoolkit.utils.common.VCS_DIRECTORIES
@@ -80,7 +81,10 @@ class Analyzer(private val config: AnalyzerConfiguration, private val labels: Ma
8081
"Using the following configuration settings:\n${repositoryConfiguration.toYaml()}"
8182
}
8283

83-
val distinctPackageManagers = packageManagers.distinct().map { it.create(config) }
84+
val distinctPackageManagers = packageManagers.distinct().map {
85+
val pluginOptions = config.getPackageManagerConfiguration(it.descriptor.id)?.options.orEmpty()
86+
it.create(PluginConfig(pluginOptions))
87+
}
8488

8589
// Associate files by the package manager factory that manages them.
8690
val managedFiles = if (distinctPackageManagers.size == 1 && absoluteProjectPath.isFile) {
@@ -101,7 +105,7 @@ class Analyzer(private val config: AnalyzerConfiguration, private val labels: Ma
101105

102106
// Fail early if multiple managers for the same project type are enabled.
103107
managedFiles.keys.groupBy { it.projectType }.forEach { (projectType, managers) ->
104-
val managerNames = managers.map { it.managerName }
108+
val managerNames = managers.map { it.descriptor.displayName }
105109
requireNotNull(managers.singleOrNull()) {
106110
"All of the $managerNames managers are able to manage '$projectType' projects. Please enable only " +
107111
"one of them."
@@ -115,7 +119,7 @@ class Analyzer(private val config: AnalyzerConfiguration, private val labels: Ma
115119
.all { it.isDirectory && (it in managedDirs || it.name in VCS_DIRECTORIES) }
116120

117121
if (!hasOnlyManagedDirs) {
118-
distinctPackageManagers.find { it.managerName == "Unmanaged" }
122+
distinctPackageManagers.find { it.descriptor.id == "Unmanaged" }
119123
?.also { managedFiles[it] = listOf(absoluteProjectPath) }
120124
}
121125

@@ -150,7 +154,7 @@ class Analyzer(private val config: AnalyzerConfiguration, private val labels: Ma
150154

151155
info.managedFiles.keys.forEach { manager ->
152156
if (manager is CommandLineTool) {
153-
toolVersions[manager.managerName] = manager.getVersion()
157+
toolVersions[manager.descriptor.id] = manager.getVersion()
154158
}
155159
}
156160

@@ -163,7 +167,7 @@ class Analyzer(private val config: AnalyzerConfiguration, private val labels: Ma
163167
logger.info { "Calling before resolution hooks for ${info.managedFiles.size} manager(s)." }
164168

165169
info.managedFiles.forEach { (manager, definitionFiles) ->
166-
manager.beforeResolution(info.absoluteProjectPath, definitionFiles)
170+
manager.beforeResolution(info.absoluteProjectPath, definitionFiles, config)
167171
}
168172

169173
val state = AnalyzerState()
@@ -177,6 +181,7 @@ class Analyzer(private val config: AnalyzerConfiguration, private val labels: Ma
177181
definitionFiles = files,
178182
analysisRoot = info.absoluteProjectPath,
179183
excludes = excludes,
184+
analyzerConfig = config,
180185
labels = labels,
181186
mustRunAfter = packageManagerDependencies[manager].orEmpty(),
182187
finishedPackageManagersState = state.finishedPackageManagersState,
@@ -185,7 +190,7 @@ class Analyzer(private val config: AnalyzerConfiguration, private val labels: Ma
185190
}.forEach { launch { it.start() } }
186191

187192
state.finishedPackageManagersState.first { finishedPackageManagers ->
188-
finishedPackageManagers.containsAll(info.managedFiles.keys.map { it.managerName })
193+
finishedPackageManagers.containsAll(info.managedFiles.keys.map { it.descriptor.id })
189194
}
190195
}
191196

@@ -201,15 +206,15 @@ class Analyzer(private val config: AnalyzerConfiguration, private val labels: Ma
201206
private fun determinePackageManagerDependencies(info: ManagedFileInfo): Map<PackageManager, Set<String>> {
202207
val packageManagersWithFiles =
203208
info.managedFiles.keys.associateByTo(sortedMapOf(String.CASE_INSENSITIVE_ORDER)) {
204-
it.managerName
209+
it.descriptor.id
205210
}
206211

207212
val result = mutableMapOf<PackageManager, MutableSet<String>>()
208213

209214
info.managedFiles.keys.forEach { packageManager ->
210215
val dependencies =
211-
packageManager.findPackageManagerDependencies(info.absoluteProjectPath, info.managedFiles)
212-
val mustRunAfterConfig = config.getPackageManagerConfiguration(packageManager.managerName)?.mustRunAfter
216+
packageManager.findPackageManagerDependencies(info.absoluteProjectPath, info.managedFiles, config)
217+
val mustRunAfterConfig = config.getPackageManagerConfiguration(packageManager.descriptor.id)?.mustRunAfter
213218

214219
// Configured mustRunAfter dependencies override programmatic mustRunAfter dependencies.
215220
val mustRunAfter = mustRunAfterConfig?.toSet() ?: dependencies.mustRunAfter
@@ -219,8 +224,8 @@ class Analyzer(private val config: AnalyzerConfiguration, private val labels: Ma
219224

220225
if (managerForName == null) {
221226
logger.debug {
222-
"Ignoring that ${packageManager.managerName} must run after $name, because there are no " +
223-
"definition files for $name."
227+
"Ignoring that ${packageManager.descriptor.displayName} must run after $name, because there " +
228+
"are no definition files for $name."
224229
}
225230
} else {
226231
result.getOrPut(packageManager) { mutableSetOf() } += name
@@ -235,11 +240,11 @@ class Analyzer(private val config: AnalyzerConfiguration, private val labels: Ma
235240

236241
if (managerForName == null) {
237242
logger.debug {
238-
"Ignoring that ${packageManager.managerName} must run before $name, because there are no " +
239-
"definition files for $name."
243+
"Ignoring that ${packageManager.descriptor.displayName} must run before $name, because there " +
244+
"are no definition files for $name."
240245
}
241246
} else {
242-
result.getOrPut(managerForName) { mutableSetOf() } += packageManager.managerName
247+
result.getOrPut(managerForName) { mutableSetOf() } += packageManager.descriptor.id
243248
}
244249
}
245250
}
@@ -261,10 +266,10 @@ private class AnalyzerState {
261266
addMutex.withLock {
262267
result.projectResults.values.flatten().forEach { builder.addResult(it) }
263268
result.dependencyGraph?.let {
264-
builder.addDependencyGraph(manager.managerName, it).addPackages(result.sharedPackages)
269+
builder.addDependencyGraph(manager.descriptor.id, it).addPackages(result.sharedPackages)
265270
}
266271

267-
_finishedPackageManagersState.value = (_finishedPackageManagersState.value + manager.managerName)
272+
_finishedPackageManagersState.value = (_finishedPackageManagersState.value + manager.descriptor.id)
268273
.toSortedSet(String.CASE_INSENSITIVE_ORDER)
269274
}
270275
}
@@ -297,6 +302,11 @@ private class PackageManagerRunner(
297302
*/
298303
val excludes: Excludes,
299304

305+
/**
306+
* The [AnalyzerConfiguration] to use.
307+
*/
308+
val analyzerConfig: AnalyzerConfiguration,
309+
300310
/**
301311
* The labels passed to ORT.
302312
*/
@@ -328,8 +338,8 @@ private class PackageManagerRunner(
328338

329339
if (remaining.isNotEmpty()) {
330340
logger.info {
331-
"${manager.managerName} is waiting for the following package managers to complete: " +
332-
remaining.joinToString(postfix = ".")
341+
"${manager.descriptor.displayName} is waiting for the following package managers to " +
342+
"complete: ${remaining.joinToString(postfix = ".")}"
333343
}
334344
}
335345

@@ -341,12 +351,12 @@ private class PackageManagerRunner(
341351
}
342352

343353
private suspend fun run() {
344-
logger.info { "Starting ${manager.managerName} analysis." }
354+
logger.info { "Starting ${manager.descriptor.displayName} analysis." }
345355

346356
withContext(Dispatchers.IO.limitedParallelism(20)) {
347-
val result = manager.resolveDependencies(analysisRoot, definitionFiles, excludes, labels)
357+
val result = manager.resolveDependencies(analysisRoot, definitionFiles, excludes, analyzerConfig, labels)
348358

349-
logger.info { "Finished ${manager.managerName} analysis." }
359+
logger.info { "Finished ${manager.descriptor.displayName} analysis." }
350360

351361
onResult(result)
352362
}

0 commit comments

Comments
 (0)