23ee2314b3
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.
290 lines
8.1 KiB
JavaScript
290 lines
8.1 KiB
JavaScript
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:
|
|
npm run install-plugin -- --vault /path/to/vault
|
|
npm run install-plugin -- --plugin-dir /path/to/vault/.obsidian/plugins/obsidian-remarkable
|
|
|
|
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
|
|
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++) {
|
|
const arg = argv[i];
|
|
|
|
if (arg === "--help" || arg === "-h") {
|
|
options.help = true;
|
|
} else if (arg === "--no-build") {
|
|
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}`);
|
|
}
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
async function getManifestId() {
|
|
const manifestPath = join(root, "manifest.json");
|
|
const manifest = JSON.parse(await readFile(manifestPath, "utf-8"));
|
|
|
|
if (!manifest.id || typeof manifest.id !== "string") {
|
|
throw new Error("manifest.json is missing a string id");
|
|
}
|
|
|
|
return manifest.id;
|
|
}
|
|
|
|
function runBuild() {
|
|
const result = spawnSync("npm", ["run", "build"], {
|
|
cwd: root,
|
|
stdio: "inherit",
|
|
});
|
|
|
|
if (result.error) {
|
|
throw result.error;
|
|
}
|
|
|
|
if (result.status !== 0) {
|
|
throw new Error(`npm run build failed with exit code ${result.status}`);
|
|
}
|
|
}
|
|
|
|
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));
|
|
|
|
if (options.help) {
|
|
printUsage();
|
|
return;
|
|
}
|
|
|
|
if (options.vault && options.pluginDir) {
|
|
throw new Error("Use either --vault or --plugin-dir, not both");
|
|
}
|
|
|
|
const manifestId = await getManifestId();
|
|
const targetDir = options.pluginDir
|
|
? resolve(options.pluginDir)
|
|
: options.vault
|
|
? join(resolve(options.vault), ".obsidian", "plugins", manifestId)
|
|
: "";
|
|
|
|
if (!targetDir) {
|
|
printUsage();
|
|
throw new Error("Missing install target. Provide --vault, --plugin-dir, OBSIDIAN_VAULT, or OBSIDIAN_PLUGIN_DIR");
|
|
}
|
|
|
|
if (options.build) {
|
|
console.log("Building plugin...");
|
|
runBuild();
|
|
}
|
|
|
|
const drawj2dJarToInstall = options.skipDeps ? "" : await checkDependencies(options, targetDir);
|
|
|
|
console.log(`Installing to ${targetDir}`);
|
|
|
|
if (!options.dryRun) {
|
|
await mkdir(targetDir, { recursive: true });
|
|
}
|
|
|
|
for (const file of runtimeFiles) {
|
|
const source = join(root, file);
|
|
const destination = join(targetDir, file);
|
|
console.log(`${options.dryRun ? "Would copy" : "Copying"} ${file}`);
|
|
|
|
if (!options.dryRun) {
|
|
await copyFile(source, destination);
|
|
}
|
|
}
|
|
|
|
const installedDrawj2dPath = await installDrawj2dJar(drawj2dJarToInstall, targetDir, options.dryRun);
|
|
await updatePluginData(targetDir, installedDrawj2dPath || (!options.skipDeps ? join(targetDir, drawj2dTargetName) : ""), options.dryRun);
|
|
|
|
console.log("Install complete.");
|
|
}
|
|
|
|
install().catch((error) => {
|
|
console.error(error instanceof Error ? error.message : error);
|
|
process.exitCode = 1;
|
|
});
|