import { spawnSync } from "node:child_process"; import { copyFileSync, cpSync, existsSync, mkdirSync, readdirSync, rmSync, statSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const appRoot = path.resolve(__dirname, ".."); const repoRoot = path.resolve(appRoot, ".."); const sidecarProject = path.join( repoRoot, "Journal.Sidecar", "Journal.Sidecar.csproj", ); const publishOutputDir = path.join(repoRoot, "output"); const tauriBinDir = path.join(appRoot, "src-tauri", "bin"); function runtimeForCurrentPlatform() { const arch = process.arch; if (process.platform === "win32") { if (arch === "arm64") return "win-arm64"; return "win-x64"; } if (process.platform === "linux") { if (arch === "arm64") return "linux-arm64"; return "linux-x64"; } if (process.platform === "darwin") { if (arch === "arm64") return "osx-arm64"; return "osx-x64"; } throw new Error( `Unsupported platform '${process.platform}' for sidecar publish.`, ); } function sidecarFileName() { return process.platform === "win32" ? "Journal.Sidecar.exe" : "Journal.Sidecar"; } function publishProject(projectPath, runtime) { const publishArgs = [ "publish", projectPath, "-c", "Release", "-r", runtime, "--self-contained", "-p:PublishSingleFile=true", "-p:IncludeNativeLibrariesForSelfExtract=false", "-p:RestoreIgnoreFailedSources=true", "-p:NuGetAudit=false", "-p:ErrorOnDuplicatePublishOutputFiles=false", "-o", publishOutputDir, ]; const publish = spawnSync("dotnet", publishArgs, { cwd: repoRoot, stdio: "inherit", }); if (publish.error) { throw publish.error; } if (publish.status !== 0) { process.exit(publish.status ?? 1); } } function stageOutput(fileName) { const publishedBinary = path.join(publishOutputDir, fileName); if (!existsSync(publishedBinary)) { throw new Error(`Published binary not found: ${publishedBinary}`); } mkdirSync(tauriBinDir, { recursive: true }); const skipExts = new Set([".pdb", ".metal"]); for (const entry of readdirSync(publishOutputDir)) { const ext = path.extname(entry).toLowerCase(); if (skipExts.has(ext)) continue; const src = path.join(publishOutputDir, entry); const dest = path.join(tauriBinDir, entry); if (entry === "runtimes") { // Only copy the runtimes subdirectory matching the target platform stageRuntimes(src, dest, runtime); } else if (statSync(src).isDirectory()) { cpSync(src, dest, { recursive: true, force: true }); } else { copyFileSync(src, dest); } } console.log(`Staged sidecar + native libs to: ${tauriBinDir}`); } function stageRuntimes(runtimesDir, destDir, rid) { // Only copy the subdirectory that matches our runtime identifier (e.g. win-x64) const ridDir = path.join(runtimesDir, rid); if (!existsSync(ridDir)) { console.warn(`No runtimes found for ${rid}, skipping runtimes/`); return; } // Remove stale runtimes from previous builds if (existsSync(destDir)) { rmSync(destDir, { recursive: true, force: true }); } const destRidDir = path.join(destDir, rid); cpSync(ridDir, destRidDir, { recursive: true, force: true }); console.log(`Copied runtimes/${rid} (skipped ${readdirSync(runtimesDir).length - 1} other platform(s))`); } const runtime = runtimeForCurrentPlatform(); const sidecarName = sidecarFileName(); console.log( `Publishing sidecar for ${process.platform}/${process.arch} (${runtime})...`, ); console.log("Publishing Journal.Sidecar..."); publishProject(sidecarProject, runtime); stageOutput(sidecarName);