98 lines
3.2 KiB
JavaScript
98 lines
3.2 KiB
JavaScript
'use strict'
|
|
|
|
const path = require('path')
|
|
const fs = require('fs')
|
|
|
|
// Packaged builds run from <portable root>/olcxja.plwl/resources/app.asar:
|
|
// the portable layout (<root>/files) is two levels above the resources dir
|
|
// and files bundled with the release are unpacked next to the asar.
|
|
function computeRoots() {
|
|
const m = __dirname.match(/^(.*)[/\\]app\.asar([/\\]|$)/)
|
|
if (m) {
|
|
const RESOURCES = path.resolve(m[1])
|
|
const APP_ROOT = path.resolve(RESOURCES, '..', '..')
|
|
return {
|
|
RESOURCES,
|
|
APP_ROOT,
|
|
// FILES = BUILD/files, so BUILD is the portable root itself.
|
|
BUILD: process.env.PLWL_BUILD_DIR || APP_ROOT,
|
|
// Bundled release files live inside the asar (Electron's patched fs
|
|
// can read them directly from the archive).
|
|
BUNDLED: fs.existsSync(path.join(RESOURCES, 'app.asar', 'files', 'translations'))
|
|
? path.join(RESOURCES, 'app.asar', 'files')
|
|
: path.join(APP_ROOT, 'files')
|
|
}
|
|
}
|
|
const APP_ROOT = path.resolve(__dirname, '..')
|
|
return {
|
|
RESOURCES: APP_ROOT,
|
|
APP_ROOT,
|
|
BUILD: process.env.PLWL_BUILD_DIR || path.join(APP_ROOT, 'build'),
|
|
BUNDLED: path.join(APP_ROOT, 'files')
|
|
}
|
|
}
|
|
|
|
const { RESOURCES, APP_ROOT, BUILD, BUNDLED } = computeRoots()
|
|
|
|
const FILES = path.join(BUILD, 'files')
|
|
const DATA = path.join(FILES, 'data')
|
|
|
|
const DIRS = {
|
|
BUILD,
|
|
APP_ROOT,
|
|
FILES,
|
|
DATA,
|
|
WINES: path.join(FILES, 'wines'),
|
|
PREFIXES: path.join(FILES, 'wineprefixes'),
|
|
APPS: path.join(FILES, 'apps'),
|
|
TRANSLATIONS: path.join(FILES, 'translations'),
|
|
BUNDLED_TRANSLATIONS: path.join(BUNDLED, 'translations'),
|
|
FAKE_STEAM: path.join(DATA, 'fake-steam')
|
|
}
|
|
|
|
function ensureDirs() {
|
|
for (const dir of [FILES, DATA, DIRS.WINES, DIRS.PREFIXES, DIRS.APPS, DIRS.TRANSLATIONS, DIRS.FAKE_STEAM]) {
|
|
fs.mkdirSync(dir, { recursive: true })
|
|
}
|
|
if (DIRS.TRANSLATIONS !== DIRS.BUNDLED_TRANSLATIONS) {
|
|
try {
|
|
for (const f of fs.readdirSync(DIRS.BUNDLED_TRANSLATIONS)) {
|
|
const dst = path.join(DIRS.TRANSLATIONS, f)
|
|
if (!fs.existsSync(dst)) fs.copyFileSync(path.join(DIRS.BUNDLED_TRANSLATIONS, f), dst)
|
|
}
|
|
} catch {}
|
|
}
|
|
}
|
|
|
|
// Portable paths: anything stored under FILES/ goes into the registry as a
|
|
// path RELATIVE to FILES (e.g. apps/<id>/game.exe), so moving the whole
|
|
// launcher folder keeps the library working. Absolute paths outside FILES
|
|
// (games left in place) are stored as-is. Resolve on read, normalize on write.
|
|
function toPortablePath(p) {
|
|
if (typeof p !== 'string' || !p || !path.isAbsolute(p)) return p
|
|
const rel = path.relative(FILES, p)
|
|
if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) return p
|
|
return rel
|
|
}
|
|
|
|
function resolvePortablePath(p) {
|
|
if (typeof p !== 'string' || !p || path.isAbsolute(p)) return p
|
|
return path.join(FILES, p)
|
|
}
|
|
|
|
function readJson(file, fallback) {
|
|
try {
|
|
return JSON.parse(fs.readFileSync(file, 'utf8'))
|
|
} catch {
|
|
return fallback
|
|
}
|
|
}
|
|
|
|
function writeJson(file, data) {
|
|
fs.mkdirSync(path.dirname(file), { recursive: true })
|
|
const tmp = file + '.tmp'
|
|
fs.writeFileSync(tmp, JSON.stringify(data, null, 2))
|
|
fs.renameSync(tmp, file)
|
|
}
|
|
|
|
module.exports = { RESOURCES, APP_ROOT, BUILD, FILES, DATA, DIRS, ensureDirs, readJson, writeJson, toPortablePath, resolvePortablePath }
|