commit: 6bcdbd769bfa8ebf78e31887e4fd54eaf1c47032 Author: Brian Harring <ferringb <AT> gmail <DOT> com> AuthorDate: Sun Dec 25 23:23:15 2022 +0000 Commit: Arthur Zamarin <arthurzam <AT> gentoo <DOT> org> CommitDate: Mon Dec 26 17:27:24 2022 +0000 URL: https://gitweb.gentoo.org/proj/pkgcore/pkgcore.git/commit/?id=6bcdbd76
Add USE_EXPAND expansion awareness for /etc/portage/package.use/* files. Specifically, if you have: `*/* PYTHON_TARGETS: -python2_7 python3_9` Pkgcore was treating `PYTHON_TARGETS:` as a use flag. That's obviously wrong, and the parsing should be tightened there. Closes: https://github.com/pkgcore/pkgcore/issues/384 Signed-off-by: Brian Harring <ferringb <AT> gmail.com> Signed-off-by: Arthur Zamarin <arthurzam <AT> gentoo.org> src/pkgcore/ebuild/domain.py | 44 ++++++++++++++++++++++++++++++++++++++------ tests/ebuild/test_domain.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/pkgcore/ebuild/domain.py b/src/pkgcore/ebuild/domain.py index 7e76f1112..6f86f7d14 100644 --- a/src/pkgcore/ebuild/domain.py +++ b/src/pkgcore/ebuild/domain.py @@ -66,15 +66,47 @@ def package_masks(iterable): logger.warning(f"{path!r}, line {lineno}: parsing error: {e}") -def package_keywords_splitter(iterable): +def restriction_payload_splitter(iterable, post_process=lambda x: x): for line, lineno, path in iterable: v = line.split() try: - yield parse_match(v[0]), tuple(v[1:]), line, lineno, path + # TODO: expand this invocation to allow threading token level validation down. + # things like "is this a valid use flag?" + yield parse_match(v[0]), tuple(post_process(v[1:])), line, lineno, path except ParseError as e: logger.warning(f"{path!r}, line {lineno}: parsing error: {e}") +def package_use_splitter(iterable): + """Parse package.use user configuration files + + Basic syntax is <query> (?:-?use_f )* (?:USE_EXPAND: (?:flags)*) + IE, a restriction to match, use flags to turn on. If a 'flag' ends in ':' + then it's considered a USE_EXPAND directive, and all that follow are values of that + USE_EXPAND target and should be expanded into their normalized/long form. + """ + + def f(tokens: list[str]): + i = iter(tokens) + for idx, x in enumerate(i): + if x.endswith(":"): + # we encountered `USE_EXPAND:` , thus all following tokens + # are values of that. + x = x.lower()[:-1] + l = tokens[0:idx] + for flag in i: + if flag.startswith("-"): + flag = f"-{x}_{flag[1:]}" + else: + flag = f"{x}_{flag}" + l.append(flag) + return l + # if we made it here, there's no USE_EXPAND; thus just return the original sequence + return tokens + + return restriction_payload_splitter(iterable, post_process=f) + + def package_env_splitter(basedir, iterable): for line, lineno, path in iterable: val = line.split() @@ -396,25 +428,25 @@ class domain(config_domain): return tuple(x[0] for x in data) # TODO: deprecated, remove in 0.11 - @load_property("package.keywords", parse_func=package_keywords_splitter) + @load_property("package.keywords", parse_func=restriction_payload_splitter) def pkg_keywords(self, data, debug=False): if debug: return tuple(data) return tuple((x[0], stable_unique(x[1])) for x in data) - @load_property("package.accept_keywords", parse_func=package_keywords_splitter) + @load_property("package.accept_keywords", parse_func=restriction_payload_splitter) def pkg_accept_keywords(self, data, debug=False): if debug: return tuple(data) return tuple((x[0], stable_unique(x[1])) for x in data) - @load_property("package.license", parse_func=package_keywords_splitter) + @load_property("package.license", parse_func=restriction_payload_splitter) def pkg_licenses(self, data, debug=False): if debug: return tuple(data) return tuple((x[0], stable_unique(x[1])) for x in data) - @load_property("package.use", parse_func=package_keywords_splitter) + @load_property("package.use", parse_func=package_use_splitter) def pkg_use(self, data, debug=False): if debug: return tuple(data) diff --git a/tests/ebuild/test_domain.py b/tests/ebuild/test_domain.py index 6629cfb9a..87c3d489f 100644 --- a/tests/ebuild/test_domain.py +++ b/tests/ebuild/test_domain.py @@ -1,3 +1,4 @@ +import textwrap from unittest import mock import pytest @@ -54,3 +55,30 @@ class TestDomain: (packages.AlwaysTrue, ((), ("X",))), (packages.AlwaysTrue, (("X",), ("Y",))), ) == self.mk_domain().pkg_use + + def test_use_expand_syntax(self): + puse = self.confdir / "package.use" + puse.mkdir() + open(puse / "a", "w").write( + textwrap.dedent( + """ + */* x_y1 + # unrelated is there to verify that it's unaffected by the USE_EXPAND + */* unrelated X: -y1 y2 + """ + ) + ) + + assert ( + (packages.AlwaysTrue, ((), ("x_y1",))), + ( + packages.AlwaysTrue, + ( + ("x_y1",), + ( + "unrelated", + "x_y2", + ), + ), + ), + ) == self.mk_domain().pkg_use
