@rudderhq/cli 0.3.5-canary.15 → 0.3.5-canary.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -13055,7 +13055,7 @@ init_install2();
13055
13055
  init_install();
13056
13056
  import * as p15 from "@clack/prompts";
13057
13057
  import { spawn as spawn2, spawnSync as spawnSync3 } from "node:child_process";
13058
- import { createHash } from "node:crypto";
13058
+ import { createHash, randomUUID } from "node:crypto";
13059
13059
  import { createWriteStream, constants as fsConstants, mkdirSync, readFileSync as readFileSync2 } from "node:fs";
13060
13060
  import { access, chmod, copyFile, cp, mkdir as mkdir3, mkdtemp, readdir as readdir3, readFile as readFile6, rm as rm2, stat as stat4, utimes, writeFile as writeFile3 } from "node:fs/promises";
13061
13061
  import { homedir, tmpdir } from "node:os";
@@ -13191,6 +13191,8 @@ var DEFAULT_DESKTOP_ASSET_CACHE_MAX_ENTRIES = 2;
13191
13191
  var DEFAULT_DESKTOP_ASSET_CACHE_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
13192
13192
  var DEFAULT_DESKTOP_ASSET_CACHE_MAX_BYTES = 768 * 1024 * 1024;
13193
13193
  var DEFAULT_DESKTOP_ASSET_CACHE_KEEP_PREVIOUS = 1;
13194
+ var DESKTOP_INSTALL_LOCK_TIMEOUT_MS = 60 * 60 * 1e3;
13195
+ var DESKTOP_INSTALL_LOCK_POLL_MS = 250;
13194
13196
  function normalizeProgressTotal(totalBytes) {
13195
13197
  return typeof totalBytes === "number" && Number.isFinite(totalBytes) && totalBytes > 0 ? totalBytes : null;
13196
13198
  }
@@ -13834,6 +13836,70 @@ async function pathExists2(targetPath) {
13834
13836
  return false;
13835
13837
  }
13836
13838
  }
