Skip to content

Commit

Permalink
Fix tests with bash 5.2.21
Browse files Browse the repository at this point in the history
  • Loading branch information
Eeems committed Dec 16, 2023
1 parent 942b2d0 commit 02e53d9
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 45 deletions.
64 changes: 38 additions & 26 deletions toltec/bash.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,22 @@ class ScriptError(Exception):
# from the result of `get_declarations()`. Subset of the list at:
# <https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html>
default_variables = {
"_",
"BASH",
"BASHOPTS",
"BASHPID",
"BASH_ALIASES",
"BASH_ARGC",
"BASH_ARGV",
"BASH_ARGV0",
"BASH_CMDS",
"BASH_COMMAND",
"BASH_LINENO",
"BASH_LOADABLES_PATH",
"BASH_SOURCE",
"BASH_SUBSHELL",
"BASH_VERSINFO",
"BASH_VERSION",
"BASHOPTS",
"BASHPID",
"COLUMNS",
"COMP_WORDBREAKS",
"DIRSTACK",
Expand Down Expand Up @@ -78,10 +80,38 @@ class ScriptError(Exception):
"SRANDOM",
"TERM",
"UID",
"_",
}


def _get_bash_stdout(src: str) -> str:
"""
Get the stdout from a bash script
:param src: bash script to run
:returns: the stdout of the script
"""
env: Dict[str, str] = {
"PATH": os.environ["PATH"],
}

subshell = subprocess.run( # pylint:disable=subprocess-run-check
["/usr/bin/env", "bash"],
input=src.encode(),
capture_output=True,
env=env,
)

errors = subshell.stderr.decode()

if subshell.returncode == 2 or "syntax error" in errors:
raise ScriptError(f"Bash syntax error\n{errors}")

if subshell.returncode != 0 or errors:
raise ScriptError(f"Bash error\n{errors}")

return subshell.stdout.decode()


def get_declarations(src: str) -> Tuple[Variables, Functions]:
"""
Extract all variables and functions defined by a Bash script.
Expand All @@ -97,28 +127,7 @@ def get_declarations(src: str) -> Tuple[Variables, Functions]:
declare -f
declare -p
"""
env: Dict[str, str] = {
"PATH": os.environ["PATH"],
}

declarations_subshell = (
subprocess.run( # pylint:disable=subprocess-run-check
["/usr/bin/env", "bash"],
input=src.encode(),
capture_output=True,
env=env,
)
)

errors = declarations_subshell.stderr.decode()

if declarations_subshell.returncode == 2 or "syntax error" in errors:
raise ScriptError(f"Bash syntax error\n{errors}")

if declarations_subshell.returncode != 0 or errors:
raise ScriptError(f"Bash error\n{errors}")

declarations = declarations_subshell.stdout.decode()
declarations = _get_bash_stdout(src)

# Parse `declare` statements and function statements
lexer = shlex.shlex(declarations, posix=True)
Expand Down Expand Up @@ -319,7 +328,10 @@ def _parse_var(lexer: shlex.shlex) -> Tuple[str, Optional[Any]]:
else:
string_token = lexer.get_token() or ""
if string_token == "$":
string_token = lexer.get_token() or ""
quoted_string = lexer.get_token() or ""
string_token = _get_bash_stdout(
"echo -n $" + shlex.quote(quoted_string)
)
var_value = _parse_string(string_token)
else:
lexer.push_token(lookahead)
Expand Down
27 changes: 8 additions & 19 deletions toltec/recipe_parsers/bash.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ def parse(path: str) -> RecipeBundle:
definition = recipe.read()
variables, functions = bash.get_declarations(definition)

for arch, variables, functions in _instantiate_arch(
path, variables, functions
):
for arch, variables, functions in _instantiate_arch(path, variables, functions):
result[arch] = _parse_recipe(path, variables, functions)

return result
Expand Down Expand Up @@ -174,21 +172,15 @@ def _parse_recipe( # pylint: disable=too-many-locals, disable=too-many-statemen

makedepends_raw = _pop_field_indexed(path, variables, "makedepends", [])
raw_vars["makedepends"] = makedepends_raw
attrs["makedepends"] = {
Dependency.parse(dep or "") for dep in makedepends_raw
}
attrs["makedepends"] = {Dependency.parse(dep or "") for dep in makedepends_raw}

attrs["maintainer"] = raw_vars["maintainer"] = _pop_field_string(
path, variables, "maintainer"
)

attrs["image"] = raw_vars["image"] = _pop_field_string(
path, variables, "image", ""
)
attrs["image"] = raw_vars["image"] = _pop_field_string(path, variables, "image", "")

attrs["arch"] = raw_vars["arch"] = _pop_field_string(
path, variables, "arch"
)
attrs["arch"] = raw_vars["arch"] = _pop_field_string(path, variables, "arch")

if attrs["image"] and "build" not in functions:
raise RecipeError(
Expand Down Expand Up @@ -305,9 +297,7 @@ def _parse_package( # pylint: disable=too-many-locals, disable=too-many-stateme
parent.path, variables, "pkgdesc"
)

attrs["url"] = raw_vars["url"] = _pop_field_string(
parent.path, variables, "url"
)
attrs["url"] = raw_vars["url"] = _pop_field_string(parent.path, variables, "url")

attrs["section"] = raw_vars["section"] = _pop_field_string(
parent.path, variables, "section"
Expand Down Expand Up @@ -407,8 +397,7 @@ def _pop_field_string(
if not isinstance(value, str):
raise RecipeError(
path,
f"Field '{name}' must be a string, \
got a {type(value).__name__}",
f"Field '{name}' must be a string, got a {type(value).__name__}",
)

return value
Expand All @@ -428,10 +417,10 @@ def _pop_field_indexed(
value = variables.pop(name)

if not isinstance(value, list):
_name = type(value).__name__
raise RecipeError(
path,
f"Field '{name}' must be an indexed array, \
got a {type(value).__name__}",
f"Field '{name}' must be an indexed array, got a {_name}",
)

return value
Expand Down

0 comments on commit 02e53d9

Please sign in to comment.