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