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.
This commit is contained in:
2026-05-31 18:00:01 +02:00
parent 07f4c27d58
commit 23ee2314b3
2 changed files with 163 additions and 3 deletions
+4
View File
@@ -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
```
---
+159 -3
View File
@@ -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 <path> Obsidian vault path. Installs to <vault>/.obsidian/plugins/<manifest id>
--plugin-dir <path> Exact plugin install directory
--drawj2d-jar <path> 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.");
}