@@ -32,6 +32,7 @@ import org.ossreviewtoolkit.model.UnknownProvenance
3232import org.ossreviewtoolkit.model.config.CopyrightGarbage
3333import org.ossreviewtoolkit.model.config.LicenseFilePatterns
3434import org.ossreviewtoolkit.model.config.PathExclude
35+ import org.ossreviewtoolkit.model.config.PathInclude
3536import org.ossreviewtoolkit.model.utils.FileArchiver
3637import org.ossreviewtoolkit.model.utils.FindingCurationMatcher
3738import 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
307348private class ResolvedLicenseBuilder (val license : SpdxSingleLicenseExpression ) {
0 commit comments