Add source config

Config manages:

- Packages
- Systemd units
This commit is contained in:
Kivi Kaitaniemi
2024-04-25 16:00:00 +03:00
parent 42c060ba35
commit ebed2cbbee
5 changed files with 270 additions and 3 deletions
+37
View File
@@ -1,3 +1,40 @@
"""
Module for writing system configurations for decman.
"""
import typing
class UserPackage:
"""
Defines a custom package.
"""
def __init__(
self,
pkgname: str,
version: str,
dependencies: list[str],
git_url: str,
pkgbase: typing.Optional[str] = None,
provides: typing.Optional[list[str]] = None,
make_dependencies: typing.Optional[list[str]] = None,
check_dependencies: typing.Optional[list[str]] = None,
):
if pkgbase is None:
pkgbase = pkgname
if provides is None:
provides = []
if make_dependencies is None:
make_dependencies = []
if check_dependencies is None:
check_dependencies = []
self.pkgname = pkgname
self.pkgbase = pkgbase
self.version = version
self.provides = provides
self.dependencies = dependencies
self.make_dependencies = make_dependencies
self.check_dependencies = check_dependencies
self.git_url = git_url
+107
View File
@@ -8,6 +8,7 @@ import json
import os
import typing
import decman.config as conf
import decman
_DECMAN_MSG_TAG = "[\033[1;35mDECMAN\033[m]"
_RED_PREFIX = "\033[91m"
@@ -220,6 +221,112 @@ class UserFacingError(Exception):
self.user_facing_msg = user_facing_msg
class Source:
"""
Configuration that describes a system.
"""
def __init__(self, pacman_packages: list[str], aur_packages: list[str],
user_packages: list[decman.UserPackage],
ignored_packages: list[str], systemd_units: list[str],
systemd_user_units: dict[str, list[str]]):
self.pacman_packages = pacman_packages
self.aur_packages = aur_packages
self.user_packages = user_packages
self.ignored_packages = ignored_packages
self.systemd_units = systemd_units
self.systemd_user_units = systemd_user_units
def units_to_enable(self, store: Store) -> list[str]:
"""
Returns all systemd units that should be enabled.
"""
result = []
for unit in self.systemd_units:
if unit not in store.enabled_systemd_units:
result.append(unit)
return result
def units_to_disable(self, store: Store) -> list[str]:
"""
Returns all systemd units that should be disabled.
"""
result = []
for unit in store.enabled_systemd_units:
if unit not in self.systemd_units:
result.append(unit)
return result
def user_units_to_enable(self, store: Store) -> dict[str, list[str]]:
"""
Returns all user systemd units that should be enabled.
"""
result = {}
for user, units in self.systemd_user_units.items():
for unit in units:
stored = f"{user}: {unit}"
if stored not in store.enabled_user_systemd_units:
entry = result.get(user, [])
entry.append(unit)
result[user] = entry
return result
def user_units_to_disable(self, store: Store) -> dict[str, list[str]]:
"""
Returns all user systemd units that should be disabled.
"""
result = {}
for stored in store.enabled_user_systemd_units:
s = stored.split(": ")
user = s[0]
unit = s[1]
if unit not in self.systemd_user_units.get(user, []):
entry = result.get(user, [])
entry.append(unit)
result[user] = entry
return result
def packages_to_remove(
self, currently_installed_packages: list[str]) -> list[str]:
"""
Returns all packages that should be removed. This includes pacman, aur and user packages.
"""
result = []
all_pkgs = self.pacman_packages + self.aur_packages + list(
map(lambda p: p.pkgname, self.user_packages))
for pkg in currently_installed_packages:
if pkg not in all_pkgs and pkg not in self.ignored_packages:
result.append(pkg)
return result
def pacman_packages_to_install(
self, currently_installed_packages: list[str]) -> list[str]:
"""
Returns all pacman packages that should be installed.
"""
result = []
for pkg in self.pacman_packages:
if pkg not in currently_installed_packages and pkg not in self.ignored_packages:
result.append(pkg)
return result
def foreign_packages_to_install(
self, currently_installed_packages: list[str]) -> list[str]:
"""
Returns all aur and user packages that should be installed.
"""
result = []
for pkg in self.aur_packages:
if pkg not in currently_installed_packages and pkg not in self.ignored_packages:
result.append(pkg)
for pkg in self.user_packages:
if pkg.pkgname not in currently_installed_packages and pkg.pkgname not in self.ignored_packages:
result.append(pkg.pkgname)
return result
class Pacman:
"""
Interface for interacting with pacman.
+29 -1
View File
@@ -19,6 +19,7 @@ import typing
import requests
import decman
import decman.config as conf
import decman.lib as l
@@ -100,6 +101,24 @@ class PackageInfo:
"""
return f"{self.pkgname}-{self.version}"
@staticmethod
def from_user_package(user_package: decman.UserPackage,
pacman: l.Pacman) -> "PackageInfo":
"""
Converts a UserPackage to PackageInfo
"""
return PackageInfo(
pkgname=user_package.pkgname,
pkgbase=user_package.pkgbase,
version=user_package.version,
provides=user_package.provides,
dependencies=user_package.dependencies,
make_dependencies=user_package.make_dependencies,
check_dependencies=user_package.check_dependencies,
git_url=user_package.git_url,
pacman=pacman,
)
class ForeignPackage:
"""
@@ -521,10 +540,16 @@ class ForeignPackageManager:
self._pacman = pacman
self._search = search
def upgrade(self, upgrade_devel: bool = False, force: bool = False):
def upgrade(self,
upgrade_devel: bool = False,
force: bool = False,
ignored_pkgs: typing.Optional[list[str]] = None):
"""
Upgrades all foreign packages.
"""
if ignored_pkgs is None:
ignored_pkgs = []
l.print_summary("Determining packages to upgrade.")
all_foreign_pkgs = self._pacman.get_versioned_foreign_packages()
@@ -538,6 +563,9 @@ class ForeignPackageManager:
as_explicit = []
as_deps = []
for pkg, ver in all_foreign_pkgs:
if pkg in ignored_pkgs:
continue
info = self._search.get_package_info(pkg)
if info is None:
raise l.UserFacingError(f"Failed to find package: {pkg}.")
+2 -2
View File
@@ -5,9 +5,9 @@ from decman.lib import UserFacingError, Pacman, Store
from decman.lib.aur import ForeignPackageManager, DepGraph, ForeignPackage, ExtendedPackageSearch
class TestAUR(unittest.TestCase):
class TestVersionComparisons(unittest.TestCase):
def setUp(self) -> None:
def setUp(self):
pacman = Pacman()
self.aur = ForeignPackageManager(Store(), pacman,
ExtendedPackageSearch(pacman))
+95
View File
@@ -0,0 +1,95 @@
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
import unittest
from decman.lib import Source, Store
from decman import UserPackage
class TestSource(unittest.TestCase):
def setUp(self):
source = Source(
pacman_packages=["p1", "p2", "p3"],
aur_packages=["A1", "A2", "A3"],
user_packages=[
UserPackage(
pkgname="U1",
version="1",
dependencies=["d1"],
git_url="/am/url/yes",
),
UserPackage(
pkgname="U2",
version="1",
dependencies=["d2"],
git_url="/am/url/yes",
)
],
ignored_packages=["i1", "i2"],
systemd_units=["1.service", "2.timer"],
systemd_user_units={"user": ["u1.service", "u2.timer"]},
)
store = Store()
store.enabled_systemd_units.extend(["1.service", "3.service"])
store.enabled_user_systemd_units.extend(
["user: u1.service", "user: u3.service"])
currently_installed_packages = [
"p1",
"p2",
"p4",
"A2",
"A3",
"A4",
"U1",
"i1",
]
self.source = source
self.store = store
self.currently_installed_packages = currently_installed_packages
def test_units_to_enable(self):
self.assertCountEqual(
self.source.units_to_enable(self.store),
["2.timer"],
)
def test_units_to_disable(self):
self.assertCountEqual(
self.source.units_to_disable(self.store),
["3.service"],
)
def test_user_units_to_enable(self):
self.assertDictEqual(
self.source.user_units_to_enable(self.store),
{"user": ["u2.timer"]},
)
def test_user_units_to_disable(self):
self.assertDictEqual(
self.source.user_units_to_disable(self.store),
{"user": ["u3.service"]},
)
def test_pacman_packages_to_install(self):
self.assertCountEqual(
self.source.pacman_packages_to_install(
self.currently_installed_packages),
["p3"],
)
def test_foreign_packages_to_install(self):
self.assertCountEqual(
self.source.foreign_packages_to_install(
self.currently_installed_packages),
["A1", "U2"],
)
def test_packages_to_remove(self):
self.assertCountEqual(
self.source.packages_to_remove(self.currently_installed_packages),
["p4", "A4"],
)