Source code for pkgcheck.checks.header
"""Various file-based header checks."""
import re
from .. import results, sources
from . import GentooRepoCheck
copyright_regex = re.compile(r"^# Copyright (?P<begin>\d{4}-)?(?P<end>\d{4}) (?P<holder>.+)$")
class _FileHeaderResult(results.Result):
"""Generic file header result."""
def __init__(self, line, **kwargs):
super().__init__(**kwargs)
self.line = line
[docs]
class InvalidCopyright(_FileHeaderResult, results.AliasResult, results.Error):
"""File with invalid copyright.
The file does not start with a valid copyright line. Each ebuild or eclass
file must start with a copyright line of the form::
# Copyright YEARS MAIN-CONTRIBUTOR [OTHER-CONTRIBUTOR]... [and others]
Files in the Gentoo repository must use::
# Copyright YEARS Gentoo Authors
"""
_name = "InvalidCopyright"
@property
def desc(self):
return f"invalid copyright: {self.line!r}"
[docs]
class OldGentooCopyright(_FileHeaderResult, results.AliasResult, results.Warning):
"""File with old Gentoo Foundation copyright.
The file still assigns copyright to the Gentoo Foundation even though
it has been committed after the new copyright policy was approved
(2018-10-21).
Ebuilds and eclasses in Gentoo repository must use 'Gentoo Authors'
instead. Files in other repositories may specify an explicit copyright
holder instead.
"""
_name = "OldGentooCopyright"
@property
def desc(self):
return f'old copyright, update to "Gentoo Authors": {self.line!r}'
[docs]
class NonGentooAuthorsCopyright(_FileHeaderResult, results.AliasResult, results.Error):
"""File with copyright stating owner other than "Gentoo Authors".
The file specifies explicit copyright owner, while the Gentoo repository
policy specifies that all ebuilds and eclasses must use "Gentoo Authors".
If the owner is not listed in metadata/AUTHORS, addition can be requested
via bugs.gentoo.org.
"""
_name = "NonGentooAuthorsCopyright"
@property
def desc(self):
return f'copyright line must state "Gentoo Authors": {self.line!r}'
class _HeaderCheck(GentooRepoCheck):
"""Scan files for incorrect copyright/license headers."""
_invalid_copyright = InvalidCopyright
_old_copyright = OldGentooCopyright
_non_gentoo_authors = NonGentooAuthorsCopyright
_invalid_license = InvalidLicenseHeader
known_results = frozenset(
[
_invalid_copyright,
_old_copyright,
_non_gentoo_authors,
_invalid_license,
]
)
_item_attr = "pkg"
license_header = "# Distributed under the terms of the GNU General Public License v2"
def args(self, item):
return {self._item_attr: item}
def feed(self, item):
if item.lines:
line = item.lines[0].strip()
if mo := copyright_regex.match(line):
# Copyright policy is active since 2018-10-21, so it applies
# to all ebuilds committed in 2019 and later
if int(mo.group("end")) >= 2019:
if mo.group("holder") == "Gentoo Foundation":
yield self._old_copyright(line, **self.args(item))
# Gentoo policy requires 'Gentoo Authors'
elif mo.group("holder") != "Gentoo Authors":
yield self._non_gentoo_authors(line, **self.args(item))
else:
yield self._invalid_copyright(line, **self.args(item))
try:
line = item.lines[1].strip("\n")
except IndexError:
line = ""
if line != self.license_header:
yield self._invalid_license(line, **self.args(item))
[docs]
class EbuildInvalidCopyright(InvalidCopyright, results.VersionResult):
__doc__ = InvalidCopyright.__doc__
[docs]
class EbuildOldGentooCopyright(OldGentooCopyright, results.VersionResult):
__doc__ = OldGentooCopyright.__doc__
[docs]
class EbuildNonGentooAuthorsCopyright(NonGentooAuthorsCopyright, results.VersionResult):
__doc__ = NonGentooAuthorsCopyright.__doc__
[docs]
class EclassInvalidCopyright(InvalidCopyright, results.EclassResult):
__doc__ = InvalidCopyright.__doc__
@property
def desc(self):
return f"{self.eclass}: {super().desc}"
[docs]
class EclassOldGentooCopyright(OldGentooCopyright, results.EclassResult):
__doc__ = OldGentooCopyright.__doc__
@property
def desc(self):
return f"{self.eclass}: {super().desc}"
[docs]
class EclassNonGentooAuthorsCopyright(NonGentooAuthorsCopyright, results.EclassResult):
__doc__ = NonGentooAuthorsCopyright.__doc__
@property
def desc(self):
return f"{self.eclass}: {super().desc}"