From a9ad2683935d3072e162b50b28d692b7504f4c37 Mon Sep 17 00:00:00 2001 From: sudacode Date: Sat, 21 Mar 2026 21:15:41 -0700 Subject: [PATCH] fix(scripts): harden patch-modernz handling --- scripts/patch-modernz.sh | 31 +++++++++----- scripts/patch-modernz.test.ts | 76 +++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 9 deletions(-) create mode 100644 scripts/patch-modernz.test.ts diff --git a/scripts/patch-modernz.sh b/scripts/patch-modernz.sh index 761368f..12b7123 100755 --- a/scripts/patch-modernz.sh +++ b/scripts/patch-modernz.sh @@ -4,19 +4,28 @@ set -euo pipefail TARGET="${HOME}/.config/mpv/scripts/modernz.lua" -while [[ $# -gt 0 ]]; do - case "$1" in - --target) - TARGET="$2" - shift 2 - ;; - --help|-h) - cat <<'EOF' +usage() { + cat <<'EOF' Usage: patch-modernz.sh [--target /path/to/modernz.lua] Applies the local ModernZ OSC sidebar-resize patch to an existing modernz.lua. If the target file does not exist, the script exits without changing anything. EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --target) + if [[ $# -lt 2 || -z "${2:-}" || "$2" == -* ]]; then + echo "patch-modernz: --target requires a non-empty file path" >&2 + usage >&2 + exit 1 + fi + TARGET="$2" + shift 2 + ;; + --help|-h) + usage exit 0 ;; *) @@ -37,7 +46,7 @@ if grep -q 'get_external_video_margin_ratio' "$TARGET" \ exit 0 fi -patch --forward --quiet "$TARGET" <<'PATCH' +if ! patch --forward --quiet "$TARGET" <<'PATCH' --- a/modernz.lua +++ b/modernz.lua @@ -931,6 +931,26 @@ local function reset_margins() @@ -140,5 +149,9 @@ patch --forward --quiet "$TARGET" <<'PATCH' if val and user_opts.visibility == "auto" and not user_opts.showonselect then osc_visible(false) PATCH +then + echo "patch-modernz: failed to apply patch to $TARGET" >&2 + exit 1 +fi echo "patch-modernz: patched $TARGET" diff --git a/scripts/patch-modernz.test.ts b/scripts/patch-modernz.test.ts new file mode 100644 index 0000000..7ceadf4 --- /dev/null +++ b/scripts/patch-modernz.test.ts @@ -0,0 +1,76 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { spawnSync } from 'node:child_process'; +import test from 'node:test'; + +function withTempDir(fn: (dir: string) => T): T { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-patch-modernz-test-')); + try { + return fn(dir); + } finally { + fs.rmSync(dir, { recursive: true, force: true }); + } +} + +function writeExecutable(filePath: string, contents: string): void { + fs.writeFileSync(filePath, contents, 'utf8'); + fs.chmodSync(filePath, 0o755); +} + +test('patch-modernz rejects a missing --target value', () => { + withTempDir((root) => { + const result = spawnSync('bash', ['scripts/patch-modernz.sh', '--target'], { + cwd: process.cwd(), + encoding: 'utf8', + env: { + ...process.env, + HOME: path.join(root, 'home'), + }, + }); + + assert.equal(result.status, 1, result.stderr || result.stdout); + assert.match(result.stderr, /--target requires a non-empty file path/); + assert.match(result.stderr, /Usage: patch-modernz\.sh/); + }); +}); + +test('patch-modernz reports patch failures explicitly', () => { + withTempDir((root) => { + const binDir = path.join(root, 'bin'); + const target = path.join(root, 'modernz.lua'); + const patchLog = path.join(root, 'patch.log'); + + fs.mkdirSync(binDir, { recursive: true }); + fs.mkdirSync(path.dirname(target), { recursive: true }); + fs.writeFileSync(target, 'original', 'utf8'); + + writeExecutable( + path.join(binDir, 'patch'), + `#!/usr/bin/env bash +set -euo pipefail +cat > "${patchLog}" +exit 1 +`, + ); + + const result = spawnSync( + 'bash', + ['scripts/patch-modernz.sh', '--target', target], + { + cwd: process.cwd(), + encoding: 'utf8', + env: { + ...process.env, + HOME: path.join(root, 'home'), + PATH: `${binDir}:${process.env.PATH || ''}`, + }, + }, + ); + + assert.equal(result.status, 1, result.stderr || result.stdout); + assert.match(result.stderr, /failed to apply patch to/); + assert.equal(fs.readFileSync(patchLog, 'utf8').includes('modernz.lua'), true); + }); +});