From 64802f858bdb32ae1e4359a88b1b99e55a787ed3 Mon Sep 17 00:00:00 2001 From: saberzero1 Date: Sat, 11 Apr 2026 15:51:50 +0200 Subject: [PATCH] feat(cli): generalize concurrency flag --- quartz/bootstrap-cli.mjs | 16 ++++++++++++---- quartz/cli/args.js | 9 +++++---- quartz/cli/plugin-git-handlers.js | 27 ++++++++++++++++----------- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/quartz/bootstrap-cli.mjs b/quartz/bootstrap-cli.mjs index b9e5652..151a604 100755 --- a/quartz/bootstrap-cli.mjs +++ b/quartz/bootstrap-cli.mjs @@ -135,6 +135,7 @@ yargs(hideBin(process.argv)) latest: argv.latest, clean: argv.clean, dryRun: argv.dryRun, + concurrency: argv.concurrency, }) }, ) @@ -157,6 +158,7 @@ yargs(hideBin(process.argv)) await handlePluginAdd(argv.repos, { name: argv.name, subdir: argv.subdir, + concurrency: argv.concurrency, }) }, ) @@ -212,11 +214,11 @@ yargs(hideBin(process.argv)) }, ) // Hidden deprecated aliases - .command("restore", false, CommonArgv, async () => { + .command("restore", false, CommonArgv, async (argv) => { console.log( "\x1b[33m⚠ 'plugin restore' is deprecated. Use 'plugin install --clean' instead.\x1b[0m", ) - await handlePluginInstallUnified({ clean: true }) + await handlePluginInstallUnified({ clean: true, concurrency: argv.concurrency }) }) .command("update [names..]", false, CommonArgv, async (argv) => { console.log( @@ -225,13 +227,18 @@ yargs(hideBin(process.argv)) await handlePluginInstallUnified({ names: argv.names?.length ? argv.names : undefined, latest: true, + concurrency: argv.concurrency, }) }) - .command("check", false, CommonArgv, async () => { + .command("check", false, CommonArgv, async (argv) => { console.log( "\x1b[33m⚠ 'plugin check' is deprecated. Use 'plugin install --latest --dry-run' instead.\x1b[0m", ) - await handlePluginInstallUnified({ latest: true, dryRun: true }) + await handlePluginInstallUnified({ + latest: true, + dryRun: true, + concurrency: argv.concurrency, + }) }) .command( "resolve", @@ -251,6 +258,7 @@ yargs(hideBin(process.argv)) await handlePluginInstallUnified({ fromConfig: true, dryRun: argv.dryRun, + concurrency: argv.concurrency, }) }, ) diff --git a/quartz/cli/args.js b/quartz/cli/args.js index a18ba88..7a6c155 100644 --- a/quartz/cli/args.js +++ b/quartz/cli/args.js @@ -11,6 +11,11 @@ export const CommonArgv = { default: false, describe: "print out extra logging information", }, + concurrency: { + number: true, + alias: ["c"], + describe: "max parallel operations (default: number of CPU cores)", + }, } export const CreateArgv = { @@ -112,8 +117,4 @@ export const BuildArgv = { default: false, describe: "show detailed bundle information", }, - concurrency: { - number: true, - describe: "how many threads to use to parse notes", - }, } diff --git a/quartz/cli/plugin-git-handlers.js b/quartz/cli/plugin-git-handlers.js index 70d9875..5ec7aed 100644 --- a/quartz/cli/plugin-git-handlers.js +++ b/quartz/cli/plugin-git-handlers.js @@ -257,12 +257,15 @@ export async function handlePluginInstallUnified({ latest = false, clean = false, dryRun = false, + concurrency: concurrencyOption, } = {}) { if (clean && latest) { console.log(styleText("red", "✗ --clean and --latest cannot be used together")) return } + const resolvedConcurrency = Math.max(1, concurrencyOption ?? os.cpus().length) + const pluginsJson = readPluginsJson() let lockfile = readLockfile() @@ -539,7 +542,7 @@ export async function handlePluginInstallUnified({ // Clone remote plugins in parallel if (remoteEntries.length > 0) { - const concurrency = Math.max(1, os.cpus().length) + const concurrency = resolvedConcurrency await runParallel( remoteEntries, concurrency, @@ -595,7 +598,7 @@ export async function handlePluginInstallUnified({ if (installed.length > 0) { console.log() console.log(styleText("cyan", "→ Building plugins...")) - const concurrency = Math.max(1, os.cpus().length) + const concurrency = resolvedConcurrency const results = await runParallel(installed, concurrency, async ({ name, pluginDir }) => { const ok = await buildPluginAsync(pluginDir, name) if (ok) console.log(styleText("green", ` ✓ ${name} built`)) @@ -722,7 +725,7 @@ export async function handlePluginInstallUnified({ // Clone remote plugins in parallel if (remotePlugins.length > 0) { - const concurrency = Math.max(1, os.cpus().length) + const concurrency = resolvedConcurrency await runParallel(remotePlugins, concurrency, async ({ name, entry, pluginDir }) => { try { if (entry.subdir) { @@ -763,7 +766,7 @@ export async function handlePluginInstallUnified({ if (restoredPlugins.length > 0) { console.log() console.log(styleText("cyan", "→ Building restored plugins...")) - const concurrency = Math.max(1, os.cpus().length) + const concurrency = resolvedConcurrency const results = await runParallel( restoredPlugins, concurrency, @@ -824,7 +827,7 @@ export async function handlePluginInstallUnified({ // Phase 2: Fetch/update plugins in parallel if (validPlugins.length > 0) { - const concurrency = Math.max(1, os.cpus().length) + const concurrency = resolvedConcurrency await runParallel(validPlugins, concurrency, async ({ name, pluginDir, entry }) => { try { console.log(styleText("cyan", `→ Updating ${name}...`)) @@ -884,7 +887,7 @@ export async function handlePluginInstallUnified({ if (updatedPlugins.length > 0) { console.log() console.log(styleText("cyan", "→ Rebuilding updated plugins...")) - const concurrency = Math.max(1, os.cpus().length) + const concurrency = resolvedConcurrency await runParallel(updatedPlugins, concurrency, async ({ name, pluginDir }) => { const ok = await buildPluginAsync(pluginDir, name) if (ok) console.log(styleText("green", ` ✓ ${name} rebuilt`)) @@ -986,7 +989,7 @@ export async function handlePluginInstallUnified({ // Run git fetch/clone operations in parallel if (gitEntries.length > 0) { - const concurrency = Math.max(1, os.cpus().length) + const concurrency = resolvedConcurrency await runParallel(gitEntries, concurrency, async ({ name, entry, pluginDir, action }) => { try { if (action === "update") { @@ -1031,7 +1034,7 @@ export async function handlePluginInstallUnified({ if (pluginsToBuild.length > 0) { console.log() console.log(styleText("cyan", "→ Building plugins...")) - const concurrency = Math.max(1, os.cpus().length) + const concurrency = resolvedConcurrency const results = await runParallel(pluginsToBuild, concurrency, async ({ name, pluginDir }) => { const ok = await buildPluginAsync(pluginDir, name) if (ok) console.log(styleText("green", ` ✓ ${name} built`)) @@ -1061,7 +1064,7 @@ export async function handlePluginInstall() { export async function handlePluginAdd( sources, - { name: nameOverride, subdir: subdirOverride } = {}, + { name: nameOverride, subdir: subdirOverride, concurrency: concurrencyOption } = {}, ) { if (nameOverride && sources.length > 1) { console.log(styleText("red", "✗ --name/--as can only be used when adding a single plugin")) @@ -1072,6 +1075,8 @@ export async function handlePluginAdd( return } + const resolvedConcurrency = Math.max(1, concurrencyOption ?? os.cpus().length) + let lockfile = readLockfile() if (!lockfile) { lockfile = { version: "1.0.0", plugins: {} } @@ -1136,7 +1141,7 @@ export async function handlePluginAdd( // Clone remote plugins in parallel if (remoteSources.length > 0) { - const concurrency = Math.max(1, os.cpus().length) + const concurrency = resolvedConcurrency await runParallel( remoteSources, concurrency, @@ -1187,7 +1192,7 @@ export async function handlePluginAdd( if (addedPlugins.length > 0) { console.log() console.log(styleText("cyan", "→ Building plugins...")) - const concurrency = Math.max(1, os.cpus().length) + const concurrency = resolvedConcurrency await runParallel(addedPlugins, concurrency, async ({ name, pluginDir }) => { const ok = await buildPluginAsync(pluginDir, name) if (ok) console.log(styleText("green", ` ✓ ${name} built`))