@@ -44,6 +44,7 @@ import org.ossreviewtoolkit.model.config.Resolutions
4444import org.ossreviewtoolkit.model.config.RuleViolationResolution
4545import org.ossreviewtoolkit.model.config.ScopeExclude
4646import org.ossreviewtoolkit.model.config.VulnerabilityResolution
47+ import org.ossreviewtoolkit.model.config.PathInclude
4748import org.ossreviewtoolkit.model.licenses.LicenseView
4849import org.ossreviewtoolkit.model.toYaml
4950import org.ossreviewtoolkit.model.utils.FindingCurationMatcher
@@ -59,7 +60,7 @@ import org.ossreviewtoolkit.utils.spdx.calculatePackageVerificationCode
5960/* *
6061 * Maps the [reporter input][input] to an [EvaluatedModel].
6162 */
62- @Suppress(" TooManyFunctions" )
63+ @Suppress(" LargeClass " , " TooManyFunctions" )
6364internal class EvaluatedModelMapper (private val input : ReporterInput ) {
6465 private val packages = mutableMapOf<Identifier , EvaluatedPackage >()
6566 private val paths = mutableListOf<EvaluatedPackagePath >()
@@ -71,6 +72,7 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) {
7172 private val issues = mutableListOf<EvaluatedIssue >()
7273 private val issueResolutions = mutableListOf<IssueResolution >()
7374 private val pathExcludes = mutableListOf<PathExclude >()
75+ private val pathIncludes = mutableListOf<PathInclude >()
7476 private val scopeExcludes = mutableListOf<ScopeExclude >()
7577 private val ruleViolations = mutableListOf<EvaluatedRuleViolation >()
7678 private val ruleViolationResolutions = mutableListOf<RuleViolationResolution >()
@@ -84,6 +86,7 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) {
8486 var id : Identifier ,
8587 var isExcluded : Boolean ,
8688 val pathExcludes : MutableList <PathExclude > = mutableListOf(),
89+ val pathIncludes : MutableList <PathInclude > = mutableListOf(),
8790 val scopeExcludes : MutableList <ScopeExclude > = mutableListOf()
8891 )
8992
@@ -134,6 +137,7 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) {
134137
135138 return EvaluatedModel (
136139 pathExcludes = pathExcludes,
140+ pathIncludes = pathIncludes,
137141 scopeExcludes = scopeExcludes,
138142 issueResolutions = issueResolutions,
139143 issues = issues,
@@ -169,21 +173,26 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) {
169173
170174 input.ortResult.getProjects().forEach { project ->
171175 val pathExcludes = input.ortResult.getExcludes().findPathExcludes(project, input.ortResult)
176+ val pathIncludes = input.ortResult.getIncludes().findPathIncludes(project, input.ortResult)
172177 val dependencies = input.ortResult.dependencyNavigator.projectDependencies(project)
173- if (pathExcludes.isEmpty()) {
178+ if (pathExcludes.isEmpty() && pathIncludes.isEmpty() ) {
174179 val info = packageExcludeInfo.getValue(project.id)
175180 if (info.isExcluded) {
176181 info.isExcluded = false
177182 info.pathExcludes.clear()
178183 info.scopeExcludes.clear()
179184 }
185+
186+ info.pathIncludes.clear()
180187 } else {
181188 dependencies.forEach { id ->
182189 val info = packageExcludeInfo.getOrPut(id) { PackageExcludeInfo (id, true ) }
183190
184191 if (info.isExcluded) {
185192 info.pathExcludes + = pathExcludes
186193 }
194+
195+ info.pathIncludes + = pathIncludes
187196 }
188197 }
189198
@@ -238,6 +247,14 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) {
238247 .flatMap { it.pathExcludes }
239248 }
240249
250+ private fun getPathIncludes (id : Identifier , provenance : Provenance ): List <PathInclude > =
251+ if (input.ortResult.isProject(id)) {
252+ input.ortResult.getIncludes().paths
253+ } else {
254+ input.ortResult.getPackageConfigurations(id, provenance)
255+ .flatMap { it.pathIncludes }
256+ }
257+
241258 private fun addProject (project : Project ) {
242259 val scanResults = mutableListOf<EvaluatedScanResult >()
243260 val detectedLicenses = mutableSetOf<LicenseId >()
@@ -246,7 +263,9 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) {
246263 val issues = mutableListOf<EvaluatedIssue >()
247264
248265 val applicablePathExcludes = input.ortResult.getExcludes().findPathExcludes(project, input.ortResult)
266+ val applicablePathIncludes = input.ortResult.getIncludes().findPathIncludes(project, input.ortResult)
249267 val evaluatedPathExcludes = pathExcludes.addIfRequired(applicablePathExcludes)
268+ pathIncludes.addIfRequired(applicablePathIncludes)
250269
251270 val evaluatedPackage = EvaluatedPackage (
252271 id = project.id,
@@ -287,7 +306,8 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) {
287306 findings.filter { it.type == EvaluatedFindingType .LICENSE }.mapNotNullTo(detectedLicenses) { it.license }
288307
289308 val includedDetectedLicenses = findings.filter {
290- it.type == EvaluatedFindingType .LICENSE && it.pathExcludes.isEmpty()
309+ val isIncluded = pathIncludes.isEmpty() || pathIncludes.any { include -> include.matches(it.path) }
310+ it.type == EvaluatedFindingType .LICENSE && it.pathExcludes.isEmpty() && isIncluded
291311 }.mapNotNullTo(mutableSetOf ()) { it.license }
292312
293313 detectedExcludedLicenses + = detectedLicenses - includedDetectedLicenses
@@ -660,6 +680,7 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) {
660680 findings : MutableList <EvaluatedFinding >
661681 ) {
662682 val pathExcludes = getPathExcludes(id, scanResult.provenance)
683+ val pathIncludes = getPathIncludes(id, scanResult.provenance)
663684 val licenseFindingCurations = getLicenseFindingCurations(id, scanResult.provenance)
664685 // Sort the curated findings here to avoid the need to sort in the web-app each time it is loaded.
665686 val curatedFindings = curationsMatcher.applyAll(scanResult.summary.licenseFindings, licenseFindingCurations)
@@ -679,6 +700,16 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) {
679700 val evaluatedPathExcludes = pathExcludes
680701 .filter { it.matches(copyrightFinding.location.getRelativePathToRoot(id)) }
681702 .let { this @EvaluatedModelMapper.pathExcludes.addIfRequired(it) }
703+ pathIncludes.let { this @EvaluatedModelMapper.pathIncludes.addIfRequired(it) }
704+
705+ val evaluatedPathIncludes = if (pathIncludes.isEmpty() || pathIncludes.any { include ->
706+ include.matches(copyrightFinding.location.getRelativePathToRoot(id))
707+ }
708+ ) {
709+ emptyList()
710+ } else {
711+ pathIncludes
712+ }
682713
683714 findings + = EvaluatedFinding (
684715 type = EvaluatedFindingType .COPYRIGHT ,
@@ -688,7 +719,8 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) {
688719 startLine = copyrightFinding.location.startLine,
689720 endLine = copyrightFinding.location.endLine,
690721 scanResult = evaluatedScanResult,
691- pathExcludes = evaluatedPathExcludes
722+ pathExcludes = evaluatedPathExcludes,
723+ isExcludedByPathIncludes = evaluatedPathExcludes.isEmpty() && evaluatedPathIncludes.isNotEmpty()
692724 )
693725 }
694726
@@ -699,6 +731,18 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) {
699731 .filter { it.matches(licenseFinding.location.getRelativePathToRoot(id)) }
700732 .let { this @EvaluatedModelMapper.pathExcludes.addIfRequired(it) }
701733
734+ pathIncludes.let { this @EvaluatedModelMapper.pathIncludes.addIfRequired(it) }
735+
736+ val evaluatedPathIncludes = if (pathIncludes.isEmpty() || pathIncludes.any {
737+ include ->
738+ include.matches(licenseFinding.location.getRelativePathToRoot(id))
739+ }
740+ ) {
741+ emptyList()
742+ } else {
743+ pathIncludes
744+ }
745+
702746 findings + = EvaluatedFinding (
703747 type = EvaluatedFindingType .LICENSE ,
704748 license = actualLicense,
@@ -707,7 +751,8 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) {
707751 startLine = licenseFinding.location.startLine,
708752 endLine = licenseFinding.location.endLine,
709753 scanResult = evaluatedScanResult,
710- pathExcludes = evaluatedPathExcludes
754+ pathExcludes = evaluatedPathExcludes,
755+ isExcludedByPathIncludes = evaluatedPathExcludes.isEmpty() && evaluatedPathIncludes.isNotEmpty()
711756 )
712757 }
713758 }
@@ -772,6 +817,12 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) {
772817 )
773818 }
774819
775- return copy(config = config.copy(excludes = excludes, resolutions = resolutions))
820+ val includes = with (config.includes) {
821+ copy(
822+ paths = paths.map { pathIncludes.addIfRequired(it) }
823+ )
824+ }
825+
826+ return copy(config = config.copy(excludes = excludes, includes = includes, resolutions = resolutions))
776827 }
777828}
0 commit comments