UNPKG

@salesforce/core

Version:

Core libraries to interact with SFDX projects, orgs, and APIs.

125 lines 4.53 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.pollUntilUnlockSync = exports.pollUntilUnlock = exports.lockInitSync = exports.lockInit = exports.asyncNoop = exports.noop = void 0; /* * Copyright (c) 2023, salesforce.com, inc. * All rights reserved. * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ const node_path_1 = require("node:path"); const proper_lockfile_1 = require("proper-lockfile"); const kit_1 = require("@salesforce/kit"); const ts_retry_promise_1 = require("ts-retry-promise"); const fs_1 = require("../fs/fs"); const sfError_1 = require("../sfError"); const logger_1 = require("../logger/logger"); const global_1 = require("../global"); const lockRetryOptions_1 = require("./lockRetryOptions"); const noop = () => { }; exports.noop = noop; const asyncNoop = async () => { }; exports.asyncNoop = asyncNoop; /** * *This method exists as a separate function so it can be used by ConfigFile OR outside of ConfigFile. * * @param filePath where to save the file * @returns 2 functions: * - writeAndUnlock: a function that takes the data to write and writes it to the file, then unlocks the file whether write succeeded or not * - unlock: a function that unlocks the file (in case you don't end up calling writeAndUnlock) */ const lockInit = async (filePath) => { // make sure we can write to the directory try { await fs_1.fs.promises.mkdir((0, node_path_1.dirname)(filePath), { recursive: true }); } catch (err) { throw sfError_1.SfError.wrap(err); } const unlock = global_1.Global.isWeb ? exports.asyncNoop : await (0, proper_lockfile_1.lock)(filePath, { ...lockRetryOptions_1.lockRetryOptions, realpath: false, fs: fs_1.fs }); return { writeAndUnlock: async (data) => { (await logger_1.Logger.child('fileLocking.writeAndUnlock')).debug(`Writing to file: ${filePath}`); try { await fs_1.fs.promises.writeFile(filePath, data); } finally { await unlock(); } }, unlock, }; }; exports.lockInit = lockInit; /** * prefer async {@link lockInit}. * See its documentation for details. */ const lockInitSync = (filePath) => { // make sure we can write to the directory try { fs_1.fs.mkdirSync((0, node_path_1.dirname)(filePath), { recursive: true }); } catch (err) { throw sfError_1.SfError.wrap(err); } const unlock = global_1.Global.isWeb ? exports.noop : (0, proper_lockfile_1.lockSync)(filePath, { ...lockRetryOptions_1.lockOptions, realpath: false, fs: fs_1.fs }); return { writeAndUnlock: (data) => { const logger = logger_1.Logger.childFromRoot('fileLocking.writeAndUnlock'); logger.debug(`Writing to file: ${filePath}`); try { fs_1.fs.writeFileSync(filePath, data); } finally { unlock(); } }, unlock, }; }; exports.lockInitSync = lockInitSync; /** * Poll until the file is unlocked. * * @param filePath file path to check */ const pollUntilUnlock = async (filePath) => { if (global_1.Global.isWeb) { return; } try { await (0, ts_retry_promise_1.retryDecorator)(proper_lockfile_1.check, { timeout: kit_1.Duration.minutes(1).milliseconds, delay: 10, until: (locked) => locked === false, // don't retry errors (typically enoent or access on the lockfile, therefore not locked) retryIf: () => false, })(filePath, lockRetryOptions_1.lockRetryOptions); } catch (e) { // intentionally swallow the error, same reason as above } }; exports.pollUntilUnlock = pollUntilUnlock; const pollUntilUnlockSync = (filePath) => { if (global_1.Global.isWeb) { return; } // Set a counter to ensure that the while loop does not run indefinitely let counter = 0; let locked = true; while (locked && counter < 100) { try { locked = (0, proper_lockfile_1.checkSync)(filePath, lockRetryOptions_1.lockOptions); counter++; } catch { // Likely a file not found error, which means the file is not locked locked = false; } } }; exports.pollUntilUnlockSync = pollUntilUnlockSync; //# sourceMappingURL=fileLocking.js.map