All Downloads are FREE. Search and download functionalities are using the official Maven repository.

toolkit.evaluator.33.1.0.source-code.Rule.kt Maven / Gradle / Ivy

Go to download

Part of the OSS Review Toolkit (ORT), a suite to automate software compliance checks.

There is a newer version: 40.0.1
Show newest version
/*
 * Copyright (C) 2017 The ORT Project Authors (see )
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 * License-Filename: LICENSE
 */

package org.ossreviewtoolkit.evaluator

import org.apache.logging.log4j.kotlin.logger

import org.ossreviewtoolkit.model.Identifier
import org.ossreviewtoolkit.model.Issue
import org.ossreviewtoolkit.model.LicenseSource
import org.ossreviewtoolkit.model.OrtResult
import org.ossreviewtoolkit.model.RuleViolation
import org.ossreviewtoolkit.model.Severity
import org.ossreviewtoolkit.utils.spdx.SpdxSingleLicenseExpression

/**
 * The base class for an evaluator rule. Rules use a set of matchers to determine if they apply, and create a list of
 * issues which are added to the [ruleSet].
 */
abstract class Rule(
    /**
     * The [RuleSet] this rule belongs to.
     */
    val ruleSet: RuleSet,

    /**
     * The name of this rule.
     */
    val name: String
) {
    private val ruleMatcherManager = RuleMatcherManager()

    /**
     * The list of all matchers that need to match for this rule to apply.
     */
    val matchers = mutableListOf()

    /**
     * The list of all issues created by this rule.
     */
    val violations = mutableListOf()

    /**
     * Return a human-readable description of this rule.
     */
    abstract val description: String

    /**
     * Return true if all [matchers] match.
     */
    private fun matches() =
        matchers.all { matcher ->
            matcher.matches().also { matches ->
                logger.info { "\t${matcher.description} == $matches" }
                if (!matches) logger.info { "\tRule skipped." }
            }
        }

    /**
     * Evaluate this rule by checking if all matchers apply. If this is the case all [violations] configured in this
     * rule are added to the [ruleSet]. To add custom behavior if the rule matches override [runInternal].
     */
    fun evaluate() {
        logger.info { description }

        if (matches()) {
            ruleSet.violations += violations

            if (violations.isNotEmpty()) {
                logger.info {
                    "\tFound violations:\n\t\t${violations.joinToString("\n\t\t") { "${it.severity}: ${it.message}" }}"
                }
            }

            runInternal()
        }
    }

    /**
     * Can be overridden to implement custom behavior, executed if a rule [matches].
     */
    open fun runInternal() {}

    /**
     * DSL function to configure [RuleMatcher]s using a [RuleMatcherManager].
     */
    fun require(block: RuleMatcherManager.() -> Unit) {
        ruleMatcherManager.block()
    }

    /**
     * A [RuleMatcher] that checks whether a [label] exists in the [ORT result][OrtResult.labels]. If [value] is null
     * the value of the label is ignored. If [splitValue] is true, the label value is interpreted as comma-separated
     * list.
     */
    fun hasLabel(label: String, value: String? = null, splitValue: Boolean = true) =
        object : RuleMatcher {
            override val description = "hasLabel(${listOfNotNull(label, value, splitValue).joinToString()})"

            override fun matches() = ruleSet.ortResult.hasLabel(label, value, splitValue)
        }

    /**
     * Return a string to be used as [source][Issue.source] for issues generated in [hint], [warning], and [error].
     */
    abstract fun issueSource(): String

    /**
     * Add an issue of the given [severity] for [pkgId] to the list of violations. Optionally, the offending [license]
     * and its [source][licenseSource] can be specified. The [message] further explains the violation itself and
     * [howToFix] explains how it can be fixed.
     */
    fun issue(
        severity: Severity,
        pkgId: Identifier?,
        license: SpdxSingleLicenseExpression?,
        licenseSource: LicenseSource?,
        message: String,
        howToFix: String
    ) {
        violations += RuleViolation(
            severity = severity,
            rule = name,
            pkg = pkgId,
            license = license,
            licenseSource = licenseSource,
            message = message,
            howToFix = howToFix
        )
    }

    /**
     * Add a [hint][Severity.HINT] to the list of [violations].
     */
    fun hint(
        pkgId: Identifier?,
        license: SpdxSingleLicenseExpression?,
        licenseSource: LicenseSource?,
        message: String,
        howToFix: String
    ) = issue(Severity.HINT, pkgId, license, licenseSource, message, howToFix)

    /**
     * Add a [warning][Severity.WARNING] to the list of [violations].
     */
    fun warning(
        pkgId: Identifier?,
        license: SpdxSingleLicenseExpression?,
        licenseSource: LicenseSource?,
        message: String,
        howToFix: String
    ) = issue(Severity.WARNING, pkgId, license, licenseSource, message, howToFix)

    /**
     * Add an [error][Severity.ERROR] to the list of [violations].
     */
    fun error(
        pkgId: Identifier?,
        license: SpdxSingleLicenseExpression?,
        licenseSource: LicenseSource?,
        message: String,
        howToFix: String
    ) = issue(Severity.ERROR, pkgId, license, licenseSource, message, howToFix)

    /**
     * A DSL helper class, providing convenience functions for adding [RuleMatcher]s to this rule.
     */
    inner class RuleMatcherManager {
        /**
         * Add a [RuleMatcher] to this rule.
         */
        operator fun RuleMatcher.unaryPlus() {
            matchers += this
        }

        /**
         * Add the negation of a [RuleMatcher] to this rule.
         */
        operator fun RuleMatcher.unaryMinus() {
            matchers += Not(this)
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy