Skip to content

Commit 31679d2

Browse files
committed
feat(LicenseInfoResolver): Apply the path includes
Signed-off-by: Nicolas Nobelis <[email protected]>
1 parent 1aef4f1 commit 31679d2

File tree

11 files changed

+275
-27
lines changed

11 files changed

+275
-27
lines changed

model/src/main/kotlin/licenses/DefaultLicenseInfoProvider.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import org.ossreviewtoolkit.model.OrtResult
2727
import org.ossreviewtoolkit.model.Provenance
2828
import org.ossreviewtoolkit.model.config.LicenseFindingCuration
2929
import org.ossreviewtoolkit.model.config.PathExclude
30+
import org.ossreviewtoolkit.model.config.PathInclude
3031
import org.ossreviewtoolkit.model.utils.filterByVcsPath
3132
import org.ossreviewtoolkit.utils.ort.ProcessedDeclaredLicense
3233

@@ -92,6 +93,7 @@ class DefaultLicenseInfoProvider(val ortResult: OrtResult) : LicenseInfoProvider
9293
copyrights = it.summary.copyrightFindings,
9394
licenseFindingCurations = config.licenseFindingCurations,
9495
pathExcludes = config.pathExcludes,
96+
pathIncludes = config.pathIncludes,
9597
relativeFindingsPath = config.relativeFindingsPath
9698
)
9799
}
@@ -104,12 +106,14 @@ class DefaultLicenseInfoProvider(val ortResult: OrtResult) : LicenseInfoProvider
104106
Configuration(
105107
ortResult.repository.config.curations.licenseFindings,
106108
ortResult.repository.config.excludes.paths,
109+
ortResult.repository.config.includes.paths,
107110
ortResult.repository.getRelativePath(project.vcsProcessed).orEmpty()
108111
)
109112
} ?: ortResult.getPackageConfigurations(id, provenance).let { packageConfigurations ->
110113
Configuration(
111114
packageConfigurations.flatMap { it.licenseFindingCurations },
112115
packageConfigurations.flatMap { it.pathExcludes },
116+
packageConfigurations.flatMap { it.pathIncludes },
113117
""
114118
)
115119
}
@@ -118,5 +122,6 @@ class DefaultLicenseInfoProvider(val ortResult: OrtResult) : LicenseInfoProvider
118122
private data class Configuration(
119123
val licenseFindingCurations: List<LicenseFindingCuration>,
120124
val pathExcludes: List<PathExclude>,
125+
val pathIncludes: List<PathInclude>,
121126
val relativeFindingsPath: String
122127
)

