adaptorex
Version:
Connect all your live interactive storytelling devices and software
148 lines (121 loc) • 4.81 kB
JavaScript
// scripts/build-appimage.mjs
// Packages the yao-pkg binary into a Linux AppImage.
// Usage: node scripts/build-appimage.mjs [--arch x86_64|arm64] [--update-tool]
const fs = require("fs")
const path = require("path")
const os = require("os")
const { execSync, spawnSync } = require("child_process")
const { createWriteStream } = require("fs")
const { pipeline } = require("stream/promises")
const { fileURLToPath } = require("url")
const { version } = require("../package.json")
function checkFileExists(p, label) {
if (!fs.existsSync(p)) {
console.error(`${label} not found: ${p}`)
process.exit(1)
}
}
async function main() {
if (process.platform !== "linux") {
console.error("AppImage builds are only supported on Linux.")
process.exit(1)
}
const args = process.argv.slice(2)
const ARCH = args.includes("--arch")
? args[args.indexOf("--arch") + 1]
: "x86_64"
const UPDATE_TOOL = args.includes("--update-tool")
const BINARY_SRC = path.join("dist", `adaptorex-linux-${ARCH}`) // yao-pkg output
const ICON_SRC = path.join(__dirname, "assets", "icon.png")
const DESKTOP_SRC = path.join(__dirname, "assets", "adaptorex.desktop")
const APPRUN_SRC = path.join(__dirname, "assets", "AppRun")
const APP_DIR = path.join("dist", `adaptorex.AppDir`)
const OUT_FILE = path.join("dist", `adaptorex-${version}-${ARCH}.AppImage`)
const TOOL_ARCH = ARCH === "arm64" ? "aarch64" : ARCH
const TOOL_CACHE = path.join(os.homedir(), ".cache", "appimagetool")
const TOOL_PATH = path.join(TOOL_CACHE, `appimagetool-${TOOL_ARCH}.AppImage`)
const TOOL_URL = `https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${TOOL_ARCH}.AppImage`
// Check if yao-pkg binary, icon file and .desktop exists
console.log("Validating inputs")
checkFileExists(BINARY_SRC, "pkg binary (run yao-pkg first)")
checkFileExists(ICON_SRC, "Icon")
checkFileExists(DESKTOP_SRC, ".desktop file")
console.log(`app: adaptorex version: ${version} arch: ${ARCH}`)
console.log("Building AppDir")
// Clean previous build
if (fs.existsSync(APP_DIR)) {
fs.rmSync(APP_DIR, { recursive: true })
console.log("Removed existing AppDir")
}
// Make Directory structure
const BIN_DIR = path.join(APP_DIR, "usr", "bin")
fs.mkdirSync(BIN_DIR, { recursive: true })
// Copy Binary
fs.copyFileSync(BINARY_SRC, path.join(BIN_DIR, "adaptorex"))
fs.chmodSync(path.join(BIN_DIR, "adaptorex"), 0o755)
console.log("Copied binary to usr/bin/")
// Icon (root AND usr/share/icons for broader DE compatibility)
const ICON_SHARE = path.join(
APP_DIR,
"usr",
"share",
"icons",
"hicolor",
"256x256",
"apps"
)
fs.mkdirSync(ICON_SHARE, { recursive: true })
fs.copyFileSync(ICON_SRC, path.join(APP_DIR, `adaptorex.png`))
fs.copyFileSync(ICON_SRC, path.join(ICON_SHARE, `adaptorex.png`))
console.log("Copied icon")
// Copy .desktop file (root AND usr/share/applications)
const DESKTOP_SHARE = path.join(APP_DIR, "usr", "share", "applications")
fs.mkdirSync(DESKTOP_SHARE, { recursive: true })
fs.copyFileSync(DESKTOP_SRC, path.join(APP_DIR, `adaptorex.desktop`))
fs.copyFileSync(DESKTOP_SRC, path.join(DESKTOP_SHARE, `adaptorex.desktop`))
console.log("Copied .desktop")
// Add AppRun script
const appRunPath = path.join(APP_DIR, "AppRun")
fs.copyFileSync(APPRUN_SRC, appRunPath)
fs.chmodSync(appRunPath, 0o755)
console.log("Copied AppRun")
// Ensure appimagetool exists. Download if missing
console.log("Checking appimagetool")
if (!fs.existsSync(TOOL_PATH) || UPDATE_TOOL) {
console.log(
UPDATE_TOOL ? "Updating appimagetool…" : "Not cached — downloading…"
)
console.log(`Downloading ${TOOL_URL}`)
fs.mkdirSync(path.dirname(TOOL_PATH), { recursive: true })
const res = await fetch(TOOL_URL)
if (!res.ok) console.error(`Download failed: HTTP ${res.status}`)
await pipeline(res.body, createWriteStream(TOOL_PATH))
fs.chmodSync(TOOL_PATH, 0o755)
console.log(`Saved to ${TOOL_PATH}`)
} else {
console.log(`Using cached appimagetool (pass --update-tool to refresh)`)
}
// Build AppImage
console.log("Running appimagetool")
fs.mkdirSync("dist", { recursive: true })
const result = spawnSync(TOOL_PATH, [APP_DIR, OUT_FILE], {
stdio: "inherit",
env: {
...process.env,
ARCH: TOOL_ARCH,
VERSION: version,
APPIMAGE_EXTRACT_AND_RUN: "1"
}
})
if (result.status !== 0) {
console.error("appimagetool exited with errors.")
}
const sizeBytes = fs.statSync(OUT_FILE).size
const sizeMB = (sizeBytes / 1024 / 1024).toFixed(1)
console.log(`AppImage ready: ${OUT_FILE} Size: ${sizeMB} MB`)
}
main().catch((err) => {
console.error(err)
process.exit(1)
})