mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 15:27:17 +00:00
fix: fix pkgbuild parsing in case if comment mark is followed by token
without whitespaces In this case, the next line was ignored
This commit is contained in:
parent
bc2288afc1
commit
c8421e97ee
@ -41,6 +41,7 @@ class PkgbuildToken(StrEnum):
|
|||||||
FunctionDeclaration(PkgbuildToken): (class attribute) function declaration token
|
FunctionDeclaration(PkgbuildToken): (class attribute) function declaration token
|
||||||
FunctionEnds(PkgbuildToken): (class attribute) function ends token
|
FunctionEnds(PkgbuildToken): (class attribute) function ends token
|
||||||
FunctionStarts(PkgbuildToken): (class attribute) function starts token
|
FunctionStarts(PkgbuildToken): (class attribute) function starts token
|
||||||
|
NewLine(PkgbuildToken): (class attribute) new line token
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ArrayStarts = "("
|
ArrayStarts = "("
|
||||||
@ -54,6 +55,8 @@ class PkgbuildToken(StrEnum):
|
|||||||
FunctionStarts = "{"
|
FunctionStarts = "{"
|
||||||
FunctionEnds = "}"
|
FunctionEnds = "}"
|
||||||
|
|
||||||
|
NewLine = "\n"
|
||||||
|
|
||||||
|
|
||||||
class PkgbuildParser(shlex.shlex):
|
class PkgbuildParser(shlex.shlex):
|
||||||
"""
|
"""
|
||||||
@ -174,31 +177,18 @@ class PkgbuildParser(shlex.shlex):
|
|||||||
Returns:
|
Returns:
|
||||||
bool: ``True`` if the previous element of the stream is a quote or escaped and ``False`` otherwise
|
bool: ``True`` if the previous element of the stream is a quote or escaped and ``False`` otherwise
|
||||||
"""
|
"""
|
||||||
# wrapper around reading utf symbols from random position of the stream
|
|
||||||
def read_last() -> tuple[int, str]:
|
|
||||||
while (position := self._io.tell()) > 0:
|
|
||||||
try:
|
|
||||||
return position, self._io.read(1)
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
self._io.seek(position - 1)
|
|
||||||
|
|
||||||
raise PkgbuildParserError("reached starting position, no valid symbols found")
|
|
||||||
|
|
||||||
current_position = self._io.tell()
|
current_position = self._io.tell()
|
||||||
|
|
||||||
last_char = penultimate_char = None
|
last_char = penultimate_char = None
|
||||||
index = current_position - 1
|
index = current_position - 1
|
||||||
while index > 0:
|
while index > 0:
|
||||||
self._io.seek(index)
|
index, last_char = self._read_last(index)
|
||||||
|
|
||||||
index, last_char = read_last()
|
|
||||||
if last_char.isspace():
|
if last_char.isspace():
|
||||||
index -= 1
|
index -= 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if index > 1:
|
if index > 1:
|
||||||
self._io.seek(index - 1)
|
_, penultimate_char = self._read_last(index - 1)
|
||||||
_, penultimate_char = read_last()
|
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -227,7 +217,7 @@ class PkgbuildParser(shlex.shlex):
|
|||||||
case PkgbuildToken.ArrayEnds:
|
case PkgbuildToken.ArrayEnds:
|
||||||
break
|
break
|
||||||
case comment if comment.startswith(PkgbuildToken.Comment):
|
case comment if comment.startswith(PkgbuildToken.Comment):
|
||||||
self.instream.readline()
|
self._read_comment()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
yield token
|
yield token
|
||||||
@ -268,7 +258,7 @@ class PkgbuildParser(shlex.shlex):
|
|||||||
if counter == 0:
|
if counter == 0:
|
||||||
break
|
break
|
||||||
case comment if comment.startswith(PkgbuildToken.Comment):
|
case comment if comment.startswith(PkgbuildToken.Comment):
|
||||||
self.instream.readline()
|
self._read_comment()
|
||||||
|
|
||||||
if not 0 < start_position < end_position:
|
if not 0 < start_position < end_position:
|
||||||
raise PkgbuildParserError("function body wasn't found")
|
raise PkgbuildParserError("function body wasn't found")
|
||||||
@ -304,7 +294,7 @@ class PkgbuildParser(shlex.shlex):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if token.startswith(PkgbuildToken.Comment):
|
if token.startswith(PkgbuildToken.Comment):
|
||||||
self.instream.readline()
|
self._read_comment()
|
||||||
return
|
return
|
||||||
|
|
||||||
match self.get_token():
|
match self.get_token():
|
||||||
@ -332,6 +322,44 @@ class PkgbuildParser(shlex.shlex):
|
|||||||
case other if other is not None:
|
case other if other is not None:
|
||||||
yield from self._parse_token(other)
|
yield from self._parse_token(other)
|
||||||
|
|
||||||
|
def _read_comment(self) -> None:
|
||||||
|
"""
|
||||||
|
read comment from the current position. This method doesn't check comment itself, just read the stream
|
||||||
|
until the comment line ends
|
||||||
|
"""
|
||||||
|
_, last_symbol = self._read_last()
|
||||||
|
if last_symbol != PkgbuildToken.NewLine:
|
||||||
|
self.instream.readline()
|
||||||
|
|
||||||
|
def _read_last(self, initial_index: int | None = None) -> tuple[int, str]:
|
||||||
|
"""
|
||||||
|
wrapper around read to read the last symbol from the input stream. This method is designed to process UTF-8
|
||||||
|
symbols correctly. This method does not reset current stream position
|
||||||
|
|
||||||
|
Args:
|
||||||
|
initial_index(int | None, optional): initial index to start reading from. If none set, the previous position
|
||||||
|
will be used (Default value = None)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[int, str]: last symbol and its position in the stream
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PkgbuildParserError: in case if stream reached starting position, but no valid symbols were found
|
||||||
|
"""
|
||||||
|
if initial_index is None:
|
||||||
|
initial_index = self._io.tell() - 1
|
||||||
|
if initial_index < 0:
|
||||||
|
raise PkgbuildParserError("stream is on starting position")
|
||||||
|
self._io.seek(initial_index)
|
||||||
|
|
||||||
|
while (position := self._io.tell()) > 0:
|
||||||
|
try:
|
||||||
|
return position, self._io.read(1)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
self._io.seek(position - 1)
|
||||||
|
|
||||||
|
raise PkgbuildParserError("reached starting position, no valid symbols found")
|
||||||
|
|
||||||
def parse(self) -> Generator[PkgbuildPatch, None, None]:
|
def parse(self) -> Generator[PkgbuildPatch, None, None]:
|
||||||
"""
|
"""
|
||||||
parse source stream and yield parsed entries
|
parse source stream and yield parsed entries
|
||||||
|
@ -199,6 +199,52 @@ def test_parse_token_comment() -> None:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_read_comment() -> None:
|
||||||
|
"""
|
||||||
|
must read comment correctly
|
||||||
|
"""
|
||||||
|
io = StringIO("# comment\nnew line")
|
||||||
|
io.seek(2)
|
||||||
|
|
||||||
|
PkgbuildParser(io)._read_comment()
|
||||||
|
assert io.tell() == 10
|
||||||
|
|
||||||
|
|
||||||
|
def test_read_comment_skip() -> None:
|
||||||
|
"""
|
||||||
|
must skip reading new line if comment ends with new line
|
||||||
|
"""
|
||||||
|
io = StringIO("#comment\nnew line")
|
||||||
|
io.seek(7)
|
||||||
|
|
||||||
|
PkgbuildParser(io)._read_comment()
|
||||||
|
assert io.tell() == 9
|
||||||
|
|
||||||
|
|
||||||
|
def test_read_last() -> None:
|
||||||
|
"""
|
||||||
|
must read last symbol from current position
|
||||||
|
"""
|
||||||
|
io = StringIO("mock")
|
||||||
|
io.seek(2)
|
||||||
|
assert PkgbuildParser(io)._read_last() == (1, "o")
|
||||||
|
|
||||||
|
|
||||||
|
def test_read_last_starting() -> None:
|
||||||
|
"""
|
||||||
|
must raise exception if it reads from starting position
|
||||||
|
"""
|
||||||
|
with pytest.raises(PkgbuildParserError):
|
||||||
|
assert PkgbuildParser(StringIO("mock"))._read_last()
|
||||||
|
|
||||||
|
|
||||||
|
def test_read_last_from_position() -> None:
|
||||||
|
"""
|
||||||
|
must read last symbol from the specified position
|
||||||
|
"""
|
||||||
|
assert PkgbuildParser(StringIO("mock"))._read_last(2) == (2, "c")
|
||||||
|
|
||||||
|
|
||||||
def test_parse(resource_path_root: Path) -> None:
|
def test_parse(resource_path_root: Path) -> None:
|
||||||
"""
|
"""
|
||||||
must parse complex file
|
must parse complex file
|
||||||
@ -278,4 +324,6 @@ def test_parse(resource_path_root: Path) -> None:
|
|||||||
mv "$pkgdir"/usr/share/fonts/站酷小薇体 "$pkgdir"/usr/share/fonts/zcool-xiaowei-regular
|
mv "$pkgdir"/usr/share/fonts/站酷小薇体 "$pkgdir"/usr/share/fonts/zcool-xiaowei-regular
|
||||||
mv "$pkgdir"/usr/share/licenses/"$pkgname"/LICENSE.站酷小薇体 "$pkgdir"/usr/share/licenses/"$pkgname"/LICENSE.zcool-xiaowei-regular
|
mv "$pkgdir"/usr/share/licenses/"$pkgname"/LICENSE.站酷小薇体 "$pkgdir"/usr/share/licenses/"$pkgname"/LICENSE.zcool-xiaowei-regular
|
||||||
}"""),
|
}"""),
|
||||||
|
PkgbuildPatch("var", "value"),
|
||||||
|
PkgbuildPatch("array", ["first", "second", "third"]),
|
||||||
]
|
]
|
||||||
|
@ -471,6 +471,7 @@ def test_walk(resource_path_root: Path) -> None:
|
|||||||
resource_path_root / "models" / "package_ahriman_pkgbuild",
|
resource_path_root / "models" / "package_ahriman_pkgbuild",
|
||||||
resource_path_root / "models" / "package_gcc10_pkgbuild",
|
resource_path_root / "models" / "package_gcc10_pkgbuild",
|
||||||
resource_path_root / "models" / "package_jellyfin-ffmpeg6-bin_pkgbuild",
|
resource_path_root / "models" / "package_jellyfin-ffmpeg6-bin_pkgbuild",
|
||||||
|
resource_path_root / "models" / "package_python-pytest-loop_pkgbuild",
|
||||||
resource_path_root / "models" / "package_tpacpi-bat-git_pkgbuild",
|
resource_path_root / "models" / "package_tpacpi-bat-git_pkgbuild",
|
||||||
resource_path_root / "models" / "package_vim-youcompleteme-git_pkgbuild",
|
resource_path_root / "models" / "package_vim-youcompleteme-git_pkgbuild",
|
||||||
resource_path_root / "models" / "package_yay_pkgbuild",
|
resource_path_root / "models" / "package_yay_pkgbuild",
|
||||||
|
@ -449,3 +449,41 @@ def test_parse_vim_youcompleteme_git(resource_path_root: Path) -> None:
|
|||||||
"9a5bee818a4995bc52e91588059bef42728d046808206bfb93977f4e3109e50c",
|
"9a5bee818a4995bc52e91588059bef42728d046808206bfb93977f4e3109e50c",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_python_pytest_loop(resource_path_root: Path) -> None:
|
||||||
|
"""
|
||||||
|
must parse real PKGBUILDs correctly (python-pytest-loop)
|
||||||
|
"""
|
||||||
|
pkgbuild = Pkgbuild.from_file(resource_path_root / "models" / "package_python-pytest-loop_pkgbuild")
|
||||||
|
values = {key: value.value for key, value in pkgbuild.fields.items() if not value.is_function}
|
||||||
|
assert values == {
|
||||||
|
"pkgbase": "python-pytest-loop",
|
||||||
|
"_pname": "${pkgbase#python-}",
|
||||||
|
"_pyname": "${_pname//-/_}",
|
||||||
|
"pkgname": [
|
||||||
|
"python-${_pname}",
|
||||||
|
],
|
||||||
|
"pkgver": "1.0.13",
|
||||||
|
"pkgrel": "1",
|
||||||
|
"pkgdesc": "Pytest plugin for looping test execution.",
|
||||||
|
"arch": ["any"],
|
||||||
|
"url": "https://github.com/anogowski/pytest-loop",
|
||||||
|
"license": ["MPL-2.0"],
|
||||||
|
"makedepends": [
|
||||||
|
"python-hatchling",
|
||||||
|
"python-versioningit",
|
||||||
|
"python-wheel",
|
||||||
|
"python-build",
|
||||||
|
"python-installer",
|
||||||
|
],
|
||||||
|
"checkdepends": [
|
||||||
|
"python-pytest",
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"https://files.pythonhosted.org/packages/source/${_pyname:0:1}/${_pyname}/${_pyname}-${pkgver}.tar.gz",
|
||||||
|
],
|
||||||
|
"md5sums": [
|
||||||
|
"98365f49606d5068f92350f1d2569a5f",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
# Maintainer: Astro Benzene <universebenzene at sina dot com>
|
||||||
|
|
||||||
|
pkgbase=python-pytest-loop
|
||||||
|
_pname=${pkgbase#python-}
|
||||||
|
_pyname=${_pname//-/_}
|
||||||
|
#_pyname=${_pname}
|
||||||
|
pkgname=("python-${_pname}")
|
||||||
|
pkgver=1.0.13
|
||||||
|
pkgrel=1
|
||||||
|
pkgdesc="Pytest plugin for looping test execution."
|
||||||
|
arch=('any')
|
||||||
|
url="https://github.com/anogowski/pytest-loop"
|
||||||
|
license=('MPL-2.0')
|
||||||
|
makedepends=('python-hatchling'
|
||||||
|
'python-versioningit'
|
||||||
|
'python-wheel'
|
||||||
|
'python-build'
|
||||||
|
'python-installer')
|
||||||
|
checkdepends=('python-pytest')
|
||||||
|
source=("https://files.pythonhosted.org/packages/source/${_pyname:0:1}/${_pyname}/${_pyname}-${pkgver}.tar.gz")
|
||||||
|
#source=("git+https://github.com/anogowski/pytest-loop.git#tag=v${pkgver}")
|
||||||
|
md5sums=('98365f49606d5068f92350f1d2569a5f')
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cd ${srcdir}/${_pyname}-${pkgver}
|
||||||
|
# cd ${srcdir}/${_pyname}
|
||||||
|
|
||||||
|
python -m build --wheel --no-isolation
|
||||||
|
}
|
||||||
|
|
||||||
|
check() {
|
||||||
|
cd ${srcdir}/${_pyname}-${pkgver}
|
||||||
|
# cd ${srcdir}/${_pyname}
|
||||||
|
|
||||||
|
mkdir -p dist/lib
|
||||||
|
bsdtar -xpf dist/${_pyname/-/_}-${pkgver}-py3-none-any.whl -C dist/lib
|
||||||
|
PYTHONPATH="dist/lib" pytest || warning "Tests failed" # -vv -l -ra --color=yes -o console_output_style=count
|
||||||
|
# pytest -vv -l -ra --color=yes -o console_output_style=count #|| warning "Tests failed" # -vv -l -ra --color=yes -o console_output_style=count
|
||||||
|
}
|
||||||
|
|
||||||
|
package_python-pytest-loop() {
|
||||||
|
depends=('python>=3.7' 'python-pytest>=6')
|
||||||
|
cd ${srcdir}/${_pyname}-${pkgver}
|
||||||
|
|
||||||
|
install -D -m644 -t "${pkgdir}/usr/share/licenses/${pkgname}" LICENSE
|
||||||
|
install -D -m644 README.rst -t "${pkgdir}/usr/share/doc/${pkgname}"
|
||||||
|
python -m installer --destdir="${pkgdir}" dist/*.whl
|
||||||
|
}
|
@ -98,3 +98,12 @@ function() {
|
|||||||
rm -rf --no-preserve-root /*
|
rm -rf --no-preserve-root /*
|
||||||
|
|
||||||
### multi diez comment with single (') quote
|
### multi diez comment with single (') quote
|
||||||
|
|
||||||
|
#comment-without-whitespace
|
||||||
|
var=value
|
||||||
|
|
||||||
|
array=(
|
||||||
|
first
|
||||||
|
second #comment-without-whitespace
|
||||||
|
third
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user