model/src/main/kotlin/licenses/LicenseInfo.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import org.ossreviewtoolkit.model.Provenance
2727
import org.ossreviewtoolkit.model.Repository
2828
import org.ossreviewtoolkit.model.config.LicenseFindingCuration
2929
import org.ossreviewtoolkit.model.config.PathExclude
30+
import org.ossreviewtoolkit.model.config.PathInclude
3031
import org.ossreviewtoolkit.model.config.RepositoryConfiguration
3132
import org.ossreviewtoolkit.utils.ort.ProcessedDeclaredLicense
3233
import org.ossreviewtoolkit.utils.spdx.SpdxExpression
@@ -136,6 +137,11 @@ data class Findings(
136137
*/
137138
val pathExcludes: List<PathExclude>,
138139

140+
/**
141+
* The list of all path includes that apply to this [provenance].
142+
*/
143+
val pathIncludes: List<PathInclude>,
144+
139145
/**
140146
* The root path of the locations of the [licenses] and [copyrights] relative to the paths used in the
141147
* [licenseFindingCurations] and [pathExcludes]. An empty string, if all refer to the same root path.

model/src/main/kotlin/licenses/LicenseInfoResolver.kt

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import org.ossreviewtoolkit.model.UnknownProvenance
3232
import org.ossreviewtoolkit.model.config.CopyrightGarbage
3333
import org.ossreviewtoolkit.model.config.LicenseFilePatterns
3434
import org.ossreviewtoolkit.model.config.PathExclude
35+
import org.ossreviewtoolkit.model.config.PathInclude
3536
import org.ossreviewtoolkit.model.utils.FileArchiver
3637
import org.ossreviewtoolkit.model.utils.FindingCurationMatcher
3738
import org.ossreviewtoolkit.model.utils.FindingsMatcher
@@ -123,9 +124,16 @@ class LicenseInfoResolver(
123124
).mapNotNull { curationResult ->
124125
val licenseFinding = curationResult.curatedFinding ?: return@mapNotNull null
125126

126-
licenseFinding.license to findings.pathExcludes.any { pathExclude ->
127+
val isExcludedByPathIncludes = licenseFinding.location.isExcludedByPathIncludes(
128+
findings.pathIncludes,
129+
findings.relativeFindingsPath
130+
)
131+
132+
val isMatchedByPathExcludes = findings.pathExcludes.any { pathExclude ->
127133
pathExclude.matches(licenseFinding.location.prependedPath(findings.relativeFindingsPath))
128134
}
135+
136+
licenseFinding.license to (isMatchedByPathExcludes || isExcludedByPathIncludes)
129137
}
130138
}.groupBy(keySelector = { it.first }, valueTransform = { it.second }).mapValues { (_, excluded) ->
131139
excluded.all { it }
@@ -190,6 +198,7 @@ class LicenseInfoResolver(
190198
val resolvedCopyrightFindings = resolveCopyrights(
191199
copyrightFindings,
192200
findings.pathExcludes,
201+
findings.pathIncludes,
193202
findings.relativeFindingsPath
194203
)
195204

@@ -204,12 +213,18 @@ class LicenseInfoResolver(
204213
it.matches(licenseFinding.location.prependedPath(findings.relativeFindingsPath))
205214
}
206215

216+
val isExcludedByPathIncludes = licenseFinding.location.isExcludedByPathIncludes(
217+
findings.pathIncludes,
218+
findings.relativeFindingsPath
219+
)
220+
207221
licenseFinding.license.decompose().forEach { singleLicense ->
208222
resolvedLocations.getOrPut(singleLicense) { mutableSetOf() } += ResolvedLicenseLocation(
209223
findings.provenance,
210224
licenseFinding.location,
211225
appliedCuration = appliedCuration,
212226
matchingPathExcludes = matchingPathExcludes,
227+
isExcludedByPathIncludes = isExcludedByPathIncludes,
213228
copyrights = resolvedCopyrightFindings
214229
)
215230
}
@@ -218,6 +233,7 @@ class LicenseInfoResolver(
218233
unmatchedCopyrights.getOrPut(findings.provenance) { mutableSetOf() } += resolveCopyrights(
219234
copyrightFindings = matchResult.unmatchedCopyrights,
220235
pathExcludes = findings.pathExcludes,
236+
pathIncludes = findings.pathIncludes,
221237
relativeFindingsPath = findings.relativeFindingsPath
222238
)
223239
}
@@ -228,14 +244,25 @@ class LicenseInfoResolver(
228244
private fun resolveCopyrights(
229245
copyrightFindings: Set<CopyrightFinding>,
230246
pathExcludes: List<PathExclude>,
247+
pathIncludes: List<PathInclude>,
231248
relativeFindingsPath: String
232249
): Set<ResolvedCopyrightFinding> =
233250
copyrightFindings.mapTo(mutableSetOf()) { finding ->
234251
val matchingPathExcludes = pathExcludes.filter {
235252
it.matches(finding.location.prependedPath(relativeFindingsPath))
236253
}
237254

238-
ResolvedCopyrightFinding(finding.statement, finding.location, matchingPathExcludes)
255+
val isExcludedByPathIncludes = finding.location.isExcludedByPathIncludes(
256+
pathIncludes,
257+
relativeFindingsPath
258+
)
259+
260+
ResolvedCopyrightFinding(
261+
finding.statement,
262+
finding.location,
263+
matchingPathExcludes,
264+
isExcludedByPathIncludes
265+
)
239266
}
240267

241268
private fun createLicenseFileInfo(id: Identifier): ResolvedLicenseFileInfo {
@@ -290,6 +317,7 @@ class LicenseInfoResolver(
290317
location = UNDEFINED_TEXT_LOCATION,
291318
appliedCuration = null,
292319
matchingPathExcludes = emptyList(),
320+
isExcludedByPathIncludes = false,
293321
copyrights = authors.mapTo(mutableSetOf()) { author ->
294322
val statement = "Copyright (C) $author".takeUnless {
295323
author.contains("Copyright", ignoreCase = true)
@@ -298,10 +326,23 @@ class LicenseInfoResolver(
298326
ResolvedCopyrightFinding(
299327
statement = statement,
300328
location = UNDEFINED_TEXT_LOCATION,
301-
matchingPathExcludes = emptyList()
329+
matchingPathExcludes = emptyList(),
330+
isExcludedByPathIncludes = false
302331
)
303332
}
304333
)
334+
335+
/**
336+
* Return true if the [TextLocation] is excluded because some path includes are defined and none of them matches
337+
* this [TextLocation] prepended with the [relativeFindingsPath].
338+
*/
339+
private fun TextLocation.isExcludedByPathIncludes(pathIncludes: List<PathInclude>, relativeFindingsPath: String) =
340+
when {
341+
pathIncludes.isEmpty() -> false
342+
else -> pathIncludes.none {
343+
it.matches(prependedPath(relativeFindingsPath))
344+
}
345+
}
305346
}
306347

