mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 10:06:15 -08:00
feat(packaging): define Linux frame-copy profiles
This commit is contained in:
1 parent
a3fbfb1bdc
commit
81f970d281
4 files changed
+254
-1
No files matched your search
@@ -98,6 +98,15 @@
|
||||
"artifactName": "${name}-${version}-${os}-${arch}.${ext}",
|
||||
"icon": "apps/web/src/assets/icons"
|
||||
},
|
||||
"deb": {
|
||||
"fpm": ["--depends=libmpv2"]
|
||||
},
|
||||
"rpm": {
|
||||
"fpm": ["--depends=mpv-libs"]
|
||||
},
|
||||
"pacman": {
|
||||
"fpm": ["--depends=mpv"]
|
||||
},
|
||||
"flatpak": {
|
||||
"branch": "stable",
|
||||
"runtime": "org.freedesktop.Platform",
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
'use strict';
|
||||
|
||||
function createProfile(name, runtimeMode, targets, manifestOrigin) {
|
||||
return Object.freeze({
|
||||
name,
|
||||
runtimeMode,
|
||||
targets: Object.freeze([...targets]),
|
||||
manifestOrigin,
|
||||
});
|
||||
}
|
||||
|
||||
const LINUX_FRAME_COPY_PROFILES = Object.freeze({
|
||||
system: createProfile(
|
||||
'system',
|
||||
'system',
|
||||
['deb', 'rpm', 'pacman'],
|
||||
'system-libmpv-frame-copy'
|
||||
),
|
||||
portable: createProfile(
|
||||
'portable',
|
||||
'bundled',
|
||||
['appimage', 'snap'],
|
||||
'bundled-lgpl-frame-copy'
|
||||
),
|
||||
flatpak: createProfile(
|
||||
'flatpak',
|
||||
'bundled',
|
||||
['flatpak'],
|
||||
'bundled-lgpl-frame-copy'
|
||||
),
|
||||
});
|
||||
const SUPPORTED_PROFILE_NAMES = Object.freeze(
|
||||
Object.keys(LINUX_FRAME_COPY_PROFILES)
|
||||
);
|
||||
|
||||
const LINUX_SYSTEM_PACKAGE_DEPENDENCIES = Object.freeze({
|
||||
deb: 'libmpv2',
|
||||
rpm: 'mpv-libs',
|
||||
pacman: 'mpv',
|
||||
});
|
||||
|
||||
function expectedProfileNames() {
|
||||
return SUPPORTED_PROFILE_NAMES.map((name) => `"${name}"`).join(', ');
|
||||
}
|
||||
|
||||
function findLinuxFrameCopyProfile(value) {
|
||||
if (value == null || (typeof value === 'string' && value.trim() === '')) {
|
||||
throw new Error(
|
||||
`Linux frame-copy profile is required. Expected one of: ${expectedProfileNames()}.`
|
||||
);
|
||||
}
|
||||
|
||||
const name = typeof value === 'string' ? value.trim() : String(value);
|
||||
const profile = LINUX_FRAME_COPY_PROFILES[name];
|
||||
if (!profile) {
|
||||
throw new Error(
|
||||
`Unsupported Linux frame-copy profile "${name}". Expected one of: ${expectedProfileNames()}.`
|
||||
);
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
function resolveLinuxFrameCopyProfile(value) {
|
||||
const profile = findLinuxFrameCopyProfile(value);
|
||||
return createProfile(
|
||||
profile.name,
|
||||
profile.runtimeMode,
|
||||
profile.targets,
|
||||
profile.manifestOrigin
|
||||
);
|
||||
}
|
||||
|
||||
function validateLinuxProfileTargets(profileName, targetNames) {
|
||||
const profile = findLinuxFrameCopyProfile(profileName);
|
||||
if (!Array.isArray(targetNames)) {
|
||||
throw new TypeError('Linux frame-copy targets must be an array.');
|
||||
}
|
||||
|
||||
const allowedTargets = new Set(profile.targets);
|
||||
return targetNames.flatMap((targetName) => {
|
||||
const normalizedTarget = String(targetName).trim().toLowerCase();
|
||||
if (allowedTargets.has(normalizedTarget)) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
`Linux frame-copy profile "${profile.name}" cannot build target "${normalizedTarget}".`,
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
LINUX_FRAME_COPY_PROFILES,
|
||||
LINUX_SYSTEM_PACKAGE_DEPENDENCIES,
|
||||
resolveLinuxFrameCopyProfile,
|
||||
validateLinuxProfileTargets,
|
||||
};
|
||||
@@ -0,0 +1,146 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import { createRequire } from 'node:module';
|
||||
import { dirname, join } from 'node:path';
|
||||
import test from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const currentDir = dirname(fileURLToPath(import.meta.url));
|
||||
const require = createRequire(import.meta.url);
|
||||
const {
|
||||
LINUX_FRAME_COPY_PROFILES,
|
||||
LINUX_SYSTEM_PACKAGE_DEPENDENCIES,
|
||||
resolveLinuxFrameCopyProfile,
|
||||
validateLinuxProfileTargets,
|
||||
} = require('./linux-frame-copy-profile.cjs');
|
||||
const electronBuilderConfig = JSON.parse(
|
||||
fs.readFileSync(
|
||||
join(currentDir, '..', '..', 'electron-builder.json'),
|
||||
'utf8'
|
||||
)
|
||||
);
|
||||
|
||||
test('defines the exact immutable Linux frame-copy profile matrix', () => {
|
||||
assert.deepEqual(LINUX_FRAME_COPY_PROFILES, {
|
||||
system: {
|
||||
name: 'system',
|
||||
runtimeMode: 'system',
|
||||
targets: ['deb', 'rpm', 'pacman'],
|
||||
manifestOrigin: 'system-libmpv-frame-copy',
|
||||
},
|
||||
portable: {
|
||||
name: 'portable',
|
||||
runtimeMode: 'bundled',
|
||||
targets: ['appimage', 'snap'],
|
||||
manifestOrigin: 'bundled-lgpl-frame-copy',
|
||||
},
|
||||
flatpak: {
|
||||
name: 'flatpak',
|
||||
runtimeMode: 'bundled',
|
||||
targets: ['flatpak'],
|
||||
manifestOrigin: 'bundled-lgpl-frame-copy',
|
||||
},
|
||||
});
|
||||
assert.equal(Object.isFrozen(LINUX_FRAME_COPY_PROFILES), true);
|
||||
for (const profile of Object.values(LINUX_FRAME_COPY_PROFILES)) {
|
||||
assert.equal(Object.isFrozen(profile), true);
|
||||
assert.equal(Object.isFrozen(profile.targets), true);
|
||||
}
|
||||
});
|
||||
|
||||
test('defines immutable system-package libmpv dependencies', () => {
|
||||
assert.deepEqual(LINUX_SYSTEM_PACKAGE_DEPENDENCIES, {
|
||||
deb: 'libmpv2',
|
||||
rpm: 'mpv-libs',
|
||||
pacman: 'mpv',
|
||||
});
|
||||
assert.equal(Object.isFrozen(LINUX_SYSTEM_PACKAGE_DEPENDENCIES), true);
|
||||
});
|
||||
|
||||
test('resolves each supported profile as an immutable defensive value', () => {
|
||||
const firstSystemProfile = resolveLinuxFrameCopyProfile('system');
|
||||
const secondSystemProfile = resolveLinuxFrameCopyProfile('system');
|
||||
|
||||
assert.deepEqual(firstSystemProfile, {
|
||||
name: 'system',
|
||||
runtimeMode: 'system',
|
||||
targets: ['deb', 'rpm', 'pacman'],
|
||||
manifestOrigin: 'system-libmpv-frame-copy',
|
||||
});
|
||||
assert.deepEqual(resolveLinuxFrameCopyProfile('portable'), {
|
||||
name: 'portable',
|
||||
runtimeMode: 'bundled',
|
||||
targets: ['appimage', 'snap'],
|
||||
manifestOrigin: 'bundled-lgpl-frame-copy',
|
||||
});
|
||||
assert.deepEqual(resolveLinuxFrameCopyProfile('flatpak'), {
|
||||
name: 'flatpak',
|
||||
runtimeMode: 'bundled',
|
||||
targets: ['flatpak'],
|
||||
manifestOrigin: 'bundled-lgpl-frame-copy',
|
||||
});
|
||||
assert.notEqual(firstSystemProfile, LINUX_FRAME_COPY_PROFILES.system);
|
||||
assert.notEqual(firstSystemProfile, secondSystemProfile);
|
||||
assert.notEqual(
|
||||
firstSystemProfile.targets,
|
||||
LINUX_FRAME_COPY_PROFILES.system.targets
|
||||
);
|
||||
assert.notEqual(firstSystemProfile.targets, secondSystemProfile.targets);
|
||||
assert.equal(Object.isFrozen(firstSystemProfile), true);
|
||||
assert.equal(Object.isFrozen(firstSystemProfile.targets), true);
|
||||
assert.throws(() => firstSystemProfile.targets.push('appimage'), TypeError);
|
||||
assert.deepEqual(resolveLinuxFrameCopyProfile('system').targets, [
|
||||
'deb',
|
||||
'rpm',
|
||||
'pacman',
|
||||
]);
|
||||
});
|
||||
|
||||
test('rejects missing and unsupported profile names with clear errors', () => {
|
||||
for (const value of [undefined, null, '', ' ']) {
|
||||
assert.throws(
|
||||
() => resolveLinuxFrameCopyProfile(value),
|
||||
/Linux frame-copy profile is required/
|
||||
);
|
||||
}
|
||||
assert.throws(
|
||||
() => resolveLinuxFrameCopyProfile('standard'),
|
||||
/Unsupported Linux frame-copy profile "standard"/
|
||||
);
|
||||
});
|
||||
|
||||
test('validates profile targets case-insensitively with deterministic errors', () => {
|
||||
const targets = ['DEB', 'AppImage', 'RPM'];
|
||||
|
||||
assert.deepEqual(validateLinuxProfileTargets('system', targets), [
|
||||
'Linux frame-copy profile "system" cannot build target "appimage".',
|
||||
]);
|
||||
assert.deepEqual(targets, ['DEB', 'AppImage', 'RPM']);
|
||||
assert.deepEqual(
|
||||
validateLinuxProfileTargets('portable', ['APPIMAGE', 'sNaP']),
|
||||
[]
|
||||
);
|
||||
assert.deepEqual(validateLinuxProfileTargets('flatpak', ['FlatPak']), []);
|
||||
});
|
||||
|
||||
test('rejects a non-array profile target list', () => {
|
||||
assert.throws(
|
||||
() => validateLinuxProfileTargets('system', 'deb'),
|
||||
/Linux frame-copy targets must be an array/
|
||||
);
|
||||
});
|
||||
|
||||
test('adds only libmpv-specific package dependencies without replacing electron-builder defaults', () => {
|
||||
for (const [target, dependency] of Object.entries(
|
||||
LINUX_SYSTEM_PACKAGE_DEPENDENCIES
|
||||
)) {
|
||||
assert.equal(
|
||||
electronBuilderConfig[target]?.depends,
|
||||
undefined,
|
||||
`${target}.depends must remain unset so electron-builder keeps its defaults`
|
||||
);
|
||||
assert.deepEqual(electronBuilderConfig[target]?.fpm, [
|
||||
`--depends=${dependency}`,
|
||||
]);
|
||||
}
|
||||
});
|
||||
@@ -21,11 +21,13 @@
|
||||
"{workspaceRoot}/tools/packaging/asar-dependency-closure.test.mjs",
|
||||
"{workspaceRoot}/tools/packaging/embedded-mpv-packaging.cjs",
|
||||
"{workspaceRoot}/tools/packaging/embedded-mpv-arch.test.mjs",
|
||||
"{workspaceRoot}/tools/packaging/linux-frame-copy-profile.cjs",
|
||||
"{workspaceRoot}/tools/packaging/linux-frame-copy-profile.test.mjs",
|
||||
"{workspaceRoot}/tools/embedded-mpv/stage-runtime.mjs",
|
||||
"{workspaceRoot}/tools/embedded-mpv/stage-windows-runtime-archive.mjs"
|
||||
],
|
||||
"options": {
|
||||
"command": "node --test tools/packaging/electron-package-identity.test.mjs tools/packaging/asar-dependency-closure.test.mjs tools/packaging/embedded-mpv-arch.test.mjs",
|
||||
"command": "node --test tools/packaging/electron-package-identity.test.mjs tools/packaging/asar-dependency-closure.test.mjs tools/packaging/embedded-mpv-arch.test.mjs tools/packaging/linux-frame-copy-profile.test.mjs",
|
||||
"cwd": "{workspaceRoot}"
|
||||
}
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user