Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions src/pkgcheck/checks/reserved.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import re
from .. import addons, bash, results, sources
from . import Check


class _ReservedNameCheck(Check):
reserved_prefixes = ('__', 'abort', 'dyn', 'prep')
reserved_substrings = ('hook', 'paludis', 'portage') # 'ebuild' is special case
reserved_ebuild_regex = re.compile(r'(.*[^a-zA-Z])?ebuild.*')

"""Portage variables whose use is half-legitimate and harmless if the package manager doesn't support them."""
special_whitelist = ('EBUILD_DEATH_HOOKS', 'EBUILD_SUCCESS_HOOKS', 'PORTAGE_QUIET')

def _check(self, used_type: str, used_names):
for used_name, node_start in used_names.items():
if used_name in self.special_whitelist:
continue
test_name = used_name.lower()
Comment thread
arthurzam marked this conversation as resolved.
lineno, _ = node_start
for reserved in self.reserved_prefixes:
if test_name.startswith(reserved):
yield used_name, used_type, reserved, 'prefix', lineno
for reserved in self.reserved_substrings:
if reserved in test_name:
yield used_name, used_type, reserved, 'substring', lineno
if self.reserved_ebuild_regex.match(test_name):
yield used_name, used_type, 'ebuild', 'substring', lineno

def _feed(self, item):
yield from self._check('function', {
item.node_str(node.child_by_field_name('name')): node.start_point
for node, _ in bash.func_query.captures(item.tree.root_node)
})
yield from self._check('variable', {
item.node_str(node.child_by_field_name('name')): node.start_point
for node, _ in bash.var_assign_query.captures(item.tree.root_node)
})


class EclassReservedName(results.EclassResult, results.Warning):
"""Eclass uses reserved variable or function name for package manager."""

def __init__(self, used_name: str, used_type: str, reserved_word: str, reserved_type: str, **kwargs):
super().__init__(**kwargs)
self.used_name = used_name
self.used_type = used_type
self.reserved_word = reserved_word
self.reserved_type = reserved_type

@property
def desc(self):
return f'{self.eclass}: {self.used_type} name "{self.used_name}" is disallowed because "{self.reserved_word}" is a reserved {self.reserved_type}'


class EclassReservedCheck(_ReservedNameCheck):
"""Scan eclasses for reserved function or variable names."""

_source = sources.EclassParseRepoSource
known_results = frozenset([EclassReservedName])
required_addons = (addons.eclass.EclassAddon,)

def __init__(self, *args, eclass_addon):
super().__init__(*args)
self.eclass_cache = eclass_addon.eclasses

def feed(self, eclass):
for *args, _ in self._feed(eclass):
yield EclassReservedName(*args, eclass=eclass.name)


class EbuildReservedName(results.LineResult, results.Warning):
"""Ebuild uses reserved variable or function name for package manager."""

def __init__(self, used_name: str, used_type: str, reserved_word: str, reserved_type: str, **kwargs):
super().__init__(**kwargs)
self.used_name = used_name
self.used_type = used_type
self.reserved_word = reserved_word
self.reserved_type = reserved_type

@property
def desc(self):
return f'line {self.lineno}: {self.used_type} name "{self.used_name}" is disallowed because "{self.reserved_word}" is a reserved {self.reserved_type}'


class EbuildReservedCheck(_ReservedNameCheck):
"""Scan ebuilds for reserved function or variable names."""

_source = sources.EbuildParseRepoSource
known_results = frozenset([EbuildReservedName])

def feed(self, pkg):
for *args, lineno in self._feed(pkg):
yield EbuildReservedName(*args, lineno=lineno, line='', pkg=pkg)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{"__class__": "EclassReservedName", "eclass": "reserved", "used_name": "prepare_locale", "used_type": "function", "reserved_word": "prep", "reserved_type": "prefix"}
{"__class__": "EclassReservedName", "eclass": "reserved", "used_name": "EBUILD_TEST", "used_type": "variable", "reserved_word": "ebuild", "reserved_type": "substring"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{"__class__": "EbuildReservedName", "category": "EbuildReservedCheck", "package": "EbuildReservedName", "version": "0", "used_name": "prepare_locale", "used_type": "function", "reserved_word": "prep", "reserved_type": "prefix", "lineno": 5, "line": ""}
{"__class__": "EbuildReservedName", "category": "EbuildReservedCheck", "package": "EbuildReservedName", "version": "0", "used_name": "DYNAMIC_DEPS", "used_type": "variable", "reserved_word": "dyn", "reserved_type": "prefix", "lineno": 6, "line": ""}
{"__class__": "EbuildReservedName", "category": "EbuildReservedCheck", "package": "EbuildReservedName", "version": "0", "used_name": "_hook_prepare", "used_type": "variable", "reserved_word": "hook", "reserved_type": "substring", "lineno": 7, "line": ""}
{"__class__": "EbuildReservedName", "category": "EbuildReservedCheck", "package": "EbuildReservedName", "version": "0", "used_name": "__ORIG_CC", "used_type": "variable", "reserved_word": "__", "reserved_type": "prefix", "lineno": 10, "line": ""}
{"__class__": "EbuildReservedName", "category": "EbuildReservedCheck", "package": "EbuildReservedName", "version": "0", "used_name": "EBUILD_TEST", "used_type": "variable", "reserved_word": "ebuild", "reserved_type": "substring", "lineno": 12, "line": ""}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--- standalone/EbuildReservedCheck/EbuildReservedName/EbuildReservedName-0.ebuild
+++ standalone/EbuildReservedCheck/EbuildReservedName/EbuildReservedName-0.ebuild
@@ -3,12 +3,11 @@ HOMEPAGE="https://github.com/pkgcore/pkgcheck"
SLOT="0"
LICENSE="BSD"

-prepare_locale() {
- DYNAMIC_DEPS="2"
- _hook_prepare="3"
+my_prepare_locale() {
+ MY_DYNAMIC_DEPS="2"
+ _my_prepare="3"
}

-__ORIG_CC="STUB"
+MY_ORIG_CC="STUB"
EBUILD_SUCCESS_HOOKS="true"
-EBUILD_TEST="1"
REBUILD_ALL="1"
21 changes: 21 additions & 0 deletions testdata/repos/eclass/eclass/reserved.eclass
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# @ECLASS: reserved.eclass
# @MAINTAINER:
# Larry the Cow <larry@example.org>
# @AUTHOR:
# Larry the Cow <larry@example.org>
# @BLURB: Stub eclass.

# @FUNCTION: prepare_locale
# @USAGE:
# @DESCRIPTION:
# Public stub function.
prepare_locale() {
local DYNAMIC_DEPS
local prepered
export EBUILD_DEATH_HOOKS="die"
}

# @ECLASS_VARIABLE: EBUILD_TEST
# @DESCRIPTION:
# Public stub function.
EBUILD_TEST="1"
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
DESCRIPTION="Ebuild with reserved names"
HOMEPAGE="https://github.com/pkgcore/pkgcheck"
SLOT="0"
LICENSE="BSD"

prepare_locale() {
DYNAMIC_DEPS="2"
_hook_prepare="3"
}

__ORIG_CC="STUB"
EBUILD_SUCCESS_HOOKS="true"
EBUILD_TEST="1"
REBUILD_ALL="1"