307348
private class ResolvedLicenseBuilder(val license: SpdxSingleLicenseExpression) {

model/src/main/kotlin/licenses/ResolvedCopyrightFinding.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,10 @@ data class ResolvedCopyrightFinding(
3939
/**
4040
* All [PathExclude]s matching this [location].
4141
*/
42-
val matchingPathExcludes: List<PathExclude>
42+
val matchingPathExcludes: List<PathExclude>,
43+
44+
/**
45+
* If true, some includes are defines and are not matching this [location].
46+
*/
47+
val isExcludedByPathIncludes: Boolean
4348
)

model/src/main/kotlin/licenses/ResolvedLicense.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ data class ResolvedLicense(
6060
* True, if this license was [detected][LicenseSource.DETECTED] and all [locations] have matching path excludes.
6161
*/
6262
val isDetectedExcluded by lazy {
63-
LicenseSource.DETECTED in sources && locations.all { it.matchingPathExcludes.isNotEmpty() }
63+
LicenseSource.DETECTED in sources && locations.all {
64+
it.matchingPathExcludes.isNotEmpty() || it.isExcludedByPathIncludes
65+
}
6466
}
6567

6668
init {
@@ -95,13 +97,16 @@ data class ResolvedLicense(
9597

9698
/**
9799
* Filter all excluded copyrights. Copyrights which have
98-
* [matching path excludes][ResolvedCopyrightFinding.matchingPathExcludes] are removed.
100+
* [matching path excludes][ResolvedCopyrightFinding.matchingPathExcludes] or for which [no include are defined]
101+
* [ResolvedCopyrightFinding.isExcludedByPathIncludes] are removed.
99102
*/
100103
fun filterExcludedCopyrights(): ResolvedLicense =
101104
copy(
102105
locations = locations.mapTo(mutableSetOf()) { location ->
103106
location.copy(
104-
copyrights = location.copyrights.filterTo(mutableSetOf()) { it.matchingPathExcludes.isEmpty() }
107+
copyrights = location.copyrights.filterTo(mutableSetOf()) {
108+
it.matchingPathExcludes.isEmpty() || it.isExcludedByPathIncludes
109+
}
105110
)
106111
}
107112
)

model/src/main/kotlin/licenses/ResolvedLicenseLocation.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ data class ResolvedLicenseLocation(
4848
*/
4949
val matchingPathExcludes: List<PathExclude>,
5050

51+
/**
52+
* If true, some includes are defines and are not matching this [location].
53+
*/
54+
val isExcludedByPathIncludes: Boolean,
55+
5156
/**
5257
* All copyright findings associated to this license location, excluding copyright garbage.
5358
*/

0 commit comments

Comments
 (0)