From 23ee2314b3570b3434594c9257f68bdc895723b8 Mon Sep 17 00:00:00 2001 From: Florian Egger Date: Sun, 31 May 2026 18:00:01 +0200 Subject: [PATCH] Add OCR dependency support to plugin installer Adds new flags `--drawj2d-jar` and `--install-deps` to handle OCR dependencies Automatically checks for required tools (unzip, Java, drawj2d.jar) Installs missing system packages when `--install-deps` is used Updates documentation with OCR setup examples The implementation includes dependency checking that can be skipped with `--skip-deps` when OCR functionality is not needed. The installer now copies and configures drawj2d.jar if provided, and updates the plugin's data.json accordingly. --- IMPLEMENTATION.md | 4 ++ scripts/install.mjs | 162 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 163 insertions(+), 3 deletions(-) diff --git a/IMPLEMENTATION.md b/IMPLEMENTATION.md index 21e6928..f44a01a 100644 --- a/IMPLEMENTATION.md +++ b/IMPLEMENTATION.md @@ -273,6 +273,10 @@ npm run install-plugin -- --vault /path/to/vault # Exact target directory also works npm run install-plugin -- --plugin-dir /path/to/vault/.obsidian/plugins/obsidian-remarkable + +# OCR dependency setup +npm run install-plugin -- --vault /path/to/vault --drawj2d-jar /path/to/drawj2d.jar +npm run install-plugin -- --vault /path/to/vault --install-deps ``` --- diff --git a/scripts/install.mjs b/scripts/install.mjs index 2f4ca03..81e5a5e 100644 --- a/scripts/install.mjs +++ b/scripts/install.mjs @@ -1,10 +1,12 @@ -import { copyFile, mkdir, readFile } from "fs/promises"; -import { dirname, join, resolve } from "path"; +import { access, copyFile, mkdir, readFile, writeFile } from "fs/promises"; +import { constants } from "fs"; +import { basename, dirname, join, resolve } from "path"; import { fileURLToPath } from "url"; import { spawnSync } from "child_process"; const root = dirname(dirname(fileURLToPath(import.meta.url))); const runtimeFiles = ["manifest.json", "main.js"]; +const drawj2dTargetName = "drawj2d.jar"; function printUsage() { console.log(`Usage: @@ -14,22 +16,29 @@ function printUsage() { Options: --vault Obsidian vault path. Installs to /.obsidian/plugins/ --plugin-dir Exact plugin install directory + --drawj2d-jar Copy a local drawj2d.jar into the plugin directory and configure it + --install-deps Try to install missing system packages such as unzip + --skip-deps Do not check OCR dependencies --no-build Skip npm run build before copying files --dry-run Print actions without writing files --help Show this help Environment: OBSIDIAN_VAULT Same as --vault - OBSIDIAN_PLUGIN_DIR Same as --plugin-dir`); + OBSIDIAN_PLUGIN_DIR Same as --plugin-dir + DRAWJ2D_JAR Same as --drawj2d-jar`); } function parseArgs(argv) { const options = { vault: process.env.OBSIDIAN_VAULT || "", pluginDir: process.env.OBSIDIAN_PLUGIN_DIR || "", + drawj2dJar: process.env.DRAWJ2D_JAR || "", build: true, dryRun: false, help: false, + installDeps: false, + skipDeps: false, }; for (let i = 0; i < argv.length; i++) { @@ -41,10 +50,16 @@ function parseArgs(argv) { options.build = false; } else if (arg === "--dry-run") { options.dryRun = true; + } else if (arg === "--install-deps") { + options.installDeps = true; + } else if (arg === "--skip-deps") { + options.skipDeps = true; } else if (arg === "--vault") { options.vault = argv[++i] || ""; } else if (arg === "--plugin-dir") { options.pluginDir = argv[++i] || ""; + } else if (arg === "--drawj2d-jar") { + options.drawj2dJar = argv[++i] || ""; } else { throw new Error(`Unknown option: ${arg}`); } @@ -79,6 +94,142 @@ function runBuild() { } } +function run(command, args, options = {}) { + return spawnSync(command, args, { + cwd: root, + stdio: options.stdio || "pipe", + encoding: "utf-8", + }); +} + +function commandExists(command, args) { + const result = run(command, args); + return !result.error && result.status === 0; +} + +function detectPackageInstallCommand(packageName) { + if (commandExists("apt-get", ["--version"])) { + return ["sudo", ["apt-get", "install", "-y", packageName]]; + } + if (commandExists("dnf", ["--version"])) { + return ["sudo", ["dnf", "install", "-y", packageName]]; + } + if (commandExists("pacman", ["--version"])) { + return ["sudo", ["pacman", "-S", "--needed", "--noconfirm", packageName]]; + } + if (commandExists("brew", ["--version"])) { + return ["brew", ["install", packageName]]; + } + return null; +} + +function installPackage(packageName, dryRun) { + const command = detectPackageInstallCommand(packageName); + if (!command) { + return false; + } + + const [binary, args] = command; + console.log(`${dryRun ? "Would run" : "Running"} ${binary} ${args.join(" ")}`); + if (dryRun) { + return true; + } + + const result = spawnSync(binary, args, { stdio: "inherit" }); + if (result.error) { + throw result.error; + } + return result.status === 0; +} + +async function fileExists(path) { + try { + await access(path, constants.R_OK); + return true; + } catch { + return false; + } +} + +async function checkDependencies(options, targetDir) { + const missing = []; + + if (!commandExists("unzip", ["-v"])) { + if (options.installDeps && installPackage("unzip", options.dryRun)) { + console.log(options.dryRun ? "unzip would be installed." : "Installed unzip."); + } else { + missing.push("unzip"); + } + } + + if (!commandExists("java", ["-version"])) { + missing.push("java"); + } + + const targetDrawj2dPath = join(targetDir, drawj2dTargetName); + const sourceDrawj2dPath = options.drawj2dJar ? resolve(options.drawj2dJar) : ""; + const hasSourceDrawj2d = sourceDrawj2dPath ? await fileExists(sourceDrawj2dPath) : false; + const hasInstalledDrawj2d = await fileExists(targetDrawj2dPath); + + if (sourceDrawj2dPath && !hasSourceDrawj2d) { + missing.push(`drawj2d jar at ${sourceDrawj2dPath}`); + } else if (!hasSourceDrawj2d && !hasInstalledDrawj2d) { + missing.push("drawj2d.jar"); + } + + if (missing.length > 0) { + throw new Error( + [ + `Missing dependencies: ${missing.join(", ")}`, + "Install unzip and Java with your system package manager.", + "Download drawj2d.jar, then rerun with --drawj2d-jar /path/to/drawj2d.jar or set DRAWJ2D_JAR.", + "Use --skip-deps only if you intentionally do not want OCR dependency checks.", + ].join("\n"), + ); + } + + return sourceDrawj2dPath && hasSourceDrawj2d ? sourceDrawj2dPath : ""; +} + +async function installDrawj2dJar(sourcePath, targetDir, dryRun) { + if (!sourcePath) { + return ""; + } + + if (basename(sourcePath) !== drawj2dTargetName) { + console.log(`Installing ${basename(sourcePath)} as ${drawj2dTargetName}`); + } + + const destination = join(targetDir, drawj2dTargetName); + console.log(`${dryRun ? "Would copy" : "Copying"} ${drawj2dTargetName}`); + + if (!dryRun) { + await copyFile(sourcePath, destination); + } + + return destination; +} + +async function updatePluginData(targetDir, drawj2dPath, dryRun) { + if (!drawj2dPath) { + return; + } + + const dataPath = join(targetDir, "data.json"); + let data = {}; + + if (await fileExists(dataPath)) { + data = JSON.parse(await readFile(dataPath, "utf-8")); + } + + data.drawj2dPath = drawj2dPath; + console.log(`${dryRun ? "Would update" : "Updating"} data.json drawj2dPath`); + + if (!dryRun) { + await writeFile(dataPath, `${JSON.stringify(data, null, 2)}\n`); + } +} + async function install() { const options = parseArgs(process.argv.slice(2)); @@ -108,6 +259,8 @@ async function install() { runBuild(); } + const drawj2dJarToInstall = options.skipDeps ? "" : await checkDependencies(options, targetDir); + console.log(`Installing to ${targetDir}`); if (!options.dryRun) { @@ -124,6 +277,9 @@ async function install() { } } + const installedDrawj2dPath = await installDrawj2dJar(drawj2dJarToInstall, targetDir, options.dryRun); + await updatePluginData(targetDir, installedDrawj2dPath || (!options.skipDeps ? join(targetDir, drawj2dTargetName) : ""), options.dryRun); + console.log("Install complete."); }