theseus/bundled-addons/pithos/core/paths.js
Local Dev 4ff75d312a Pithos 0.3.18: JSON key export, Linux desktop builds
Export JSON… gives scripts and agents one file with endpoint, key, secret
and drive. The desktop app now ships for Linux too (AppImage, .deb,
tar.gz), using per-user s3d paths there.
2026-10-04 22:49:48 +02:00

73 lines
3.2 KiB
JavaScript

// Where s3d keeps its config and data on each OS, mirroring the lookup in
// s3d's cmd/s3d/main.go (configSearchPaths / applicationDirectoryOS) so the
// GUI and a hand-run `s3d` always agree on which instance they are touching.
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
// s3d's Linux defaults (/etc/s3d, /var/lib/s3d) suit a system service. A
// desktop user who cannot write there, and has no system config, gets the
// XDG per-user places instead; new configs then name that directory
// explicitly, so a hand-run s3d with S3D_CONFIG_FILE agrees.
const xdg = (envName, fallback) => process.env[envName] || path.join(os.homedir(), ...fallback);
const userConfigFile = () => path.join(xdg('XDG_CONFIG_HOME', ['.config']), 's3d', 's3d.yml');
const userDataDir = () => path.join(xdg('XDG_DATA_HOME', ['.local', 'share']), 's3d');
function writable(p) {
// the nearest existing folder decides whether p could be created
for (let d = p; ; d = path.dirname(d)) {
if (fs.existsSync(d)) { try { fs.accessSync(d, fs.constants.W_OK); return true; } catch { return false; } }
if (path.dirname(d) === d) return false;
}
}
export function linuxUserMode() {
if (process.platform === 'win32' || process.platform === 'darwin') return false;
if (['/etc/s3d/s3d.yml', '/var/lib/s3d/s3d.yml'].some((p) => fs.existsSync(p))) return false;
return !(writable('/etc/s3d') && writable('/var/lib/s3d'));
}
export function defaultDataDir() {
switch (process.platform) {
case 'win32': return path.join(process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'), 's3d');
case 'darwin': return path.join(os.homedir(), 'Library', 'Application Support', 's3d');
default: return linuxUserMode() ? userDataDir() : '/var/lib/s3d';
}
}
export function configSearchPaths() {
const paths = [];
if (process.env.S3D_DATA_DIR) paths.push(path.join(process.env.S3D_DATA_DIR, 's3d.yml'));
switch (process.platform) {
case 'win32': paths.push(path.join(defaultDataDir(), 's3d.yml')); break;
case 'darwin': paths.push(path.join(defaultDataDir(), 's3d.yml')); break;
default:
if (linuxUserMode()) paths.push(userConfigFile());
paths.push('/etc/s3d/s3d.yml', '/var/lib/s3d/s3d.yml');
}
return paths;
}
// The config file this GUI manages: an explicit S3D_CONFIG_FILE wins, then the
// first existing search path, then the first search path (created on save).
export function resolveConfigPath(explicit) {
if (explicit) return path.resolve(explicit);
if (process.env.S3D_CONFIG_FILE) return path.resolve(process.env.S3D_CONFIG_FILE);
const candidates = configSearchPaths();
return candidates.find((p) => fs.existsSync(p)) || candidates[0];
}
const EXE = process.platform === 'win32' ? 's3d.exe' : 's3d';
// Binary lookup: explicit path, S3D_BIN, the vendored copy next to Pithos, then PATH.
export function resolveBinary(explicit, vendorDir) {
const tries = [explicit, process.env.S3D_BIN, vendorDir && path.join(vendorDir, EXE)].filter(Boolean);
for (const p of tries) if (fs.existsSync(p)) return path.resolve(p);
for (const dir of (process.env.PATH || '').split(path.delimiter)) {
if (!dir) continue;
const p = path.join(dir, EXE);
if (fs.existsSync(p)) return p;
}
return null;
}