13839
+ function resolveDesktopInstallLockPath(paths) {
13840
+ const installRootHash = createHash("sha256").update(path21.resolve(paths.installRoot)).digest("hex").slice(0, 16);
13841
+ return path21.join(path21.dirname(paths.appPath), `.rudder-desktop-install-${installRootHash}.lock`);
13842
+ }
13843
+ async function readDesktopInstallLock(lockPath) {
13844
+ try {
13845
+ const parsed = JSON.parse(await readFile6(lockPath, "utf8"));
13846
+ if (typeof parsed.pid !== "number" || !Number.isInteger(parsed.pid) || parsed.pid <= 0 || typeof parsed.lockId !== "string" || typeof parsed.installRoot !== "string" || typeof parsed.createdAt !== "string") {
13847
+ return null;
13848
+ }
13849
+ return {
13850
+ lockId: parsed.lockId,
13851
+ pid: parsed.pid,
13852
+ installRoot: parsed.installRoot,
13853
+ createdAt: parsed.createdAt
13854
+ };
13855
+ } catch {
13856
+ return null;
13857
+ }
13858
+ }
13859
+ async function withDesktopInstallLock(paths, fn, options = {}) {
13860
+ const lockPath = resolveDesktopInstallLockPath(paths);
13861
+ const lockDir = path21.dirname(lockPath);
13862
+ const timeoutMs = options.timeoutMs ?? DESKTOP_INSTALL_LOCK_TIMEOUT_MS;
13863
+ const pollMs = options.pollMs ?? DESKTOP_INSTALL_LOCK_POLL_MS;
13864
+ const startedAt = Date.now();
13865
+ const payload = {
13866
+ lockId: randomUUID(),
13867
+ pid: process.pid,
13868
+ installRoot: path21.resolve(paths.installRoot),
13869
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
13870
+ };
13871
+ await mkdir3(lockDir, { recursive: true });
13872
+ while (true) {
13873
+ try {
13874
+ await writeFile3(lockPath, `${JSON.stringify(payload, null, 2)}
13875
+ `, { encoding: "utf8", flag: "wx" });
13876
+ break;
13877
+ } catch (error) {
13878
+ const err = error;
13879
+ if (err.code !== "EEXIST") throw error;
13880
+ const existing = await readDesktopInstallLock(lockPath);
13881
+ const stale = !existing || !processExists(existing.pid);
13882
+ if (stale) {
13883
+ await rm2(lockPath, { force: true });
13884
+ continue;
13885
+ }
13886
+ if (Date.now() - startedAt >= timeoutMs) {
13887
+ throw new Error(
13888
+ `Timed out waiting for Rudder Desktop install lock for ${paths.appPath}. Held by pid ${existing.pid} for ${existing.installRoot}.`
13889
+ );
13890
+ }
13891
+ await delay2(pollMs);
13892
+ }
13893
+ }
13894
+ try {
13895
+ return await fn();
13896
+ } finally {
13897
+ const existing = await readDesktopInstallLock(lockPath);
13898
+ if (existing?.lockId === payload.lockId) {
13899
+ await rm2(lockPath, { force: true });
13900
+ }
13901
+ }
13902
+ }
13837
13903
  function runChecked(command, args, options = {}) {
13838
13904
  const result = spawnSync3(command, args, {
13839
13905
  encoding: "utf8",
@@ -14286,152 +14352,154 @@ async function startCommand(opts) {
14286
14352
  p15.outro(pc15.green("Dry run complete."));
14287
14353
  return;
14288
14354
  }
14289
- const directReleaseVersion = resolveDesktopReleaseVersion(tag);
14290
- const progressFactory = desktopProgressJson ? createDesktopProgressFactory() : createByteProgress;
14291
- let release = null;
14292
- try {
14293
- release = await runStartPhase(
14294
- "Resolving Desktop release...",
14295
- "Desktop release resolved.",
14296
- () => fetchGithubRelease(repo, tag),
14297
- desktopProgressJson ? "resolving_release" : null
14298
- );
14299
- } catch (error) {
14300
- if (!directReleaseVersion) throw error;
14301
- p15.log.warn(
14302
- `Desktop release metadata could not be resolved; falling back to deterministic download URLs. ${formatFetchError(error)}`
14303
- );
14304
- }
14305
- const releaseTag = release?.tag_name ?? (directReleaseVersion ? tag : null);
14306
- if (!releaseTag) {
14307
- throw new Error(`Unable to resolve Rudder Desktop release tag for ${repo}@${tag}.`);
14308
- }
14309
- const assetCandidates = resolveDesktopAssetCandidates({
14310
- releaseAssets: release?.assets ?? [],
14311
- target,
14312
- repo,
14313
- tag,
14314
- directReleaseVersion,
14315
- allowShellAssets: runtimeSupportsShellAssets
14316
- });
14317
- if (assetCandidates.length === 0) {
14318
- throw new Error(`No Rudder Desktop portable asset found for ${target.platform}/${target.arch} in ${repo}@${releaseTag}.`);
14319
- }
14320
- const checksumAsset = selectChecksumAsset(release?.assets ?? []) ?? (directReleaseVersion ? buildGithubReleaseAsset(repo, tag, DESKTOP_CHECKSUM_ASSET_NAME) : null);
14321
- const checksums = await downloadChecksums(checksumAsset, outputDir, progressFactory);
14322
- let selectedCandidate;
14323
- try {
14324
- selectedCandidate = selectChecksummedDesktopAssetCandidate(assetCandidates, checksums);
14325
- } catch (error) {
14326
- throw new Error(`No checksummed Rudder Desktop asset found for ${target.platform}/${target.arch} in ${repo}@${releaseTag}.`);
14327
- }
14328
- for (const warning of selectedCandidate.warnings) p15.log.warn(warning);
14329
- let selectedAsset = selectedCandidate.asset;
14330
- let selectedAssetKind = selectedCandidate.kind;
14331
- let expectedChecksum = selectedCandidate.expectedChecksum;
14332
- const metadata = await readInstallMetadata(installPaths.metadataPath);
14333
- if (isInstalledDesktopCurrent(metadata, releaseTag, selectedAsset.name, expectedChecksum) && await pathExists2(installPaths.executablePath)) {
14334
- p15.log.success(`Rudder Desktop is already installed at ${pc15.cyan(installPaths.appPath)}.`);
14335
- await runStartPhase(
14336
- "Refreshing Desktop launchers...",
14337
- "Desktop launchers ready.",
14338
- async () => {
14339
- await removeMacQuarantine(installPaths, target);
14340
- await createPlatformLaunchers(installPaths, target);
14341
- },
14342
- desktopProgressJson ? "preparing_restart" : null
14343
- );
14344
- } else {
14345
- let cachedAsset;
14355
+ await withDesktopInstallLock(installPaths, async () => {
14356
+ const directReleaseVersion = resolveDesktopReleaseVersion(tag);
14357
+ const progressFactory = desktopProgressJson ? createDesktopProgressFactory() : createByteProgress;
14358
+ let release = null;
14346
14359
  try {
14347
- cachedAsset = await downloadDesktopAssetWithCache(selectedAsset, expectedChecksum, {
14348
- outputDir,
14349
- progressFactory
14350
- });
14360
+ release = await runStartPhase(
14361
+ "Resolving Desktop release...",
14362
+ "Desktop release resolved.",
14363
+ () => fetchGithubRelease(repo, tag),
14364
+ desktopProgressJson ? "resolving_release" : null
14365
+ );
14351
14366
  } catch (error) {
14352
- const fullCandidate = assetCandidates.find((candidate) => candidate.kind === "full");
14353
- if (selectedAssetKind !== "shell" || !fullCandidate) throw error;
14367
+ if (!directReleaseVersion) throw error;
14354
14368
  p15.log.warn(
14355
- `Layered Desktop shell asset download failed; falling back to the full portable asset. ${formatFetchError(error)}`
14369
+ `Desktop release metadata could not be resolved; falling back to deterministic download URLs. ${formatFetchError(error)}`
14356
14370
  );
14357
- selectedAsset = fullCandidate.asset;
14358
- selectedAssetKind = fullCandidate.kind;
14359
- expectedChecksum = resolveAssetChecksum(checksums, selectedAsset.name);
14360
- cachedAsset = await downloadDesktopAssetWithCache(selectedAsset, expectedChecksum, {
14361
- outputDir,
14362
- progressFactory
14363
- });
14364
14371
  }
14365
- if (cachedAsset.cacheStatus === "hit") {
14366
- p15.log.success(`Desktop asset cache hit at ${pc15.cyan(cachedAsset.path)}.`);
14367
- if (desktopProgressJson) {
14372
+ const releaseTag = release?.tag_name ?? (directReleaseVersion ? tag : null);
14373
+ if (!releaseTag) {
14374
+ throw new Error(`Unable to resolve Rudder Desktop release tag for ${repo}@${tag}.`);
14375
+ }
14376
+ const assetCandidates = resolveDesktopAssetCandidates({
14377
+ releaseAssets: release?.assets ?? [],
14378
+ target,
14379
+ repo,
14380
+ tag,
14381
+ directReleaseVersion,
14382
+ allowShellAssets: runtimeSupportsShellAssets
14383
+ });
14384
+ if (assetCandidates.length === 0) {
14385
+ throw new Error(`No Rudder Desktop portable asset found for ${target.platform}/${target.arch} in ${repo}@${releaseTag}.`);
14386
+ }
14387
+ const checksumAsset = selectChecksumAsset(release?.assets ?? []) ?? (directReleaseVersion ? buildGithubReleaseAsset(repo, tag, DESKTOP_CHECKSUM_ASSET_NAME) : null);
14388
+ const checksums = await downloadChecksums(checksumAsset, outputDir, progressFactory);
14389
+ let selectedCandidate;
14390
+ try {
14391
+ selectedCandidate = selectChecksummedDesktopAssetCandidate(assetCandidates, checksums);
14392
+ } catch (error) {
14393
+ throw new Error(`No checksummed Rudder Desktop asset found for ${target.platform}/${target.arch} in ${repo}@${releaseTag}.`);
14394
+ }
14395
+ for (const warning of selectedCandidate.warnings) p15.log.warn(warning);
14396
+ let selectedAsset = selectedCandidate.asset;
14397
+ let selectedAssetKind = selectedCandidate.kind;
14398
+ let expectedChecksum = selectedCandidate.expectedChecksum;
14399
+ const metadata = await readInstallMetadata(installPaths.metadataPath);
14400
+ if (isInstalledDesktopCurrent(metadata, releaseTag, selectedAsset.name, expectedChecksum) && await pathExists2(installPaths.executablePath)) {
14401
+ p15.log.success(`Rudder Desktop is already installed at ${pc15.cyan(installPaths.appPath)}.`);
14402
+ await runStartPhase(
14403
+ "Refreshing Desktop launchers...",
14404
+ "Desktop launchers ready.",
14405
+ async () => {
14406
+ await removeMacQuarantine(installPaths, target);
14407
+ await createPlatformLaunchers(installPaths, target);
14408
+ },
14409
+ desktopProgressJson ? "preparing_restart" : null
14410
+ );
14411
+ } else {
14412
+ let cachedAsset;
14413
+ try {
14414
+ cachedAsset = await downloadDesktopAssetWithCache(selectedAsset, expectedChecksum, {
14415
+ outputDir,
14416
+ progressFactory
14417
+ });
14418
+ } catch (error) {
14419
+ const fullCandidate = assetCandidates.find((candidate) => candidate.kind === "full");
14420
+ if (selectedAssetKind !== "shell" || !fullCandidate) throw error;
14421
+ p15.log.warn(
14422
+ `Layered Desktop shell asset download failed; falling back to the full portable asset. ${formatFetchError(error)}`
14423
+ );
14424
+ selectedAsset = fullCandidate.asset;
14425
+ selectedAssetKind = fullCandidate.kind;
14426
+ expectedChecksum = resolveAssetChecksum(checksums, selectedAsset.name);
14427
+ cachedAsset = await downloadDesktopAssetWithCache(selectedAsset, expectedChecksum, {
14428
+ outputDir,
14429
+ progressFactory
14430
+ });
14431
+ }
14432
+ if (cachedAsset.cacheStatus === "hit") {
14433
+ p15.log.success(`Desktop asset cache hit at ${pc15.cyan(cachedAsset.path)}.`);
14434
+ if (desktopProgressJson) {
14435
+ writeDesktopProgress({
14436
+ phase: "downloading_asset",
14437
+ message: `Desktop asset cache hit for ${selectedAsset.name}.`,
14438
+ percent: 100
14439
+ });
14440
+ }
14441
+ }
14442
+ const checksum = await runStartPhase(
14443
+ "Verifying Desktop checksum...",
14444
+ `Verified ${pc15.cyan(path21.basename(cachedAsset.path))}.`,
14445
+ () => assertChecksumMatch(cachedAsset.path, expectedChecksum),
14446
+ desktopProgressJson ? "verifying_checksum" : null
14447
+ );
14448
+ if (desktopProgressJson && opts.desktopWaitForApply === true) {
14368
14449
  writeDesktopProgress({
14369
- phase: "downloading_asset",
14370
- message: `Desktop asset cache hit for ${selectedAsset.name}.`,
14450
+ phase: "ready_to_install",
14451
+ message: "Desktop update is downloaded and verified.",
14371
14452
  percent: 100
14372
14453
  });
14454
+ await waitForDesktopApplySignal();
14455
+ writeDesktopProgress({
14456
+ phase: "preparing_restart",
14457
+ message: "Applying Desktop update..."
14458
+ });
14373
14459
  }
14460
+ await runStartPhase(
14461
+ "Replacing existing Rudder Desktop if needed...",
14462
+ "Existing Desktop install is ready for replacement.",
14463
+ () => prepareForDesktopReplace(installPaths, target, { waitForActiveRuns: opts.waitForActiveRuns === true }),
14464
+ desktopProgressJson ? opts.waitForActiveRuns === true ? "waiting_for_active_runs" : "preparing_restart" : null
14465
+ );
14466
+ await runStartPhase(
14467
+ "Installing portable Desktop app...",
14468
+ `Installed Rudder Desktop to ${pc15.cyan(installPaths.appPath)}.`,
14469
+ () => installPortableDesktop(cachedAsset.path, installPaths, target),
14470
+ desktopProgressJson ? "preparing_restart" : null
14471
+ );
14472
+ await runStartPhase(
14473
+ "Preparing Desktop launchers...",
14474
+ "Desktop launchers ready.",
14475
+ async () => {
14476
+ await removeMacQuarantine(installPaths, target);
14477
+ await createPlatformLaunchers(installPaths, target);
14478
+ },
14479
+ desktopProgressJson ? "preparing_restart" : null
14480
+ );
14481
+ await writeInstallMetadata(installPaths, releaseTag, selectedAsset.name, checksum, selectedAssetKind);
14374
14482
  }
14375
- const checksum = await runStartPhase(
14376
- "Verifying Desktop checksum...",
14377
- `Verified ${pc15.cyan(path21.basename(cachedAsset.path))}.`,
14378
- () => assertChecksumMatch(cachedAsset.path, expectedChecksum),
14379
- desktopProgressJson ? "verifying_checksum" : null
14380
- );
14381
- if (desktopProgressJson && opts.desktopWaitForApply === true) {
14382
- writeDesktopProgress({
14383
- phase: "ready_to_install",
14384
- message: "Desktop update is downloaded and verified.",
14385
- percent: 100
14386
- });
14387
- await waitForDesktopApplySignal();
14388
- writeDesktopProgress({
14389
- phase: "preparing_restart",
14390
- message: "Applying Desktop update..."
14391
- });
14392
- }
14393
- await runStartPhase(
14394
- "Replacing existing Rudder Desktop if needed...",
14395
- "Existing Desktop install is ready for replacement.",
14396
- () => prepareForDesktopReplace(installPaths, target, { waitForActiveRuns: opts.waitForActiveRuns === true }),
14397
- desktopProgressJson ? opts.waitForActiveRuns === true ? "waiting_for_active_runs" : "preparing_restart" : null
14398
- );
14399
- await runStartPhase(
14400
- "Installing portable Desktop app...",
14401
- `Installed Rudder Desktop to ${pc15.cyan(installPaths.appPath)}.`,
14402
- () => installPortableDesktop(cachedAsset.path, installPaths, target),
14403
- desktopProgressJson ? "preparing_restart" : null
14404
- );
14405
- await runStartPhase(
14406
- "Preparing Desktop launchers...",
14407
- "Desktop launchers ready.",
14408
- async () => {
14409
- await removeMacQuarantine(installPaths, target);
14410
- await createPlatformLaunchers(installPaths, target);
14411
- },
14412
- desktopProgressJson ? "preparing_restart" : null
14413
- );
14414
- await writeInstallMetadata(installPaths, releaseTag, selectedAsset.name, checksum, selectedAssetKind);
14415
- }
14416
- const desktopAssetPrune = await maybePruneDesktopAssetCache({
14417
- protectedChecksums: [expectedChecksum]
14418
- });
14419
- if (desktopAssetPrune) {
14420
- if (desktopAssetPrune.deleted.length > 0) {
14421
- p15.log.success(
14422
- `Pruned ${desktopAssetPrune.deleted.length} old Desktop asset cache(s), freed ${formatBytes(desktopAssetPrune.freedBytes)}.`
14483
+ const desktopAssetPrune = await maybePruneDesktopAssetCache({
14484
+ protectedChecksums: [expectedChecksum]
14485
+ });
14486
+ if (desktopAssetPrune) {
14487
+ if (desktopAssetPrune.deleted.length > 0) {
14488
+ p15.log.success(
14489
+ `Pruned ${desktopAssetPrune.deleted.length} old Desktop asset cache(s), freed ${formatBytes(desktopAssetPrune.freedBytes)}.`
14490
+ );
14491
+ }
14492
+ for (const warning of desktopAssetPrune.warnings) p15.log.warn(warning);
14493
+ }
14494
+ if (opts.open !== false) {
14495
+ await runStartPhase(
14496
+ "Launching Rudder Desktop...",
14497
+ "Rudder Desktop launched.",
14498
+ () => launchDesktop(installPaths, target),
14499
+ desktopProgressJson ? "closing" : null
14423
14500
  );
14424
14501
  }
14425
- for (const warning of desktopAssetPrune.warnings) p15.log.warn(warning);
14426
- }
14427
- if (opts.open !== false) {
14428
- await runStartPhase(
14429
- "Launching Rudder Desktop...",
14430
- "Rudder Desktop launched.",
14431
- () => launchDesktop(installPaths, target),
14432
- desktopProgressJson ? "closing" : null
14433
- );
14434
- }
14502
+ });
14435
14503
  }
14436
14504
  p15.outro(pc15.green("Rudder start complete."));
14437
14505
  }