diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..d7b6e44 --- /dev/null +++ b/mise.toml @@ -0,0 +1,34 @@ +[tools] +# specify single or multiple versions +pnpm = 'latest' +node = 'lts' +rust = '1.79.0' + + +[tasks."build"] +depends = ["build:*"] +description = 'Build the CLI' + +[tasks."build:backend"] +description = 'Build the Backend' +run = "node --no-warnings=ExperimentalWarning 'util/build.mjs' -o backend" +sources = ['backend/Cargo.toml', 'backend/src/**/*.rs'] +outputs = ['build/bin/backend'] + +[tasks."build:frontend"] +description = 'Build the Frontend' +run = "node --no-warnings=ExperimentalWarning 'util/build.mjs' -o frontend" +sources = ['package.json', 'lib/package.json', '{src,lib}/**/*.{ts,tsx,codegen}'] +outputs = ['dist/index.js'] + +[tasks."build:collect"] +depends = ["build:backend", "build:frontend"] +description = 'Collect the build artifacts' +run = "node --no-warnings=ExperimentalWarning 'util/build.mjs' -o collect" +sources = ['backend/target/release/backend', 'dist/index.js', 'main.py', 'package.json', 'plugin.json', 'README.md'] +outputs = ['build/**/*.*'] + +[tasks."upload"] +depends = ["build"] +description = 'Upload MicroSDeck to the SteamDeck' +run = "node --no-warnings=ExperimentalWarning 'util/build.mjs' -o upload" \ No newline at end of file diff --git a/util/build.mjs b/util/build.mjs index 91b53db..201667c 100644 --- a/util/build.mjs +++ b/util/build.mjs @@ -6,6 +6,51 @@ import { Version, UpdateVersion, ResetVersion } from './versioning.mjs'; import { Logger } from './log.mjs'; import { exit } from 'process'; +if (process.argv.includes('-h') || process.argv.includes('--help')) { + console.log( +` __ __ _ ___ ___ _ ___ _ _ _ + | \\/ (_)__ _ _ ___/ __| \\ ___ __| |__ | _ )_ _(_) |__| | + | |\\/| | / _| '_/ _ \\__ \\ |) / -_) _| / / | _ \\ || | | / _\` | + |_| |_|_\\__|_| \\___/___/___/\\___\\__|_\\_\\ |___/\\_,_|_|_\\__,_| + + by @CEbbinghaus + `); + + console.log(` +Basic Usage: ./build [flags] + + -h, --help: Prints this help dialogue + -o, --only: Only run the specified part (backend, frontend, collect, copy, upload) + --skip-backend: Skips building the backend +--skip-frontend: Skips building the frontend + --skip-collect: Skips copying all the assets into the built output + --skip-copy: Skips copying the build output to plugin directory (must be run on steamdeck itself) + --upload: Uploads the build output to the steamdeck. (requires a deploy.json in the root repo directory) + `) + process.exit(0); +} + +const only = []; +if (process.argv.includes('-o') || process.argv.includes('--only')) { + let [opt0, opt1] = [process.argv.indexOf('-o'), process.argv.indexOf('--only')]; + + var index = opt1 > 0 ? opt1 : opt0; + if (index == process.argv.length - 1) { + console.error('No argument provided for --only flag'); + process.exit(1); + } + + for (let i = index + 1; i < process.argv.length; i++) { + let arg = process.argv[i]; + if(arg.startsWith('-')) break; + only.push(arg); + } +} + +if (only.length == 0) { + only.push('backend', 'frontend', 'collect', 'copy', 'upload'); +} + const basePath = resolve(process.cwd()); /** @@ -39,13 +84,13 @@ if (!existsSync('plugin.json')) { UpdateVersion("package.json", "lib/package.json"); -if (!process.argv.includes('--skip-backend')) { +if (!process.argv.includes('--skip-backend') && only.includes('backend')) { Logger.Log('Building backend'); runCommand('cargo build --release', 'backend'); } -if (!process.argv.includes('--skip-frontend')) { +if (!process.argv.includes('--skip-frontend') && only.includes('frontend')) { if (!process.argv.includes('--skip-dependencies')) { Logger.Log('Installing dependencies'); runCommand('pnpm install'); @@ -55,7 +100,7 @@ if (!process.argv.includes('--skip-frontend')) { runCommand('pnpm run bundle'); } -if (!process.argv.includes('--skip-collect')) { +if (!process.argv.includes('--skip-collect') && only.includes('collect')) { Logger.Log('Collecting outputs into /build folder'); mkdirSync('build/dist', { recursive: true }); mkdirSync('build/bin', { recursive: true }); @@ -73,19 +118,22 @@ if (!is_local) { Logger.Info('Not running on steamdeck'); } -if (is_local && !process.argv.includes('--skip-copy')) { +if (is_local && (!process.argv.includes('--skip-copy') && only.includes('copy'))) { Logger.Log('Copying build folder to local plugin directory'); execSync(`sudo rm -rf /home/deck/homebrew/plugins/${PluginName}`); execSync(`sudo cp -r build/ /home/deck/homebrew/plugins/${PluginName}`); execSync(`sudo chmod 555 /home/deck/homebrew/plugins/${PluginName}`); } else { - Logger.Log('Skipping copying build folder to local plugin directory'); + if (!process.argv.includes('--skip-copy') || only.includes('copy')) + Logger.Log('Skipping copying build folder to local plugin directory'); } -if (process.argv.includes('--upload')) { +if (process.argv.includes('--upload') || only.includes('upload')) { Logger.Log("Uploading plugin to SteamDeck"); - if (!statfsSync(join(basePath, 'deploy.json'))) { + try { + statfsSync(join(basePath, 'deploy.json')) + } catch (e) { Logger.Error("deploy.json not found. Cannot deploy without it"); exit(1); } @@ -96,9 +144,15 @@ if (process.argv.includes('--upload')) { const tmpPath = `/tmp/${Date.now()}` - execSync(`ssh -i ${keyfile} ${user}@${host} "[ -d ${deployPath} ] && sudo rm -rf ${deployPath} || exit 0"`); - execSync(`scp -i ${keyfile} -r build/ ${user}@${host}:"${tmpPath}"`); - execSync(`ssh -i ${keyfile} ${user}@${host} "sudo mv "${tmpPath}" "${deployPath}" && sudo chmod 555 ${deployPath}"`); + let keyfileArg = ""; + + if(keyfile) { + keyfileArg = `-i ${keyfile}`; + } + + execSync(`ssh ${keyfileArg} ${user}@${host} "[ -d ${deployPath} ] && sudo rm -rf ${deployPath} || exit 0"`); + execSync(`scp ${keyfileArg} -r build/ ${user}@${host}:"${tmpPath}"`); + execSync(`ssh ${keyfileArg} ${user}@${host} "sudo mv "${tmpPath}" "${deployPath}" && sudo chmod 555 ${deployPath}"`); } ResetVersion("package.json", "lib/package.json"); diff --git a/util/versioning.mjs b/util/versioning.mjs index eb95b9c..9cfb9ec 100644 --- a/util/versioning.mjs +++ b/util/versioning.mjs @@ -1,4 +1,4 @@ -import { readFileSync, writeFileSync } from "fs"; +import { readFileSync, writeFileSync, openSync, fstatSync, utimesSync, closeSync, truncateSync } from "fs"; import { dirname, resolve } from "path"; import { fileURLToPath } from "url"; @@ -8,9 +8,23 @@ function ReadPackageVersion() { } function WriteVersionToPackage(file, version) { - const pkg = JSON.parse(readFileSync(file)); - pkg.version = version; - writeFileSync(file, JSON.stringify(pkg, null, " ")); + const fd = openSync(file, 'a+'); + // Get last modified time of file + const { atime, mtime } = fstatSync(fd); + + try { + + var value = readFileSync(fd, { encoding: "utf-8", flag: "r" }); + const pkg = JSON.parse(value); + pkg.version = version; + truncateSync(fd, 0); + writeFileSync(fd, JSON.stringify(pkg, null, " ")); + } finally { + closeSync(fd); + } + + // update file so it doesn't get marked as changed + utimesSync(file, atime, mtime); } /** @@ -34,6 +48,8 @@ export function UpdateVersion(...packages) { WriteVersionToPackage(packagePath, Version); } } + +// If this file is being run rather than imported as a module if (process.argv[1] === fileURLToPath(import.meta.url)) { // The script was run directly.