mirror of
https://github.com/wekan/wekan.git
synced 2026-11-07 11:02:33 -05:00
One executable per platform: that platform's published bundle repackaged as a Node.js single executable application whose ZIP Node 26.11 mounts as a virtual file system (useVfs + vfsArchive). Only FerretDB is copied out, once and verified, to wekan-files/bin; native addons load from the VFS. Everything WeKan writes is in wekan-files beside the executable, which WRITABLE_PATH points at: attachments, avatars, db, bin, backup, logs, versions. WeKan now treats a WRITABLE_PATH named wekan-files as the files root (models/lib/filesRoot.js, shared by every place that derived it). Started in a terminal it shows a menu: start, stop, status, version info as Admin Panel / Version shows it, update to the newest release or change to any other (checksum verified, backed up first, the old executable kept), backup to wekan-files/backup/YYYY-MM-DD_HH-MM-SS, run at boot (systemd, launchd, Task Scheduler, cron, Termux:Boot), log, settings. Every entry is also a command. start runs the start-wekan.sh loop: recovery, requested restore, FerretDB, recovery page, WeKan, restart. Meteor's main.js chdir()s into the bundle, which a VFS cannot be, so the server role keeps a virtual working directory. Node 26.11.1 breaks fs.writev/readv while any VFS is mounted; they are rebuilt on fs.write and fs.read. single-file.yml builds every target in releases/single-file/targets.json from its verified bundle (Macs on a Mac, to re-sign), starts it where a runner exists with browser tests on amd64, and attaches what started. Release All and Release All Missing call it. Thanks to xet7 !
36 lines
1.6 KiB
JavaScript
36 lines
1.6 KiB
JavaScript
// Pure, dependency-free storage path computation (no Meteor imports) so it can
|
|
// be unit tested directly with plain Node. Used by the attachment storage
|
|
// settings (Admin Panel > Attachments) and kept in sync with the path logic in
|
|
// models/attachments.js, models/avatars.js and server/initializeDirs.js.
|
|
//
|
|
// #6473: the Admin Panel used to compute these paths ON THE CLIENT from
|
|
// process.env.WRITABLE_PATH, which never exists in a browser, so it always
|
|
// showed "/data" — a path that does not exist on a Snap install
|
|
// (WRITABLE_PATH=$SNAP_COMMON/files there). The real paths are:
|
|
// - Docker (WRITABLE_PATH=/data): /data/files/{attachments,avatars}
|
|
// - Snap (WRITABLE_PATH=$SNAP_COMMON/files): $SNAP_COMMON/files/{attachments,avatars}
|
|
// - Dev (WRITABLE_PATH unset): <cwd>/files/{attachments,avatars}
|
|
//
|
|
// Snap already appends '/files' to WRITABLE_PATH, so that case is detected and
|
|
// '/files' is not appended twice.
|
|
const path = require('path');
|
|
const { isFilesRoot } = require('./filesRoot');
|
|
|
|
/**
|
|
* Compute the real attachment/avatar storage paths for a given base path.
|
|
* @param {string} [basePath] WRITABLE_PATH (falls back to process.cwd())
|
|
* @return {{writablePath: string, attachments: string, avatars: string}}
|
|
*/
|
|
function computeStoragePaths(basePath) {
|
|
const base = basePath || process.cwd();
|
|
const endsWithFiles = isFilesRoot(base);
|
|
const root = endsWithFiles ? base : path.join(base, 'files');
|
|
return {
|
|
writablePath: base,
|
|
attachments: path.join(root, 'attachments'),
|
|
avatars: path.join(root, 'avatars'),
|
|
};
|
|
}
|
|
|
|
module.exports = { computeStoragePaths };
|