mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-10-24 20:35:01 +00:00
feat: restore iterable method in parser
This commit is contained in:
1 parent
f776b33310
commit
c38cb5f680
4 files changed
+28
-15
No files matched your search
@@ -21,7 +21,7 @@ import re
|
|||||||
import shlex
|
import shlex
|
||||||
import tree_sitter_bash
|
import tree_sitter_bash
|
||||||
|
|
||||||
from collections.abc import Iterator
|
from collections.abc import Iterable, Iterator
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from tree_sitter import Language, Node, Parser
|
from tree_sitter import Language, Node, Parser
|
||||||
from typing import IO, cast
|
from typing import IO, cast
|
||||||
@@ -78,7 +78,7 @@ class PkgbuildNodeField(StrEnum):
|
|||||||
Value = "value"
|
Value = "value"
|
||||||
|
|
||||||
|
|
||||||
class PkgbuildParser:
|
class PkgbuildParser(Iterable[PkgbuildPatch]):
|
||||||
"""
|
"""
|
||||||
PKGBUILD parser implementation in python
|
PKGBUILD parser implementation in python
|
||||||
|
|
||||||
@@ -97,24 +97,29 @@ class PkgbuildParser:
|
|||||||
original source, with their formatting preserved. Assignments inside shell statements and control-flow nodes are
|
original source, with their formatting preserved. Assignments inside shell statements and control-flow nodes are
|
||||||
extracted without checking whether those statements would run.
|
extracted without checking whether those statements would run.
|
||||||
|
|
||||||
|
Each iteration parses the stored source independently, starting from the beginning.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
Parse package assignments::
|
Parse package assignments::
|
||||||
|
|
||||||
>>> source = b"pkgname=example\\npkgver=1\\n"
|
>>> source = b"pkgname=example\\npkgver=1\\n"
|
||||||
>>> for patch in PkgbuildParser(BytesIO(source)).parse():
|
>>> for patch in PkgbuildParser(BytesIO(source)):
|
||||||
... print(patch.key, patch.value)
|
... print(patch.key, patch.value)
|
||||||
|
|
||||||
Function bodies are returned as function patches::
|
Function bodies are returned as function patches::
|
||||||
|
|
||||||
>>> source = b"pkgver() { printf 1; }"
|
>>> source = b"pkgver() { printf 1; }"
|
||||||
>>> for patch in list(PkgbuildParser(BytesIO(source)).parse())
|
>>> for patch in PkgbuildParser(BytesIO(source)):
|
||||||
... print(patch.key, patch.value)
|
... print(patch.key, patch.value)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_BRACE_EXPANSION = re.compile(r"(.*)\{([^{}]+)\}(.*)")
|
_BRACE_EXPANSION = re.compile(r"(.*)\{([^{}]+)\}(.*)")
|
||||||
|
|
||||||
def __init__(self, stream: IO[bytes]) -> None:
|
def __init__(self, stream: IO[bytes]) -> None:
|
||||||
""""""
|
"""
|
||||||
|
Args:
|
||||||
|
stream(IO[bytes]): input PKGBUILD stream
|
||||||
|
"""
|
||||||
self._content = stream.read()
|
self._content = stream.read()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -256,3 +261,12 @@ class PkgbuildParser:
|
|||||||
)
|
)
|
||||||
|
|
||||||
yield from self._read(tree.root_node)
|
yield from self._read(tree.root_node)
|
||||||
|
|
||||||
|
def __iter__(self) -> Iterator[PkgbuildPatch]:
|
||||||
|
"""
|
||||||
|
iterate over the parsed entries
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Iterator[PkgbuildPatch]: parsed entries
|
||||||
|
"""
|
||||||
|
return self.parse()
|
||||||
@@ -80,8 +80,7 @@ class Pkgbuild(Mapping[str, Any]):
|
|||||||
Returns:
|
Returns:
|
||||||
Self: constructed instance of self
|
Self: constructed instance of self
|
||||||
"""
|
"""
|
||||||
parser = PkgbuildParser(stream)
|
fields = {patch.key: patch for patch in PkgbuildParser(stream)}
|
||||||
fields = {patch.key: patch for patch in parser.parse()}
|
|
||||||
|
|
||||||
# pkgbase is optional field, the pkgname must be used instead if not set
|
# pkgbase is optional field, the pkgname must be used instead if not set
|
||||||
# however, pkgname is not presented is "package()" functions which we are parsing here too,
|
# however, pkgname is not presented is "package()" functions which we are parsing here too,
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ def test_parse_array_exception() -> None:
|
|||||||
"""
|
"""
|
||||||
parser = PkgbuildParser(BytesIO(b"var=(first second"))
|
parser = PkgbuildParser(BytesIO(b"var=(first second"))
|
||||||
with pytest.raises(PkgbuildParserError):
|
with pytest.raises(PkgbuildParserError):
|
||||||
assert list(parser.parse())
|
list(parser.parse())
|
||||||
|
|
||||||
|
|
||||||
def test_parse_function() -> None:
|
def test_parse_function() -> None:
|
||||||
@@ -119,11 +119,11 @@ def test_parse_function_exception() -> None:
|
|||||||
"""
|
"""
|
||||||
parser = PkgbuildParser(BytesIO(b"var() echo hello world } "))
|
parser = PkgbuildParser(BytesIO(b"var() echo hello world } "))
|
||||||
with pytest.raises(PkgbuildParserError):
|
with pytest.raises(PkgbuildParserError):
|
||||||
assert list(parser.parse())
|
list(parser.parse())
|
||||||
|
|
||||||
parser = PkgbuildParser(BytesIO(b"var() { echo hello world"))
|
parser = PkgbuildParser(BytesIO(b"var() { echo hello world"))
|
||||||
with pytest.raises(PkgbuildParserError):
|
with pytest.raises(PkgbuildParserError):
|
||||||
assert list(parser.parse())
|
list(parser.parse())
|
||||||
|
|
||||||
|
|
||||||
def test_parse_function_inner_shell() -> None:
|
def test_parse_function_inner_shell() -> None:
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ def test_from_io(pkgbuild_ahriman: Pkgbuild, mocker: MockerFixture) -> None:
|
|||||||
must correctly load from io
|
must correctly load from io
|
||||||
"""
|
"""
|
||||||
load_mock = mocker.patch("ahriman.core.alpm.pkgbuild_parser.PkgbuildParser.parse",
|
load_mock = mocker.patch("ahriman.core.alpm.pkgbuild_parser.PkgbuildParser.parse",
|
||||||
return_value=pkgbuild_ahriman.fields.values())
|
return_value=iter(pkgbuild_ahriman.fields.values()))
|
||||||
assert Pkgbuild.from_io(BytesIO(b"mock")) == pkgbuild_ahriman
|
assert Pkgbuild.from_io(BytesIO(b"mock")) == pkgbuild_ahriman
|
||||||
load_mock.assert_called_once_with()
|
load_mock.assert_called_once_with()
|
||||||
|
|
||||||
@@ -60,9 +60,9 @@ def test_from_io_pkgbase(pkgbuild_ahriman: Pkgbuild, mocker: MockerFixture) -> N
|
|||||||
must assign missing pkgbase if pkgname is presented
|
must assign missing pkgbase if pkgname is presented
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.alpm.pkgbuild_parser.PkgbuildParser.parse", side_effect=[
|
mocker.patch("ahriman.core.alpm.pkgbuild_parser.PkgbuildParser.parse", side_effect=[
|
||||||
[value for key, value in pkgbuild_ahriman.fields.items() if key not in ("pkgbase",)],
|
iter([value for key, value in pkgbuild_ahriman.fields.items() if key not in ("pkgbase",)]),
|
||||||
[value for key, value in pkgbuild_ahriman.fields.items() if key not in ("pkgbase", "pkgname",)],
|
iter([value for key, value in pkgbuild_ahriman.fields.items() if key not in ("pkgbase", "pkgname",)]),
|
||||||
[value for key, value in pkgbuild_ahriman.fields.items()] + [PkgbuildPatch("pkgbase", "pkgbase")],
|
iter([value for key, value in pkgbuild_ahriman.fields.items()] + [PkgbuildPatch("pkgbase", "pkgbase")]),
|
||||||
])
|
])
|
||||||
|
|
||||||
assert Pkgbuild.from_io(BytesIO(b"mock"))["pkgbase"] == pkgbuild_ahriman["pkgname"]
|
assert Pkgbuild.from_io(BytesIO(b"mock"))["pkgbase"] == pkgbuild_ahriman["pkgname"]
|
||||||
@@ -75,7 +75,7 @@ def test_from_io_empty(pkgbuild_ahriman: Pkgbuild, mocker: MockerFixture) -> Non
|
|||||||
must skip empty patches
|
must skip empty patches
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.alpm.pkgbuild_parser.PkgbuildParser.parse",
|
mocker.patch("ahriman.core.alpm.pkgbuild_parser.PkgbuildParser.parse",
|
||||||
return_value=list(pkgbuild_ahriman.fields.values()) + [PkgbuildPatch("", "")])
|
return_value=iter(list(pkgbuild_ahriman.fields.values()) + [PkgbuildPatch("", "")]))
|
||||||
assert Pkgbuild.from_io(BytesIO(b"mock")) == pkgbuild_ahriman
|
assert Pkgbuild.from_io(BytesIO(b"mock")) == pkgbuild_ahriman
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user