mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-06-12 19:55:19 +02:00
add pacman maker for Arch Linux packages (#604)
Custom Electron Forge maker that wraps makepkg to produce a .pkg.tar.zst with /opt/<app>, /usr/bin wrapper, .desktop entry, and hicolor icon. Only activates on Linux when makepkg is present, so other platforms are unaffected.
This commit is contained in:
parent
80fef06da0
commit
0aec665220
4 changed files with 153 additions and 0 deletions
|
|
@ -86,6 +86,21 @@ module.exports = {
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: require.resolve('./makers/maker-pacman.cjs'),
|
||||
platforms: ['linux'],
|
||||
config: {
|
||||
name: 'rowboat',
|
||||
bin: 'rowboat',
|
||||
executableName: 'rowboat',
|
||||
description: 'AI coworker with memory',
|
||||
maintainer: 'rowboatlabs',
|
||||
homepage: 'https://rowboatlabs.com',
|
||||
license: 'Apache',
|
||||
icon: path.join(__dirname, 'icons/icon.png'),
|
||||
mimeType: ['x-scheme-handler/rowboat'],
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-zip',
|
||||
platform: ["darwin", "win32", "linux"],
|
||||
|
|
|
|||
134
apps/x/apps/main/makers/maker-pacman.cjs
Normal file
134
apps/x/apps/main/makers/maker-pacman.cjs
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
// Custom Electron Forge maker that produces Arch Linux .pkg.tar.zst packages
|
||||
// via makepkg. Runs only on Linux with makepkg available (i.e. an Arch host).
|
||||
//
|
||||
// CJS on purpose: forge.config.cjs require()s us.
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
const MakerBase = require('@electron-forge/maker-base').default;
|
||||
|
||||
const ARCH_MAP = { x64: 'x86_64', arm64: 'aarch64', ia32: 'i686', armv7l: 'armv7h' };
|
||||
|
||||
class MakerPacman extends MakerBase {
|
||||
name = 'pacman';
|
||||
defaultPlatforms = ['linux'];
|
||||
|
||||
isSupportedOnCurrentPlatform() {
|
||||
if (process.platform !== 'linux') return false;
|
||||
try {
|
||||
execSync('command -v makepkg', { stdio: 'ignore' });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async make({ dir, makeDir, targetArch, packageJSON, appName }) {
|
||||
const pkgArch = ARCH_MAP[targetArch] || targetArch;
|
||||
|
||||
const cfg = this.config || {};
|
||||
const pkgName = (cfg.name || appName || packageJSON.name).toLowerCase();
|
||||
// pacman pkgver disallows '-'; map prerelease tags through.
|
||||
const pkgVersion = String(packageJSON.version || '0.0.0').replace(/-/g, '_');
|
||||
const pkgDesc = (cfg.description || packageJSON.description || '').replace(/"/g, '\\"');
|
||||
const maintainer = cfg.maintainer || 'unknown';
|
||||
const homepage = cfg.homepage || packageJSON.homepage || '';
|
||||
const license = cfg.license || 'custom';
|
||||
const bin = cfg.bin || pkgName;
|
||||
const execName = cfg.executableName || appName || pkgName;
|
||||
const mimeTypes = cfg.mimeType || [];
|
||||
const depends = cfg.depends || [];
|
||||
const iconSrc = cfg.icon;
|
||||
|
||||
const outDir = path.resolve(path.join(makeDir, 'pacman', targetArch));
|
||||
await this.ensureDirectory(outDir);
|
||||
|
||||
// Clean prior contents so makepkg starts fresh each run.
|
||||
for (const f of fs.readdirSync(outDir)) {
|
||||
fs.rmSync(path.join(outDir, f), { recursive: true, force: true });
|
||||
}
|
||||
|
||||
// Wrapper script — execs the packaged Electron binary, forwards args (incl. rowboat:// URLs).
|
||||
fs.writeFileSync(
|
||||
path.join(outDir, bin),
|
||||
`#!/bin/sh\nexec "/opt/${pkgName}/${execName}" "$@"\n`,
|
||||
{ mode: 0o755 },
|
||||
);
|
||||
|
||||
const desktop = [
|
||||
'[Desktop Entry]',
|
||||
`Name=${appName || pkgName}`,
|
||||
`Comment=${pkgDesc}`,
|
||||
`Exec=${bin} %U`,
|
||||
`Icon=${pkgName}`,
|
||||
'Type=Application',
|
||||
'Categories=Utility;',
|
||||
'Terminal=false',
|
||||
mimeTypes.length ? `MimeType=${mimeTypes.join(';')};` : null,
|
||||
'',
|
||||
].filter(Boolean).join('\n');
|
||||
fs.writeFileSync(path.join(outDir, `${pkgName}.desktop`), desktop);
|
||||
|
||||
const sources = [bin, `${pkgName}.desktop`];
|
||||
let iconInstall = '';
|
||||
if (iconSrc && fs.existsSync(iconSrc)) {
|
||||
fs.copyFileSync(iconSrc, path.join(outDir, 'icon.png'));
|
||||
sources.push('icon.png');
|
||||
iconInstall = ` install -Dm644 "$srcdir/icon.png" "$pkgdir/usr/share/icons/hicolor/512x512/apps/${pkgName}.png"`;
|
||||
}
|
||||
|
||||
const sumsLine = sources.map(() => "'SKIP'").join(' ');
|
||||
const sourceLine = sources.map((s) => `'${s}'`).join(' ');
|
||||
const dependsLine = depends.map((d) => `'${d}'`).join(' ');
|
||||
// Embed the packager output dir as a bash-safe literal.
|
||||
const appDirEscaped = dir.replace(/'/g, `'\\''`);
|
||||
|
||||
const pkgbuild = `# Maintainer: ${maintainer}
|
||||
# Auto-generated by maker-pacman.cjs — do not edit by hand.
|
||||
pkgname=${pkgName}
|
||||
pkgver=${pkgVersion}
|
||||
pkgrel=1
|
||||
pkgdesc="${pkgDesc}"
|
||||
arch=('${pkgArch}')
|
||||
url="${homepage}"
|
||||
license=('${license}')
|
||||
depends=(${dependsLine})
|
||||
options=('!strip' '!debug')
|
||||
source=(${sourceLine})
|
||||
sha256sums=(${sumsLine})
|
||||
|
||||
_appdir='${appDirEscaped}'
|
||||
|
||||
package() {
|
||||
install -dm755 "$pkgdir/opt/$pkgname"
|
||||
cp -a "$_appdir/." "$pkgdir/opt/$pkgname/"
|
||||
|
||||
# Electron's sandbox helper needs setuid root for the namespace sandbox.
|
||||
if [ -f "$pkgdir/opt/$pkgname/chrome-sandbox" ]; then
|
||||
chmod 4755 "$pkgdir/opt/$pkgname/chrome-sandbox"
|
||||
fi
|
||||
|
||||
install -Dm755 "$srcdir/${bin}" "$pkgdir/usr/bin/${bin}"
|
||||
install -Dm644 "$srcdir/${pkgName}.desktop" "$pkgdir/usr/share/applications/${pkgName}.desktop"
|
||||
${iconInstall}
|
||||
}
|
||||
`;
|
||||
fs.writeFileSync(path.join(outDir, 'PKGBUILD'), pkgbuild);
|
||||
|
||||
execSync('makepkg -f --noconfirm --nodeps', {
|
||||
cwd: outDir,
|
||||
stdio: 'inherit',
|
||||
env: { ...process.env, PKGEXT: '.pkg.tar.zst', CARCH: pkgArch },
|
||||
});
|
||||
|
||||
return fs
|
||||
.readdirSync(outDir)
|
||||
.filter((f) => f.endsWith('.pkg.tar.zst'))
|
||||
.map((f) => path.join(outDir, f));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MakerPacman;
|
||||
module.exports.default = MakerPacman;
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@electron-forge/cli": "^7.10.2",
|
||||
"@electron-forge/maker-base": "^7.11.1",
|
||||
"@electron-forge/maker-deb": "^7.11.1",
|
||||
"@electron-forge/maker-dmg": "^7.10.2",
|
||||
"@electron-forge/maker-rpm": "^7.11.1",
|
||||
|
|
|
|||
3
apps/x/pnpm-lock.yaml
generated
3
apps/x/pnpm-lock.yaml
generated
|
|
@ -95,6 +95,9 @@ importers:
|
|||
'@electron-forge/cli':
|
||||
specifier: ^7.10.2
|
||||
version: 7.11.1(encoding@0.1.13)(esbuild@0.24.2)
|
||||
'@electron-forge/maker-base':
|
||||
specifier: ^7.11.1
|
||||
version: 7.11.1
|
||||
'@electron-forge/maker-deb':
|
||||
specifier: ^7.11.1
|
||||
version: 7.11.1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue