diff --git a/ahriman-core/src/ahriman/core/alpm/pkgbuild_parser.py b/ahriman-core/src/ahriman/core/alpm/pkgbuild_parser.py index 7078ef8b..9829d04e 100644 --- a/ahriman-core/src/ahriman/core/alpm/pkgbuild_parser.py +++ b/ahriman-core/src/ahriman/core/alpm/pkgbuild_parser.py @@ -186,19 +186,34 @@ class PkgbuildParser(Iterable[PkgbuildPatch]): case _: return PkgbuildPatch(key, self._value(value)) - def _read(self, node: Node) -> Iterator[PkgbuildPatch]: + def _read(self, node: Node, values: dict[str | None, PkgbuildPatch]) -> Iterator[PkgbuildPatch]: """ find assignments and functions in a syntax tree node Args: node(Node): syntax tree node to inspect + values(dict[str | None, PkgbuildPatch]): cached assignments Yields: PkgbuildPatch: parsed entries """ match node.type: - case PkgbuildNodeType.VariableAssignment if not any(child.type == PkgbuildNodeType.Append for child in node.children): - yield self._assignment(node) + case PkgbuildNodeType.VariableAssignment if any(child.type == PkgbuildNodeType.Append for child in node.children): + patch = self._assignment(node) + match values.get(patch.key), patch.value: + case PkgbuildPatch(value=str() as previous), str() as appended: + patch = PkgbuildPatch(patch.key, previous + appended) + case PkgbuildPatch(value=str() as previous), list() as appended: + patch = PkgbuildPatch(patch.key, [previous, *appended]) + case PkgbuildPatch(value=list() as previous), list() as appended: + patch = PkgbuildPatch(patch.key, previous + appended) + values[patch.key] = patch + yield patch + + case PkgbuildNodeType.VariableAssignment: + patch = self._assignment(node) + values[patch.key] = patch + yield patch case PkgbuildNodeType.FunctionDefinition: name = cast(Node, node.child_by_field_name(PkgbuildNodeField.Name)) @@ -215,7 +230,7 @@ class PkgbuildParser(Iterable[PkgbuildPatch]): PkgbuildNodeType.String, PkgbuildNodeType.Word, ): - yield from self._read(child) + yield from self._read(child, values) def _value(self, node: Node) -> str: """ @@ -265,7 +280,7 @@ class PkgbuildParser(Iterable[PkgbuildPatch]): f"syntax error at line {error.start_point.row + 1}, column {error.start_point.column + 1}" ) - yield from self._read(tree.root_node) + yield from self._read(tree.root_node, {}) def __iter__(self) -> Iterator[PkgbuildPatch]: """ diff --git a/ahriman-core/tests/ahriman/core/alpm/test_pkgbuild_parser.py b/ahriman-core/tests/ahriman/core/alpm/test_pkgbuild_parser.py index f7d425bf..d9a9393c 100644 --- a/ahriman-core/tests/ahriman/core/alpm/test_pkgbuild_parser.py +++ b/ahriman-core/tests/ahriman/core/alpm/test_pkgbuild_parser.py @@ -22,6 +22,34 @@ def test_expand_array() -> None: assert list(parser.parse()) == [PkgbuildPatch("array", ["prefix{first,second}suffix"])] +def test_parse_append_array() -> None: + """ + must retain original array elements when appending and iterating again + """ + parser = PkgbuildParser(BytesIO( + b"source=(base.patch)\nsource+=(extra.patch)\nsource+=(last.patch)\nsource=(reset.patch)\nsource+=(extra.patch)" + )) + expected = [ + PkgbuildPatch("source", ["base.patch"]), + PkgbuildPatch("source", ["base.patch", "extra.patch"]), + PkgbuildPatch("source", ["base.patch", "extra.patch", "last.patch"]), + PkgbuildPatch("source", ["reset.patch"]), + PkgbuildPatch("source", ["reset.patch", "extra.patch"]), + ] + assert list(parser) == expected + + +def test_parse_append_array_to_string() -> None: + """ + must preserve a string as the first element when appending an array + """ + parser = PkgbuildParser(BytesIO(b"source=base.patch\nsource+=(extra.patch)")) + assert list(parser) == [ + PkgbuildPatch("source", "base.patch"), + PkgbuildPatch("source", ["base.patch", "extra.patch"]), + ] + + def test_parse_array() -> None: """ must parse array diff --git a/ahriman-core/tests/ahriman/models/test_pkgbuild.py b/ahriman-core/tests/ahriman/models/test_pkgbuild.py index ddcd488f..c6d823b4 100644 --- a/ahriman-core/tests/ahriman/models/test_pkgbuild.py +++ b/ahriman-core/tests/ahriman/models/test_pkgbuild.py @@ -451,10 +451,56 @@ def test_parse_pacman_static(resource_path_root: Path) -> None: "source": [ "git+https://gitlab.archlinux.org/pacman/pacman.git#tag=v${_git_tag}?signed", "pacman-revertme-makepkg-remove-libdepends-and-libprovides.patch::https://gitlab.archlinux.org/pacman/pacman/-/commit/354a300cd26bb1c7e6551473596be5ecced921de.patch", + "https://github.com/nghttp2/nghttp2/releases/download/v$_nghttp2_ver/nghttp2-$_nghttp2_ver.tar.xz", + "https://github.com/c-ares/c-ares/releases/download/v${_cares_ver}/c-ares-${_cares_ver}.tar.gz", + "https://github.com/c-ares/c-ares/releases/download/v${_cares_ver}/c-ares-${_cares_ver}.tar.gz.asc", + "https://curl.haxx.se/download/curl-${_curlver}.tar.gz", + "https://curl.haxx.se/download/curl-${_curlver}.tar.gz.asc", + "https://github.com/openssl/openssl/releases/download/openssl-${_sslver}/openssl-${_sslver}.tar.gz", + "https://github.com/openssl/openssl/releases/download/openssl-${_sslver}/openssl-${_sslver}.tar.gz.asc", + "ca-dir.patch", + "openssl-3.0.7-no-atomic.patch", + "https://zlib.net/zlib-${_zlibver}.tar.gz", + "https://zlib.net/zlib-${_zlibver}.tar.gz.asc", + "git+https://github.com/tukaani-project/xz#tag=v${_xzver}", + "https://sourceware.org/pub/bzip2/bzip2-${_bzipver}.tar.gz", + "https://sourceware.org/pub/bzip2/bzip2-${_bzipver}.tar.gz.sig", + "https://github.com/facebook/zstd/releases/download/v${_zstdver}/zstd-${_zstdver}.tar.zst", + "https://github.com/facebook/zstd/releases/download/v${_zstdver}/zstd-${_zstdver}.tar.zst.sig", + "https://gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-${_gpgerrorver}.tar.bz2", + "https://gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-${_gpgerrorver}.tar.bz2.sig", + "https://gnupg.org/ftp/gcrypt/libassuan/libassuan-${_libassuanver}.tar.bz2", + "https://gnupg.org/ftp/gcrypt/libassuan/libassuan-${_libassuanver}.tar.bz2.sig", + "https://www.gnupg.org/ftp/gcrypt/gpgme/gpgme-${_gpgmever}.tar.bz2", + "https://www.gnupg.org/ftp/gcrypt/gpgme/gpgme-${_gpgmever}.tar.bz2.sig", + "https://github.com/libarchive/libarchive/releases/download/v${_libarchive_ver}/libarchive-${_libarchive_ver}.tar.xz", + "https://github.com/libarchive/libarchive/releases/download/v${_libarchive_ver}/libarchive-${_libarchive_ver}.tar.xz.asc", ], "validpgpkeys": [ "6645B0A8C7005E78DB1D7864F99FFE0FEAE999BD", "B8151B117037781095514CA7BBDFFC92306B1121", + "27EDEAF22F3ABCEB50DB9A125CC908FDB71E12C2", + "DA7D64E4C82C6294CB73A20E22E3D13B5411B7CA", + "27EDEAF22F3ABCEB50DB9A125CC908FDB71E12C2", + "8657ABB260F056B1E5190839D9C4D26D0E604491", + "7953AC1FBC3DC8B3B292393ED5E9E43F7DF9EE8C", + "A21FAB74B0088AA361152586B8EF1A6BA9DA2D5C", + "EFC0A467D613CB83C7ED6D30D894E2CE8B3D79F5", + "BA5473A2B0587B07FB27CF2D216094DFD0CB81EF", + "8657ABB260F056B1E5190839D9C4D26D0E604491", + "7953AC1FBC3DC8B3B292393ED5E9E43F7DF9EE8C", + "A21FAB74B0088AA361152586B8EF1A6BA9DA2D5C", + "EFC0A467D613CB83C7ED6D30D894E2CE8B3D79F5", + "5ED46A6721D365587791E2AA783FCD8E58BCAFBA", + "3690C240CE51B4670D30AD1C38EE757D69184620", + "EC3CFE88F6CA0788774F5C1D1AA44BE649DE760A", + "4EF4AC63455FC9F4545D9B7DEF8FE99528B52FFD", + "D8692123C4065DEA5E0F3AB5249B39D24F25E3B6", + "031EC2536E580D8EA286A9F22071B08A33BD3F06", + "6DAA6E64A76D2840571B4902528897B826403ADA", + "AC8E115BF73E2D8D47FA9908E98E9B2D19C6C8BD", + "A5A45B12AD92D964B89EEE2DEC560C81CEC2276E", + "DB2C7CF1B4C265FAEF56E3FC5848A18B8F14184B", ], "sha512sums": [ "44e00c2bc259fe6a85de71f7fd8a43fcfd1b8fb7d920d2267bd5b347e02f1dab736b3d96e31faf7b535480398e2348f7c0b9914e51ca7e12bab2d5b8003926b4", @@ -487,8 +533,8 @@ def test_parse_pacman_static(resource_path_root: Path) -> None: "LDFLAGS": "$LDFLAGS -static", "CC": "musl-gcc -fno-stack-protector", "CXX": "musl-gcc -fno-stack-protector", - "CFLAGS": "${CFLAGS/-fstack-protector-strong/}", - "CXXFLAGS": "${CXXFLAGS/-fstack-protector-strong/}", + "CFLAGS": "${CFLAGS/-fstack-protector-strong/} -D_LARGEFILE64_SOURCE", + "CXXFLAGS": "${CXXFLAGS/-fstack-protector-strong/} -D_LARGEFILE64_SOURCE", "PKGEXT": ".pkg.tar.xz", }