Added the option for installing flatpaks to the user installation.

This commit is contained in:
Dávid Groniewsky
2025-10-01 11:15:26 +02:00
parent 515a27cb7d
commit 613beaa917
5 changed files with 68 additions and 28 deletions
+9 -1
View File
@@ -382,7 +382,14 @@ class Module:
def flatpak_packages(self) -> list[str]:
"""
Override this method to return flatpak packages that should be installed as a part of this
Override this method to return flatpak packages that should be installed to the system installation as a part of this
Module.
"""
return []
def flatpak_user_packages(self) -> list[str]:
"""
Override this method to return flatpak packages that should be installed to the user installation as a part of this
Module.
"""
return []
@@ -420,4 +427,5 @@ files: dict[str, File] = {}
directories: dict[str, Directory] = {}
modules: list[Module] = []
flatpak_packages: list[str] = []
flatpak_user_packages: list[str] = []
ignored_flatpak_packages: list[str] = []
+17 -3
View File
@@ -29,7 +29,6 @@ def main():
epilog="See more help at: https://github.com/kiviktnm/decman",
)
parser.add_argument(
"--source", action="store", help="python file containing configuration"
)
@@ -186,7 +185,7 @@ def _set_up(store: l.Store, args):
args.print,
not args.no_packages,
not args.no_foreign_packages,
not args.no_flatpaks
not args.no_flatpaks,
not args.no_files,
not args.no_systemd_units,
not args.no_commands,
@@ -214,7 +213,9 @@ class Core:
) = opts
if conf.enable_flatpak and not shutil.which("flatpak"):
l.print_error("Flatpaks have been enabled in the source file, but the flatpak command could not be found. Either disable flatpaks or make sure that flatpak is installed and can be accessed by decman. Exiting.")
l.print_error(
"Flatpaks have been enabled in the source file, but the flatpak command could not be found. Either disable flatpaks or make sure that flatpak is installed and can be accessed by decman. Exiting."
)
exit()
self.store = store
@@ -284,9 +285,14 @@ class Core:
to_remove_flatpak = self.source.flatpak_packages_to_remove(
currently_installed_flatpak
)
currently_installed_user_flatpak = self.flatpak.get_installed(True)
to_remove_user_flatpak = self.source.flatpak_packages_to_remove(
currently_installed_user_flatpak, as_user=True
)
l.print_list("Removing pacman packages:", to_remove)
l.print_list("Removing flatpak packages:", to_remove_flatpak)
l.print_list("Removing user flatpak packages:", to_remove_user_flatpak)
if self.only_print:
return
@@ -296,6 +302,7 @@ class Core:
# flatpak
if conf.enable_flatpak and self.update_flatpaks:
self.flatpak.remove(to_remove_flatpak)
self.flatpak.remove(to_remove_user_flatpak, True)
def _upgrade_pkgs(self):
"""
@@ -331,9 +338,14 @@ class Core:
to_install_flatpak = self.source.flatpak_packages_to_install(
currently_installed_flatpak
)
currently_installed_user_flatpak = self.flatpak.get_installed(True)
to_install_user_flatpak = self.source.flatpak_packages_to_install(
currently_installed_user_flatpak, True
)
l.print_list("Installing pacman packages:", to_install_pacman)
l.print_list("Installing flatpak packages:", to_install_flatpak)
l.print_list("Installing user flatpak packages:", to_install_user_flatpak)
# fpm prints a summary so no need to print it twice
if self.only_print:
@@ -346,6 +358,7 @@ class Core:
if conf.enable_flatpak and self.update_flatpaks:
self.flatpak.install(to_install_flatpak)
self.flatpak.install(to_install_user_flatpak, True)
def _create_and_remove_files(self):
l.print_summary("Installing files.")
@@ -416,6 +429,7 @@ def _resolve_source() -> l.Source:
directories=decman.directories,
modules=set(decman.modules),
flatpak_packages=set(decman.flatpak_packages),
flatpak_user_packages=set(decman.flatpak_user_packages),
ignored_flatpak_packages=set(decman.ignored_flatpak_packages),
)
+17 -10
View File
@@ -34,12 +34,19 @@ class Commands:
"""
return ["pacman", "-Qeq", "--color=never"]
def list_flatpak_pkgs(self) -> list[str]:
def list_flatpak_pkgs(self, as_user: bool = False) -> list[str]:
"""
Running this command outputs a newline separated list of installed flatpak application ids
The first line just says 'Application ID' so this one is ignored.
"""
return ["flatpak", "list", "--app", "--columns", "application"]
return [
"flatpak",
"list",
"--app",
"--user" if as_user else "--system",
"--columns",
"application",
]
def list_foreign_pkgs_versioned(self) -> list[str]:
"""
@@ -54,11 +61,11 @@ class Commands:
"""
return ["pacman", "-S", "--color=always", "--needed"] + pkgs
def install_flatpak_pkgs(self, pkgs: list[str]) -> list[str]:
def install_flatpak_pkgs(self, pkgs: list[str], as_user: bool = False) -> list[str]:
"""
Running this command installs all listed packages, and their dependencies/runtimes automatically.
"""
return ["flatpak", "install"] + pkgs
return ["flatpak", "install", "--user" if as_user else "--system"] + pkgs
def install_files(self, pkg_files: list[str]) -> list[str]:
"""
@@ -91,11 +98,11 @@ class Commands:
"""
return ["pacman", "-Syu", "--color=always"]
def upgrade_flatpak(self) -> list[str]:
def upgrade_flatpak(self, as_user: bool = False) -> list[str]:
"""
Updates all installed flatpak REFs including runtimes and dependencies.
"""
return ["flatpak", "update"]
return ["flatpak", "update", "--user" if as_user else "--system"]
def remove(self, pkgs: list[str]) -> list[str]:
"""
@@ -104,17 +111,17 @@ class Commands:
"""
return ["pacman", "-Rs", "--color=always"] + pkgs
def remove_flatpak(self, pkgs: list[str]) -> list[str]:
def remove_flatpak(self, pkgs: list[str], as_user: bool = False) -> list[str]:
"""
Running this command will remove the listed REFs. Unused dependencies might be kept, but to remove them another command needs to be run.
"""
return ["flatpak", "remove"] + pkgs
return ["flatpak", "remove", "--user" if as_user else "--system"] + pkgs
def remove_unused_flatpak(self) -> list[str]:
def remove_unused_flatpak(self, as_user: bool = False) -> list[str]:
"""
This will remove all unused flatpak dependencies and runtimes.
"""
return ["flatpak", "remove", "--unused"]
return ["flatpak", "remove", "--unused", "--user" if as_user else "--system"]
def enable_units(self, units: list[str]) -> list[str]:
"""
+23 -14
View File
@@ -420,6 +420,7 @@ class Source:
directories: dict[str, decman.Directory],
modules: set[decman.Module],
flatpak_packages: set[str],
flatpak_user_packages: set[str],
ignored_flatpak_packages: set[str],
):
self.pacman_packages = pacman_packages
@@ -432,6 +433,7 @@ class Source:
self.directories = directories
self.modules = modules
self.flatpak_packages = flatpak_packages
self.flatpak_user_packages = flatpak_user_packages
self.ignored_flatpak_packages = ignored_flatpak_packages
def run_on_enable(self, store: Store):
@@ -644,14 +646,14 @@ class Source:
return result
def flatpak_packages_to_install(
self, currently_installed_packages: list[str]
self, currently_installed_packages: list[str], as_user: bool = False
) -> list[str]:
"""
Returns all flatpak packages, that are not installed or ignored
"""
result: list[str] = []
for pkg in self._all_flatpak_packages():
for pkg in self._all_flatpak_packages(as_user):
if pkg in self.ignored_flatpak_packages:
continue
if pkg not in currently_installed_packages:
@@ -659,16 +661,17 @@ class Source:
return result
def flatpak_packages_to_remove(
self, currently_installed_packages: list[str]
self, currently_installed_packages: list[str], as_user: bool = False
) -> list[str]:
"""
This returns a list of flatpak app ids, that need to be removed since they are installed but not found in either the list of ignored packages or the list of flatpak packages that need to be installed.
This returns a list of flatpak app ids, that need to be removed since they are installed but not found in either the list of ignored packages,
the list of system packages or the list of user packages that need to be installed.
"""
result: list[str] = []
for package in currently_installed_packages:
if package in self.ignored_flatpak_packages:
continue
if package not in self._all_flatpak_packages():
if package not in self._all_flatpak_packages(as_user):
result.append(package)
return result
@@ -702,12 +705,18 @@ class Source:
result.update(module.pacman_packages())
return result
def _all_flatpak_packages(self) -> set[str]:
def _all_flatpak_packages(self, as_user: bool = False) -> set[str]:
result = set()
result.update(self.flatpak_packages)
result.update(
self.flatpak_packages if not as_user else self.flatpak_user_packages
)
for module in self.modules:
if module.enabled:
result.update(module.flatpak_packages())
result.update(
module.flatpak_packages()
if not as_user
else module.flatpak_user_packages()
)
return result
@@ -969,14 +978,14 @@ class Flatpak:
def __init__(self) -> None:
pass
def get_installed(self) -> list[str]:
def get_installed(self, as_user: bool = False) -> list[str]:
"""
Return all of the installed applications. Dependencies and runtimes are exluded since they will not be explicitly installed and thus flatpak will manage them.
"""
try:
packages = (
subprocess.run(
conf.commands.list_flatpak_pkgs(),
conf.commands.list_flatpak_pkgs(as_user),
check=True,
stdout=subprocess.PIPE,
)
@@ -995,7 +1004,7 @@ class Flatpak:
user_facing_msg=f"Failed to get installed flatpak packages using '{error.cmd}'. Output: {error.stdout}."
) from error
def install(self, packages: list[str]):
def install(self, packages: list[str], as_user: bool = False):
"""
Install the listed flatpak packages.
"""
@@ -1003,7 +1012,7 @@ class Flatpak:
return
returncode, _output = echo_and_capture_command(
conf.commands.install_flatpak_pkgs(packages)
conf.commands.install_flatpak_pkgs(packages, as_user)
)
if returncode != 0:
raise err.UserFacingError(
@@ -1020,7 +1029,7 @@ class Flatpak:
f"Failed to upgrade flatpak packages. Process exited with code {returncode}."
)
def remove(self, packages: list[str]):
def remove(self, packages: list[str], as_user: bool = False):
"""
Remove all the listed packages and their unused dependecies. This has to happen in two steps.
"""
@@ -1028,7 +1037,7 @@ class Flatpak:
return
returncode, _output = echo_and_capture_command(
conf.commands.remove_flatpak(packages)
conf.commands.remove_flatpak(packages, as_user)
)
if not returncode == 0:
+2
View File
@@ -141,6 +141,7 @@ class TestSource(unittest.TestCase):
files={},
directories={},
flatpak_packages={"f1", "f2", "f3"},
flatpak_user_packages={"fu1", "fu2", "fu3"},
ignored_flatpak_packages={"i1", "i2"},
)
@@ -290,6 +291,7 @@ class TestModuleUserServices(unittest.TestCase):
directories={},
modules={self.ModuleWithUserServiceOne(), self.ModuleWithUserServiceTwo()},
flatpak_packages=set(),
flatpak_user_packages=set(),
ignored_flatpak_packages=set(),
)
self.store = Store()