mirror of
https://github.com/kiviktnm/decman.git
synced 2026-09-19 12:08:28 +00:00
Add complete example
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
# Imagine something here
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Why are you looking here?
|
||||||
|
|
||||||
|
What is '%msg%'?
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Thats right!
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
echo "Hello, World!"
|
||||||
+95
-4
@@ -1,19 +1,110 @@
|
|||||||
# from import is ok for importing classes and functions
|
# from import is ok for importing classes and functions
|
||||||
# just remember to not import variables this way
|
# just remember to not import variables this way
|
||||||
from decman import Module, sh
|
from decman import Module, File, Directory, UserPackage, sh, prg
|
||||||
|
|
||||||
import decman
|
|
||||||
|
|
||||||
|
|
||||||
class MyModule(Module):
|
class MyModule(Module):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.pkgs = ["rust"]
|
self.pkgs = ["rust"]
|
||||||
super().__init__("Example module", True, "1")
|
self.update_rustup = False
|
||||||
|
# Modules have names and versions.
|
||||||
|
# Names must be unique.
|
||||||
|
|
||||||
|
# If you disable a module, all packages, files etc assocated with module are removed.
|
||||||
|
super().__init__(name="Example module", enabled=True, version="1")
|
||||||
|
|
||||||
|
# You can add any methods etc to your modules.
|
||||||
def enable_my_custom_feature(self, b: bool):
|
def enable_my_custom_feature(self, b: bool):
|
||||||
if b:
|
if b:
|
||||||
self.pkgs = ["rustup"]
|
self.pkgs = ["rustup"]
|
||||||
|
self.update_rustup = True
|
||||||
|
|
||||||
|
# This is ran, when the module gets enabled
|
||||||
|
def on_enable(self):
|
||||||
|
# Run arbitary shell code easily with the included sh function.
|
||||||
|
sh("groupadd mygroup")
|
||||||
|
|
||||||
|
# or run a program with arguments.
|
||||||
|
prg(["usermod", "--append", "--groups", "mygroup", "kk"])
|
||||||
|
|
||||||
|
def on_disable(self):
|
||||||
|
# You can run commands as any user
|
||||||
|
sh("whoami", user="kk")
|
||||||
|
|
||||||
|
# And override environment variables
|
||||||
|
sh("echo $HI", env_overrides={"HI": "Hello!"})
|
||||||
|
|
||||||
|
# Same options apply to prg as well.
|
||||||
|
|
||||||
|
def after_update(self):
|
||||||
|
# Run code after running decman.
|
||||||
|
if self.update_rustup:
|
||||||
|
prg(["rustup", "update"], user="kk")
|
||||||
|
|
||||||
|
def after_version_change(self):
|
||||||
|
# Modules have version numbers to allow conditionally running code.
|
||||||
|
# You could for example run mkinitcpio only after your config has changed.
|
||||||
|
# Just remember to change the version number.
|
||||||
|
prg(["mkinitcpio", "-P"])
|
||||||
|
|
||||||
|
# Files defined here are the same as outside of modules.
|
||||||
|
# There is however an additional feature:
|
||||||
|
# You may add variables to text files, that will be replaced with the given value.
|
||||||
|
|
||||||
|
def file_variables(self) -> dict[str, str]:
|
||||||
|
return {"%msg%": "Hello, world!"}
|
||||||
|
|
||||||
|
def files(self) -> dict[str, File]:
|
||||||
|
# Variables are substituted in text files automatically.
|
||||||
|
return {
|
||||||
|
"/usr/local/bin/say-hello":
|
||||||
|
File(content="#!/usr/bin/env bash\necho %msg%", permissions=0o755),
|
||||||
|
# Variables are not substituted in binary files.
|
||||||
|
"/usr/local/share/say-hello/image.png":
|
||||||
|
File(source_file="files/i-dont-exist.png", bin_file=True),
|
||||||
|
}
|
||||||
|
|
||||||
|
def directories(self) -> dict[str, Directory]:
|
||||||
|
# Directories are handeled the same way. Variables are substituted in text files.
|
||||||
|
return {
|
||||||
|
"/home/kk/.config/mod-app/":
|
||||||
|
Directory(source_directory="files/app-config", owner="kk")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Packages and systemd units are basically the same with modules as without modules.
|
||||||
|
|
||||||
def pacman_packages(self) -> list[str]:
|
def pacman_packages(self) -> list[str]:
|
||||||
|
# Return pacman packages depending on the usage of this module.
|
||||||
return self.pkgs
|
return self.pkgs
|
||||||
|
|
||||||
|
def user_packages(self) -> list[UserPackage]:
|
||||||
|
return [
|
||||||
|
UserPackage(
|
||||||
|
pkgname="decman",
|
||||||
|
version="0.0.1",
|
||||||
|
dependencies=[
|
||||||
|
"python",
|
||||||
|
"python-requests",
|
||||||
|
"devtools",
|
||||||
|
"systemd",
|
||||||
|
"pacman",
|
||||||
|
],
|
||||||
|
make_dependencies=[
|
||||||
|
"python-setuptools",
|
||||||
|
"python-build",
|
||||||
|
"python-installer",
|
||||||
|
"python-wheel",
|
||||||
|
],
|
||||||
|
git_url="https://github.com/kiviktnm/decman-pkgbuild.git",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
def aur_packages(self) -> list[str]:
|
||||||
|
return ["protonvpn"]
|
||||||
|
|
||||||
|
def systemd_units(self) -> list[str]:
|
||||||
|
return ["reflector.timer"]
|
||||||
|
|
||||||
|
def systemd_user_units(self) -> dict[str, list[str]]:
|
||||||
|
return {"kk": ["syncthing.service"]}
|
||||||
|
|||||||
+252
-2
@@ -1,9 +1,259 @@
|
|||||||
|
# This example covers all decman features and many useful ways of configuring a system.
|
||||||
|
# Configuration can be as simple or as complex as is needed.
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Remember: Do NOT use from imports for global variables
|
||||||
|
# BAD: from decman import packages/modules/etc
|
||||||
import decman
|
import decman
|
||||||
|
import decman.config
|
||||||
|
|
||||||
|
# This is fine since the thing being imported is a class and not a global variable.
|
||||||
|
from decman import UserPackage, File, Directory
|
||||||
|
|
||||||
|
# Configuring what packages are installed is easy.
|
||||||
|
# Duplicates are OK, so if you have multiple modules that want to ensure a package is installed,
|
||||||
|
# you can add the same package multiple times.
|
||||||
|
decman.packages += ["python", "python", "devtools", "git", "networkmanager"]
|
||||||
|
|
||||||
|
# Decman matches installed packages to those defined in the configuration.
|
||||||
|
# This means that:
|
||||||
|
# - all packages not installed on the system but defined in the source are installed
|
||||||
|
# - all packages installed on the system but not defined in the source are removed
|
||||||
|
# To make decman not care if a package is installed or not, add it to ignored_packages.
|
||||||
|
# Ignored packages can be normal packages or aur packages.
|
||||||
|
decman.ignored_packages += ["rustup", "yay"]
|
||||||
|
|
||||||
|
# Installing AUR packages is easy.
|
||||||
|
decman.aur_packages += ["protonvpn"]
|
||||||
|
|
||||||
|
# To import GPG keys, set the GNUPGHOME environment variable.
|
||||||
|
# It can easily be done with python as well.
|
||||||
|
os.environ["GNUPGHOME"] = "/home/kk/.gnupg/"
|
||||||
|
# You then must set the user that builds the packages to the owner of the GPG home.
|
||||||
|
decman.config.makepkg_user = "kk"
|
||||||
|
|
||||||
|
# You can also install packages from anywhere, but then you must include some
|
||||||
|
# information about the package. The git_url is the url to the PKGBUILD,
|
||||||
|
# This example may not be up to date, but you should keep these up to date with the PKGBUILD.
|
||||||
|
decman.user_packages.append(
|
||||||
|
UserPackage(
|
||||||
|
pkgname="decman",
|
||||||
|
version="0.0.1",
|
||||||
|
dependencies=[
|
||||||
|
"python",
|
||||||
|
"python-requests",
|
||||||
|
"devtools",
|
||||||
|
"systemd",
|
||||||
|
"pacman",
|
||||||
|
],
|
||||||
|
make_dependencies=[
|
||||||
|
"python-setuptools",
|
||||||
|
"python-build",
|
||||||
|
"python-installer",
|
||||||
|
"python-wheel",
|
||||||
|
],
|
||||||
|
git_url="https://github.com/kiviktnm/decman-pkgbuild.git",
|
||||||
|
))
|
||||||
|
|
||||||
|
# Managing only packages with decman is not that interesting.
|
||||||
|
# Decman also has really powerful ways of managing config files, scripts etc.
|
||||||
|
|
||||||
|
# IMPORTANT: Decman will remove files that were created by decman, but are no longer in the decman source.
|
||||||
|
# Keep your decman source in version control to avoid losing important files accidentally.
|
||||||
|
|
||||||
|
# Define file content inline.
|
||||||
|
# By default text file encoding is utf-8 but it can be changed.
|
||||||
|
decman.files["/etc/vconsole.conf"] = File(content="KEYMAP=us",
|
||||||
|
encoding="utf-8")
|
||||||
|
|
||||||
|
# Include file content from another file, set the file owner and permissions.
|
||||||
|
# The source_file is relative to the directory where the main decman source.py is located.
|
||||||
|
# By default, the file group is set to the group of the owner, but it can be overridden with the group argument.
|
||||||
|
decman.files["/home/kk/.bin/user-script.sh"] = File(
|
||||||
|
source_file="files/user-script.sh", owner="kk", permissions=0o744)
|
||||||
|
|
||||||
|
# Non-text files such as images can also be managed.
|
||||||
|
decman.files["/home/kk/.background.png"] = File(
|
||||||
|
source_file="files/i-dont-actually-exist.png", bin_file=True, owner="kk")
|
||||||
|
|
||||||
|
# If you need to install multiple files at once, use directories.
|
||||||
|
# All files from the source directory will be copied recursively to the target.
|
||||||
|
decman.directories["/home/kk/.config/app/"] = Directory(
|
||||||
|
source_directory="files/app-config", owner="kk")
|
||||||
|
|
||||||
|
# Decman has built in support for managing systemd units as well.
|
||||||
|
# Decman will enable services declared here, and disable services removed from here.
|
||||||
|
# If you don't want decman to manage a service, don't add it here. It will ignore all units that
|
||||||
|
# weren't enabled here.
|
||||||
|
decman.enabled_systemd_units += ["NetworkManager.service"]
|
||||||
|
|
||||||
|
# You can manage units for users as well.
|
||||||
|
|
||||||
|
# Ensure that previous user unit declarations aren't overwritten and they are initialized.
|
||||||
|
decman.enabled_systemd_user_units[
|
||||||
|
"kk"] = decman.enabled_systemd_user_units.get("kk", [])
|
||||||
|
# Add user unit.
|
||||||
|
decman.enabled_systemd_user_units["kk"].append("syncthing.service")
|
||||||
|
|
||||||
|
# Most powerful feature of decman are modules.
|
||||||
|
# In this file you see how to include your module, but to really see what modules are capable of
|
||||||
|
# look at the MyModule class.
|
||||||
from my_module import MyModule
|
from my_module import MyModule
|
||||||
|
|
||||||
my_own_mod = MyModule()
|
my_own_mod = MyModule()
|
||||||
|
|
||||||
my_own_mod.enable_my_custom_feature(True)
|
# You have full access to python, which makes your configuration very dynamic.
|
||||||
|
# For example: do something if the computers hostname is arch-1
|
||||||
|
if socket.gethostname() == "arch-1":
|
||||||
|
# Modules make dynamic configuration easy.
|
||||||
|
# This executes code defined in MyModule which can affect for example what packages are
|
||||||
|
# installed as a part of this module.
|
||||||
|
my_own_mod.enable_my_custom_feature(True)
|
||||||
|
|
||||||
decman.packages += ["python", "python"]
|
|
||||||
decman.modules += [my_own_mod]
|
decman.modules += [my_own_mod]
|
||||||
|
|
||||||
|
# Configuring the behavior of decman is also done here.
|
||||||
|
# These are the default values.
|
||||||
|
|
||||||
|
# Show debug output
|
||||||
|
decman.config.debug_output = False
|
||||||
|
|
||||||
|
# Make output less verbose. Summaries are still printed.
|
||||||
|
decman.config.quiet_output = False
|
||||||
|
|
||||||
|
# Suppress output of some commands that you probably don't want to see.
|
||||||
|
decman.config.suppress_command_output = True
|
||||||
|
|
||||||
|
# The user which builds aur and user packages.
|
||||||
|
# decman.config.makepkg_user = "nobody" # This was set in a previous example. Let's not override it.
|
||||||
|
|
||||||
|
# The build directory decman uses for creating a chroot etc.
|
||||||
|
decman.config.build_dir = "/tmp/decman/build"
|
||||||
|
|
||||||
|
# Built packages are stored here.
|
||||||
|
decman.config.pkg_cache_dir = "/var/cache/decman"
|
||||||
|
|
||||||
|
# Timeout in seconds for fetching aur package details.
|
||||||
|
decman.config.aur_rpc_timeout = 30
|
||||||
|
|
||||||
|
# Enable installing and upgrading foreign packages.
|
||||||
|
decman.config.enable_fpm = True
|
||||||
|
|
||||||
|
|
||||||
|
# Changing the default commands decman uses for things is a bit more complex.
|
||||||
|
# Create a child class of the decman.config.Commands class and override methods.
|
||||||
|
# These are the defaults.
|
||||||
|
class MyCommands(decman.config.Commands):
|
||||||
|
|
||||||
|
def list_pkgs(self) -> list[str]:
|
||||||
|
return ["pacman", "-Qeq", "--color=never"]
|
||||||
|
|
||||||
|
def list_foreign_pkgs_versioned(self) -> list[str]:
|
||||||
|
return ["pacman", "-Qm", "--color=never"]
|
||||||
|
|
||||||
|
def install_pkgs(self, pkgs: list[str]) -> list[str]:
|
||||||
|
return ["pacman", "-S", "--asexplicit"] + pkgs
|
||||||
|
|
||||||
|
def install_files(self, pkg_files: list[str]) -> list[str]:
|
||||||
|
return ["pacman", "-U", "--asdeps"] + pkg_files
|
||||||
|
|
||||||
|
def set_as_explicitly_installed(self, pkgs: list[str]) -> list[str]:
|
||||||
|
return ["pacman", "-D", "--asexplicit"] + pkgs
|
||||||
|
|
||||||
|
def install_deps(self, deps: list[str]) -> list[str]:
|
||||||
|
return ["pacman", "-S", "--needed", "--asdeps"] + deps
|
||||||
|
|
||||||
|
def is_installable(self, pkg: str) -> list[str]:
|
||||||
|
return ["pacman", "-Sddp", pkg]
|
||||||
|
|
||||||
|
def upgrade(self) -> list[str]:
|
||||||
|
return ["pacman", "-Syu"]
|
||||||
|
|
||||||
|
def remove(self, pkgs: list[str]) -> list[str]:
|
||||||
|
return ["pacman", "-Rs"] + pkgs
|
||||||
|
|
||||||
|
def enable_units(self, units: list[str]) -> list[str]:
|
||||||
|
return ["systemctl", "enable", "--now", "--quiet"] + units
|
||||||
|
|
||||||
|
def disable_units(self, units: list[str]) -> list[str]:
|
||||||
|
return ["systemctl", "disable", "--quiet"] + units
|
||||||
|
|
||||||
|
def enable_user_units(self, units: list[str]) -> list[str]:
|
||||||
|
return ["systemctl", "enable", "--now", "--quiet", "--user"] + units
|
||||||
|
|
||||||
|
def disable_user_units(self, units: list[str]) -> list[str]:
|
||||||
|
return ["systemctl", "disable", "--quiet"] + units
|
||||||
|
|
||||||
|
def compare_versions(self, installed_version: str,
|
||||||
|
new_version: str) -> list[str]:
|
||||||
|
return ["vercmp", installed_version, new_version]
|
||||||
|
|
||||||
|
def git_clone(self, repo: str, dest: str) -> list[str]:
|
||||||
|
return ["git", "clone", repo, dest]
|
||||||
|
|
||||||
|
def git_diff(self, from_commit: str) -> list[str]:
|
||||||
|
return ["git", "diff", from_commit]
|
||||||
|
|
||||||
|
def git_get_commit_id(self) -> list[str]:
|
||||||
|
return ["git", "rev-parse", "HEAD"]
|
||||||
|
|
||||||
|
def review_file(self, file: str) -> list[str]:
|
||||||
|
return ["less", file]
|
||||||
|
|
||||||
|
def make_chroot(self, chroot_dir: str, with_pkgs: list[str]) -> list[str]:
|
||||||
|
return ["mkarchroot", chroot_dir] + with_pkgs
|
||||||
|
|
||||||
|
def install_chroot_packages(self, chroot_dir: str, packages: list[str]):
|
||||||
|
return [
|
||||||
|
"arch-nspawn", chroot_dir, "pacman", "-S", "--needed",
|
||||||
|
"--noconfirm"
|
||||||
|
] + packages
|
||||||
|
|
||||||
|
def remove_chroot_packages(self, chroot_dir: str, packages: list[str]):
|
||||||
|
return ["arch-nspawn", chroot_dir, "pacman", "-Rsu", "--noconfirm"
|
||||||
|
] + packages
|
||||||
|
|
||||||
|
def make_chroot_pkg(self, chroot_wd_dir: str, user: str,
|
||||||
|
pkgfiles_to_install: list[str]) -> list[str]:
|
||||||
|
makechrootpkg_cmd = [
|
||||||
|
"makechrootpkg", "-c", "-r", chroot_wd_dir, "-U", user
|
||||||
|
]
|
||||||
|
|
||||||
|
for pkgfile in pkgfiles_to_install:
|
||||||
|
makechrootpkg_cmd += ["-I", pkgfile]
|
||||||
|
|
||||||
|
return makechrootpkg_cmd
|
||||||
|
|
||||||
|
|
||||||
|
# To apply your overrides, set the commands variable.
|
||||||
|
decman.config.commands = MyCommands()
|
||||||
|
|
||||||
|
# Alternative to the built in AUR support:
|
||||||
|
# If you don't want to use the built in AUR helper, you can use some pacman wrapper that can run as root, such as pikaur.
|
||||||
|
# To do this, override commands and disable fpm.
|
||||||
|
|
||||||
|
|
||||||
|
class PikaurWrapperCommands(decman.config.Commands):
|
||||||
|
|
||||||
|
def list_pkgs(self) -> list[str]:
|
||||||
|
return ["pikaur", "-Qeq"]
|
||||||
|
|
||||||
|
def install_pkgs(self, pkgs: list[str]) -> list[str]:
|
||||||
|
return ["pikaur", "-S", "--asexplicit"] + pkgs
|
||||||
|
|
||||||
|
def upgrade(self) -> list[str]:
|
||||||
|
return ["pikaur", "-Syu"]
|
||||||
|
|
||||||
|
def remove(self, pkgs: list[str]) -> list[str]:
|
||||||
|
return ["pikaur", "-Rs"] + pkgs
|
||||||
|
|
||||||
|
# it doesn't matter if all pacman commands aren't overridden since they wont be used when fpm is disabled.
|
||||||
|
|
||||||
|
|
||||||
|
# decman.config.enable_fpm = False
|
||||||
|
# decman.config.commands = PikaurWrapperCommands()
|
||||||
|
|
||||||
|
# Then simply add all AUR packages to decman.packages
|
||||||
|
# decman.packages += ["pikaur"]
|
||||||
|
|||||||
Reference in New Issue
Block a user