mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-10-30 13:06:38 +00:00
Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47158d9db4 | ||
|
|
96558886bd | ||
|
|
4a745321ec | ||
|
|
4446c950ec | ||
|
|
8d569e6075 | ||
|
|
c375236327 | ||
|
|
ddbb4b06ff | ||
|
|
2d66b67123 | ||
|
|
27cfcd07eb | ||
|
|
2080f1e06f | ||
|
|
2544d44051 | ||
|
|
b07ad8cc0c | ||
|
|
c38cb5f680 | ||
|
|
f776b33310 | ||
|
|
eafa1b417a |
No files matched your search
@@ -16,7 +16,7 @@ pacman -S --noconfirm --asdeps base-devel npm python-build python-hatchling pyth
|
|||||||
# optional dependencies
|
# optional dependencies
|
||||||
if [[ -z $MINIMAL_INSTALL ]]; then
|
if [[ -z $MINIMAL_INSTALL ]]; then
|
||||||
# web server
|
# web server
|
||||||
pacman -S --noconfirm --asdeps python-aioauth-client python-aiohttp python-aiohttp-apispec-git python-aiohttp-cors python-aiohttp-jinja2 python-aiohttp-security python-aiohttp-session python-aiohttp-sse-git python-cryptography python-jinja
|
pacman -S --noconfirm --asdeps python-aioauth-client python-aiohttp python-aiohttp-apispec-git python-aiohttp-cors python-aiohttp-jinja2 python-aiohttp-security python-aiohttp-session python-aiohttp-sse python-cryptography python-jinja
|
||||||
# additional features
|
# additional features
|
||||||
pacman -S --noconfirm --asdeps gnupg ipython python-boto3 python-cerberus python-matplotlib python-systemd rsync
|
pacman -S --noconfirm --asdeps gnupg ipython python-boto3 python-cerberus python-matplotlib python-systemd rsync
|
||||||
fi
|
fi
|
||||||
@@ -41,6 +41,7 @@ systemd-machine-id-setup
|
|||||||
|
|
||||||
# remove unused dependencies
|
# remove unused dependencies
|
||||||
pacman -Qdtq | pacman -Rscn --noconfirm -
|
pacman -Qdtq | pacman -Rscn --noconfirm -
|
||||||
|
find "/var/cache/pacman/pkg" -type f -delete
|
||||||
|
|
||||||
# initial setup command as root
|
# initial setup command as root
|
||||||
[[ -z $MINIMAL_INSTALL ]] && WEB_ARGS=("--web-port" "8080")
|
[[ -z $MINIMAL_INSTALL ]] && WEB_ARGS=("--web-port" "8080")
|
||||||
@@ -60,6 +61,6 @@ sudo -u ahriman -- ahriman --log-handler console package-add --now ahriman
|
|||||||
# check if package was actually installed
|
# check if package was actually installed
|
||||||
test -n "$(find "/var/lib/ahriman/repository/github/x86_64" -name "ahriman*pkg*")"
|
test -n "$(find "/var/lib/ahriman/repository/github/x86_64" -name "ahriman*pkg*")"
|
||||||
# run package check
|
# run package check
|
||||||
sudo -u ahriman -- ahriman repo-update
|
sudo -u ahriman -- ahriman --log-handler console repo-update --refresh
|
||||||
# stop web service lol
|
# stop web service lol
|
||||||
[[ -z $WEB_PID ]] || kill $WEB_PID
|
[[ -z $WEB_PID ]] || kill $WEB_PID
|
||||||
@@ -229,6 +229,17 @@ The projects also uses typing checks (provided by `mypy`) and some linter checks
|
|||||||
|
|
||||||
Frontend checks normally are performed by `eslint` (e.g. `npx run eslint`).
|
Frontend checks normally are performed by `eslint` (e.g. `npx run eslint`).
|
||||||
|
|
||||||
|
## AI usage policy
|
||||||
|
|
||||||
|
AI tools may be used when working on the project, including writing code, tests, and documentation, debugging problems, and preparing issue reports. Contributors remain responsible for everything they submit, including content generated or suggested by AI.
|
||||||
|
|
||||||
|
* Review and understand every submitted change. You must be able to explain the implementation, respond to review feedback, and correct any problems.
|
||||||
|
* Do not list AI tools as commit authors or co-authors, including in `Co-authored-by` trailers. Authorship must remain with the human contributors responsible for the changes.
|
||||||
|
* Discussions in issues and pull requests must be led by humans. Participate personally, explain your reasoning, and respond to questions and review feedback yourself. AI tools may help with wording or translation, but must not conduct discussions on your behalf.
|
||||||
|
* Verify claims, references, and reproduction steps before submitting an issue or pull request. Do not submit unreviewed AI output or claim that checks passed unless they were run and you verified the results.
|
||||||
|
|
||||||
|
Maintainers may close submissions that do not meet these requirements. Using AI does not transfer responsibility for reviewing or fixing a contribution to maintainers.
|
||||||
|
|
||||||
## Developers how to
|
## Developers how to
|
||||||
|
|
||||||
### Run automated checks
|
### Run automated checks
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.TH AHRIMAN "1" "2026\-10\-20" "ahriman 2.23.1" "ArcH linux ReposItory MANager"
|
.TH AHRIMAN "1" "2026\-10\-25" "ahriman 2.23.5" "ArcH linux ReposItory MANager"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ahriman \- ArcH linux ReposItory MANager
|
ahriman \- ArcH linux ReposItory MANager
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
|||||||
@@ -17,4 +17,4 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
__version__ = "2.23.1"
|
__version__ = "2.23.5"
|
||||||
@@ -17,15 +17,15 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
import re
|
|
||||||
import shlex
|
import shlex
|
||||||
import tree_sitter_bash
|
import tree_sitter_bash
|
||||||
|
|
||||||
from collections.abc import Iterator
|
from collections.abc import Iterable, Iterator
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from tree_sitter import Language, Node, Parser
|
from tree_sitter import Language, Node, Parser
|
||||||
from typing import IO, cast
|
from typing import IO, cast
|
||||||
|
|
||||||
|
from ahriman.core.configuration.shell_interpolator import ShellInterpolator
|
||||||
from ahriman.core.exceptions import PkgbuildParserError
|
from ahriman.core.exceptions import PkgbuildParserError
|
||||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ class PkgbuildNodeField(StrEnum):
|
|||||||
Value = "value"
|
Value = "value"
|
||||||
|
|
||||||
|
|
||||||
class PkgbuildParser:
|
class PkgbuildParser(Iterable[PkgbuildPatch]):
|
||||||
"""
|
"""
|
||||||
PKGBUILD parser implementation in python
|
PKGBUILD parser implementation in python
|
||||||
|
|
||||||
@@ -97,45 +97,28 @@ class PkgbuildParser:
|
|||||||
original source, with their formatting preserved. Assignments inside shell statements and control-flow nodes are
|
original source, with their formatting preserved. Assignments inside shell statements and control-flow nodes are
|
||||||
extracted without checking whether those statements would run.
|
extracted without checking whether those statements would run.
|
||||||
|
|
||||||
|
Each iteration parses the stored source independently, starting from the beginning.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
Parse package assignments::
|
Parse package assignments::
|
||||||
|
|
||||||
>>> source = b"pkgname=example\\npkgver=1\\n"
|
>>> source = b"pkgname=example\\npkgver=1\\n"
|
||||||
>>> for patch in PkgbuildParser(BytesIO(source)).parse():
|
>>> for patch in PkgbuildParser(BytesIO(source)):
|
||||||
... print(patch.key, patch.value)
|
... print(patch.key, patch.value)
|
||||||
|
|
||||||
Function bodies are returned as function patches::
|
Function bodies are returned as function patches::
|
||||||
|
|
||||||
>>> source = b"pkgver() { printf 1; }"
|
>>> source = b"pkgver() { printf 1; }"
|
||||||
>>> for patch in list(PkgbuildParser(BytesIO(source)).parse())
|
>>> for patch in PkgbuildParser(BytesIO(source)):
|
||||||
... print(patch.key, patch.value)
|
... print(patch.key, patch.value)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_BRACE_EXPANSION = re.compile(r"(.*)\{([^{}]+)\}(.*)")
|
|
||||||
|
|
||||||
def __init__(self, stream: IO[bytes]) -> None:
|
def __init__(self, stream: IO[bytes]) -> None:
|
||||||
""""""
|
|
||||||
self._content = stream.read()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _expand_array(value: str, *, expand: bool = True) -> list[str]:
|
|
||||||
"""
|
"""
|
||||||
expand comma-separated brace expressions in a value
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
value(str): value that may contain a brace expression
|
stream(IO[bytes]): input PKGBUILD stream
|
||||||
expand(bool, optional): whether brace expansion is allowed (Default value = True)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
list[str]: expanded values if applicable
|
|
||||||
"""
|
"""
|
||||||
match = PkgbuildParser._BRACE_EXPANSION.fullmatch(value)
|
self._content = stream.read()
|
||||||
# if there is no comma inside it should be treated as normal value
|
|
||||||
if match is None or not expand or "," not in match.group(2):
|
|
||||||
return [value]
|
|
||||||
|
|
||||||
prefix, values, suffix = match.groups()
|
|
||||||
return [f"{prefix}{item}{suffix}" for item in values.split(",")]
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _text(node: Node) -> str:
|
def _text(node: Node) -> str:
|
||||||
@@ -150,6 +133,19 @@ class PkgbuildParser:
|
|||||||
"""
|
"""
|
||||||
return cast(bytes, node.text).decode("utf8", errors="backslashreplace")
|
return cast(bytes, node.text).decode("utf8", errors="backslashreplace")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _unquote(value: str) -> str:
|
||||||
|
"""
|
||||||
|
remove shell quotes and escapes from a single value
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value(str): shell value to unquote
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: unquoted value
|
||||||
|
"""
|
||||||
|
return "".join(shlex.split(value, comments=False, posix=True))
|
||||||
|
|
||||||
def _assignment(self, node: Node) -> PkgbuildPatch:
|
def _assignment(self, node: Node) -> PkgbuildPatch:
|
||||||
"""
|
"""
|
||||||
convert an assignment node
|
convert an assignment node
|
||||||
@@ -164,31 +160,83 @@ class PkgbuildParser:
|
|||||||
value = cast(Node, node.child_by_field_name(PkgbuildNodeField.Value))
|
value = cast(Node, node.child_by_field_name(PkgbuildNodeField.Value))
|
||||||
key = self._text(name)
|
key = self._text(name)
|
||||||
|
|
||||||
|
# bash permits assignments without a value (for example ``IFS=``).
|
||||||
|
# tree-sitter represents those assignments without a value node.
|
||||||
|
if value is None:
|
||||||
|
return PkgbuildPatch(key, "")
|
||||||
|
|
||||||
match value.type:
|
match value.type:
|
||||||
case PkgbuildNodeType.Array:
|
case PkgbuildNodeType.Array:
|
||||||
array_values = []
|
array_values = []
|
||||||
for element in filter(lambda child: child.type != PkgbuildNodeType.Comment, value.named_children):
|
for element in filter(lambda child: child.type != PkgbuildNodeType.Comment, value.named_children):
|
||||||
item = self._value(element)
|
array_values.extend(self._expand_array(element))
|
||||||
values = self._expand_array(item, expand=element.type == PkgbuildNodeType.Concatenation)
|
|
||||||
array_values.extend(values)
|
|
||||||
return PkgbuildPatch(key, array_values)
|
return PkgbuildPatch(key, array_values)
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
return PkgbuildPatch(key, self._value(value))
|
return PkgbuildPatch(key, self._value(value))
|
||||||
|
|
||||||
def _read(self, node: Node) -> Iterator[PkgbuildPatch]:
|
def _expand_array(self, node: Node) -> list[str]:
|
||||||
|
"""
|
||||||
|
expand simple comma-separated brace groups in an array element
|
||||||
|
|
||||||
|
Args:
|
||||||
|
node(Node): array element to expand
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: expanded element values
|
||||||
|
"""
|
||||||
|
if node.type != PkgbuildNodeType.Concatenation:
|
||||||
|
return [self._value(node)]
|
||||||
|
|
||||||
|
values = [""]
|
||||||
|
children = node.named_children
|
||||||
|
while children:
|
||||||
|
match children[:3]:
|
||||||
|
case [
|
||||||
|
Node(type=PkgbuildNodeType.Word, text=b"{"),
|
||||||
|
Node(type=PkgbuildNodeType.Word) as content,
|
||||||
|
Node(type=PkgbuildNodeType.Word, text=b"}"),
|
||||||
|
] if "," in (escaped := self._text(content).replace("\\,", ShellInterpolator.DATA_LINK_ESCAPE)):
|
||||||
|
parts = [
|
||||||
|
self._unquote(part).replace(ShellInterpolator.DATA_LINK_ESCAPE, ",")
|
||||||
|
for part in escaped.split(",")
|
||||||
|
]
|
||||||
|
children = children[3:]
|
||||||
|
|
||||||
|
case [head, *_]:
|
||||||
|
parts = [self._value(head)]
|
||||||
|
children = children[1:]
|
||||||
|
values = [prefix + part for prefix in values for part in parts]
|
||||||
|
return values
|
||||||
|
|
||||||
|
def _read(self, node: Node, values: dict[str | None, PkgbuildPatch]) -> Iterator[PkgbuildPatch]:
|
||||||
"""
|
"""
|
||||||
find assignments and functions in a syntax tree node
|
find assignments and functions in a syntax tree node
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
node(Node): syntax tree node to inspect
|
node(Node): syntax tree node to inspect
|
||||||
|
values(dict[str | None, PkgbuildPatch]): cached assignments
|
||||||
|
|
||||||
Yields:
|
Yields:
|
||||||
PkgbuildPatch: parsed entries
|
PkgbuildPatch: parsed entries
|
||||||
"""
|
"""
|
||||||
match node.type:
|
match node.type:
|
||||||
case PkgbuildNodeType.VariableAssignment if not any(child.type == PkgbuildNodeType.Append for child in node.children):
|
case PkgbuildNodeType.VariableAssignment if any(child.type == PkgbuildNodeType.Append for child in node.children):
|
||||||
yield self._assignment(node)
|
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:
|
case PkgbuildNodeType.FunctionDefinition:
|
||||||
name = cast(Node, node.child_by_field_name(PkgbuildNodeField.Name))
|
name = cast(Node, node.child_by_field_name(PkgbuildNodeField.Name))
|
||||||
@@ -205,7 +253,7 @@ class PkgbuildParser:
|
|||||||
PkgbuildNodeType.String,
|
PkgbuildNodeType.String,
|
||||||
PkgbuildNodeType.Word,
|
PkgbuildNodeType.Word,
|
||||||
):
|
):
|
||||||
yield from self._read(child)
|
yield from self._read(child, values)
|
||||||
|
|
||||||
def _value(self, node: Node) -> str:
|
def _value(self, node: Node) -> str:
|
||||||
"""
|
"""
|
||||||
@@ -229,7 +277,7 @@ class PkgbuildParser:
|
|||||||
case _:
|
case _:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
return "".join(shlex.split(value, comments=False, posix=True))
|
return self._unquote(value)
|
||||||
|
|
||||||
def parse(self) -> Iterator[PkgbuildPatch]:
|
def parse(self) -> Iterator[PkgbuildPatch]:
|
||||||
"""
|
"""
|
||||||
@@ -255,4 +303,13 @@ class PkgbuildParser:
|
|||||||
f"syntax error at line {error.start_point.row + 1}, column {error.start_point.column + 1}"
|
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]:
|
||||||
|
"""
|
||||||
|
iterate over the parsed entries
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Iterator[PkgbuildPatch]: parsed entries
|
||||||
|
"""
|
||||||
|
return self.parse()
|
||||||
@@ -80,8 +80,7 @@ class Pkgbuild(Mapping[str, Any]):
|
|||||||
Returns:
|
Returns:
|
||||||
Self: constructed instance of self
|
Self: constructed instance of self
|
||||||
"""
|
"""
|
||||||
parser = PkgbuildParser(stream)
|
fields = {patch.key: patch for patch in PkgbuildParser(stream)}
|
||||||
fields = {patch.key: patch for patch in parser.parse()}
|
|
||||||
|
|
||||||
# pkgbase is optional field, the pkgname must be used instead if not set
|
# pkgbase is optional field, the pkgname must be used instead if not set
|
||||||
# however, pkgname is not presented is "package()" functions which we are parsing here too,
|
# however, pkgname is not presented is "package()" functions which we are parsing here too,
|
||||||
|
|||||||
@@ -18,9 +18,48 @@ def test_expand_array() -> None:
|
|||||||
parser = PkgbuildParser(BytesIO(b"array=(prefix{first,second}suffix)"))
|
parser = PkgbuildParser(BytesIO(b"array=(prefix{first,second}suffix)"))
|
||||||
assert list(parser.parse()) == [PkgbuildPatch("array", ["prefixfirstsuffix", "prefixsecondsuffix"])]
|
assert list(parser.parse()) == [PkgbuildPatch("array", ["prefixfirstsuffix", "prefixsecondsuffix"])]
|
||||||
|
|
||||||
|
parser = PkgbuildParser(BytesIO(br"array=(prefix{first\,second,third}suffix)"))
|
||||||
|
assert list(parser.parse()) == [PkgbuildPatch("array", ["prefixfirst,secondsuffix", "prefixthirdsuffix"])]
|
||||||
|
|
||||||
parser = PkgbuildParser(BytesIO(b"""array=("prefix{first,second}suffix")"""))
|
parser = PkgbuildParser(BytesIO(b"""array=("prefix{first,second}suffix")"""))
|
||||||
assert list(parser.parse()) == [PkgbuildPatch("array", ["prefix{first,second}suffix"])]
|
assert list(parser.parse()) == [PkgbuildPatch("array", ["prefix{first,second}suffix"])]
|
||||||
|
|
||||||
|
parser = PkgbuildParser(BytesIO(b"""array=(x"{a,b}" x'{a,b}' "{x,y}"{a,b})"""))
|
||||||
|
assert list(parser) == [PkgbuildPatch("array", ["x{a,b}", "x{a,b}", "{x,y}a", "{x,y}b"])]
|
||||||
|
|
||||||
|
parser = PkgbuildParser(BytesIO(b"""array=(${v:-a,b}suffix ${v:-a,b}{,.sig} $(echo '{a,b}')suffix)"""))
|
||||||
|
assert list(parser) == [PkgbuildPatch("array", [
|
||||||
|
"${v:-a,b}suffix", "${v:-a,b}", "${v:-a,b}.sig", "$(echo '{a,b}')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:
|
def test_parse_array() -> None:
|
||||||
"""
|
"""
|
||||||
@@ -71,7 +110,7 @@ def test_parse_array_exception() -> None:
|
|||||||
"""
|
"""
|
||||||
parser = PkgbuildParser(BytesIO(b"var=(first second"))
|
parser = PkgbuildParser(BytesIO(b"var=(first second"))
|
||||||
with pytest.raises(PkgbuildParserError):
|
with pytest.raises(PkgbuildParserError):
|
||||||
assert list(parser.parse())
|
list(parser.parse())
|
||||||
|
|
||||||
|
|
||||||
def test_parse_function() -> None:
|
def test_parse_function() -> None:
|
||||||
@@ -119,11 +158,11 @@ def test_parse_function_exception() -> None:
|
|||||||
"""
|
"""
|
||||||
parser = PkgbuildParser(BytesIO(b"var() echo hello world } "))
|
parser = PkgbuildParser(BytesIO(b"var() echo hello world } "))
|
||||||
with pytest.raises(PkgbuildParserError):
|
with pytest.raises(PkgbuildParserError):
|
||||||
assert list(parser.parse())
|
list(parser.parse())
|
||||||
|
|
||||||
parser = PkgbuildParser(BytesIO(b"var() { echo hello world"))
|
parser = PkgbuildParser(BytesIO(b"var() { echo hello world"))
|
||||||
with pytest.raises(PkgbuildParserError):
|
with pytest.raises(PkgbuildParserError):
|
||||||
assert list(parser.parse())
|
list(parser.parse())
|
||||||
|
|
||||||
|
|
||||||
def test_parse_function_inner_shell() -> None:
|
def test_parse_function_inner_shell() -> None:
|
||||||
|
|||||||
@@ -578,6 +578,7 @@ def test_walk(resource_path_root: Path) -> None:
|
|||||||
resource_path_root / "models" / "package_pacman-static_pkgbuild",
|
resource_path_root / "models" / "package_pacman-static_pkgbuild",
|
||||||
resource_path_root / "models" / "package_python-pytest-loop_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_ttf-google-fonts-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",
|
||||||
resource_path_root / "models" / "pkgbuild",
|
resource_path_root / "models" / "pkgbuild",
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ def test_from_io(pkgbuild_ahriman: Pkgbuild, mocker: MockerFixture) -> None:
|
|||||||
must correctly load from io
|
must correctly load from io
|
||||||
"""
|
"""
|
||||||
load_mock = mocker.patch("ahriman.core.alpm.pkgbuild_parser.PkgbuildParser.parse",
|
load_mock = mocker.patch("ahriman.core.alpm.pkgbuild_parser.PkgbuildParser.parse",
|
||||||
return_value=pkgbuild_ahriman.fields.values())
|
return_value=iter(pkgbuild_ahriman.fields.values()))
|
||||||
assert Pkgbuild.from_io(BytesIO(b"mock")) == pkgbuild_ahriman
|
assert Pkgbuild.from_io(BytesIO(b"mock")) == pkgbuild_ahriman
|
||||||
load_mock.assert_called_once_with()
|
load_mock.assert_called_once_with()
|
||||||
|
|
||||||
@@ -60,9 +60,9 @@ def test_from_io_pkgbase(pkgbuild_ahriman: Pkgbuild, mocker: MockerFixture) -> N
|
|||||||
must assign missing pkgbase if pkgname is presented
|
must assign missing pkgbase if pkgname is presented
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.alpm.pkgbuild_parser.PkgbuildParser.parse", side_effect=[
|
mocker.patch("ahriman.core.alpm.pkgbuild_parser.PkgbuildParser.parse", side_effect=[
|
||||||
[value for key, value in pkgbuild_ahriman.fields.items() if key not in ("pkgbase",)],
|
iter([value for key, value in pkgbuild_ahriman.fields.items() if key not in ("pkgbase",)]),
|
||||||
[value for key, value in pkgbuild_ahriman.fields.items() if key not in ("pkgbase", "pkgname",)],
|
iter([value for key, value in pkgbuild_ahriman.fields.items() if key not in ("pkgbase", "pkgname",)]),
|
||||||
[value for key, value in pkgbuild_ahriman.fields.items()] + [PkgbuildPatch("pkgbase", "pkgbase")],
|
iter([value for key, value in pkgbuild_ahriman.fields.items()] + [PkgbuildPatch("pkgbase", "pkgbase")]),
|
||||||
])
|
])
|
||||||
|
|
||||||
assert Pkgbuild.from_io(BytesIO(b"mock"))["pkgbase"] == pkgbuild_ahriman["pkgname"]
|
assert Pkgbuild.from_io(BytesIO(b"mock"))["pkgbase"] == pkgbuild_ahriman["pkgname"]
|
||||||
@@ -75,7 +75,7 @@ def test_from_io_empty(pkgbuild_ahriman: Pkgbuild, mocker: MockerFixture) -> Non
|
|||||||
must skip empty patches
|
must skip empty patches
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.alpm.pkgbuild_parser.PkgbuildParser.parse",
|
mocker.patch("ahriman.core.alpm.pkgbuild_parser.PkgbuildParser.parse",
|
||||||
return_value=list(pkgbuild_ahriman.fields.values()) + [PkgbuildPatch("", "")])
|
return_value=iter(list(pkgbuild_ahriman.fields.values()) + [PkgbuildPatch("", "")]))
|
||||||
assert Pkgbuild.from_io(BytesIO(b"mock")) == pkgbuild_ahriman
|
assert Pkgbuild.from_io(BytesIO(b"mock")) == pkgbuild_ahriman
|
||||||
|
|
||||||
|
|
||||||
@@ -399,6 +399,182 @@ def test_parse_jellyfin_ffmpeg6_bin(resource_path_root: Path) -> None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_pacman_static(resource_path_root: Path) -> None:
|
||||||
|
"""
|
||||||
|
must parse real PKGBUILDs correctly (pacman-static)
|
||||||
|
"""
|
||||||
|
pkgbuild = Pkgbuild.from_file(resource_path_root / "models" / "package_pacman-static_pkgbuild")
|
||||||
|
values = {key: value.value for key, value in pkgbuild.fields.items() if not value.is_function}
|
||||||
|
assert values == {
|
||||||
|
"pkgbase": "pacman-static",
|
||||||
|
"pkgname": "pacman-static",
|
||||||
|
"pkgver": "7.0.0.r6.gc685ae6",
|
||||||
|
"_cares_ver": "1.34.4",
|
||||||
|
"_nghttp2_ver": "1.64.0",
|
||||||
|
"_curlver": "8.12.1",
|
||||||
|
"_sslver": "3.4.1",
|
||||||
|
"_zlibver": "1.3.1",
|
||||||
|
"_xzver": "5.6.4",
|
||||||
|
"_bzipver": "1.0.8",
|
||||||
|
"_zstdver": "1.5.6",
|
||||||
|
"_libarchive_ver": "3.7.7",
|
||||||
|
"_gpgerrorver": "1.51",
|
||||||
|
"_libassuanver": "3.0.0",
|
||||||
|
"_gpgmever": "1.24.2",
|
||||||
|
"pkgrel": "15",
|
||||||
|
"_git_tag": "7.0.0",
|
||||||
|
"_git_patch_level_commit": "c685ae6412af04cae1eaa5d6bda8c277c7ffb8c8",
|
||||||
|
"pkgdesc": "Statically-compiled pacman (to fix or install systems without libc)",
|
||||||
|
"arch": [
|
||||||
|
"i486",
|
||||||
|
"i686",
|
||||||
|
"pentium4",
|
||||||
|
"x86_64",
|
||||||
|
"arm",
|
||||||
|
"armv6h",
|
||||||
|
"armv7h",
|
||||||
|
"aarch64"
|
||||||
|
],
|
||||||
|
"url": "https://www.archlinux.org/pacman/",
|
||||||
|
"license": ["GPL-2.0-or-later"],
|
||||||
|
"depends": ["pacman"],
|
||||||
|
"makedepends": [
|
||||||
|
"meson",
|
||||||
|
"musl",
|
||||||
|
"kernel-headers-musl",
|
||||||
|
"git",
|
||||||
|
],
|
||||||
|
"options": [
|
||||||
|
"!emptydirs",
|
||||||
|
"!lto",
|
||||||
|
],
|
||||||
|
"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",
|
||||||
|
"1a108c4384b6104e627652488659de0b1ac3330640fc3250f0a283af7c5884daab187c1efc024b2545262da1911d2b0b7b0d5e4e5b68bb98db25a760c9f1fb1a",
|
||||||
|
"b544196c3b7a55faacd11700d11e2fe4f16a7418282c9abb24a668544a15293580fd1a2cc5f93367c8a17c7ee45335c6d2f5c68a72dd176d516fd033f203eeec",
|
||||||
|
"3285e14d94bc736d6caddfe7ad7e3c6a6e69d49b079c989bb3e8aba4da62c022e38229d1e691aaa030b7d3bcd89e458d203f260806149a71ad9adb31606eae02",
|
||||||
|
"SKIP",
|
||||||
|
"9fcdcceab8bce43e888db79a38c775ff15790a806d3cc5cc96f396a829c6da2383b258481b5642153da14087943f6ef607af0aa3b75df6f41b95c6cd61d835eb",
|
||||||
|
"SKIP",
|
||||||
|
"1de6307c587686711f05d1e96731c43526fa3af51e4cd94c06c880954b67f6eb4c7db3177f0ea5937d41bc1f8cadcf5bce75025b5c1a46a469376960f1001c5f",
|
||||||
|
"SKIP",
|
||||||
|
"b1873dbb7a49460b007255689102062756972de5cc2d38b12cc9f389b6be412da6797579b1acd3717a8cd2ee118fd9801b94e55f063d4328f050f0876a5eb53c",
|
||||||
|
"b5887ea77417fae49b6cb1e9fa782d3021f268d5219701d87a092235964f73fa72a31428b630445517f56f2bb69dcbbb24119ef9dbf8b4e40a753369a9f9a16f",
|
||||||
|
"580677aad97093829090d4b605ac81c50327e74a6c2de0b85dd2e8525553f3ddde17556ea46f8f007f89e435493c9a20bc997d1ef1c1c2c23274528e3c46b94f",
|
||||||
|
"SKIP",
|
||||||
|
"e3216eca5fae2c9ce419e698bfbe186903088dad0a579749cb49bcde8f9d4073b98bf1570fe69190a9a41feb2a7c9814498ec9b867527de1c74ff75a1cbdfc17",
|
||||||
|
"083f5e675d73f3233c7930ebe20425a533feedeaaa9d8cc86831312a6581cefbe6ed0d08d2fa89be81082f2a5abdabca8b3c080bf97218a1bd59dc118a30b9f3",
|
||||||
|
"SKIP",
|
||||||
|
"21f9da445afd76acaf3acb22d216c2b584d95e8c68e00f5cb3f6673f2d556dd14a7593344adf8ffd194bba3314387ee0e486d6248f6c935abca2edd8a4cf95ed",
|
||||||
|
"SKIP",
|
||||||
|
"4489f615c6a0389577a7d1fd7d3917517bb2fe032abd9a6d87dfdbd165dabcf53f8780645934020bf27517b67a064297475888d5b368176cf06bc22f1e735e2b",
|
||||||
|
"SKIP",
|
||||||
|
"7c5c95c1b85bef2d4890c068a5a8ea8a1fe0d8def6ab09e5f34fc2746d8808bbb0fc168e3bd66d52ee5ed799dcf9f258f4125cda98c8384f6411bcad8d8b3139",
|
||||||
|
"SKIP",
|
||||||
|
"ad69101d1fceef6cd1dd6d5348f6f2be06912da6b6a7d0fece3ce08cf35054e6953b80ca9c4748554882892faa44e7c54e705cf25bbf2b796cd4ad12b09da185",
|
||||||
|
"SKIP",
|
||||||
|
"2524f71f4c2ebc254a1927279be3394e820d0a0c6dec7ef835a862aa08c35756edaa4208bcdc710dd092872b59c200b555b78670372e2830822e278ff1ec4e4a",
|
||||||
|
"SKIP",
|
||||||
|
],
|
||||||
|
"LDFLAGS": "$LDFLAGS -static",
|
||||||
|
"CC": "musl-gcc -fno-stack-protector",
|
||||||
|
"CXX": "musl-gcc -fno-stack-protector",
|
||||||
|
"CFLAGS": "${CFLAGS/-fstack-protector-strong/} -D_LARGEFILE64_SOURCE",
|
||||||
|
"CXXFLAGS": "${CXXFLAGS/-fstack-protector-strong/} -D_LARGEFILE64_SOURCE",
|
||||||
|
"PKGEXT": ".pkg.tar.xz",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_parse_tpacpi_bat_git(resource_path_root: Path) -> None:
|
def test_parse_tpacpi_bat_git(resource_path_root: Path) -> None:
|
||||||
"""
|
"""
|
||||||
must parse real PKGBUILDs correctly (tpacpi-bat-git)
|
must parse real PKGBUILDs correctly (tpacpi-bat-git)
|
||||||
@@ -424,42 +600,87 @@ def test_parse_tpacpi_bat_git(resource_path_root: Path) -> None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_parse_yay(resource_path_root: Path) -> None:
|
def test_parse_ttf_google_fonts_git(resource_path_root: Path) -> None:
|
||||||
"""
|
"""
|
||||||
must parse real PKGBUILDs correctly (yay)
|
must parse real PKGBUILDs correctly (ttf-google-fonts-git)
|
||||||
"""
|
"""
|
||||||
pkgbuild = Pkgbuild.from_file(resource_path_root / "models" / "package_yay_pkgbuild")
|
pkgbuild = Pkgbuild.from_file(resource_path_root / "models" / "package_ttf-google-fonts-git_pkgbuild")
|
||||||
values = {key: value.value for key, value in pkgbuild.fields.items() if not value.is_function}
|
values = {key: value.value for key, value in pkgbuild.fields.items() if not value.is_function}
|
||||||
|
assert "ttf-google-fonts-git" in pkgbuild.packages()
|
||||||
assert values == {
|
assert values == {
|
||||||
"pkgbase": "yay",
|
"pkgname": "ttf-google-fonts-git",
|
||||||
"pkgname": "yay",
|
"pkgver": "r11002.cdabad3d0",
|
||||||
"pkgver": "12.3.5",
|
|
||||||
"pkgrel": "1",
|
"pkgrel": "1",
|
||||||
"pkgdesc": "Yet another yogurt. Pacman wrapper and AUR helper written in go.",
|
"epoch": "1",
|
||||||
"arch": [
|
"pkgdesc": "TrueType fonts from the Google Fonts project (git version)",
|
||||||
"i686",
|
"arch": ["any"],
|
||||||
"pentium4",
|
"url": "https://github.com/google/fonts",
|
||||||
"x86_64",
|
"license": ["custom:SIL Open Font License", "custom:Ubuntu Font License v1.0"],
|
||||||
"arm",
|
|
||||||
"armv7h",
|
|
||||||
"armv6h",
|
|
||||||
"aarch64",
|
|
||||||
"riscv64",
|
|
||||||
],
|
|
||||||
"url": "https://github.com/Jguer/yay",
|
|
||||||
"options": ["!lto"],
|
|
||||||
"license": ["GPL-3.0-or-later"],
|
|
||||||
"depends": [
|
"depends": [
|
||||||
"pacman>6.1",
|
"adobe-source-code-pro-fonts",
|
||||||
"git",
|
"adobe-source-sans-fonts",
|
||||||
|
"adobe-source-serif-fonts",
|
||||||
|
"cantarell-fonts",
|
||||||
|
"noto-fonts",
|
||||||
|
"noto-fonts-extra",
|
||||||
|
"ttf-anonymous-pro",
|
||||||
|
"ttf-caladea",
|
||||||
|
"ttf-croscore",
|
||||||
|
"ttf-fira-sans",
|
||||||
|
"ttf-fira-mono",
|
||||||
|
"ttf-inconsolata",
|
||||||
|
"ttf-lato",
|
||||||
|
"ttf-merriweather",
|
||||||
|
"ttf-merriweather-sans",
|
||||||
|
"ttf-opensans",
|
||||||
|
"ttf-oswald",
|
||||||
|
"ttf-quintessential",
|
||||||
|
"ttf-roboto",
|
||||||
|
"ttf-roboto-mono",
|
||||||
|
"ttf-signika",
|
||||||
|
"ttf-ubuntu-font-family",
|
||||||
],
|
],
|
||||||
"optdepends": [
|
"makedepends": ["git", "fontconfig"],
|
||||||
"sudo: privilege elevation",
|
"conflicts": [
|
||||||
"doas: privilege elevation",
|
"jsmath-fonts",
|
||||||
|
"lohit-fonts",
|
||||||
|
"ttf-andika",
|
||||||
|
"ttf-arabeyes-fonts",
|
||||||
|
"ttf-cardo",
|
||||||
|
"ttf-comfortaa",
|
||||||
|
"ttf-google-fonts-typewolf",
|
||||||
|
"ttf-lora-cyrillic",
|
||||||
|
"ttf-lekton",
|
||||||
|
"ttf-medievalsharp",
|
||||||
|
"ttf-nova",
|
||||||
|
"ttf-oxygen",
|
||||||
|
"ttf-oxygen-git",
|
||||||
|
"ttf-pt-fonts",
|
||||||
|
"ttf-source-code-pro-ibx",
|
||||||
|
"ttf-source-sans-pro-ibx",
|
||||||
|
"ttf-vollkorn-ibx",
|
||||||
],
|
],
|
||||||
"makedepends": ["go>=1.21"],
|
"provides": [
|
||||||
"source": ["${pkgname}-${pkgver}.tar.gz::https://github.com/Jguer/yay/archive/v${pkgver}.tar.gz"],
|
"jsmath-fonts",
|
||||||
"sha256sums": ["2fb6121a6eb4c5e6afaf22212b2ed15022500a4bc34bb3dc0f9782c1d43c3962"],
|
"lohit-fonts",
|
||||||
|
"ttf-andika",
|
||||||
|
"ttf-cardo",
|
||||||
|
"ttf-carlito",
|
||||||
|
"ttf-comfortaa",
|
||||||
|
"ttf-lora-cyrillic",
|
||||||
|
"ttf-lekton",
|
||||||
|
"ttf-medievalsharp",
|
||||||
|
"ttf-nova",
|
||||||
|
"ttf-oxygen",
|
||||||
|
"ttf-oxygen-git",
|
||||||
|
"ttf-pt-fonts",
|
||||||
|
"ttf-source-code-pro-ibx",
|
||||||
|
"ttf-source-sans-pro-ibx",
|
||||||
|
"ttf-vollkorn-ibx",
|
||||||
|
],
|
||||||
|
"source": ["git+${url}.git"],
|
||||||
|
"sha512sums": ["SKIP"],
|
||||||
|
"pkgbase": "ttf-google-fonts-git",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -526,131 +747,40 @@ def test_parse_vim_youcompleteme_git(resource_path_root: Path) -> None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_parse_python_pytest_loop(resource_path_root: Path) -> None:
|
def test_parse_yay(resource_path_root: Path) -> None:
|
||||||
"""
|
"""
|
||||||
must parse real PKGBUILDs correctly (python-pytest-loop)
|
must parse real PKGBUILDs correctly (yay)
|
||||||
"""
|
"""
|
||||||
pkgbuild = Pkgbuild.from_file(resource_path_root / "models" / "package_python-pytest-loop_pkgbuild")
|
pkgbuild = Pkgbuild.from_file(resource_path_root / "models" / "package_yay_pkgbuild")
|
||||||
values = {key: value.value for key, value in pkgbuild.fields.items() if not value.is_function}
|
values = {key: value.value for key, value in pkgbuild.fields.items() if not value.is_function}
|
||||||
assert values == {
|
assert values == {
|
||||||
"pkgbase": "python-pytest-loop",
|
"pkgbase": "yay",
|
||||||
"_pname": "${pkgbase#python-}",
|
"pkgname": "yay",
|
||||||
"_pyname": "${_pname//-/_}",
|
"pkgver": "12.3.5",
|
||||||
"pkgname": ["python-${_pname}"],
|
|
||||||
"pkgver": "1.0.13",
|
|
||||||
"pkgrel": "1",
|
"pkgrel": "1",
|
||||||
"pkgdesc": "Pytest plugin for looping test execution.",
|
"pkgdesc": "Yet another yogurt. Pacman wrapper and AUR helper written in go.",
|
||||||
"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",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_pacman_static(resource_path_root: Path) -> None:
|
|
||||||
"""
|
|
||||||
must parse real PKGBUILDs correctly (pacman-static)
|
|
||||||
"""
|
|
||||||
pkgbuild = Pkgbuild.from_file(resource_path_root / "models" / "package_pacman-static_pkgbuild")
|
|
||||||
values = {key: value.value for key, value in pkgbuild.fields.items() if not value.is_function}
|
|
||||||
assert values == {
|
|
||||||
"pkgbase": "pacman-static",
|
|
||||||
"pkgname": "pacman-static",
|
|
||||||
"pkgver": "7.0.0.r6.gc685ae6",
|
|
||||||
"_cares_ver": "1.34.4",
|
|
||||||
"_nghttp2_ver": "1.64.0",
|
|
||||||
"_curlver": "8.12.1",
|
|
||||||
"_sslver": "3.4.1",
|
|
||||||
"_zlibver": "1.3.1",
|
|
||||||
"_xzver": "5.6.4",
|
|
||||||
"_bzipver": "1.0.8",
|
|
||||||
"_zstdver": "1.5.6",
|
|
||||||
"_libarchive_ver": "3.7.7",
|
|
||||||
"_gpgerrorver": "1.51",
|
|
||||||
"_libassuanver": "3.0.0",
|
|
||||||
"_gpgmever": "1.24.2",
|
|
||||||
"pkgrel": "15",
|
|
||||||
"_git_tag": "7.0.0",
|
|
||||||
"_git_patch_level_commit": "c685ae6412af04cae1eaa5d6bda8c277c7ffb8c8",
|
|
||||||
"pkgdesc": "Statically-compiled pacman (to fix or install systems without libc)",
|
|
||||||
"arch": [
|
"arch": [
|
||||||
"i486",
|
|
||||||
"i686",
|
"i686",
|
||||||
"pentium4",
|
"pentium4",
|
||||||
"x86_64",
|
"x86_64",
|
||||||
"arm",
|
"arm",
|
||||||
"armv6h",
|
|
||||||
"armv7h",
|
"armv7h",
|
||||||
"aarch64"
|
"armv6h",
|
||||||
|
"aarch64",
|
||||||
|
"riscv64",
|
||||||
],
|
],
|
||||||
"url": "https://www.archlinux.org/pacman/",
|
"url": "https://github.com/Jguer/yay",
|
||||||
"license": ["GPL-2.0-or-later"],
|
"options": ["!lto"],
|
||||||
"depends": ["pacman"],
|
"license": ["GPL-3.0-or-later"],
|
||||||
"makedepends": [
|
"depends": [
|
||||||
"meson",
|
"pacman>6.1",
|
||||||
"musl",
|
|
||||||
"kernel-headers-musl",
|
|
||||||
"git",
|
"git",
|
||||||
],
|
],
|
||||||
"options": [
|
"optdepends": [
|
||||||
"!emptydirs",
|
"sudo: privilege elevation",
|
||||||
"!lto",
|
"doas: privilege elevation",
|
||||||
],
|
],
|
||||||
"source": [
|
"makedepends": ["go>=1.21"],
|
||||||
"git+https://gitlab.archlinux.org/pacman/pacman.git#tag=v${_git_tag}?signed",
|
"source": ["${pkgname}-${pkgver}.tar.gz::https://github.com/Jguer/yay/archive/v${pkgver}.tar.gz"],
|
||||||
"pacman-revertme-makepkg-remove-libdepends-and-libprovides.patch::https://gitlab.archlinux.org/pacman/pacman/-/commit/354a300cd26bb1c7e6551473596be5ecced921de.patch",
|
"sha256sums": ["2fb6121a6eb4c5e6afaf22212b2ed15022500a4bc34bb3dc0f9782c1d43c3962"],
|
||||||
],
|
|
||||||
"validpgpkeys": [
|
|
||||||
"6645B0A8C7005E78DB1D7864F99FFE0FEAE999BD",
|
|
||||||
"B8151B117037781095514CA7BBDFFC92306B1121",
|
|
||||||
],
|
|
||||||
"sha512sums": [
|
|
||||||
"44e00c2bc259fe6a85de71f7fd8a43fcfd1b8fb7d920d2267bd5b347e02f1dab736b3d96e31faf7b535480398e2348f7c0b9914e51ca7e12bab2d5b8003926b4",
|
|
||||||
"1a108c4384b6104e627652488659de0b1ac3330640fc3250f0a283af7c5884daab187c1efc024b2545262da1911d2b0b7b0d5e4e5b68bb98db25a760c9f1fb1a",
|
|
||||||
"b544196c3b7a55faacd11700d11e2fe4f16a7418282c9abb24a668544a15293580fd1a2cc5f93367c8a17c7ee45335c6d2f5c68a72dd176d516fd033f203eeec",
|
|
||||||
"3285e14d94bc736d6caddfe7ad7e3c6a6e69d49b079c989bb3e8aba4da62c022e38229d1e691aaa030b7d3bcd89e458d203f260806149a71ad9adb31606eae02",
|
|
||||||
"SKIP",
|
|
||||||
"9fcdcceab8bce43e888db79a38c775ff15790a806d3cc5cc96f396a829c6da2383b258481b5642153da14087943f6ef607af0aa3b75df6f41b95c6cd61d835eb",
|
|
||||||
"SKIP",
|
|
||||||
"1de6307c587686711f05d1e96731c43526fa3af51e4cd94c06c880954b67f6eb4c7db3177f0ea5937d41bc1f8cadcf5bce75025b5c1a46a469376960f1001c5f",
|
|
||||||
"SKIP",
|
|
||||||
"b1873dbb7a49460b007255689102062756972de5cc2d38b12cc9f389b6be412da6797579b1acd3717a8cd2ee118fd9801b94e55f063d4328f050f0876a5eb53c",
|
|
||||||
"b5887ea77417fae49b6cb1e9fa782d3021f268d5219701d87a092235964f73fa72a31428b630445517f56f2bb69dcbbb24119ef9dbf8b4e40a753369a9f9a16f",
|
|
||||||
"580677aad97093829090d4b605ac81c50327e74a6c2de0b85dd2e8525553f3ddde17556ea46f8f007f89e435493c9a20bc997d1ef1c1c2c23274528e3c46b94f",
|
|
||||||
"SKIP",
|
|
||||||
"e3216eca5fae2c9ce419e698bfbe186903088dad0a579749cb49bcde8f9d4073b98bf1570fe69190a9a41feb2a7c9814498ec9b867527de1c74ff75a1cbdfc17",
|
|
||||||
"083f5e675d73f3233c7930ebe20425a533feedeaaa9d8cc86831312a6581cefbe6ed0d08d2fa89be81082f2a5abdabca8b3c080bf97218a1bd59dc118a30b9f3",
|
|
||||||
"SKIP",
|
|
||||||
"21f9da445afd76acaf3acb22d216c2b584d95e8c68e00f5cb3f6673f2d556dd14a7593344adf8ffd194bba3314387ee0e486d6248f6c935abca2edd8a4cf95ed",
|
|
||||||
"SKIP",
|
|
||||||
"4489f615c6a0389577a7d1fd7d3917517bb2fe032abd9a6d87dfdbd165dabcf53f8780645934020bf27517b67a064297475888d5b368176cf06bc22f1e735e2b",
|
|
||||||
"SKIP",
|
|
||||||
"7c5c95c1b85bef2d4890c068a5a8ea8a1fe0d8def6ab09e5f34fc2746d8808bbb0fc168e3bd66d52ee5ed799dcf9f258f4125cda98c8384f6411bcad8d8b3139",
|
|
||||||
"SKIP",
|
|
||||||
"ad69101d1fceef6cd1dd6d5348f6f2be06912da6b6a7d0fece3ce08cf35054e6953b80ca9c4748554882892faa44e7c54e705cf25bbf2b796cd4ad12b09da185",
|
|
||||||
"SKIP",
|
|
||||||
"2524f71f4c2ebc254a1927279be3394e820d0a0c6dec7ef835a862aa08c35756edaa4208bcdc710dd092872b59c200b555b78670372e2830822e278ff1ec4e4a",
|
|
||||||
"SKIP",
|
|
||||||
],
|
|
||||||
"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/}",
|
|
||||||
"PKGEXT": ".pkg.tar.xz",
|
|
||||||
}
|
}
|
||||||
+2
-2
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
pkgbase='ahriman'
|
pkgbase='ahriman'
|
||||||
pkgname=('ahriman' 'ahriman-core' 'ahriman-triggers' 'ahriman-web')
|
pkgname=('ahriman' 'ahriman-core' 'ahriman-triggers' 'ahriman-web')
|
||||||
pkgver=2.23.1
|
pkgver=2.23.5
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="ArcH linux ReposItory MANager"
|
pkgdesc="ArcH linux ReposItory MANager"
|
||||||
arch=('any')
|
arch=('any')
|
||||||
@@ -80,7 +80,7 @@ package_ahriman-triggers() {
|
|||||||
package_ahriman-web() {
|
package_ahriman-web() {
|
||||||
pkgname='ahriman-web'
|
pkgname='ahriman-web'
|
||||||
pkgdesc="ArcH linux ReposItory MANager, web server"
|
pkgdesc="ArcH linux ReposItory MANager, web server"
|
||||||
depends=("$pkgbase-core=$pkgver" 'python-aiohttp-cors' 'python-aiohttp-jinja2' 'python-aiohttp-sse-git')
|
depends=("$pkgbase-core=$pkgver" 'python-aiohttp-cors' 'python-aiohttp-jinja2' 'python-aiohttp-sse')
|
||||||
optdepends=('python-aioauth-client: OAuth2 authorization support'
|
optdepends=('python-aioauth-client: OAuth2 authorization support'
|
||||||
'python-aiohttp-apispec>=3.0.0: autogenerated API documentation'
|
'python-aiohttp-apispec>=3.0.0: autogenerated API documentation'
|
||||||
'python-aiohttp-openmetrics: HTTP metrics support'
|
'python-aiohttp-openmetrics: HTTP metrics support'
|
||||||
|
|||||||
+1
-1
@@ -59,7 +59,7 @@ RUN runuser -u build -- install-aur-package \
|
|||||||
python-aiohttp-jinja2 \
|
python-aiohttp-jinja2 \
|
||||||
python-aiohttp-session \
|
python-aiohttp-session \
|
||||||
python-aiohttp-security \
|
python-aiohttp-security \
|
||||||
python-aiohttp-sse-git \
|
python-aiohttp-sse \
|
||||||
python-requests-unixsocket2 \
|
python-requests-unixsocket2 \
|
||||||
python-tree-sitter \
|
python-tree-sitter \
|
||||||
python-tree-sitter-bash
|
python-tree-sitter-bash
|
||||||
|
|||||||
@@ -42,5 +42,5 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "2.23.1"
|
"version": "2.23.5"
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,9 @@ import PackageRebuildDialog from "components/dialogs/PackageRebuildDialog";
|
|||||||
import PackageTableToolbar from "components/table/PackageTableToolbar";
|
import PackageTableToolbar from "components/table/PackageTableToolbar";
|
||||||
import StatusCell from "components/table/StatusCell";
|
import StatusCell from "components/table/StatusCell";
|
||||||
import { useDebounce } from "hooks/useDebounce";
|
import { useDebounce } from "hooks/useDebounce";
|
||||||
|
import { navigate, packageHref } from "hooks/useLocationQuery";
|
||||||
import { usePackageTable } from "hooks/usePackageTable";
|
import { usePackageTable } from "hooks/usePackageTable";
|
||||||
|
import { useRepository } from "hooks/useRepository";
|
||||||
import type { PackageRow } from "models/PackageRow";
|
import type { PackageRow } from "models/PackageRow";
|
||||||
import React, { useMemo } from "react";
|
import React, { useMemo } from "react";
|
||||||
|
|
||||||
@@ -59,6 +61,7 @@ function createListColumn(
|
|||||||
|
|
||||||
export default function PackageTable(): React.JSX.Element {
|
export default function PackageTable(): React.JSX.Element {
|
||||||
const table = usePackageTable();
|
const table = usePackageTable();
|
||||||
|
const { currentRepository } = useRepository();
|
||||||
const { handleRemove, handleUpdate, isAuthorized } = table;
|
const { handleRemove, handleUpdate, isAuthorized } = table;
|
||||||
const apiRef = useGridApiRef();
|
const apiRef = useGridApiRef();
|
||||||
const debouncedSearch = useDebounce(table.searchText, 300);
|
const debouncedSearch = useDebounce(table.searchText, 300);
|
||||||
@@ -79,11 +82,20 @@ export default function PackageTable(): React.JSX.Element {
|
|||||||
headerName: "package base",
|
headerName: "package base",
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
renderCell: params =>
|
renderCell: params =>
|
||||||
params.row.webUrl ?
|
<Link
|
||||||
<Link href={params.row.webUrl} rel="noopener noreferrer" target="_blank" underline="hover">
|
href={packageHref(currentRepository?.key ?? "", params.row.base)}
|
||||||
|
onClick={event => {
|
||||||
|
const modified = event.ctrlKey || event.metaKey || event.shiftKey || event.altKey;
|
||||||
|
if (event.button === 0 && !modified) {
|
||||||
|
event.preventDefault();
|
||||||
|
navigate(packageHref(currentRepository?.key ?? "", params.row.base));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
tabIndex={params.tabIndex}
|
||||||
|
underline="hover"
|
||||||
|
>
|
||||||
{params.value as string}
|
{params.value as string}
|
||||||
</Link>
|
</Link>,
|
||||||
: params.value as string,
|
|
||||||
},
|
},
|
||||||
{ align: "right", field: "version", headerAlign: "right", headerName: "version", width: 180 },
|
{ align: "right", field: "version", headerAlign: "right", headerName: "version", width: 180 },
|
||||||
createListColumn("packages", "packages", { flex: 1, minWidth: 120 }),
|
createListColumn("packages", "packages", { flex: 1, minWidth: 120 }),
|
||||||
@@ -124,7 +136,7 @@ export default function PackageTable(): React.JSX.Element {
|
|||||||
],
|
],
|
||||||
} satisfies GridColDef<PackageRow>] : [],
|
} satisfies GridColDef<PackageRow>] : [],
|
||||||
],
|
],
|
||||||
[handleRemove, handleUpdate, isAuthorized],
|
[currentRepository, handleRemove, handleUpdate, isAuthorized],
|
||||||
);
|
);
|
||||||
|
|
||||||
return <Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
|
return <Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
|
||||||
@@ -195,6 +207,7 @@ export default function PackageTable(): React.JSX.Element {
|
|||||||
<PackageRebuildDialog onClose={() => table.setDialogOpen(null)} open={table.dialogOpen === "rebuild"} />
|
<PackageRebuildDialog onClose={() => table.setDialogOpen(null)} open={table.dialogOpen === "rebuild"} />
|
||||||
<KeyImportDialog onClose={() => table.setDialogOpen(null)} open={table.dialogOpen === "keyImport"} />
|
<KeyImportDialog onClose={() => table.setDialogOpen(null)} open={table.dialogOpen === "keyImport"} />
|
||||||
<PackageInfoDialog
|
<PackageInfoDialog
|
||||||
|
key={`${currentRepository?.key}/${table.selectedPackage}`}
|
||||||
onClose={() => table.setSelectedPackage(null)}
|
onClose={() => table.setSelectedPackage(null)}
|
||||||
open={table.selectedPackage !== null}
|
open={table.selectedPackage !== null}
|
||||||
packageBase={table.selectedPackage}
|
packageBase={table.selectedPackage}
|
||||||
|
|||||||
@@ -18,31 +18,23 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import { RepositoryContext } from "contexts/RepositoryContext";
|
import { RepositoryContext } from "contexts/RepositoryContext";
|
||||||
|
import { navigate, packageHref, useLocationQuery } from "hooks/useLocationQuery";
|
||||||
import type { RepositoryId } from "models/RepositoryId";
|
import type { RepositoryId } from "models/RepositoryId";
|
||||||
import React, { type ReactNode, useCallback, useMemo, useState, useSyncExternalStore } from "react";
|
import React, { type ReactNode, useCallback, useMemo, useState } from "react";
|
||||||
|
|
||||||
function subscribeToHash(callback: () => void): () => void {
|
|
||||||
window.addEventListener("hashchange", callback);
|
|
||||||
return () => window.removeEventListener("hashchange", callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHashSnapshot(): string {
|
|
||||||
return window.location.hash.replace("#", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RepositoryProvider({ children }: { children: ReactNode }): React.JSX.Element {
|
export function RepositoryProvider({ children }: { children: ReactNode }): React.JSX.Element {
|
||||||
const [repositories, setRepositories] = useState<RepositoryId[]>([]);
|
const [repositories, setRepositories] = useState<RepositoryId[]>([]);
|
||||||
const hash = useSyncExternalStore(subscribeToHash, getHashSnapshot);
|
const repositoryKey = new URLSearchParams(useLocationQuery()).get("repository_id");
|
||||||
|
|
||||||
const currentRepository = useMemo(() => {
|
const currentRepository = useMemo(() => {
|
||||||
if (repositories.length === 0) {
|
if (repositories.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return repositories.find(repository => repository.key === hash) ?? repositories[0] ?? null;
|
return repositories.find(repository => repository.key === repositoryKey) ?? repositories[0] ?? null;
|
||||||
}, [repositories, hash]);
|
}, [repositories, repositoryKey]);
|
||||||
|
|
||||||
const setCurrentRepository = useCallback((repository: RepositoryId) => {
|
const setCurrentRepository = useCallback((repository: RepositoryId) => {
|
||||||
window.location.hash = repository.key;
|
navigate(packageHref(repository.key, null));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const value = useMemo(() => ({
|
const value = useMemo(() => ({
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021-2026 ahriman team.
|
||||||
|
*
|
||||||
|
* This file is part of ahriman
|
||||||
|
* (see https://github.com/arcan1s/ahriman).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import { useSyncExternalStore } from "react";
|
||||||
|
|
||||||
|
function subscribe(callback: () => void): () => void {
|
||||||
|
window.addEventListener("popstate", callback);
|
||||||
|
return () => window.removeEventListener("popstate", callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSnapshot(): string {
|
||||||
|
return window.location.search;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useLocationQuery(): string {
|
||||||
|
return useSyncExternalStore(subscribe, getSnapshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function packageHref(repositoryKey: string, packageBase: string | null): string {
|
||||||
|
const query = new URLSearchParams(window.location.search);
|
||||||
|
query.set("repository_id", repositoryKey);
|
||||||
|
if (packageBase) {
|
||||||
|
query.set("package", packageBase);
|
||||||
|
} else {
|
||||||
|
query.delete("package");
|
||||||
|
}
|
||||||
|
return `${window.location.pathname}?${query}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function navigate(href: string): void {
|
||||||
|
if (href === `${window.location.pathname}${window.location.search}`) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.history.pushState(null, "", href);
|
||||||
|
window.dispatchEvent(new PopStateEvent("popstate"));
|
||||||
|
}
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
*/
|
*/
|
||||||
import type { GridFilterModel } from "@mui/x-data-grid";
|
import type { GridFilterModel } from "@mui/x-data-grid";
|
||||||
import { useLocalStorage } from "hooks/useLocalStorage";
|
import { useLocalStorage } from "hooks/useLocalStorage";
|
||||||
|
import { navigate, packageHref, useLocationQuery } from "hooks/useLocationQuery";
|
||||||
|
import { useRepository } from "hooks/useRepository";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
export type DialogType = "dashboard" | "add" | "rebuild" | "keyImport";
|
export type DialogType = "dashboard" | "add" | "rebuild" | "keyImport";
|
||||||
@@ -43,7 +45,14 @@ export interface UseTableStateResult {
|
|||||||
export function useTableState(): UseTableStateResult {
|
export function useTableState(): UseTableStateResult {
|
||||||
const [selectionModel, setSelectionModel] = useState<string[]>([]);
|
const [selectionModel, setSelectionModel] = useState<string[]>([]);
|
||||||
const [dialogOpen, setDialogOpen] = useState<DialogType | null>(null);
|
const [dialogOpen, setDialogOpen] = useState<DialogType | null>(null);
|
||||||
const [selectedPackage, setSelectedPackage] = useState<string | null>(null);
|
const { currentRepository } = useRepository();
|
||||||
|
const packageBase = new URLSearchParams(useLocationQuery()).get("package");
|
||||||
|
const selectedPackage = currentRepository && packageBase ? packageBase : null;
|
||||||
|
const setSelectedPackage = (base: string | null): void => {
|
||||||
|
if (currentRepository) {
|
||||||
|
navigate(packageHref(currentRepository.key, base));
|
||||||
|
}
|
||||||
|
};
|
||||||
const [searchText, setSearchText] = useState("");
|
const [searchText, setSearchText] = useState("");
|
||||||
|
|
||||||
const [paginationModel, setPaginationModel] = useLocalStorage("ahriman-packages-pagination", {
|
const [paginationModel, setPaginationModel] = useLocalStorage("ahriman-packages-pagination", {
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
# Maintainer: Andrew Crerar <crerar@archlinux.org>
|
||||||
|
# Contributor: Mohammadreza Abdollahzadeh <morealaz at gmail dot com>
|
||||||
|
# Contributor: FadeMind <fademind@gmail.com>
|
||||||
|
# Contributor: Vlad M. <vlad@archlinux.net>
|
||||||
|
# Contributor: Sebastian Stammler <stammler.s@gmail.com>
|
||||||
|
# Contributor: Sarkasper <echo a2FzcGVyLm1lbnRlbkBnbXguY29tCg== | base64 -d>
|
||||||
|
# Contributor: Daniel Micay <danielmicay@gmail.com>
|
||||||
|
# Contributor: Michalis Georgiou <mechmg93@gmail.comr>
|
||||||
|
# Contributor: Alexander De Sousa <archaur.xandy21@spamgourmet.com>
|
||||||
|
|
||||||
|
pkgname=ttf-google-fonts-git
|
||||||
|
pkgver=r11002.cdabad3d0
|
||||||
|
pkgrel=1
|
||||||
|
epoch=1
|
||||||
|
pkgdesc="TrueType fonts from the Google Fonts project (git version)"
|
||||||
|
arch=('any')
|
||||||
|
url="https://github.com/google/fonts"
|
||||||
|
license=('custom:SIL Open Font License' 'custom:Ubuntu Font License v1.0')
|
||||||
|
|
||||||
|
depends=('adobe-source-code-pro-fonts'
|
||||||
|
'adobe-source-sans-fonts'
|
||||||
|
'adobe-source-serif-fonts'
|
||||||
|
'cantarell-fonts'
|
||||||
|
'noto-fonts'
|
||||||
|
'noto-fonts-extra'
|
||||||
|
'ttf-anonymous-pro'
|
||||||
|
'ttf-caladea'
|
||||||
|
'ttf-croscore'
|
||||||
|
'ttf-fira-sans'
|
||||||
|
'ttf-fira-mono'
|
||||||
|
'ttf-inconsolata'
|
||||||
|
'ttf-lato'
|
||||||
|
'ttf-merriweather'
|
||||||
|
'ttf-merriweather-sans'
|
||||||
|
'ttf-opensans'
|
||||||
|
'ttf-oswald'
|
||||||
|
'ttf-quintessential'
|
||||||
|
'ttf-roboto'
|
||||||
|
'ttf-roboto-mono'
|
||||||
|
'ttf-signika'
|
||||||
|
'ttf-ubuntu-font-family')
|
||||||
|
makedepends=('git' 'fontconfig')
|
||||||
|
conflicts=('jsmath-fonts'
|
||||||
|
'lohit-fonts'
|
||||||
|
'ttf-andika'
|
||||||
|
'ttf-arabeyes-fonts'
|
||||||
|
'ttf-cardo'
|
||||||
|
'ttf-comfortaa'
|
||||||
|
'ttf-google-fonts-typewolf'
|
||||||
|
'ttf-lora-cyrillic'
|
||||||
|
'ttf-lekton'
|
||||||
|
'ttf-medievalsharp'
|
||||||
|
'ttf-nova'
|
||||||
|
'ttf-oxygen'
|
||||||
|
'ttf-oxygen-git'
|
||||||
|
'ttf-pt-fonts'
|
||||||
|
'ttf-source-code-pro-ibx'
|
||||||
|
'ttf-source-sans-pro-ibx'
|
||||||
|
'ttf-vollkorn-ibx')
|
||||||
|
provides=('jsmath-fonts'
|
||||||
|
'lohit-fonts'
|
||||||
|
'ttf-andika'
|
||||||
|
'ttf-cardo'
|
||||||
|
'ttf-carlito'
|
||||||
|
'ttf-comfortaa'
|
||||||
|
'ttf-lora-cyrillic'
|
||||||
|
'ttf-lekton'
|
||||||
|
'ttf-medievalsharp'
|
||||||
|
'ttf-nova'
|
||||||
|
'ttf-oxygen'
|
||||||
|
'ttf-oxygen-git'
|
||||||
|
'ttf-pt-fonts'
|
||||||
|
'ttf-source-code-pro-ibx'
|
||||||
|
'ttf-source-sans-pro-ibx'
|
||||||
|
'ttf-vollkorn-ibx')
|
||||||
|
source=(git+"${url}".git)
|
||||||
|
sha512sums=('SKIP')
|
||||||
|
|
||||||
|
pkgver() {
|
||||||
|
cd fonts
|
||||||
|
|
||||||
|
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare() {
|
||||||
|
cd fonts
|
||||||
|
|
||||||
|
# NOTE: Adobe Blank is not meant to be installed.
|
||||||
|
# See: https://github.com/google/fonts/issues/2106#issuecomment-520067314
|
||||||
|
rm --recursive "${srcdir}/fonts/ofl/adobeblank"
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
# NOTE: These are the font families that already exist in the [extra] repo
|
||||||
|
# or should not be installed by this package, due to user reports
|
||||||
|
# of system instability.
|
||||||
|
declare -A omitted_font_families=(
|
||||||
|
[anonymous-pro]=1
|
||||||
|
[arimo]=1
|
||||||
|
[caladea]=1
|
||||||
|
[cantarell]=1
|
||||||
|
[carlito]=1
|
||||||
|
[cousine]=1
|
||||||
|
[dai-banna-sil]=1
|
||||||
|
[fira-sans]=1
|
||||||
|
[fira-mono]=1
|
||||||
|
[inconsolata]=1
|
||||||
|
[merriweather]=1
|
||||||
|
[merriweather-sans]=1
|
||||||
|
[noto-color-emoji]=1
|
||||||
|
[noto-sans]=1
|
||||||
|
[noto-sans-tamil]=1
|
||||||
|
[noto-serif]=1
|
||||||
|
[open-sans]=1
|
||||||
|
[oswald]=1
|
||||||
|
[quintessential]=1
|
||||||
|
[roboto]=1
|
||||||
|
[roboto-condensed]=1
|
||||||
|
[roboto-mono]=1
|
||||||
|
[source-sans-3]=1
|
||||||
|
[source-sans-pro]=1
|
||||||
|
[source-serif-4]=1
|
||||||
|
[source-serif-pro]=1
|
||||||
|
[tinos]=1
|
||||||
|
[ubuntu]=1
|
||||||
|
[ubuntu-mono]=1
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
while IFS= read -rd '' file; do
|
||||||
|
font_family=$(fc-query -f '%{family[0]|downcase|translate( ,-)}\n' "$file" | sed -n '1p')
|
||||||
|
|
||||||
|
# NOTE: Skip the rest of the loop if we're not supposed to be touching this family
|
||||||
|
((omitted_font_families["$font_family"])) && continue
|
||||||
|
|
||||||
|
pkg_font_path="$pkgdir"/usr/share/fonts/"$font_family"
|
||||||
|
install -Dm644 "$file" -t "$pkg_font_path" # TODO: Check and make sure $font_family is being created
|
||||||
|
|
||||||
|
# NOTE: If the font's license already exists, we don't need to copy the license again.
|
||||||
|
src_license_path="${file%/*}"/OFL.txt
|
||||||
|
pkg_font_license="$pkgdir"/usr/share/licenses/"$pkgname"/LICENSE."$font_family"
|
||||||
|
if [[ -f "$src_license_path" && ! -f "$pkg_font_license" ]]; then
|
||||||
|
install -Dm644 "$src_license_path" "$pkg_font_license"
|
||||||
|
fi
|
||||||
|
done < <(find "$srcdir" -type f -iname \*.ttf -print0)
|
||||||
|
|
||||||
|
# NOTE: Since the zcool xiaowei chinese font has special characters. We need to change
|
||||||
|
# the folder name to prevent errors during package compression.
|
||||||
|
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
|
||||||
|
}
|
||||||
Reference in new issue
Block a user