mirror of
https://github.com/kiviktnm/decman.git
synced 2026-09-19 12:08:28 +00:00
Implement PKGBUILD parsing for CustomPackages
This commit is contained in:
@@ -17,6 +17,7 @@ decman = "decman.app:main"
|
||||
[project.entry-points."decman.plugins"]
|
||||
systemd = "decman.plugins.systemd:Systemd"
|
||||
pacman = "decman.plugins.pacman:Pacman"
|
||||
aur = "decman.plugins.pacman:AUR"
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
|
||||
@@ -25,3 +25,5 @@ quiet_output: bool = False
|
||||
color_output: bool = True
|
||||
|
||||
module_on_disable_scripts_dir: str = "/var/lib/decman/scripts/"
|
||||
|
||||
arch: str = "x86_64"
|
||||
|
||||
@@ -48,17 +48,47 @@ def custom_packages(fn):
|
||||
return fn
|
||||
|
||||
|
||||
class AUR(plugins.Plugin):
|
||||
"""
|
||||
Plugin that manages additional pacman packages installed outside the pacman repos.
|
||||
|
||||
AUR packages are added directly to ``packages`` or declared by modules via ``@aur_packages``.
|
||||
|
||||
Custom packages are added directly to ``custom_packages`` or declared by modules via
|
||||
``@custom_packages``.
|
||||
"""
|
||||
|
||||
NAME = "aur"
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.packages: set[str] = set()
|
||||
self.custom_packages: set[CustomPackage] = set()
|
||||
self.commands = PacmanCommands()
|
||||
|
||||
def available(self) -> bool:
|
||||
return shutil.which("pacman") is not None
|
||||
|
||||
def process_modules(self, store: _store.Store, modules: set[module.Module]):
|
||||
# This is used to track changes in modules.
|
||||
store.ensure("aur_packages_for_module", {})
|
||||
store.ensure("custom_packages_for_module", {})
|
||||
|
||||
def apply(
|
||||
self, store: _store.Store, dry_run: bool = False, params: list[str] | None = None
|
||||
) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
class Pacman(plugins.Plugin):
|
||||
"""
|
||||
Plugin that manages pacman packages added directly to ``packages`` or declared by modules via
|
||||
@packages.
|
||||
``@packages``.
|
||||
"""
|
||||
|
||||
NAME = "pacman"
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.packages: set[str] = set()
|
||||
self.aur_packages: set[str] = set()
|
||||
self.commands = PacmanCommands()
|
||||
|
||||
def available(self) -> bool:
|
||||
|
||||
@@ -173,6 +173,13 @@ class PacmanCommands:
|
||||
|
||||
return makechrootpkg_cmd
|
||||
|
||||
def print_srcinfo(self) -> list[str]:
|
||||
"""
|
||||
Running this command prints SRCINFO generated from the package in the current
|
||||
working directory.
|
||||
"""
|
||||
return ["makepkg", "--printsrcinfo"]
|
||||
|
||||
|
||||
class PacmanInterface:
|
||||
"""
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import dataclasses
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
import requests # type: ignore
|
||||
|
||||
import decman.config as config
|
||||
import decman.core.command as command
|
||||
import decman.core.error as errors
|
||||
import decman.core.output as output
|
||||
from decman.plugins.pacman.commands import PacmanInterface
|
||||
from decman.plugins.pacman.error import AurRPCError
|
||||
from decman.plugins.pacman.commands import PacmanCommands, PacmanInterface
|
||||
from decman.plugins.pacman.error import AurRPCError, PKGBUILDParseError
|
||||
|
||||
|
||||
def strip_dependency(dep: str) -> str:
|
||||
@@ -138,9 +144,14 @@ class CustomPackage:
|
||||
"""
|
||||
Custom package installed from some other location than the official repos or the AUR.
|
||||
|
||||
``pkgname`` is required because the PKGBUILD might be for split packages.
|
||||
|
||||
Exactly one of ``git_url`` or ``pkgbuild_directory`` must be provided.
|
||||
|
||||
Parameters:
|
||||
``pkgname``:
|
||||
Name of the package.
|
||||
|
||||
``git_url``:
|
||||
URL to a git repository containing the PKGBUILD.
|
||||
|
||||
@@ -148,23 +159,237 @@ class CustomPackage:
|
||||
Path to the directory containing the PKGBUILD.
|
||||
"""
|
||||
|
||||
def __init__(self, git_url: str | None, pkgbuild_directory: str | None) -> None:
|
||||
def __init__(self, pkgname: str, git_url: str | None, pkgbuild_directory: str | None) -> None:
|
||||
if git_url is None and pkgbuild_directory is None:
|
||||
raise ValueError("Both git_url and pkgbuild_directory cannot be None.")
|
||||
|
||||
if git_url is not None and pkgbuild_directory is not None:
|
||||
raise ValueError("Both git_url and pkgbuild_directory cannot be set.")
|
||||
|
||||
self.pkgname = pkgname
|
||||
self.git_url = git_url
|
||||
self.pkgbuild_directory = pkgbuild_directory
|
||||
|
||||
def parse(self) -> PackageInfo:
|
||||
def parse(self, commands: PacmanCommands) -> PackageInfo:
|
||||
"""
|
||||
Parses this package's PKGBUILD to ``PackageInfo``.
|
||||
|
||||
If this fails, raises a ``PKGBUILDParseError``.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
if self.pkgbuild_directory is not None:
|
||||
srcinfo = self._srcinfo_from_pkgbuild_directory(commands)
|
||||
else:
|
||||
srcinfo = self._srcinfo_from_git(commands)
|
||||
|
||||
return self._parse_srcinfo(srcinfo)
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if not isinstance(other, CustomPackage):
|
||||
return False
|
||||
return (
|
||||
self.git_url == other.git_url
|
||||
and self.pkgbuild_directory == other.pkgbuild_directory
|
||||
and self.pkgname == other.pkgname
|
||||
)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.pkgname, self.git_url, self.pkgbuild_directory))
|
||||
|
||||
def __str__(self) -> str:
|
||||
if self.git_url is not None:
|
||||
return f"CustomPackage(pkgname={self.pkgname}, git_url={self.git_url})"
|
||||
return (
|
||||
f"CustomPackage(pkgname={self.pkgname}, pkgbuild_directory={self.pkgbuild_directory})"
|
||||
)
|
||||
|
||||
def _srcinfo_from_pkgbuild_directory(self, commands: PacmanCommands) -> str:
|
||||
assert self.pkgbuild_directory is not None, (
|
||||
"This will not get called if pkgbuild_directory is unset."
|
||||
)
|
||||
|
||||
path = pathlib.Path(self.pkgbuild_directory)
|
||||
if not path.is_dir():
|
||||
raise PKGBUILDParseError(
|
||||
self.git_url,
|
||||
self.pkgbuild_directory,
|
||||
f"pkgbuild_directory '{path}' does not exist or is not a directory.",
|
||||
)
|
||||
|
||||
if not (path / "PKGBUILD").exists():
|
||||
raise PKGBUILDParseError(
|
||||
self.git_url, self.pkgbuild_directory, f"No PKGBUILD found in '{path}'."
|
||||
)
|
||||
|
||||
return self._run_makepkg_printsrcinfo(path, commands)
|
||||
|
||||
def _srcinfo_from_git(self, commands: PacmanCommands) -> str:
|
||||
assert self.git_url is not None, "This will not get called if git_url is unset."
|
||||
with tempfile.TemporaryDirectory(prefix="decman-pkgbuild-") as tmpdir:
|
||||
tmp_path = pathlib.Path(tmpdir)
|
||||
try:
|
||||
cmd = commands.git_clone(self.git_url, tmpdir)
|
||||
command.check_run_result(cmd, command.run(cmd))
|
||||
except errors.CommandFailedError as error:
|
||||
raise PKGBUILDParseError(
|
||||
self.git_url, self.pkgbuild_directory, "Failed to clone PKGBUILD repository."
|
||||
) from error
|
||||
|
||||
if not (tmp_path / "PKGBUILD").exists():
|
||||
raise PKGBUILDParseError(
|
||||
self.git_url,
|
||||
self.pkgbuild_directory,
|
||||
f"Cloned repository '{self.git_url}' does not contain a PKGBUILD.",
|
||||
)
|
||||
|
||||
return self._run_makepkg_printsrcinfo(tmp_path, commands)
|
||||
|
||||
def _run_makepkg_printsrcinfo(self, path: pathlib.Path, commands: PacmanCommands) -> str:
|
||||
orig_wd = os.getcwd()
|
||||
try:
|
||||
os.chdir(path)
|
||||
cmd = commands.print_srcinfo()
|
||||
_, srcinfo = command.check_run_result(cmd, command.run(cmd))
|
||||
except errors.CommandFailedError as error:
|
||||
raise PKGBUILDParseError(
|
||||
self.git_url, self.pkgbuild_directory, "Failed to generate SRCINFO using makepkg."
|
||||
) from error
|
||||
finally:
|
||||
os.chdir(orig_wd)
|
||||
|
||||
return srcinfo
|
||||
|
||||
def _parse_srcinfo(self, srcinfo: str) -> PackageInfo:
|
||||
pkgbase: str | None = None
|
||||
pkgver: str | None = None
|
||||
pkgrel: str | None = None
|
||||
epoch: str | None = None
|
||||
provides: list[str] = []
|
||||
|
||||
# I'm not sure if split packages can have dependencies listed in the base.
|
||||
# Easy to handle regardless
|
||||
base_depends: list[str] = []
|
||||
base_makedepends: list[str] = []
|
||||
base_checkdepends: list[str] = []
|
||||
|
||||
pkg_depends: list[str] = []
|
||||
pkg_makedepends: list[str] = []
|
||||
pkg_checkdepends: list[str] = []
|
||||
|
||||
current_pkg: str | None = None
|
||||
found_pkgnames = set()
|
||||
|
||||
for raw in srcinfo.splitlines():
|
||||
line = raw.strip()
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
|
||||
key, value = (part.strip() for part in line.split("=", 1))
|
||||
|
||||
is_base = current_pkg is None
|
||||
is_target_pkg = current_pkg == self.pkgname
|
||||
|
||||
match key:
|
||||
case "pkgbase":
|
||||
pkgbase = value
|
||||
current_pkg = None
|
||||
|
||||
case "pkgname":
|
||||
current_pkg = value
|
||||
found_pkgnames.add(value)
|
||||
|
||||
case "pkgver":
|
||||
if pkgver is None or current_pkg == self.pkgname:
|
||||
pkgver = value
|
||||
|
||||
case "pkgrel":
|
||||
if pkgrel is None or current_pkg == self.pkgname:
|
||||
pkgrel = value
|
||||
|
||||
case "epoch":
|
||||
if epoch is None or current_pkg == self.pkgname:
|
||||
epoch = value
|
||||
|
||||
case "provides":
|
||||
if is_target_pkg:
|
||||
provides.append(value)
|
||||
|
||||
case "depends":
|
||||
if is_base:
|
||||
base_depends.append(value)
|
||||
elif is_target_pkg:
|
||||
pkg_depends.append(value)
|
||||
|
||||
case "makedepends":
|
||||
if is_base:
|
||||
base_makedepends.append(value)
|
||||
elif is_target_pkg:
|
||||
pkg_makedepends.append(value)
|
||||
|
||||
case "checkdepends":
|
||||
if is_base:
|
||||
base_checkdepends.append(value)
|
||||
elif is_target_pkg:
|
||||
pkg_checkdepends.append(value)
|
||||
|
||||
case _ if key.startswith("depends") and key.removeprefix("depends_") == config.arch:
|
||||
if is_base:
|
||||
base_depends.append(value)
|
||||
elif is_target_pkg:
|
||||
pkg_depends.append(value)
|
||||
|
||||
case _ if (
|
||||
key.startswith("makedepends")
|
||||
and key.removeprefix("makedepends_") == config.arch
|
||||
):
|
||||
if is_base:
|
||||
base_makedepends.append(value)
|
||||
elif is_target_pkg:
|
||||
pkg_makedepends.append(value)
|
||||
|
||||
case _ if (
|
||||
key.startswith("checkdepends")
|
||||
and key.removeprefix("checkdepends_") == config.arch
|
||||
):
|
||||
if is_base:
|
||||
base_checkdepends.append(value)
|
||||
elif is_target_pkg:
|
||||
pkg_checkdepends.append(value)
|
||||
|
||||
if pkgbase is None or pkgver is None:
|
||||
raise PKGBUILDParseError(
|
||||
self.git_url,
|
||||
self.pkgbuild_directory,
|
||||
"Missing required fields (pkgbase/pkgver) in SRCINFO.",
|
||||
)
|
||||
|
||||
if self.pkgname not in found_pkgnames:
|
||||
raise PKGBUILDParseError(
|
||||
self.git_url,
|
||||
self.pkgbuild_directory,
|
||||
f"Package {self.pkgname} not found in SRCINFO.\
|
||||
Packages present: {' '.join(found_pkgnames)}.",
|
||||
)
|
||||
|
||||
version_core = pkgver
|
||||
if pkgrel is not None:
|
||||
version_core = f"{version_core}-{pkgrel}"
|
||||
|
||||
if epoch is not None:
|
||||
version = f"{epoch}:{version_core}"
|
||||
else:
|
||||
version = version_core
|
||||
|
||||
return PackageInfo(
|
||||
pkgname=self.pkgname,
|
||||
pkgbase=pkgbase,
|
||||
version=version,
|
||||
git_url=self.git_url,
|
||||
pkgbuild_directory=self.pkgbuild_directory,
|
||||
provides=tuple(provides),
|
||||
dependencies=tuple(base_depends + pkg_depends),
|
||||
make_dependencies=tuple(base_makedepends + pkg_makedepends),
|
||||
check_dependencies=tuple(base_checkdepends + pkg_checkdepends),
|
||||
)
|
||||
|
||||
|
||||
class PackageSearch:
|
||||
|
||||
+246
-3
@@ -1,8 +1,9 @@
|
||||
import pathlib
|
||||
|
||||
import pytest
|
||||
|
||||
from decman.plugins.pacman import package as pkg_mod
|
||||
from decman.plugins.pacman.error import AurRPCError
|
||||
from decman.plugins.pacman.error import AurRPCError, PKGBUILDParseError
|
||||
from decman.plugins.pacman.package import (
|
||||
CustomPackage,
|
||||
PackageInfo,
|
||||
@@ -102,10 +103,252 @@ def test_packageinfo_foreign_and_native_dependencies_are_split_and_stripped():
|
||||
|
||||
def test_custompackage_requires_exactly_one_source():
|
||||
with pytest.raises(ValueError, match="cannot be None"):
|
||||
CustomPackage(git_url=None, pkgbuild_directory=None)
|
||||
CustomPackage("pkg", git_url=None, pkgbuild_directory=None)
|
||||
|
||||
with pytest.raises(ValueError, match="cannot be set"):
|
||||
CustomPackage(git_url="git://example", pkgbuild_directory="/tmp")
|
||||
CustomPackage("pkg", git_url="git://example", pkgbuild_directory="/tmp")
|
||||
|
||||
|
||||
class DummyCommands:
|
||||
"""Minimal stub; only here so type checks pass where needed."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"srcinfo, expected_version",
|
||||
[
|
||||
(
|
||||
"""
|
||||
pkgbase = foo
|
||||
pkgver = 1.2.3
|
||||
pkgrel = 4
|
||||
pkgname = foo
|
||||
""",
|
||||
"1.2.3-4",
|
||||
),
|
||||
(
|
||||
"""
|
||||
pkgbase = foo
|
||||
pkgver = 1.2.3
|
||||
pkgrel = 4
|
||||
epoch = 2
|
||||
pkgname = foo
|
||||
""",
|
||||
"2:1.2.3-4",
|
||||
),
|
||||
(
|
||||
"""
|
||||
pkgbase = foo
|
||||
pkgver = 1.2.3
|
||||
pkgname = foo
|
||||
""",
|
||||
"1.2.3",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_parse_srcinfo_version_handling(srcinfo: str, expected_version: str) -> None:
|
||||
pkg = CustomPackage(pkgname="foo", git_url=None, pkgbuild_directory="/dummy")
|
||||
|
||||
info = pkg._parse_srcinfo(srcinfo)
|
||||
|
||||
assert info.pkgname == "foo"
|
||||
assert info.pkgbase == "foo"
|
||||
assert info.version == expected_version
|
||||
|
||||
|
||||
def test_parse_srcinfo_single_package_dependencies() -> None:
|
||||
srcinfo = """
|
||||
pkgbase = foo
|
||||
pkgver = 1.2.3
|
||||
pkgrel = 1
|
||||
depends = bar>=1.0
|
||||
makedepends = baz
|
||||
checkdepends = qux
|
||||
|
||||
pkgname = foo
|
||||
"""
|
||||
|
||||
pkg = CustomPackage(pkgname="foo", git_url=None, pkgbuild_directory="/dummy")
|
||||
|
||||
info = pkg._parse_srcinfo(srcinfo)
|
||||
|
||||
assert info.dependencies == ("bar>=1.0",)
|
||||
assert info.make_dependencies == ("baz",)
|
||||
assert info.check_dependencies == ("qux",)
|
||||
|
||||
|
||||
def test_parse_srcinfo_split_package_uses_only_target_pkg_dependencies(monkeypatch) -> None:
|
||||
# Ensure arch-specific keys match
|
||||
monkeypatch.setattr(pkg_mod.config, "arch", "x86_64", raising=False)
|
||||
|
||||
srcinfo = """
|
||||
pkgbase = clion
|
||||
pkgver = 2025.3
|
||||
pkgrel = 1
|
||||
makedepends = rsync
|
||||
depends = base-dep
|
||||
depends_x86_64 = base-arch-dep
|
||||
|
||||
pkgname = clion
|
||||
depends = libdbusmenu-glib
|
||||
depends_x86_64 = clion-arch-dep
|
||||
checkdepends = clion-check
|
||||
|
||||
pkgname = clion-jre
|
||||
depends = jre-dep
|
||||
makedepends = jre-make
|
||||
|
||||
pkgname = clion-cmake
|
||||
depends = cmake-dep
|
||||
"""
|
||||
|
||||
pkg = CustomPackage(pkgname="clion", git_url=None, pkgbuild_directory="/dummy")
|
||||
|
||||
info = pkg._parse_srcinfo(srcinfo)
|
||||
|
||||
# version
|
||||
assert info.pkgbase == "clion"
|
||||
assert info.version == "2025.3-1"
|
||||
|
||||
# base deps + target pkg deps (including arch-specific)
|
||||
assert info.dependencies == (
|
||||
"base-dep",
|
||||
"base-arch-dep",
|
||||
"libdbusmenu-glib",
|
||||
"clion-arch-dep",
|
||||
)
|
||||
|
||||
# only base and target pkg makedepends
|
||||
assert info.make_dependencies == ("rsync",)
|
||||
|
||||
# base + target pkg checkdepends
|
||||
assert info.check_dependencies == ("clion-check",)
|
||||
|
||||
|
||||
def test_parse_srcinfo_arch_specific_ignored_for_other_arch(monkeypatch) -> None:
|
||||
# Different arch → *_x86_64 keys should be ignored
|
||||
monkeypatch.setattr(pkg_mod.config, "arch", "aarch64", raising=False)
|
||||
|
||||
srcinfo = """
|
||||
pkgbase = foo
|
||||
pkgver = 1.0
|
||||
pkgrel = 1
|
||||
depends_x86_64 = base-arch-dep
|
||||
|
||||
pkgname = foo
|
||||
depends = common-dep
|
||||
depends_x86_64 = pkg-arch-dep
|
||||
"""
|
||||
|
||||
pkg = CustomPackage(pkgname="foo", git_url=None, pkgbuild_directory="/dummy")
|
||||
|
||||
info = pkg._parse_srcinfo(srcinfo)
|
||||
|
||||
# Only common deps, no *_x86_64 because arch != x86_64
|
||||
assert info.dependencies == ("common-dep",)
|
||||
|
||||
|
||||
def test_parse_srcinfo_missing_required_fields_raises() -> None:
|
||||
# Missing pkgbase
|
||||
srcinfo_no_pkgbase = """
|
||||
pkgver = 1.0
|
||||
pkgrel = 1
|
||||
pkgname = foo
|
||||
"""
|
||||
pkg = CustomPackage(pkgname="foo", git_url=None, pkgbuild_directory="/dummy")
|
||||
|
||||
with pytest.raises(PKGBUILDParseError) as excinfo:
|
||||
pkg._parse_srcinfo(srcinfo_no_pkgbase)
|
||||
assert "pkgbase/pkgver" in str(excinfo.value)
|
||||
|
||||
# Missing pkgver
|
||||
srcinfo_no_pkgver = """
|
||||
pkgbase = foo
|
||||
pkgname = foo
|
||||
"""
|
||||
|
||||
with pytest.raises(PKGBUILDParseError) as excinfo2:
|
||||
pkg._parse_srcinfo(srcinfo_no_pkgver)
|
||||
assert "pkgbase/pkgver" in str(excinfo2.value)
|
||||
|
||||
|
||||
def test_parse_srcinfo_missing_target_pkg_raises() -> None:
|
||||
srcinfo = """
|
||||
pkgbase = foo
|
||||
pkgver = 1.0
|
||||
pkgrel = 1
|
||||
pkgname = other
|
||||
"""
|
||||
|
||||
pkg = CustomPackage(pkgname="foo", git_url=None, pkgbuild_directory="/dummy")
|
||||
|
||||
with pytest.raises(PKGBUILDParseError) as excinfo:
|
||||
pkg._parse_srcinfo(srcinfo)
|
||||
|
||||
msg = str(excinfo.value)
|
||||
assert "Package foo not found in SRCINFO" in msg
|
||||
assert "other" in msg # listed in present packages
|
||||
|
||||
|
||||
def test_srcinfo_from_pkgbuild_directory_missing_dir_raises(tmp_path: pathlib.Path) -> None:
|
||||
missing = tmp_path / "does-not-exist"
|
||||
|
||||
pkg = CustomPackage(pkgname="foo", git_url=None, pkgbuild_directory=str(missing))
|
||||
|
||||
with pytest.raises(PKGBUILDParseError) as excinfo:
|
||||
pkg._srcinfo_from_pkgbuild_directory(DummyCommands())
|
||||
|
||||
msg = str(excinfo.value)
|
||||
assert "does not exist or is not a directory" in msg
|
||||
|
||||
|
||||
def test_srcinfo_from_pkgbuild_directory_missing_pkgbuild_raises(tmp_path: pathlib.Path) -> None:
|
||||
path = tmp_path / "pkgdir"
|
||||
path.mkdir()
|
||||
|
||||
pkg = CustomPackage(pkgname="foo", git_url=None, pkgbuild_directory=str(path))
|
||||
|
||||
with pytest.raises(PKGBUILDParseError) as excinfo:
|
||||
pkg._srcinfo_from_pkgbuild_directory(DummyCommands())
|
||||
|
||||
msg = str(excinfo.value)
|
||||
assert "No PKGBUILD found" in msg
|
||||
|
||||
|
||||
def test_custom_package_equality_and_hash() -> None:
|
||||
a1 = CustomPackage(
|
||||
pkgname="foo", git_url="https://example.com/repo.git", pkgbuild_directory=None
|
||||
)
|
||||
a2 = CustomPackage(
|
||||
pkgname="foo", git_url="https://example.com/repo.git", pkgbuild_directory=None
|
||||
)
|
||||
b = CustomPackage(pkgname="foo", git_url=None, pkgbuild_directory="/some/path")
|
||||
|
||||
assert a1 == a2
|
||||
assert hash(a1) == hash(a2)
|
||||
|
||||
assert a1 != b
|
||||
assert hash(a1) != hash(b)
|
||||
|
||||
|
||||
def test_custom_package_str_git_and_directory() -> None:
|
||||
git_pkg = CustomPackage(
|
||||
pkgname="foo",
|
||||
git_url="https://example.com/repo.git",
|
||||
pkgbuild_directory=None,
|
||||
)
|
||||
dir_pkg = CustomPackage(
|
||||
pkgname="foo",
|
||||
git_url=None,
|
||||
pkgbuild_directory="/some/path",
|
||||
)
|
||||
|
||||
assert "pkgname=foo" in str(git_pkg)
|
||||
assert "git_url=https://example.com/repo.git" in str(git_pkg)
|
||||
|
||||
assert "pkgname=foo" in str(dir_pkg)
|
||||
assert "pkgbuild_directory=/some/path" in str(dir_pkg)
|
||||
|
||||
|
||||
# --- PackageSearch: caching ------------------------------------------------
|
||||
Reference in New Issue
Block a user