Merge pull request #41 from kiviktnm/split-packages

Split plugins to seperate packages
This commit is contained in:
Kivi Kaitaniemi
2025-12-27 04:01:02 +02:00
committed by GitHub
23 changed files with 223 additions and 90 deletions
+15 -3
View File
@@ -7,15 +7,27 @@ Before committing ensure all tests pass and format files.
Run decman as root to test all changes:
```sh
sudo uv run decman
sudo uv run --all-packages decman
```
## Python shell
Running a python shell with all the packages.
```sh
sudo uv run --all-packages python
sudo uv run --exact --package decman python
```
## Testing
Run all unit tests (`-s` disables output capturing):
Run all unit tests (`-s` disables output capturing, needed for PTY test):
```sh
uv run pytest -s
uv run --package decman pytest -s tests/
uv run --package decman-pacman pytest packages/decman-pacman/tests/
uv run --package decman-systemd pytest packages/decman-systemd/tests/
uv run --package decman-flatpak pytest packages/decman-flatpak/tests/
```
## Formatting
+4 -4
View File
@@ -391,7 +391,7 @@ Create your own modules by subclassing `Plugin`. Then override the methods docum
from decman.plugins import Plugin
class MyPlugin(Plugin):
# Plugins should be singletons.
# Plugins should be singletons. (Only one instance exists ever.)
# This name should be the same as the key used in decman.plugins dict.
NAME = "my-plugin"
```
@@ -454,10 +454,8 @@ In `pyproject.toml` set:
```toml
[project.entry-points."decman.plugins"]
systemd = "decman.plugins.systemd:Systemd"
pacman = "decman.plugins.pacman:Pacman"
aur = "decman.plugins.aur:AUR"
flatpak = "decman.plugins.flatpak:Flatpak"
```
## Useful utilities
@@ -474,6 +472,7 @@ decman.prg(
["nvim", "--headless", "+Lazy! sync", "+qa"],
user = "user",
env_overrides = {"EXAMPLE": "value"},
pass_environment = True,
mimic_login = True,
pty = True,
check = True,
@@ -484,7 +483,8 @@ decman.prg(
- `cmd: list[str]`: Command to execute.
- `user: str`: User name to run the command as. If set, the command is executed after dropping privileges to this user.
- `env_overrides dict[str, str]`: Environment variables to override or add for the command execution. These values are merged on top of the current process environment.
- `pass_environment: bool`: Copy decman's execution environment variables and pass them to the subprocess.
- `env_overrides: dict[str, str]`: Environment variables to override or add for the command execution. These values are merged on top of the current process environment.
- `mimic_login: bool`: If mimic_login is True, will set the following environment variables according to the given user's passwd file details. This only happens when user is set.
- `HOME`
- `USER`
+3 -23
View File
@@ -6,7 +6,8 @@ I recommend reading decman's new documentation. This document is supposed to be
This change is mostly architectural and doesn't change decman's behavior, but there are a few exceptions.
- The pacman plugin will now remove orphan packages
- The pacman plugin will now remove orphan packages.
- **Packages that are only optionally required by other packages are considered orphans.**
- Explicitly installed packages that are required by other explicitly installed packages are no longer uninstalled when removed from the source.
- Module's `on_disable` will now be executed when the module is no longer present in `decman.modules`.
- It will be executed even when the module is removed completely from the source
@@ -596,7 +597,7 @@ class MyCommands(decman.config.Commands):
#### New
AUR and pacman commands are a seperate setting, but they share the same subclass, so it's possible to set them in a one place. New commands have also been added but it is better to look at the plugin documentation for those options. Notable changes are: `list_pkgs` have been split to `list_explicit_native` and `list_explicit_foreign`.
AUR and pacman commands are a seperate setting, but they share the same subclass, so it's possible to set them in a one place. Many pacman query commands have been deleted since pyalpm is used now. New commands have also been added but it is better to look at the plugin documentation for those options.
These values are the new defaults.
@@ -608,18 +609,6 @@ decman.aur.commands = MyAurAndPacmanCommands()
decman.pacman.commands = MyAurAndPacmanCommands()
class MyAurAndPacmanCommands(aur.AurCommands):
def list_explicit_native(self) -> list[str]:
return ["pacman", "-Qeqn", "--color=never"]
def list_explicit_foreign(self) -> list[str]:
return ["pacman", "-Qeqm", "--color=never"]
def list_orphans_native(self) -> list[str]:
return ["pacman", "-Qndtq", "--color=never"]
def list_dependants(self, pkg: str) -> list[str]:
return ["pacman", "-Rc", "--print", "--print-format", "%n", pkg]
def install(self, pkgs: set[str]) -> list[str]:
return ["pacman", "-S", "--needed"] + list(pkgs)
@@ -635,15 +624,6 @@ class MyAurAndPacmanCommands(aur.AurCommands):
def remove(self, pkgs: set[str]) -> list[str]:
return ["pacman", "-Rs"] + list(pkgs)
def list_orphans_foreign(self) -> list[str]:
return ["pacman", "-Qmdtq", "--color=never"]
def list_foreign_versioned(self) -> list[str]:
return ["pacman", "-Qm", "--color=never"]
def is_installable(self, pkg: str) -> list[str]:
return ["pacman", "-Sddp", pkg]
def install_as_dependencies(self, pkgs: set[str]) -> list[str]:
return ["pacman", "-S", "--needed", "--asdeps"] + list(pkgs)
+20
View File
@@ -0,0 +1,20 @@
[project]
name = "decman-flatpak"
version = "1.0.0"
requires-python = ">=3.13"
dependencies = ["decman==1.0.0"]
[project.entry-points."decman.plugins"]
flatpak = "decman.plugins.flatpak:Flatpak"
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[tool.setuptools.packages.find]
where = ["src"]
namespaces = true
include = ["decman.plugins*"]
[tool.pytest.ini_options]
testpaths = ["tests"]
+25
View File
@@ -0,0 +1,25 @@
[project]
name = "decman-pacman"
version = "1.0.0"
requires-python = ">=3.13"
dependencies = [
"decman==1.0.0",
"pyalpm",
"requests",
]
[project.entry-points."decman.plugins"]
pacman = "decman.plugins.pacman:Pacman"
aur = "decman.plugins.aur:AUR"
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[tool.setuptools.packages.find]
where = ["src"]
namespaces = true
include = ["decman.plugins*"]
[tool.pytest.ini_options]
testpaths = ["tests"]
@@ -2,13 +2,6 @@ import os
import shutil
import pyalpm
import decman.config as config
import decman.core.error as errors
import decman.core.module as module
import decman.core.output as output
import decman.core.store as _store
import decman.plugins as plugins
from decman.plugins.aur.commands import AurCommands, AurPacmanInterface
from decman.plugins.aur.error import (
AurRPCError,
@@ -19,6 +12,13 @@ from decman.plugins.aur.error import (
from decman.plugins.aur.fpm import ForeignPackageManager
from decman.plugins.aur.package import CustomPackage, PackageSearch
import decman.config as config
import decman.core.error as errors
import decman.core.module as module
import decman.core.output as output
import decman.core.store as _store
import decman.plugins as plugins
# Re-exports
__all__ = [
"AUR",
@@ -1,8 +1,8 @@
import decman.plugins.pacman as pacman
import pyalpm
import decman.config as config
import decman.core.command as command
import decman.plugins.pacman as pacman
class AurCommands(pacman.PacmanCommands):
@@ -3,15 +3,16 @@ import shutil
import time
import typing
from decman.plugins.aur.commands import AurCommands
from decman.plugins.aur.error import ForeignPackageManagerError
from decman.plugins.aur.package import AurPacmanInterface, PackageSearch
from decman.plugins.aur.resolver import DepGraph, ForeignPackage
import decman.config as config
import decman.core.command as command
import decman.core.error as errors
import decman.core.output as output
import decman.core.store as _store
from decman.plugins.aur.commands import AurCommands
from decman.plugins.aur.error import ForeignPackageManagerError
from decman.plugins.aur.package import AurPacmanInterface, PackageSearch
from decman.plugins.aur.resolver import DepGraph, ForeignPackage
def find_latest_cached_package(store: _store.Store, package: str) -> tuple[str, str] | None:
@@ -4,15 +4,15 @@ import pathlib
import shutil
import tempfile
import decman.plugins.pacman as pacman_module
import requests # type: ignore
from decman.plugins.aur.commands import AurCommands, AurPacmanInterface
from decman.plugins.aur.error import AurRPCError, PKGBUILDParseError
import decman.config as config
import decman.core.command as command
import decman.core.error as errors
import decman.core.output as output
import decman.plugins.pacman as pacman_module
from decman.plugins.aur.commands import AurCommands, AurPacmanInterface
from decman.plugins.aur.error import AurRPCError, PKGBUILDParseError
@dataclasses.dataclass(frozen=True, slots=True)
@@ -1,7 +1,6 @@
import pathlib
import pytest
from decman.plugins.aur import package as pkg_mod
from decman.plugins.aur.error import AurRPCError, PKGBUILDParseError
from decman.plugins.aur.package import (
@@ -1,5 +1,4 @@
import pytest
from decman.plugins.aur.error import DependencyCycleError
from decman.plugins.aur.resolver import DepGraph, ForeignPackage
+20
View File
@@ -0,0 +1,20 @@
[project]
name = "decman-systemd"
version = "1.0.0"
requires-python = ">=3.13"
dependencies = ["decman==1.0.0"]
[project.entry-points."decman.plugins"]
systemd = "decman.plugins.systemd:Systemd"
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[tool.setuptools.packages.find]
where = ["src"]
namespaces = true
include = ["decman.plugins*"]
[tool.pytest.ini_options]
testpaths = ["tests"]
+21 -10
View File
@@ -7,20 +7,15 @@ authors = [
{name = "Kivi Kaitaniemi"}
]
requires-python = ">=3.13"
dependencies = [
"requests",
"pyalpm",
]
[project.optional-dependencies]
pacman = ["decman-pacman"]
systemd = ["decman-systemd"]
flatpak = ["decman-flatpak"]
[project.scripts]
decman = "decman.app:main"
[project.entry-points."decman.plugins"]
systemd = "decman.plugins.systemd:Systemd"
pacman = "decman.plugins.pacman:Pacman"
aur = "decman.plugins.aur:AUR"
flatpak = "decman.plugins.flatpak:Flatpak"
[dependency-groups]
dev = [
"ruff>=0.14.9",
@@ -31,6 +26,22 @@ dev = [
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[tool.uv.workspace]
members = [
"packages/decman-pacman",
"packages/decman-systemd",
"packages/decman-flatpak",
]
[tool.uv.sources]
decman = { workspace = true }
decman-pacman = { workspace = true }
decman-systemd = { workspace = true }
decman-flatpak = { workspace = true }
[tool.pytest.ini_options]
testpaths = ["tests"]
[tool.ruff]
line-length = 100
target-version = "py313"
+38 -28
View File
@@ -8,11 +8,44 @@ from decman.core.module import Module
from decman.core.store import Store
from decman.plugins import Plugin, available_plugins
# Plugin types
from decman.plugins.aur import AUR
from decman.plugins.flatpak import Flatpak
from decman.plugins.pacman import Pacman
from decman.plugins.systemd import Systemd
plugins: dict[str, Plugin] = available_plugins()
# Quick access for default plugins
try:
from decman.plugins.aur import AUR
from decman.plugins.pacman import Pacman
pacman: None | Pacman = None
_pacman = plugins.get("pacman", None)
if isinstance(_pacman, Pacman):
pacman = _pacman
aur: None | AUR = None
_aur = plugins.get("aur", None)
if isinstance(_aur, AUR):
aur = _aur
except ModuleNotFoundError:
pass
try:
from decman.plugins.flatpak import Flatpak
flatpak: None | Flatpak = None
_flatpak = plugins.get("flatpak", None)
if isinstance(_flatpak, Flatpak):
flatpak = _flatpak
except ModuleNotFoundError:
pass
try:
from decman.plugins.systemd import Systemd
systemd: None | Systemd = None
_systemd = plugins.get("systemd", None)
if isinstance(_systemd, Systemd):
systemd = _systemd
except ModuleNotFoundError:
pass
__all__ = [
"SourceError",
@@ -31,7 +64,6 @@ __all__ = [
files: dict[str, File] = {}
directories: dict[str, Directory] = {}
modules: set[Module] = set()
plugins: dict[str, Plugin] = available_plugins()
execution_order: list[str] = [
"files",
"pacman",
@@ -39,28 +71,6 @@ execution_order: list[str] = [
"systemd",
]
# Default plugins get quick access
pacman: None | Pacman = None
aur: None | AUR = None
systemd: None | Systemd = None
flatpak: None | Flatpak = None
_pacman = plugins.get("pacman", None)
if isinstance(_pacman, Pacman):
pacman = _pacman
_aur = plugins.get("aur", None)
if isinstance(_aur, AUR):
aur = _aur
_systemd = plugins.get("systemd", None)
if isinstance(_systemd, Systemd):
systemd = _systemd
_flatpak = plugins.get("flatpak", None)
if isinstance(_flatpak, Flatpak):
flatpak = _flatpak
def sh(
sh_cmd: str,
Generated
+61 -5
View File
@@ -2,6 +2,14 @@ version = 1
revision = 3
requires-python = ">=3.13"
[manifest]
members = [
"decman",
"decman-flatpak",
"decman-pacman",
"decman-systemd",
]
[[package]]
name = "certifi"
version = "2025.11.12"
@@ -65,9 +73,16 @@ wheels = [
name = "decman"
version = "1.0.0"
source = { editable = "." }
dependencies = [
{ name = "pyalpm" },
{ name = "requests" },
[package.optional-dependencies]
flatpak = [
{ name = "decman-flatpak" },
]
pacman = [
{ name = "decman-pacman" },
]
systemd = [
{ name = "decman-systemd" },
]
[package.dev-dependencies]
@@ -78,9 +93,11 @@ dev = [
[package.metadata]
requires-dist = [
{ name = "pyalpm" },
{ name = "requests" },
{ name = "decman-flatpak", marker = "extra == 'flatpak'", editable = "packages/decman-flatpak" },
{ name = "decman-pacman", marker = "extra == 'pacman'", editable = "packages/decman-pacman" },
{ name = "decman-systemd", marker = "extra == 'systemd'", editable = "packages/decman-systemd" },
]
provides-extras = ["pacman", "systemd", "flatpak"]
[package.metadata.requires-dev]
dev = [
@@ -88,6 +105,45 @@ dev = [
{ name = "ruff", specifier = ">=0.14.9" },
]
[[package]]
name = "decman-flatpak"
version = "1.0.0"
source = { editable = "packages/decman-flatpak" }
dependencies = [
{ name = "decman" },
]
[package.metadata]
requires-dist = [{ name = "decman", editable = "." }]
[[package]]
name = "decman-pacman"
version = "1.0.0"
source = { editable = "packages/decman-pacman" }
dependencies = [
{ name = "decman" },
{ name = "pyalpm" },
{ name = "requests" },
]
[package.metadata]
requires-dist = [
{ name = "decman", editable = "." },
{ name = "pyalpm" },
{ name = "requests" },
]
[[package]]
name = "decman-systemd"
version = "1.0.0"
source = { editable = "packages/decman-systemd" }
dependencies = [
{ name = "decman" },
]
[package.metadata]
requires-dist = [{ name = "decman", editable = "." }]
[[package]]
name = "idna"
version = "3.11"