chore: tier map for plugins that are not pinned yet

This commit is contained in:
LukeGus committed 2026-11-06 18:18:51 -06:00
1 parent 950e5398c9
commit 76d41a2cbb
6 files changed
+179 -12

No files matched your search

+57 -5
View File
@@ -161,6 +161,46 @@ function loadBundledPlugins(root) {
return plugins;
}
/**
* docker/plugin-tiers.json: tier and onboarding for official plugins that are
* not pinned yet, used the first time `--all` pins them.
*/
function parsePluginTiers(raw) {
const problems = [];
const tiers = {};
const map = raw?.plugins;
if (!map || typeof map !== "object" || Array.isArray(map)) {
return { tiers, problems: ['plugin-tiers.json needs a "plugins" object'] };
}
for (const [id, entry] of Object.entries(map)) {
if (!ID.test(id) || !entry || typeof entry !== "object") {
problems.push(`${id} needs an object`);
continue;
}
if (!PROFILES.includes(entry.tier)) {
problems.push(`${id} tier must be one of ${PROFILES.join(", ")}`);
continue;
}
const before = problems.length;
const onboarding = parseOnboarding(entry.onboarding, id, problems);
if (problems.length > before) continue;
tiers[id] = { tier: entry.tier, ...(onboarding ? { onboarding } : {}) };
}
return { tiers, problems };
}
function loadPluginTiers(root) {
const file = path.join(root, "docker", "plugin-tiers.json");
if (!fs.existsSync(file)) return {};
const { tiers, problems } = parsePluginTiers(
JSON.parse(fs.readFileSync(file, "utf8")),
);
if (problems.length > 0) {
throw new Error(`docker/plugin-tiers.json:\n ${problems.join("\n ")}`);
}
return tiers;
}
/** Refuses an artifact whose bytes are not the ones the config pinned. */
function checkSha256(buffer, expected, id) {
const actual = crypto.createHash("sha256").update(buffer).digest("hex");
@@ -286,12 +326,19 @@ function pluginsForProfile(plugins, profile) {
* Pins the newest registry version of each wanted plugin. `ids` is the list
* to pin, or null for every plugin in the index. `current` is the existing
* pin list, so fields the registry does not know (onboarding, tier) carry over;
* a plugin new to the list starts in the full tier. coreVersion, when given,
* a plugin new to the list takes them from `defaults` (plugin-tiers.json),
* else starts in the full tier. coreVersion, when given,
* skips releases whose engine.termix range does not include it, so the image
* never ships a plugin its own core cannot run. With ids null, a plugin new to
* the list that has no usable release (only betas, say) is left out.
*/
function pinsFromIndex(index, ids, current = [], coreVersion = null) {
function pinsFromIndex(
index,
ids,
current = [],
coreVersion = null,
defaults = {},
) {
const plugins = Array.isArray(index?.plugins) ? index.plugins : [];
const byId = new Map(plugins.map((plugin) => [plugin.id, plugin]));
const currentById = new Map(current.map((entry) => [entry.id, entry]));
@@ -315,9 +362,12 @@ function pinsFromIndex(index, ids, current = [], coreVersion = null) {
if (ids === null && !currentById.has(id)) return null;
throw new Error(`${id} is not in the registry index`);
}
const onboarding = currentById.get(id)?.onboarding;
const defaultLook = currentById.get(id)?.defaultLook === true;
const tier = currentById.get(id)?.tier ?? "full";
const existing = currentById.get(id);
const onboarding = existing
? existing.onboarding
: defaults[id]?.onboarding;
const defaultLook = existing?.defaultLook === true;
const tier = existing?.tier ?? defaults[id]?.tier ?? "full";
return {
id,
source: "tmxplug",
@@ -485,6 +535,8 @@ module.exports = {
buildBundledIndex,
pinsFromIndex,
loadBundledPlugins,
parsePluginTiers,
loadPluginTiers,
checkSha256,
fetchArtifact,
extractArtifact,