diff --git a/README.md b/README.md index 4ff6e55..0848373 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ Then import your module in your main source file. import decman from syncthing import Syncthing -decman.modules |= {Syncthing()} +decman.modules += [Syncthing()] ``` Then run decman. diff --git a/docs/README.md b/docs/README.md index 024e1b8..062dd97 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,6 +7,8 @@ This contains the documentation for decman. Each plugin has its own documentatio - [aur](/docs/aur.md) - [flatpak](/docs/flatpak.md) +Check out [extras](docs/extras.md) for documentation for built-in modules. + ## Quick notes "Decman source" or "source" refers to your system configuration. It is set using the `--source` command line argument with decman. @@ -210,11 +212,11 @@ A **Module** is the primary unit for grouping related files, directories, packag Each module is uniquely identified by its `name`. -Remember to add modules to decman. +Remember to add modules to decman. Modules are added to a list to preserve deterministic execution order for hooks. ```py import decman -decman.modules |= {MyModule()} +decman.modules += [MyModule()] ``` ### Basic Structure @@ -418,7 +420,7 @@ This method only gathers information. It doesn't apply it. ```py from decman import Store, Module -def process_modules(self, store: Store, modules: set[Module]): +def process_modules(self, store: Store, modules: list[Module]): ... # Toy example for setting modules as changed diff --git a/docs/aur.md b/docs/aur.md index aa2d069..2ba3da8 100644 --- a/docs/aur.md +++ b/docs/aur.md @@ -79,6 +79,11 @@ class MyModule(decman.Module): If these sets change, this plugin will flag the module as changed. The module's `on_change` method will be executed. +## Keys used in the decman store + +- `aur_packages_for_module` +- `custom_packages_for_module` + ## Configuration This module has partially the same configuration with pacman. You'll have to define pacman output keywords and database options again. diff --git a/docs/flatpak.md b/docs/flatpak.md index 331c688..25f621f 100644 --- a/docs/flatpak.md +++ b/docs/flatpak.md @@ -47,6 +47,11 @@ class MyModule(decman.Module): If packages or user packages change, this plugin will flag the module as changed. The module's `on_change` method will be executed. +## Keys used in the decman store + +- `flatpaks_for_module` +- `user_flatpaks_for_module` + ## Configuration It's possible to override the commands this plugin uses. Create your own `FlatpakCommands` class and override methods returning commands. These are the defaults. diff --git a/docs/migrate-to-v1.md b/docs/migrate-to-v1.md index ebbec13..5df6625 100644 --- a/docs/migrate-to-v1.md +++ b/docs/migrate-to-v1.md @@ -232,8 +232,6 @@ class MyModule(Module): #### New -`decman.modules` is now a set instead of a list. If you wish to have multiple instances of the same module class, just name them differently. Name needs to be unique accross modules. - Modules no longer have `version`s or `enabled` values. A module is enabled when it gets added to `decman.modules` and disabled when it gets removed from `decman.modules`. Versions are no longer needed because `after_version_change` has been removed and `on_change` has been added. `on_change` is executed automatically after the content of the module changes. `on_disable` will be executed automatically when the module is removed from `decman.modules`. It is no longer a instance method. Instead it must be a self-contained method with no references outside it. Not even imports. Module methods will get a `Store` instance passed to them as an argument. It can be used to store key-value pairs between decman runs. @@ -245,7 +243,7 @@ import decman from decman import Module, Store, prg, sh from decman.plugins import pacman, aur, systemd, flatpak -decman.modules |= {MyModule()} +decman.modules += [MyModule()] class MyModule(Module): def __init__(self): diff --git a/docs/pacman.md b/docs/pacman.md index 4a57905..9a81017 100644 --- a/docs/pacman.md +++ b/docs/pacman.md @@ -42,6 +42,10 @@ class MyModule(decman.Module): If this set changes, this plugin will flag the module as changed. The module's `on_change` method will be executed. +## Keys used in the decman store + +- `packages_for_module` + ## Configuration This plugin has a pacman output highlight function. If pacman output contains some keywords, it will be highlighted. You can disable this feature or set the keywords. diff --git a/docs/systemd.md b/docs/systemd.md index 6234a5f..d945cf3 100644 --- a/docs/systemd.md +++ b/docs/systemd.md @@ -45,6 +45,11 @@ class MyModule(decman.Module): If units or user units change, this plugin will flag the module as changed. The module's `on_change` method will be executed. +## Keys used in the decman store + +- `systemd_units_for_module` +- `systemd_user_units_for_module` + ## Configuration It's possible to override the commands this plugin uses. Create your own `SystemdCommands` class and override methods returning commands. These are the defaults. diff --git a/example/README.md b/example/README.md index 80be67c..c837d2d 100644 --- a/example/README.md +++ b/example/README.md @@ -85,7 +85,7 @@ import decman from base import BaseModule decman.pacman.packages |= {"openssh", "qemu-guest-agent", "sudo", "vim"} -decman.modules |= {BaseModule()} +decman.modules += [BaseModule()] ``` This config is already enough to run decman for the first time. @@ -162,7 +162,7 @@ from kde import KDE ... -decman.modules |= {BaseModule(), KDE()} +decman.modules += [BaseModule(), KDE()] ``` I'll run decman once again. I'll also start SDDM manually, since decman can't autostart it. diff --git a/example/plugin/decman_plugin_example.py b/example/plugin/decman_plugin_example.py index 2381664..cf39aac 100644 --- a/example/plugin/decman_plugin_example.py +++ b/example/plugin/decman_plugin_example.py @@ -9,7 +9,7 @@ class Example(decman.Plugin): def available(self) -> bool: return os.path.exists("/tmp/example_plugin_available") - def process_modules(self, store: decman.Store, modules: set[decman.Module]): + def process_modules(self, store: decman.Store, modules: list[decman.Module]): # Toy example for setting modules as changed for module in modules: module._changed = True diff --git a/example/source.py b/example/source.py index 049e185..70a79b4 100644 --- a/example/source.py +++ b/example/source.py @@ -5,7 +5,7 @@ import decman decman.pacman.packages |= {"openssh", "qemu-guest-agent", "sudo", "vim"} -decman.modules |= {BaseModule(), KDE()} +decman.modules += [BaseModule(), KDE()] decman.files["/home/arch/.vimrc"] = decman.File( source_file="./files/vimrc", owner="arch", permissions=0o600 diff --git a/plugins/decman-flatpak/src/decman/plugins/flatpak.py b/plugins/decman-flatpak/src/decman/plugins/flatpak.py index 0bfa0b8..1a9fa01 100644 --- a/plugins/decman-flatpak/src/decman/plugins/flatpak.py +++ b/plugins/decman-flatpak/src/decman/plugins/flatpak.py @@ -46,7 +46,7 @@ class Flatpak(plugins.Plugin): def available(self) -> bool: return shutil.which("flatpak") is not None - def process_modules(self, store: _store.Store, modules: set[module.Module]): + def process_modules(self, store: _store.Store, modules: list[module.Module]): # These store keys are used to track changes in modules. # This way when these change, module can be marked as changed store.ensure("flatpaks_for_module", {}) diff --git a/plugins/decman-pacman/src/decman/plugins/aur/__init__.py b/plugins/decman-pacman/src/decman/plugins/aur/__init__.py index 9f04737..848529a 100644 --- a/plugins/decman-pacman/src/decman/plugins/aur/__init__.py +++ b/plugins/decman-pacman/src/decman/plugins/aur/__init__.py @@ -90,7 +90,7 @@ class AUR(plugins.Plugin): and shutil.which("mkarchroot") is not None ) - def process_modules(self, store: _store.Store, modules: set[module.Module]): + def process_modules(self, store: _store.Store, modules: list[module.Module]): # This is used to track changes in modules. store.ensure("aur_packages_for_module", {}) store.ensure("custom_packages_for_module", {}) diff --git a/plugins/decman-pacman/src/decman/plugins/pacman.py b/plugins/decman-pacman/src/decman/plugins/pacman.py index 0ec77bd..894ec73 100644 --- a/plugins/decman-pacman/src/decman/plugins/pacman.py +++ b/plugins/decman-pacman/src/decman/plugins/pacman.py @@ -58,7 +58,7 @@ class Pacman(plugins.Plugin): def available(self) -> bool: return shutil.which("pacman") is not None - def process_modules(self, store: _store.Store, modules: set[module.Module]): + def process_modules(self, store: _store.Store, modules: list[module.Module]): # This is used to track changes in modules. store.ensure("packages_for_module", {}) diff --git a/plugins/decman-systemd/src/decman/plugins/systemd.py b/plugins/decman-systemd/src/decman/plugins/systemd.py index 143a406..bad2351 100644 --- a/plugins/decman-systemd/src/decman/plugins/systemd.py +++ b/plugins/decman-systemd/src/decman/plugins/systemd.py @@ -83,7 +83,7 @@ class Systemd(plugins.Plugin): def available(self) -> bool: return shutil.which("systemctl") is not None - def process_modules(self, store: _store.Store, modules: set[module.Module]): + def process_modules(self, store: _store.Store, modules: list[module.Module]): # These store keys are used to track changes in modules. # This way when these change, module can be marked as changed store.ensure("systemd_units_for_module", {}) diff --git a/src/decman/__init__.py b/src/decman/__init__.py index bebb7b0..db70810 100644 --- a/src/decman/__init__.py +++ b/src/decman/__init__.py @@ -63,7 +63,7 @@ __all__ = [ # ----------------------------------------- files: dict[str, File] = {} directories: dict[str, Directory] = {} -modules: set[Module] = set() +modules: list[Module] = [] execution_order: list[str] = [ "files", "pacman", diff --git a/src/decman/core/file_manager.py b/src/decman/core/file_manager.py index 0241f0a..9d5bd99 100644 --- a/src/decman/core/file_manager.py +++ b/src/decman/core/file_manager.py @@ -10,7 +10,7 @@ import decman.core.store as _store def update_files( store: _store.Store, - modules: set[module.Module], + modules: list[module.Module], files: dict[str, fs.File], directories: dict[str, fs.Directory], dry_run: bool = False, diff --git a/src/decman/core/store.py b/src/decman/core/store.py index 4ab0b77..58e4aeb 100644 --- a/src/decman/core/store.py +++ b/src/decman/core/store.py @@ -74,5 +74,14 @@ class _SetJSONEncoder(json.JSONEncoder): def _decode_sets(obj: typing.Any) -> typing.Any: if isinstance(obj, dict) and obj.get("__type__") == "set" and "items" in obj: - return set(obj["items"]) + # decode lists inside sets as tuples + norm = [] + + for item in obj["items"]: + if isinstance(item, list): + norm.append(tuple(item)) + else: + norm.append(item) + + return set(norm) return obj diff --git a/src/decman/plugins/__init__.py b/src/decman/plugins/__init__.py index e264087..bdfb1cc 100644 --- a/src/decman/plugins/__init__.py +++ b/src/decman/plugins/__init__.py @@ -40,7 +40,7 @@ class Plugin: """ return True - def process_modules(self, store: _store.Store, modules: set[module.Module]): + def process_modules(self, store: _store.Store, modules: list[module.Module]): """ Processes a module. """