Add plugin installation script and documentation
The new `install-plugin` script automates plugin installation to Obsidian vaults with support for both vault paths and direct plugin directory targets. It includes options for skipping builds and dry runs. Documentation in IMPLEMENTATION.md now includes usage examples for the new installation method alongside the existing manual installation instructions.
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
import { copyFile, mkdir, readFile } from "fs/promises";
|
||||
import { 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"];
|
||||
|
||||
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
|
||||
--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`);
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
const options = {
|
||||
vault: process.env.OBSIDIAN_VAULT || "",
|
||||
pluginDir: process.env.OBSIDIAN_PLUGIN_DIR || "",
|
||||
build: true,
|
||||
dryRun: false,
|
||||
help: 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 === "--vault") {
|
||||
options.vault = argv[++i] || "";
|
||||
} else if (arg === "--plugin-dir") {
|
||||
options.pluginDir = 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}`);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Install complete.");
|
||||
}
|
||||
|
||||
install().catch((error) => {
|
||||
console.error(error instanceof Error ? error.message : error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
Reference in New Issue
Block a user