Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Example

This directory contains an example of a minimal decman configuration. This also functions as a tutorial for starting out with decman. I recommend looking at the docs after this.

Tutorial

Installing decman

I will first install git and base-devel. Then I'll clone the PKGBUILD and install decman.

sudo pacman -S git base-devel
git clone https://aur.archlinux.org/decman.git
cd decman/
makepkg -sic

Starting out

I will create a source directory for the system's configuration.

mkdir ~/source
cd ~/source

Decman will remove all explicitly installed packages not found in the source. Let's find all explicitly installed packages.

$ pacman -Qeq
base
base-devel
btrfs-progs
decman
dosfstools
efibootmgr
git
grub
linux
openssh
qemu-guest-agent
sudo
vim

First thing to note: decman is not a native package. I remember this, but if you don't, you can find only native packages with pacman -Qeqn and foreign packages with pacman -Qeqm. Since decman is not a native package, the pacman plugin cannot handle it. I'll add decman to AUR packages.

Instead of adding all of these packages to decman.pacman.packages, I will first create a module for base system packages in ~/source/base.py.

import decman
from decman.plugins import pacman, aur

class BaseModule(decman.Module):

    def __init__(self):
        # I'll intend this module to be a singleton (only one instance ever),
        # so I'll inline the module name
        super().__init__("base")

    @pacman.packages
    def pkgs(self) -> set[str]:
        return {
            "base",
            "btrfs-progs",
            "dosfstools",
            "efibootmgr",
            "grub",
            "linux",

            # I'll also include git and base-devel here, they are essential to this system
            "git",
            "base-devel",
        }

    @aur.packages
    def aurpkgs(self) -> set[str]:
        return {"decman"}

Then I'll create the main source file with the rest of the packages. I'll import BaseModule and add it to decman.modules. The main file is ~/source/source.py.

import decman
from base import BaseModule

decman.pacman.packages |= {"openssh", "qemu-guest-agent", "sudo", "vim"}
decman.modules += [BaseModule()]

This config is already enough to run decman for the first time.

sudo decman --source /home/arch/source/source.py

This will run a system upgrade, but otherwise nothing else happens, since my system already matches the desired configuration.

Extending my config with files and commands

Now I'll want to gradually add more stuff to my config. As an example, I'll add my custom mkinitcpio.conf. I'll create the file ~/source/files/mkinitcpio.conf with the desired content. Then I'll add the file to my BaseModule. Since I want to run the command mkinitcpio -P every time I update my config, I'll add a on change hook as well. I'll update the file ~/source/base.py.

class BaseModule(decman.Module):
    ...

    def files(self) -> dict[str, decman.File]:
        return {"/etc/mkinitcpio.conf": decman.File(source_file="./files/mkinitcpio.conf")}

    def on_change(self, store):
        decman.prg(["mkinitcpio", "-P"])

I'll also add my vim config to decman. I could now create a Vim module, but since my config is simple, I feel that is not needed. I'll update the main source file ~/source/source.py.

import decman

...

decman.files["/home/arch/.vimrc"] = decman.File(source_file="./files/vimrc", owner="arch", permissions=0o600)

Then I'll apply my changes. Decman will remember my source, so no need to give it as an argument anymore. I don't want to waste time checking for aur updates, so I'll skip them.

sudo decman --skip aur

Systemd services and flatpaks

I want add a desktop environment. I'll create a module for that in the file ~/source/kde.py. I'll use SDDM as the login manager. SDDM service needs to be enabled, so I'll use the systemd plugin for that.

import decman
from decman.plugins import pacman, systemd

class KDE(decman.Module):

    def __init__(self):
        super().__init__("kde")

    @pacman.packages
    def pkgs(self) -> set[str]:
        return {
            "plasma-desktop",
            "konsole",
            "sddm",
        }

    @systemd.units
    def units(self) -> set[str]:
        return {"sddm.service"}

I'll add the module to enabled modules in ~/source/source.py.

import decman
from base import BaseModule
from kde import KDE

...

decman.modules += [BaseModule(), KDE()]

I'll run decman once again. I'll also start SDDM manually, since decman can't autostart it.

sudo decman
sudo systemctl start sddm

Lastly I want to install some packages with flatpak. I'll first have to install flatpak to make the plugin available. I'll do it manually since it's quicker.

sudo pacman -S flatpak

Then I'll modify ~/source/source.py. I must add flatpak to execution steps to run the plugin.

import decman

...

decman.execution_order = [
    "files",
    "pacman",
    "aur",
    "flatpak",
    "systemd",
]

decman.pacman.packages.add("flatpak")
decman.flatpak.packages |= {"org.mozilla.firefox", "org.signal.Signal"}

Then run decman.

sudo decman

Maintaining a system with decman

Decman is intended to replace your upgrade procedures. Instead of running yay -Syu for example, you would run sudo decman. With after_update hooks you can chain other update commands such as rustup update. This way you'll only have to remember to run decman. All other update steps are defined in your source.

Plugins

It is possible to create your own plugins for decman. However, you probably won't need to do that, as modules are already very capable. This example directory also contains a very minimal plugin. To learn more about plugins, look at the docs.