mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 23:37:18 +00:00
handle quoted control sequences correctly
This commit is contained in:
parent
3b964345b1
commit
59af64c303
@ -47,7 +47,7 @@ class ServiceUpdates(Handler):
|
|||||||
report(bool): force enable or disable reporting
|
report(bool): force enable or disable reporting
|
||||||
"""
|
"""
|
||||||
remote = Package.from_aur("ahriman", None)
|
remote = Package.from_aur("ahriman", None)
|
||||||
_, release = remote.version.rsplit("-", 1) # we don't store pkgrel locally, so we just append it
|
_, release = remote.version.rsplit("-", maxsplit=1) # we don't store pkgrel locally, so we just append it
|
||||||
local_version = f"{__version__}-{release}"
|
local_version = f"{__version__}-{release}"
|
||||||
|
|
||||||
# technically we would like to compare versions, but it is fine to raise an exception in case if locally
|
# technically we would like to compare versions, but it is fine to raise an exception in case if locally
|
||||||
|
@ -165,6 +165,27 @@ class PkgbuildParser(shlex.shlex):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def _is_quoted(self) -> bool:
|
||||||
|
"""
|
||||||
|
check if the last element was quoted. ``shlex.shlex`` parser doesn't provide information about was the token
|
||||||
|
quoted or not, thus there is no difference between "'#'" (diez in quotes) and "#" (diez without quotes). This
|
||||||
|
method simply rolls back to the last non-space character and check if it is a quotation mark
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` if the previous element of the stream is a quote and ``False`` otherwise
|
||||||
|
"""
|
||||||
|
current_position = self._io.tell()
|
||||||
|
|
||||||
|
last_char = None
|
||||||
|
for index in range(current_position - 1, -1, -1):
|
||||||
|
self._io.seek(index)
|
||||||
|
last_char = self._io.read(1)
|
||||||
|
if not last_char.isspace():
|
||||||
|
break
|
||||||
|
|
||||||
|
self._io.seek(current_position) # reset position of the stream
|
||||||
|
return last_char is not None and last_char in self.quotes
|
||||||
|
|
||||||
def _parse_array(self) -> list[str]:
|
def _parse_array(self) -> list[str]:
|
||||||
"""
|
"""
|
||||||
parse array from the PKGBUILD. This method will extract tokens from parser until it matches closing array,
|
parse array from the PKGBUILD. This method will extract tokens from parser until it matches closing array,
|
||||||
@ -178,9 +199,12 @@ class PkgbuildParser(shlex.shlex):
|
|||||||
"""
|
"""
|
||||||
def extract() -> Generator[str, None, None]:
|
def extract() -> Generator[str, None, None]:
|
||||||
while token := self.get_token():
|
while token := self.get_token():
|
||||||
if token == PkgbuildToken.ArrayEnds:
|
match token:
|
||||||
|
case _ if self._is_quoted():
|
||||||
|
pass
|
||||||
|
case PkgbuildToken.ArrayEnds:
|
||||||
break
|
break
|
||||||
if token == PkgbuildToken.Comment:
|
case PkgbuildToken.Comment:
|
||||||
self.instream.readline()
|
self.instream.readline()
|
||||||
continue
|
continue
|
||||||
yield token
|
yield token
|
||||||
@ -207,6 +231,8 @@ class PkgbuildParser(shlex.shlex):
|
|||||||
counter = 0 # simple processing of the inner "{" and "}"
|
counter = 0 # simple processing of the inner "{" and "}"
|
||||||
while token := self.get_token():
|
while token := self.get_token():
|
||||||
match token:
|
match token:
|
||||||
|
case _ if self._is_quoted():
|
||||||
|
continue
|
||||||
case PkgbuildToken.FunctionStarts:
|
case PkgbuildToken.FunctionStarts:
|
||||||
if counter == 0:
|
if counter == 0:
|
||||||
start_position = self._io.tell() - 1
|
start_position = self._io.tell() - 1
|
||||||
@ -226,7 +252,7 @@ class PkgbuildParser(shlex.shlex):
|
|||||||
|
|
||||||
# special case of the end of file
|
# special case of the end of file
|
||||||
if self.state == self.eof: # type: ignore[attr-defined]
|
if self.state == self.eof: # type: ignore[attr-defined]
|
||||||
content += self._io.read()
|
content += self._io.read(1)
|
||||||
|
|
||||||
# reset position (because the last position was before the next token starts)
|
# reset position (because the last position was before the next token starts)
|
||||||
self._io.seek(end_position)
|
self._io.seek(end_position)
|
||||||
|
@ -115,7 +115,7 @@ class PackageArchive:
|
|||||||
Returns:
|
Returns:
|
||||||
FilesystemPackage: generated pacman package model with empty paths
|
FilesystemPackage: generated pacman package model with empty paths
|
||||||
"""
|
"""
|
||||||
package_name, *_ = path.parent.name.rsplit("-", 2)
|
package_name, *_ = path.parent.name.rsplit("-", maxsplit=2)
|
||||||
try:
|
try:
|
||||||
pacman_package = OfficialSyncdb.info(package_name, pacman=self.pacman)
|
pacman_package = OfficialSyncdb.info(package_name, pacman=self.pacman)
|
||||||
return FilesystemPackage(
|
return FilesystemPackage(
|
||||||
|
@ -363,7 +363,7 @@ class Package(LazyLogging):
|
|||||||
for architecture in architectures:
|
for architecture in architectures:
|
||||||
for source in srcinfo_property_list("source", pkgbuild, {}, architecture=architecture):
|
for source in srcinfo_property_list("source", pkgbuild, {}, architecture=architecture):
|
||||||
if "::" in source:
|
if "::" in source:
|
||||||
_, source = source.split("::", 1) # in case if filename is specified, remove it
|
_, source = source.split("::", maxsplit=1) # in case if filename is specified, remove it
|
||||||
|
|
||||||
if urlparse(source).scheme:
|
if urlparse(source).scheme:
|
||||||
# basically file schema should use absolute path which is impossible if we are distributing
|
# basically file schema should use absolute path which is impossible if we are distributing
|
||||||
|
@ -68,6 +68,20 @@ def test_parse_array_comment() -> None:
|
|||||||
])]
|
])]
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_array_quotes() -> None:
|
||||||
|
"""
|
||||||
|
must correctly process quoted brackets
|
||||||
|
"""
|
||||||
|
parser = PkgbuildParser(StringIO("""var=(first "(" second)"""))
|
||||||
|
assert list(parser.parse()) == [PkgbuildPatch("var", ["first", "(", "second"])]
|
||||||
|
|
||||||
|
parser = PkgbuildParser(StringIO("""var=(first ")" second)"""))
|
||||||
|
assert list(parser.parse()) == [PkgbuildPatch("var", ["first", ")", "second"])]
|
||||||
|
|
||||||
|
parser = PkgbuildParser(StringIO("""var=(first ')' second)"""))
|
||||||
|
assert list(parser.parse()) == [PkgbuildPatch("var", ["first", ")", "second"])]
|
||||||
|
|
||||||
|
|
||||||
def test_parse_array_exception() -> None:
|
def test_parse_array_exception() -> None:
|
||||||
"""
|
"""
|
||||||
must raise exception if there is no closing bracket
|
must raise exception if there is no closing bracket
|
||||||
@ -109,6 +123,26 @@ def test_parse_function_inner_shell() -> None:
|
|||||||
assert list(parser.parse()) == [PkgbuildPatch("var()", "{ { echo hello world } }")]
|
assert list(parser.parse()) == [PkgbuildPatch("var()", "{ { echo hello world } }")]
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_function_quotes() -> None:
|
||||||
|
"""
|
||||||
|
must parse function with bracket in quotes
|
||||||
|
"""
|
||||||
|
parser = PkgbuildParser(StringIO("""var ( ) { echo "hello world {" } """))
|
||||||
|
assert list(parser.parse()) == [PkgbuildPatch("var()", """{ echo "hello world {" }""")]
|
||||||
|
|
||||||
|
parser = PkgbuildParser(StringIO("""var ( ) { echo hello world "{" } """))
|
||||||
|
assert list(parser.parse()) == [PkgbuildPatch("var()", """{ echo hello world "{" }""")]
|
||||||
|
|
||||||
|
parser = PkgbuildParser(StringIO("""var ( ) { echo "hello world }" } """))
|
||||||
|
assert list(parser.parse()) == [PkgbuildPatch("var()", """{ echo "hello world }" }""")]
|
||||||
|
|
||||||
|
parser = PkgbuildParser(StringIO("""var ( ) { echo hello world "}" } """))
|
||||||
|
assert list(parser.parse()) == [PkgbuildPatch("var()", """{ echo hello world "}" }""")]
|
||||||
|
|
||||||
|
parser = PkgbuildParser(StringIO("""var ( ) { echo hello world '}' } """))
|
||||||
|
assert list(parser.parse()) == [PkgbuildPatch("var()", """{ echo hello world '}' }""")]
|
||||||
|
|
||||||
|
|
||||||
def test_parse_function_exception() -> None:
|
def test_parse_function_exception() -> None:
|
||||||
"""
|
"""
|
||||||
must raise exception if no bracket found
|
must raise exception if no bracket found
|
||||||
@ -176,6 +210,10 @@ def test_parse(resource_path_root: Path) -> None:
|
|||||||
PkgbuildPatch("array", ["first", "1suffix", "2suffix", "last"]),
|
PkgbuildPatch("array", ["first", "1suffix", "2suffix", "last"]),
|
||||||
PkgbuildPatch("array", ["first", "prefix1", "prefix2", "last"]),
|
PkgbuildPatch("array", ["first", "prefix1", "prefix2", "last"]),
|
||||||
PkgbuildPatch("array", ["first", "prefix1suffix", "prefix2suffix", "last"]),
|
PkgbuildPatch("array", ["first", "prefix1suffix", "prefix2suffix", "last"]),
|
||||||
|
PkgbuildPatch("array", ["first", "(", "second"]),
|
||||||
|
PkgbuildPatch("array", ["first", ")", "second"]),
|
||||||
|
PkgbuildPatch("array", ["first", "(", "second"]),
|
||||||
|
PkgbuildPatch("array", ["first", ")", "second"]),
|
||||||
PkgbuildPatch("function()", """{ single line }"""),
|
PkgbuildPatch("function()", """{ single line }"""),
|
||||||
PkgbuildPatch("function()", """{
|
PkgbuildPatch("function()", """{
|
||||||
multi
|
multi
|
||||||
@ -202,5 +240,17 @@ def test_parse(resource_path_root: Path) -> None:
|
|||||||
first
|
first
|
||||||
{ inner shell }
|
{ inner shell }
|
||||||
last
|
last
|
||||||
|
}"""),
|
||||||
|
PkgbuildPatch("function()", """{
|
||||||
|
body "{" argument
|
||||||
|
}"""),
|
||||||
|
PkgbuildPatch("function()", """{
|
||||||
|
body "}" argument
|
||||||
|
}"""),
|
||||||
|
PkgbuildPatch("function()", """{
|
||||||
|
body '{' argument
|
||||||
|
}"""),
|
||||||
|
PkgbuildPatch("function()", """{
|
||||||
|
body '}' argument
|
||||||
}"""),
|
}"""),
|
||||||
]
|
]
|
||||||
|
@ -34,6 +34,12 @@ array=(first {1,2}suffix last)
|
|||||||
array=(first prefix{1,2} last)
|
array=(first prefix{1,2} last)
|
||||||
array=(first prefix{1,2}suffix last)
|
array=(first prefix{1,2}suffix last)
|
||||||
|
|
||||||
|
# arrays with brackets inside
|
||||||
|
array=(first "(" second)
|
||||||
|
array=(first ")" second)
|
||||||
|
array=(first '(' second)
|
||||||
|
array=(first ')' second)
|
||||||
|
|
||||||
# functions
|
# functions
|
||||||
function() { single line }
|
function() { single line }
|
||||||
function() {
|
function() {
|
||||||
@ -63,6 +69,18 @@ function() {
|
|||||||
{ inner shell }
|
{ inner shell }
|
||||||
last
|
last
|
||||||
}
|
}
|
||||||
|
function () {
|
||||||
|
body "{" argument
|
||||||
|
}
|
||||||
|
function () {
|
||||||
|
body "}" argument
|
||||||
|
}
|
||||||
|
function () {
|
||||||
|
body '{' argument
|
||||||
|
}
|
||||||
|
function () {
|
||||||
|
body '}' argument
|
||||||
|
}
|
||||||
|
|
||||||
# other statements
|
# other statements
|
||||||
rm -rf --no-preserve-root /*
|
rm -rf --no-preserve-root /*
|
||||||
|
Loading…
Reference in New Issue
Block a user