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