Line data Source code
1 : /*
2 : * Copyright (C) 2025 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 :
6 55 : import cockpit from 'cockpit';
7 :
8 : import { PackageManager, InstallProgressType, UnsupportedError, NotFoundError } from './_internal/packagemanager-abstract';
9 : import { Dnf5DaemonManager } from './_internal/dnf5daemon';
10 : import { PackageKitManager } from './_internal/packagekit';
11 :
12 55 : let package_manager: PackageManager | null = null;
13 :
14 19 : function debug(...args: unknown[]) {
15 2 : if (window.debugging == 'all' || window.debugging?.includes('packagemanager'))
16 2 : console.debug('packagemanager', ...args);
17 19 : }
18 :
19 20 : async function is_immutable_os() {
20 20 : try {
21 20 : const options = await cockpit.spawn(["findmnt", "-T", "/usr", "-n", "-o", "VFS-OPTIONS"]);
22 20 : return options.split(",").indexOf("ro") >= 0;
23 2 : } catch (err) {
24 2 : debug("Unable to detect immutable OS", err);
25 2 : return false;
26 2 : }
27 20 : }
28 :
29 20 : async function detect_dnf5daemon() {
30 20 : const client = cockpit.dbus("org.rpm.dnf.v0", { superuser: "try" });
31 20 : let detected = false;
32 20 : try {
33 20 : await client.call("/org/rpm/dnf/v0", "org.freedesktop.DBus.Peer", "Ping", []);
34 20 : detected = true;
35 2 : } catch (err) {
36 2 : debug("dnf5daemon not supported", err);
37 2 : }
38 :
39 20 : client.close();
40 20 : return detected;
41 20 : }
42 :
43 20 : async function detect_packagekit() {
44 20 : const client = cockpit.dbus("org.freedesktop.PackageKit", { superuser: "try" });
45 20 : let detected = false;
46 20 : try {
47 20 : await client.call("/org/freedesktop/PackageKit", "org.freedesktop.DBus.Properties",
48 20 : "Get", ["org.freedesktop.PackageKit", "VersionMajor"]);
49 15 : detected = true;
50 2 : } catch (err) {
51 6 : debug("PackageKit not supported", err);
52 6 : }
53 :
54 19 : client.close();
55 19 : return detected;
56 20 : }
57 :
58 : // Cache result for a session
59 : // HACK: allow overriding the package manager to make the software updates page
60 : // keep using PackageKit until the dnf5daemon API is sufficient.
61 20 : export async function getPackageManager(force_packagekit: boolean = false): Promise<PackageManager> {
62 20 : if (package_manager !== null)
63 11 : return Promise.resolve(package_manager);
64 :
65 20 : const [unsupported, has_dnf5daemon, has_packagekit] = await Promise.all([is_immutable_os(), detect_dnf5daemon(), detect_packagekit()]);
66 :
67 19 : if (unsupported)
68 2 : throw new UnsupportedError("Cockpit does not support installing additional packages on immutable operating systems");
69 :
70 19 : if (has_dnf5daemon && !force_packagekit) {
71 19 : debug("constructing dnf5daemon");
72 19 : package_manager = new Dnf5DaemonManager();
73 19 : return Promise.resolve(package_manager);
74 19 : }
75 :
76 2 : if (has_packagekit) {
77 2 : debug("constructing packagekit");
78 2 : package_manager = new PackageKitManager();
79 2 : return Promise.resolve(package_manager);
80 2 : }
81 :
82 2 : throw new NotFoundError("No package manager found");
83 20 : }
84 :
85 : export { InstallProgressType };
|