mirror of
https://github.com/kiviktnm/decman.git
synced 2026-09-19 12:08:28 +00:00
Add source config
Config manages: - Packages - Systemd units
This commit is contained in:
@@ -1,3 +1,40 @@
|
|||||||
"""
|
"""
|
||||||
Module for writing system configurations for decman.
|
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
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import typing
|
import typing
|
||||||
import decman.config as conf
|
import decman.config as conf
|
||||||
|
import decman
|
||||||
|
|
||||||
_DECMAN_MSG_TAG = "[\033[1;35mDECMAN\033[m]"
|
_DECMAN_MSG_TAG = "[\033[1;35mDECMAN\033[m]"
|
||||||
_RED_PREFIX = "\033[91m"
|
_RED_PREFIX = "\033[91m"
|
||||||
@@ -220,6 +221,112 @@ class UserFacingError(Exception):
|
|||||||
self.user_facing_msg = user_facing_msg
|
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:
|
class Pacman:
|
||||||
"""
|
"""
|
||||||
Interface for interacting with pacman.
|
Interface for interacting with pacman.
|
||||||
|
|||||||
+29
-1
@@ -19,6 +19,7 @@ import typing
|
|||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
import decman
|
||||||
import decman.config as conf
|
import decman.config as conf
|
||||||
import decman.lib as l
|
import decman.lib as l
|
||||||
|
|
||||||
@@ -100,6 +101,24 @@ class PackageInfo:
|
|||||||
"""
|
"""
|
||||||
return f"{self.pkgname}-{self.version}"
|
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:
|
class ForeignPackage:
|
||||||
"""
|
"""
|
||||||
@@ -521,10 +540,16 @@ class ForeignPackageManager:
|
|||||||
self._pacman = pacman
|
self._pacman = pacman
|
||||||
self._search = search
|
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.
|
Upgrades all foreign packages.
|
||||||
"""
|
"""
|
||||||
|
if ignored_pkgs is None:
|
||||||
|
ignored_pkgs = []
|
||||||
|
|
||||||
l.print_summary("Determining packages to upgrade.")
|
l.print_summary("Determining packages to upgrade.")
|
||||||
|
|
||||||
all_foreign_pkgs = self._pacman.get_versioned_foreign_packages()
|
all_foreign_pkgs = self._pacman.get_versioned_foreign_packages()
|
||||||
@@ -538,6 +563,9 @@ class ForeignPackageManager:
|
|||||||
as_explicit = []
|
as_explicit = []
|
||||||
as_deps = []
|
as_deps = []
|
||||||
for pkg, ver in all_foreign_pkgs:
|
for pkg, ver in all_foreign_pkgs:
|
||||||
|
if pkg in ignored_pkgs:
|
||||||
|
continue
|
||||||
|
|
||||||
info = self._search.get_package_info(pkg)
|
info = self._search.get_package_info(pkg)
|
||||||
if info is None:
|
if info is None:
|
||||||
raise l.UserFacingError(f"Failed to find package: {pkg}.")
|
raise l.UserFacingError(f"Failed to find package: {pkg}.")
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ from decman.lib import UserFacingError, Pacman, Store
|
|||||||
from decman.lib.aur import ForeignPackageManager, DepGraph, ForeignPackage, ExtendedPackageSearch
|
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()
|
pacman = Pacman()
|
||||||
self.aur = ForeignPackageManager(Store(), pacman,
|
self.aur = ForeignPackageManager(Store(), pacman,
|
||||||
ExtendedPackageSearch(pacman))
|
ExtendedPackageSearch(pacman))
|
||||||
|
|||||||
@@ -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"],
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user