UNPKG

nx

Version:

The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.

184 lines (183 loc) • 7.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.resetHandler = resetHandler; const node_fs_1 = require("node:fs"); const client_1 = require("../../daemon/client/client"); const tmp_dir_1 = require("../../daemon/tmp-dir"); const cache_directory_1 = require("../../utils/cache-directory"); const output_1 = require("../../utils/output"); const native_file_cache_location_1 = require("../../native/native-file-cache-location"); const workspace_root_1 = require("../../utils/workspace-root"); const client_2 = require("../../nx-cloud/utilities/client"); const get_cloud_options_1 = require("../../nx-cloud/utilities/get-cloud-options"); const nx_cloud_utils_1 = require("../../utils/nx-cloud-utils"); const configuration_1 = require("../../config/configuration"); const update_manager_1 = require("../../nx-cloud/update-manager"); // Wait at max 5 seconds before giving up on a failing operation. const INCREMENTAL_BACKOFF_MAX_DURATION = 5000; // If an operation fails, wait 100ms before first retry. const INCREMENTAL_BACKOFF_FIRST_DELAY = 100; async function resetHandler(args) { let errors = []; const all = args.onlyDaemon === undefined && args.onlyCache === undefined && args.onlyWorkspaceData === undefined; const nxJson = (0, configuration_1.readNxJson)(); const cloudEnabled = (0, nx_cloud_utils_1.isNxCloudUsed)(nxJson); const startupMessage = all ? 'Resetting the Nx cache and stopping the daemon.' : 'Resetting:'; const bodyLines = []; if (!all) { if (args.onlyDaemon) { bodyLines.push('- Nx Daemon and its workspace data'); } if (args.onlyCache) { bodyLines.push('- Cache directory'); } if (args.onlyWorkspaceData) { bodyLines.push('- Workspace data directory'); } if (args.onlyCloud && cloudEnabled) { bodyLines.push('- Nx Cloud Client'); } } output_1.output.note({ title: startupMessage, bodyLines }); if (all || args.onlyDaemon) { try { await killDaemon(); } catch (e) { errors.push('Failed to stop the Nx Daemon.', e.toString()); } try { await cleanupDaemonWorkspaceData(); } catch (e) { errors.push('Failed to clean up the daemon workspace data directory.', e.toString()); } } if (all || args.onlyCache) { try { await cleanupCacheEntries(); } catch (e) { errors.push('Failed to clean up the cache directory.', e.toString()); } } if (all || args.onlyWorkspaceData) { try { await cleanupNativeFileCache(); } catch { // ignore, deleting the native file cache is not critical and can fail if another process is locking the file } try { await cleanupWorkspaceData(); } catch (e) { errors.push('Failed to clean up the workspace data directory.', e.toString()); } } if ((cloudEnabled && all) || args.onlyCloud) { try { await resetCloudClient(); await removeInstalledNxCloudClient(); } catch (e) { errors.push('Failed to reset the Nx Cloud client.', e.toString()); } } if (errors.length > 0) { output_1.output.error({ title: 'Failed to reset the Nx workspace.', bodyLines: errors, }); process.exit(1); } else { output_1.output.success({ title: 'Successfully reset the Nx workspace.', }); } } async function killDaemon() { if (client_1.daemonClient.enabled()) { return client_1.daemonClient.stop(); } } function cleanupDaemonWorkspaceData() { return incrementalBackoff(INCREMENTAL_BACKOFF_FIRST_DELAY, INCREMENTAL_BACKOFF_MAX_DURATION, () => { (0, node_fs_1.rmSync)(tmp_dir_1.DAEMON_DIR_FOR_CURRENT_WORKSPACE, { recursive: true, force: true, }); }); } async function resetCloudClient() { // Remove nx cloud marker files. This helps if the use happens to run `nx-cloud start-ci-run` or // similar commands on their local machine. try { (await (0, client_2.getCloudClient)((0, get_cloud_options_1.getCloudOptions)())).invoke('cleanup'); } catch { } } function removeInstalledNxCloudClient() { return incrementalBackoff(INCREMENTAL_BACKOFF_FIRST_DELAY, INCREMENTAL_BACKOFF_MAX_DURATION, () => { (0, node_fs_1.rmSync)((0, update_manager_1.getBundleInstallDefaultLocation)(), { recursive: true, force: true }); }); } function cleanupCacheEntries() { return incrementalBackoff(INCREMENTAL_BACKOFF_FIRST_DELAY, INCREMENTAL_BACKOFF_MAX_DURATION, () => { (0, node_fs_1.rmSync)(cache_directory_1.cacheDir, { recursive: true, force: true }); // `cacheDir` is the shared directory whenever sharing is available, so // this is the checkout's own `.nx/cache`: still there from before the // move, and still what a later run falls back to if `~/.nx` stops being // reachable. Reset means both. removeIfDistinct((0, cache_directory_1.cacheDirectoryForWorkspace)(workspace_root_1.workspaceRoot), cache_directory_1.cacheDir); }); } /** Skips the no-op when the two resolve to one directory. */ function removeIfDistinct(dir, from) { if (dir !== from) { (0, node_fs_1.rmSync)(dir, { recursive: true, force: true }); } } function cleanupNativeFileCache() { return incrementalBackoff(INCREMENTAL_BACKOFF_FIRST_DELAY, INCREMENTAL_BACKOFF_MAX_DURATION, () => { // Null when the native cache root is not a real directory we own, which // would mean deleting through a path another user planted. const cacheDir = (0, native_file_cache_location_1.getNativeFileCacheLocationToDelete)(); if (cacheDir) { (0, node_fs_1.rmSync)(cacheDir, { recursive: true, force: true }); } }); } function cleanupWorkspaceData() { return incrementalBackoff(INCREMENTAL_BACKOFF_FIRST_DELAY, INCREMENTAL_BACKOFF_MAX_DURATION, () => { (0, node_fs_1.rmSync)(cache_directory_1.workspaceDataDirectory, { recursive: true, force: true }); // Also clean wherever the DB actually lives, which is outside this // checkout whenever the shared root is reachable. Resolved through the // same decision the DB itself uses, so reset cannot delete a directory // this process never wrote to -- a sandboxed agent that fell back to its // own checkout, or a configured location, yields nothing extra. removeIfDistinct((0, cache_directory_1.sharedDataDirectory)(workspace_root_1.workspaceRoot, 'workspace-data'), cache_directory_1.workspaceDataDirectory); }); } async function incrementalBackoff(ms, maxDuration, callback) { try { callback(); } catch (e) { if (ms < maxDuration) { await sleep(ms); await incrementalBackoff(ms * 2, maxDuration, callback); } else { throw e; } } } function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); }