mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-10-25 12:55:00 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c375236327 | ||
|
|
ddbb4b06ff | ||
|
|
2d66b67123 | ||
|
|
27cfcd07eb | ||
|
|
2080f1e06f | ||
|
|
2544d44051 | ||
|
|
b07ad8cc0c | ||
|
|
c38cb5f680 | ||
|
|
f776b33310 | ||
|
|
eafa1b417a | ||
|
|
d0aff05be5 | ||
|
|
8a6b71a425 |
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
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
.TH AHRIMAN "1" "2026\-10\-20" "ahriman 2.23.0" "ArcH linux ReposItory MANager"
|
.TH AHRIMAN "1" "2026\-10\-25" "ahriman 2.23.4" "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.0"
|
__version__ = "2.23.4"
|
||||||
@@ -21,7 +21,7 @@ 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
|
||||||
@@ -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,24 +97,29 @@ 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"(.*)\{([^{}]+)\}(.*)")
|
_BRACE_EXPANSION = re.compile(r"(.*)\{([^{}]+)\}(.*)")
|
||||||
|
|
||||||
def __init__(self, stream: IO[bytes]) -> None:
|
def __init__(self, stream: IO[bytes]) -> None:
|
||||||
""""""
|
"""
|
||||||
|
Args:
|
||||||
|
stream(IO[bytes]): input PKGBUILD stream
|
||||||
|
"""
|
||||||
self._content = stream.read()
|
self._content = stream.read()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -164,6 +169,11 @@ 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 = []
|
||||||
@@ -256,3 +266,12 @@ class PkgbuildParser:
|
|||||||
)
|
)
|
||||||
|
|
||||||
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,
|
||||||
|
|||||||
@@ -71,7 +71,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 +119,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,169 +399,6 @@ def test_parse_jellyfin_ffmpeg6_bin(resource_path_root: Path) -> None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_parse_tpacpi_bat_git(resource_path_root: Path) -> None:
|
|
||||||
"""
|
|
||||||
must parse real PKGBUILDs correctly (tpacpi-bat-git)
|
|
||||||
"""
|
|
||||||
pkgbuild = Pkgbuild.from_file(resource_path_root / "models" / "package_tpacpi-bat-git_pkgbuild")
|
|
||||||
values = {key: value.value for key, value in pkgbuild.fields.items() if not value.is_function}
|
|
||||||
assert values == {
|
|
||||||
"pkgbase": "tpacpi-bat-git",
|
|
||||||
"pkgname": "tpacpi-bat-git",
|
|
||||||
"pkgver": "3.1.r13.g4959b52",
|
|
||||||
"pkgrel": "1",
|
|
||||||
"pkgdesc": "A Perl script with ACPI calls for recent ThinkPads which are not supported by tp_smapi",
|
|
||||||
"arch": ["any"],
|
|
||||||
"url": "https://github.com/teleshoes/tpacpi-bat",
|
|
||||||
"license": ["GPL3"],
|
|
||||||
"depends": ["perl", "acpi_call"],
|
|
||||||
"makedepends": ["git"],
|
|
||||||
"provides": ["tpacpi-bat"],
|
|
||||||
"conflicts": ["tpacpi-bat"],
|
|
||||||
"backup": ["etc/conf.d/tpacpi"],
|
|
||||||
"source": ["git+https://github.com/teleshoes/tpacpi-bat.git"],
|
|
||||||
"b2sums": ["SKIP"],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_yay(resource_path_root: Path) -> None:
|
|
||||||
"""
|
|
||||||
must parse real PKGBUILDs correctly (yay)
|
|
||||||
"""
|
|
||||||
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}
|
|
||||||
assert values == {
|
|
||||||
"pkgbase": "yay",
|
|
||||||
"pkgname": "yay",
|
|
||||||
"pkgver": "12.3.5",
|
|
||||||
"pkgrel": "1",
|
|
||||||
"pkgdesc": "Yet another yogurt. Pacman wrapper and AUR helper written in go.",
|
|
||||||
"arch": [
|
|
||||||
"i686",
|
|
||||||
"pentium4",
|
|
||||||
"x86_64",
|
|
||||||
"arm",
|
|
||||||
"armv7h",
|
|
||||||
"armv6h",
|
|
||||||
"aarch64",
|
|
||||||
"riscv64",
|
|
||||||
],
|
|
||||||
"url": "https://github.com/Jguer/yay",
|
|
||||||
"options": ["!lto"],
|
|
||||||
"license": ["GPL-3.0-or-later"],
|
|
||||||
"depends": [
|
|
||||||
"pacman>6.1",
|
|
||||||
"git",
|
|
||||||
],
|
|
||||||
"optdepends": [
|
|
||||||
"sudo: privilege elevation",
|
|
||||||
"doas: privilege elevation",
|
|
||||||
],
|
|
||||||
"makedepends": ["go>=1.21"],
|
|
||||||
"source": ["${pkgname}-${pkgver}.tar.gz::https://github.com/Jguer/yay/archive/v${pkgver}.tar.gz"],
|
|
||||||
"sha256sums": ["2fb6121a6eb4c5e6afaf22212b2ed15022500a4bc34bb3dc0f9782c1d43c3962"],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_vim_youcompleteme_git(resource_path_root: Path) -> None:
|
|
||||||
"""
|
|
||||||
must parse real PKGBUILDs correctly (vim-youcompleteme-git)
|
|
||||||
"""
|
|
||||||
pkgbuild = Pkgbuild.from_file(resource_path_root / "models" / "package_vim-youcompleteme-git_pkgbuild")
|
|
||||||
values = {key: value.value for key, value in pkgbuild.fields.items() if not value.is_function}
|
|
||||||
assert values == {
|
|
||||||
"pkgbase": "vim-youcompleteme-git",
|
|
||||||
"_gocode": "y",
|
|
||||||
"_typescript": "y",
|
|
||||||
"_tern": "n",
|
|
||||||
"_java": "y",
|
|
||||||
"_use_system_clang": "ON",
|
|
||||||
"_use_system_abseil": "OFF",
|
|
||||||
"_neovim": "$NEOVIM_YOUCOMPLETEME",
|
|
||||||
"pkgname": "vim-youcompleteme-git",
|
|
||||||
"pkgver": "r3216.0d855962",
|
|
||||||
"pkgrel": "1",
|
|
||||||
"pkgdesc": "A code-completion engine for Vim",
|
|
||||||
"arch": ["x86_64"],
|
|
||||||
"url": "https://ycm-core.github.io/YouCompleteMe/",
|
|
||||||
"license": ["GPL3"],
|
|
||||||
"groups": ["vim-plugins"],
|
|
||||||
"depends": [
|
|
||||||
"vim",
|
|
||||||
"python>=3.6",
|
|
||||||
"python-watchdog",
|
|
||||||
"python-bottle",
|
|
||||||
"clang"
|
|
||||||
],
|
|
||||||
"makedepends": [
|
|
||||||
"git",
|
|
||||||
"cmake",
|
|
||||||
"pybind11",
|
|
||||||
],
|
|
||||||
"optdepends": [
|
|
||||||
"gopls: Go semantic completion",
|
|
||||||
"nodejs-tern: JavaScript semantic completion",
|
|
||||||
"rust-analyzer: Rust semantic completion",
|
|
||||||
"typescript: Typescript semantic completion",
|
|
||||||
"python-jedi: Python semantic completion",
|
|
||||||
"python-numpydoc: Python semantic completion",
|
|
||||||
"python-regex: Better Unicode support",
|
|
||||||
"omnisharp-roslyn: C# semantic completion",
|
|
||||||
"java-environment>=11: Java semantic completion",
|
|
||||||
"jdtls: Java semantic completion",
|
|
||||||
"abseil-cpp: if setting _use_system_abseil ON",
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"git+https://github.com/ycm-core/YouCompleteMe.git",
|
|
||||||
"git+https://github.com/ycm-core/ycmd.git",
|
|
||||||
"clangd-15.0.1.tar.bz2::https://github.com/ycm-core/llvm/releases/download/15.0.1/clangd-15.0.1-x86_64-unknown-linux-gnu.tar.bz2",
|
|
||||||
"libclang-15.0.1.tar.bz2::https://github.com/ycm-core/llvm/releases/download/15.0.1/libclang-15.0.1-x86_64-unknown-linux-gnu.tar.bz2",
|
|
||||||
],
|
|
||||||
"sha256sums": [
|
|
||||||
"SKIP",
|
|
||||||
"SKIP",
|
|
||||||
"10a64c468d1dd2a384e0e5fd4eb2582fd9f1dfa706b6d2d2bb88fb0fbfc2718d",
|
|
||||||
"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",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_parse_pacman_static(resource_path_root: Path) -> None:
|
def test_parse_pacman_static(resource_path_root: Path) -> None:
|
||||||
"""
|
"""
|
||||||
must parse real PKGBUILDs correctly (pacman-static)
|
must parse real PKGBUILDs correctly (pacman-static)
|
||||||
@@ -654,3 +491,248 @@ def test_parse_pacman_static(resource_path_root: Path) -> None:
|
|||||||
"CXXFLAGS": "${CXXFLAGS/-fstack-protector-strong/}",
|
"CXXFLAGS": "${CXXFLAGS/-fstack-protector-strong/}",
|
||||||
"PKGEXT": ".pkg.tar.xz",
|
"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:
|
||||||
|
"""
|
||||||
|
must parse real PKGBUILDs correctly (tpacpi-bat-git)
|
||||||
|
"""
|
||||||
|
pkgbuild = Pkgbuild.from_file(resource_path_root / "models" / "package_tpacpi-bat-git_pkgbuild")
|
||||||
|
values = {key: value.value for key, value in pkgbuild.fields.items() if not value.is_function}
|
||||||
|
assert values == {
|
||||||
|
"pkgbase": "tpacpi-bat-git",
|
||||||
|
"pkgname": "tpacpi-bat-git",
|
||||||
|
"pkgver": "3.1.r13.g4959b52",
|
||||||
|
"pkgrel": "1",
|
||||||
|
"pkgdesc": "A Perl script with ACPI calls for recent ThinkPads which are not supported by tp_smapi",
|
||||||
|
"arch": ["any"],
|
||||||
|
"url": "https://github.com/teleshoes/tpacpi-bat",
|
||||||
|
"license": ["GPL3"],
|
||||||
|
"depends": ["perl", "acpi_call"],
|
||||||
|
"makedepends": ["git"],
|
||||||
|
"provides": ["tpacpi-bat"],
|
||||||
|
"conflicts": ["tpacpi-bat"],
|
||||||
|
"backup": ["etc/conf.d/tpacpi"],
|
||||||
|
"source": ["git+https://github.com/teleshoes/tpacpi-bat.git"],
|
||||||
|
"b2sums": ["SKIP"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_ttf_google_fonts_git(resource_path_root: Path) -> None:
|
||||||
|
"""
|
||||||
|
must parse real PKGBUILDs correctly (ttf-google-fonts-git)
|
||||||
|
"""
|
||||||
|
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}
|
||||||
|
assert "ttf-google-fonts-git" in pkgbuild.packages()
|
||||||
|
assert values == {
|
||||||
|
"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"],
|
||||||
|
"pkgbase": "ttf-google-fonts-git",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_vim_youcompleteme_git(resource_path_root: Path) -> None:
|
||||||
|
"""
|
||||||
|
must parse real PKGBUILDs correctly (vim-youcompleteme-git)
|
||||||
|
"""
|
||||||
|
pkgbuild = Pkgbuild.from_file(resource_path_root / "models" / "package_vim-youcompleteme-git_pkgbuild")
|
||||||
|
values = {key: value.value for key, value in pkgbuild.fields.items() if not value.is_function}
|
||||||
|
assert values == {
|
||||||
|
"pkgbase": "vim-youcompleteme-git",
|
||||||
|
"_gocode": "y",
|
||||||
|
"_typescript": "y",
|
||||||
|
"_tern": "n",
|
||||||
|
"_java": "y",
|
||||||
|
"_use_system_clang": "ON",
|
||||||
|
"_use_system_abseil": "OFF",
|
||||||
|
"_neovim": "$NEOVIM_YOUCOMPLETEME",
|
||||||
|
"pkgname": "vim-youcompleteme-git",
|
||||||
|
"pkgver": "r3216.0d855962",
|
||||||
|
"pkgrel": "1",
|
||||||
|
"pkgdesc": "A code-completion engine for Vim",
|
||||||
|
"arch": ["x86_64"],
|
||||||
|
"url": "https://ycm-core.github.io/YouCompleteMe/",
|
||||||
|
"license": ["GPL3"],
|
||||||
|
"groups": ["vim-plugins"],
|
||||||
|
"depends": [
|
||||||
|
"vim",
|
||||||
|
"python>=3.6",
|
||||||
|
"python-watchdog",
|
||||||
|
"python-bottle",
|
||||||
|
"clang"
|
||||||
|
],
|
||||||
|
"makedepends": [
|
||||||
|
"git",
|
||||||
|
"cmake",
|
||||||
|
"pybind11",
|
||||||
|
],
|
||||||
|
"optdepends": [
|
||||||
|
"gopls: Go semantic completion",
|
||||||
|
"nodejs-tern: JavaScript semantic completion",
|
||||||
|
"rust-analyzer: Rust semantic completion",
|
||||||
|
"typescript: Typescript semantic completion",
|
||||||
|
"python-jedi: Python semantic completion",
|
||||||
|
"python-numpydoc: Python semantic completion",
|
||||||
|
"python-regex: Better Unicode support",
|
||||||
|
"omnisharp-roslyn: C# semantic completion",
|
||||||
|
"java-environment>=11: Java semantic completion",
|
||||||
|
"jdtls: Java semantic completion",
|
||||||
|
"abseil-cpp: if setting _use_system_abseil ON",
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"git+https://github.com/ycm-core/YouCompleteMe.git",
|
||||||
|
"git+https://github.com/ycm-core/ycmd.git",
|
||||||
|
"clangd-15.0.1.tar.bz2::https://github.com/ycm-core/llvm/releases/download/15.0.1/clangd-15.0.1-x86_64-unknown-linux-gnu.tar.bz2",
|
||||||
|
"libclang-15.0.1.tar.bz2::https://github.com/ycm-core/llvm/releases/download/15.0.1/libclang-15.0.1-x86_64-unknown-linux-gnu.tar.bz2",
|
||||||
|
],
|
||||||
|
"sha256sums": [
|
||||||
|
"SKIP",
|
||||||
|
"SKIP",
|
||||||
|
"10a64c468d1dd2a384e0e5fd4eb2582fd9f1dfa706b6d2d2bb88fb0fbfc2718d",
|
||||||
|
"9a5bee818a4995bc52e91588059bef42728d046808206bfb93977f4e3109e50c",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_yay(resource_path_root: Path) -> None:
|
||||||
|
"""
|
||||||
|
must parse real PKGBUILDs correctly (yay)
|
||||||
|
"""
|
||||||
|
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}
|
||||||
|
assert values == {
|
||||||
|
"pkgbase": "yay",
|
||||||
|
"pkgname": "yay",
|
||||||
|
"pkgver": "12.3.5",
|
||||||
|
"pkgrel": "1",
|
||||||
|
"pkgdesc": "Yet another yogurt. Pacman wrapper and AUR helper written in go.",
|
||||||
|
"arch": [
|
||||||
|
"i686",
|
||||||
|
"pentium4",
|
||||||
|
"x86_64",
|
||||||
|
"arm",
|
||||||
|
"armv7h",
|
||||||
|
"armv6h",
|
||||||
|
"aarch64",
|
||||||
|
"riscv64",
|
||||||
|
],
|
||||||
|
"url": "https://github.com/Jguer/yay",
|
||||||
|
"options": ["!lto"],
|
||||||
|
"license": ["GPL-3.0-or-later"],
|
||||||
|
"depends": [
|
||||||
|
"pacman>6.1",
|
||||||
|
"git",
|
||||||
|
],
|
||||||
|
"optdepends": [
|
||||||
|
"sudo: privilege elevation",
|
||||||
|
"doas: privilege elevation",
|
||||||
|
],
|
||||||
|
"makedepends": ["go>=1.21"],
|
||||||
|
"source": ["${pkgname}-${pkgver}.tar.gz::https://github.com/Jguer/yay/archive/v${pkgver}.tar.gz"],
|
||||||
|
"sha256sums": ["2fb6121a6eb4c5e6afaf22212b2ed15022500a4bc34bb3dc0f9782c1d43c3962"],
|
||||||
|
}
|
||||||
+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.0
|
pkgver=2.23.4
|
||||||
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
|
||||||
|
|||||||
@@ -125,6 +125,10 @@ sphinxcontrib-serializinghtml==2.0.0
|
|||||||
# via sphinx
|
# via sphinx
|
||||||
stdlib-list==0.11.1
|
stdlib-list==0.11.1
|
||||||
# via pydeps
|
# via pydeps
|
||||||
|
tree-sitter==0.26.0
|
||||||
|
# via ahriman-core
|
||||||
|
tree-sitter-bash==0.25.1
|
||||||
|
# via ahriman-core
|
||||||
urllib3==2.4.0
|
urllib3==2.4.0
|
||||||
# via
|
# via
|
||||||
# botocore
|
# botocore
|
||||||
|
|||||||
@@ -42,5 +42,5 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "2.23.0"
|
"version": "2.23.4"
|
||||||
}
|
}
|
||||||
@@ -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)}
|
||||||
{params.value as string}
|
onClick={event => {
|
||||||
</Link>
|
const modified = event.ctrlKey || event.metaKey || event.shiftKey || event.altKey;
|
||||||
: params.value as string,
|
if (event.button === 0 && !modified) {
|
||||||
|
event.preventDefault();
|
||||||
|
navigate(packageHref(currentRepository?.key ?? "", params.row.base));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
tabIndex={params.tabIndex}
|
||||||
|
underline="hover"
|
||||||
|
>
|
||||||
|
{params.value as string}
|
||||||
|
</Link>,
|
||||||
},
|
},
|
||||||
{ 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