mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 07:17:17 +00:00
fix: parse array variable from command
This commit is contained in:
parent
6d05389639
commit
2b33510ada
12
docs/faq.rst
12
docs/faq.rst
@ -208,6 +208,18 @@ This command will prompt for new value of the PKGBUILD variable ``version``. You
|
||||
|
||||
sudo -u ahriman ahriman patch-add ahriman version version.patch
|
||||
|
||||
The command also supports arrays, but in this case you need to specify full array, e.g.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo -u ahriman ahriman patch-add ahriman depends
|
||||
|
||||
Post new function or variable value below. Press Ctrl-D to finish:
|
||||
(python python-aiohttp)
|
||||
^D
|
||||
|
||||
will set depends PKGBUILD variable (exactly) to array ``["python", "python-aiohttp"]``.
|
||||
|
||||
Alternatively you can create full-diff patches, which are calculated by using ``git diff`` from current PKGBUILD master branch:
|
||||
|
||||
#.
|
||||
|
@ -102,8 +102,9 @@ class Patch(Handler):
|
||||
patch = "".join(list(sys.stdin))
|
||||
else:
|
||||
patch = patch_path.read_text(encoding="utf8")
|
||||
patch = patch.strip() # remove spaces around the patch
|
||||
return PkgbuildPatch(variable, patch)
|
||||
# remove spaces around the patch and parse to correct type
|
||||
parsed = PkgbuildPatch.parse(patch.strip())
|
||||
return PkgbuildPatch(variable, parsed)
|
||||
|
||||
@staticmethod
|
||||
def patch_set_create(application: Application, package_base: str, patch: PkgbuildPatch) -> None:
|
||||
|
@ -56,7 +56,6 @@ __all__ = [
|
||||
"srcinfo_property",
|
||||
"srcinfo_property_list",
|
||||
"trim_package",
|
||||
"unquote",
|
||||
"utcnow",
|
||||
"walk",
|
||||
]
|
||||
@ -466,38 +465,6 @@ def trim_package(package_name: str) -> str:
|
||||
return package_name
|
||||
|
||||
|
||||
def unquote(source: str) -> str:
|
||||
"""
|
||||
like :func:`shlex.quote()`, but opposite
|
||||
|
||||
Args:
|
||||
source(str): source string to remove quotes
|
||||
|
||||
Returns:
|
||||
str: string with quotes removed
|
||||
|
||||
Raises:
|
||||
ValueError: if no closing quotation
|
||||
"""
|
||||
def generator() -> Generator[str, None, None]:
|
||||
token = None
|
||||
for char in source:
|
||||
if token is not None:
|
||||
if char == token:
|
||||
token = None # closed quote
|
||||
else:
|
||||
yield char # character inside quotes
|
||||
elif char in ("'", "\""):
|
||||
token = char # first quote found
|
||||
else:
|
||||
yield char # normal character
|
||||
|
||||
if token is not None:
|
||||
raise ValueError("No closing quotation")
|
||||
|
||||
return "".join(generator())
|
||||
|
||||
|
||||
def utcnow() -> datetime.datetime:
|
||||
"""
|
||||
get current time
|
||||
|
@ -21,9 +21,9 @@ import shlex
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Self
|
||||
from typing import Any, Generator, Self
|
||||
|
||||
from ahriman.core.util import dataclass_view, unquote
|
||||
from ahriman.core.util import dataclass_view
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@ -81,14 +81,57 @@ class PkgbuildPatch:
|
||||
Self: package properties
|
||||
"""
|
||||
key, *value_parts = variable.split("=", maxsplit=1)
|
||||
|
||||
raw_value = next(iter(value_parts), "") # extract raw value
|
||||
if raw_value.startswith("(") and raw_value.endswith(")"):
|
||||
value: str | list[str] = shlex.split(raw_value[1:-1]) # arrays for poor
|
||||
else:
|
||||
value = unquote(raw_value)
|
||||
return cls(key, cls.parse(raw_value))
|
||||
|
||||
return cls(key, value)
|
||||
@staticmethod
|
||||
def parse(source: str) -> str | list[str]:
|
||||
"""
|
||||
parse string value to the PKGBUILD patch value. This method simply takes string, tries to identify it as array
|
||||
or just string and return the respective value. Functions should be processed correctly, however, not guaranteed
|
||||
|
||||
Args:
|
||||
source(str): source string to parse
|
||||
|
||||
Returns:
|
||||
str | list[str]: parsed value either string or list of strings
|
||||
"""
|
||||
if source.startswith("(") and source.endswith(")"):
|
||||
return shlex.split(source[1:-1]) # arrays for poor
|
||||
return PkgbuildPatch.unquote(source)
|
||||
|
||||
@staticmethod
|
||||
def unquote(source: str) -> str:
|
||||
"""
|
||||
like :func:`shlex.quote()`, but opposite
|
||||
|
||||
Args:
|
||||
source(str): source string to remove quotes
|
||||
|
||||
Returns:
|
||||
str: string with quotes removed
|
||||
|
||||
Raises:
|
||||
ValueError: if no closing quotation
|
||||
"""
|
||||
|
||||
def generator() -> Generator[str, None, None]:
|
||||
token = None
|
||||
for char in source:
|
||||
if token is not None:
|
||||
if char == token:
|
||||
token = None # closed quote
|
||||
else:
|
||||
yield char # character inside quotes
|
||||
elif char in ("'", "\""):
|
||||
token = char # first quote found
|
||||
else:
|
||||
yield char # normal character
|
||||
|
||||
if token is not None:
|
||||
raise ValueError("No closing quotation")
|
||||
|
||||
return "".join(generator())
|
||||
|
||||
def serialize(self) -> str:
|
||||
"""
|
||||
|
@ -122,11 +122,10 @@ def test_patch_create_from_function(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must create function patch from file
|
||||
"""
|
||||
path = Path("local")
|
||||
patch = PkgbuildPatch("version", "patch")
|
||||
read_mock = mocker.patch("pathlib.Path.read_text", return_value=patch.value)
|
||||
|
||||
assert Patch.patch_create_from_function(patch.key, path) == patch
|
||||
assert Patch.patch_create_from_function(patch.key, Path("local")) == patch
|
||||
read_mock.assert_called_once_with(encoding="utf8")
|
||||
|
||||
|
||||
@ -148,6 +147,15 @@ def test_patch_create_from_function_strip(mocker: MockerFixture) -> None:
|
||||
assert Patch.patch_create_from_function(patch.key, None) == patch
|
||||
|
||||
|
||||
def test_patch_create_from_function_array(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must correctly read array variable
|
||||
"""
|
||||
patch = PkgbuildPatch("version", ["array", "patch"])
|
||||
mocker.patch("pathlib.Path.read_text", return_value=f"({" ".join(patch.value)})")
|
||||
assert Patch.patch_create_from_function(patch.key, Path("local")) == patch
|
||||
|
||||
|
||||
def test_patch_set_list(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must list available patches for the command
|
||||
|
@ -12,7 +12,7 @@ from unittest.mock import call as MockCall
|
||||
from ahriman.core.exceptions import BuildError, CalledProcessError, OptionError, UnsafeRunError
|
||||
from ahriman.core.util import check_output, check_user, dataclass_view, enum_values, extract_user, filter_json, \
|
||||
full_version, minmax, package_like, parse_version, partition, pretty_datetime, pretty_size, safe_filename, \
|
||||
srcinfo_property, srcinfo_property_list, trim_package, unquote, utcnow, walk
|
||||
srcinfo_property, srcinfo_property_list, trim_package, utcnow, walk
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.package_source import PackageSource
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
@ -445,26 +445,6 @@ def test_trim_package() -> None:
|
||||
assert trim_package("package: a description") == "package"
|
||||
|
||||
|
||||
def test_unquote() -> None:
|
||||
"""
|
||||
must remove quotation marks
|
||||
"""
|
||||
for source in (
|
||||
"abc",
|
||||
"ab'c",
|
||||
"ab\"c",
|
||||
):
|
||||
assert unquote(shlex.quote(source)) == source
|
||||
|
||||
|
||||
def test_unquote_error() -> None:
|
||||
"""
|
||||
must raise value error on invalid quotation
|
||||
"""
|
||||
with pytest.raises(ValueError):
|
||||
unquote("ab'c")
|
||||
|
||||
|
||||
def test_utcnow() -> None:
|
||||
"""
|
||||
must generate correct timestamp
|
||||
|
@ -1,3 +1,6 @@
|
||||
import pytest
|
||||
import shlex
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import MagicMock, call
|
||||
@ -48,6 +51,35 @@ def test_from_env() -> None:
|
||||
assert PkgbuildPatch.from_env("KEY") == PkgbuildPatch("KEY", "")
|
||||
|
||||
|
||||
def test_parse() -> None:
|
||||
"""
|
||||
must parse string correctly
|
||||
"""
|
||||
assert PkgbuildPatch.parse("VALUE") == "VALUE"
|
||||
assert PkgbuildPatch.parse("(ARRAY VALUE)") == ["ARRAY", "VALUE"]
|
||||
assert PkgbuildPatch.parse("""("QU'OUTED" ARRAY VALUE)""") == ["QU'OUTED", "ARRAY", "VALUE"]
|
||||
|
||||
|
||||
def test_unquote() -> None:
|
||||
"""
|
||||
must remove quotation marks
|
||||
"""
|
||||
for source in (
|
||||
"abc",
|
||||
"ab'c",
|
||||
"ab\"c",
|
||||
):
|
||||
assert PkgbuildPatch.unquote(shlex.quote(source)) == source
|
||||
|
||||
|
||||
def test_unquote_error() -> None:
|
||||
"""
|
||||
must raise value error on invalid quotation
|
||||
"""
|
||||
with pytest.raises(ValueError):
|
||||
PkgbuildPatch.unquote("ab'c")
|
||||
|
||||
|
||||
def test_serialize() -> None:
|
||||
"""
|
||||
must correctly serialize string values
|
||||
|
Loading…
Reference in New Issue
Block a user