Skip to content

Commit

Permalink
lib: Generalize manifest config reading
Browse files Browse the repository at this point in the history
We already use that on the storaged and apps pages, and going to add it
to metrics as well. As storage and apps want to look at different
os-release fields, start with a very generic "matchlist" API. We may later add
an async convenience wrapper which reads os-release by itself and matches on
common fields.

While at it, factorize the duplicated config reading in apps to a
get_packages() helper, consistently use `async`, and split the imports
into "library" and "page specific".
  • Loading branch information
martinpitt committed May 29, 2024
1 parent eb33baf commit 45096b7
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 59 deletions.
70 changes: 30 additions & 40 deletions pkg/apps/application-list.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ import { Stack, StackItem } from "@patternfly/react-core/dist/esm/layouts/Stack/

import { RebootingIcon } from "@patternfly/react-icons";

import { check_uninstalled_packages } from "packagekit.js";
import { check_uninstalled_packages } from "packagekit";
import { get_manifest_config_matchlist } from "utils";
import { read_os_release } from "os-release";
import { EmptyStatePanel } from "cockpit-components-empty-state.jsx";
import { useInit } from "hooks";

import * as PackageKit from "./packagekit.js";
import { read_os_release } from "os-release.js";
import { icon_url, show_error, launch, ProgressBar, CancelButton } from "./utils.jsx";
import { ActionButton } from "./application.jsx";
import { EmptyStatePanel } from "cockpit-components-empty-state.jsx";
import { useInit } from "../lib/hooks.js";

const _ = cockpit.gettext;

Expand Down Expand Up @@ -103,25 +105,6 @@ export const ApplicationList = ({ metainfo_db, appProgress, appProgressTitle, ac
comps.push(metainfo_db.components[id]);
comps.sort((a, b) => a.name.localeCompare(b.name));

function get_config(name, os_release, def) {
// ID is a single value, ID_LIKE is a list
const os_list = [os_release?.ID || "", ...(os_release?.ID_LIKE || "").split(/\s+/)];

if (cockpit.manifests.apps && cockpit.manifests.apps.config) {
const val = cockpit.manifests.apps.config[name];
if (typeof val === 'object' && val !== null && !Array.isArray(val)) {
for (const os of os_list) {
if (val[os])
return val[os];
}
return def;
}
return val !== undefined ? val : def;
} else {
return def;
}
}

async function check_missing_data(packages) {
try {
const missing = await check_uninstalled_packages(packages);
Expand All @@ -131,26 +114,33 @@ export const ApplicationList = ({ metainfo_db, appProgress, appProgressTitle, ac
}
}

useInit(async () => {
async function get_packages() {
const os_release = await read_os_release();
const configPackages = get_config('appstream_config_packages', os_release, []);
const dataPackages = get_config('appstream_data_packages', os_release, []);
await check_missing_data([...dataPackages, ...configPackages]);
// ID is a single value, ID_LIKE is a list
const os_list = [os_release?.ID, ...(os_release?.ID_LIKE || "").split(/\s+/)];
const configPackages = get_manifest_config_matchlist('apps', 'appstream_config_packages', [], os_list);
const dataPackages = get_manifest_config_matchlist('apps', 'appstream_data_packages', [], os_list);
return [configPackages, dataPackages];
}

useInit(async () => {
const [config, data] = await get_packages();
await check_missing_data([...config, ...data]);
});

function refresh() {
read_os_release().then(os_release => {
const configPackages = get_config('appstream_config_packages', os_release, []);
const dataPackages = get_config('appstream_data_packages', os_release, []);
PackageKit.refresh(metainfo_db.origin_files,
configPackages,
dataPackages,
setProgress)
.finally(async () => {
await check_missing_data([...dataPackages, ...configPackages]);
setProgress(false);
}).catch(show_error);
});
async function refresh() {
const [configPackages, dataPackages] = await get_packages();
try {
await PackageKit.refresh(metainfo_db.origin_files,
configPackages,
dataPackages,
setProgress);
} catch (e) {
show_error(e);
} finally {
await check_missing_data([...dataPackages, ...configPackages]);
setProgress(false);
}
}

let refresh_progress, refresh_button, tbody;
Expand Down
38 changes: 38 additions & 0 deletions pkg/lib/utils.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import React from "react";

import cockpit from "cockpit";

export function fmt_to_fragments(fmt) {
const args = Array.prototype.slice.call(arguments, 1);

Expand All @@ -31,3 +33,39 @@ export function fmt_to_fragments(fmt) {

return React.createElement.apply(null, [React.Fragment, { }].concat(fmt.split(/(\$[0-9]+)/g).map(replace)));
}

function try_fields(dict, fields, def) {
for (let i = 0; i < fields.length; i++)
if (fields[i] && dict[fields[i]])
return dict[fields[i]];
return def;
}

/**
* Get an entry from a manifest's ".config[config_name]" field.
*
* This can either be a direct value, e.g.
*
* "config": { "color": "yellow" }
*
* Or an object indexed by any value in "matches". Commonly these are fields
* from os-release(5) like PLATFORM_ID or ID; e.g.
*
* "config": {
* "fedora": { "color": "blue" },
* "platform:el9": { "color": "red" }
* }
*/
export function get_manifest_config_matchlist(manifest_name, config_name, default_value, matches) {
const config = cockpit.manifests[manifest_name]?.config;

if (config) {
const val = config[config_name];
if (typeof val === 'object' && val !== null && !Array.isArray(val))
return try_fields(val, matches, default_value);
else
return val !== undefined ? val : default_value;
} else {
return default_value;
}
}
23 changes: 4 additions & 19 deletions pkg/storaged/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
*/

import cockpit from 'cockpit';
import * as PK from 'packagekit.js';
import * as PK from 'packagekit';
import { superuser } from 'superuser';
import { get_manifest_config_matchlist } from 'utils';

import * as utils from './utils.js';

Expand Down Expand Up @@ -1473,24 +1474,8 @@ client.wait_for = function wait_for(cond) {
});
};

function try_fields(dict, fields, def) {
for (let i = 0; i < fields.length; i++)
if (fields[i] && dict[fields[i]])
return dict[fields[i]];
return def;
}

client.get_config = (name, def) => {
if (cockpit.manifests.storage && cockpit.manifests.storage.config) {
const val = cockpit.manifests.storage.config[name];
if (typeof val === 'object' && val !== null)
return try_fields(val, [client.os_release.PLATFORM_ID, client.os_release.ID], def);
else
return val !== undefined ? val : def;
} else {
return def;
}
};
client.get_config = (name, def) =>
get_manifest_config_matchlist("storage", name, def, [client.os_release.PLATFORM_ID, client.os_release.ID]);

client.in_anaconda_mode = () => !!client.anaconda;

Expand Down

0 comments on commit 45096b7

Please sign in to comment.