import path from 'path'; import fs from 'fs'; import { getTsPackage } from '../ts-package'; import { getLockFilePath, PackageError } from '../system'; import { getHash } from './general'; /* ****************************************************************************************************************** */ // region: Config /* ****************************************************************************************************************** */ const lockFileWaitMs = 2_000; // endregion /* ****************************************************************************************************************** */ // region: Helpers /* ****************************************************************************************************************** */ function waitForLockRelease(lockFilePath: string) { const start = Date.now(); while (fs.existsSync(lockFilePath)) { sleep(100); if ((Date.now() - start) > lockFileWaitMs) throw new Error( `Could not acquire lock to write file. If problem persists, run ts-patch clear-cache and try again. `); } function sleep(ms: number) { const wakeUpTime = Date.now() + ms; while (Date.now() < wakeUpTime) {} } } // endregion /* ****************************************************************************************************************** */ // region: Utils /* ****************************************************************************************************************** */ /** * Attempts to locate global installation of TypeScript */ export function getGlobalTsDir() { const errors = []; const dir = require('global-prefix'); const check = (dir: string) => { try { return getTsPackage(dir) } catch (e) { errors.push(e); return {}; } }; const { packageDir } = (check(dir) || check(path.join(dir, 'lib'))); if (!packageDir) throw new PackageError(`Could not find global TypeScript installation! Are you sure it's installed globally?`); return packageDir; } export const mkdirIfNotExist = (dir: string) => !fs.existsSync(dir) && fs.mkdirSync(dir, { recursive: true }); export function withFileLock(filePath: string, fn: () => T): T { const lockFileName = getHash(filePath) + '.lock'; const lockFilePath = getLockFilePath(lockFileName); try { const lockFileDir = path.dirname(lockFilePath); if (!fs.existsSync(lockFileDir)) fs.mkdirSync(lockFileDir, { recursive: true }); waitForLockRelease(lockFilePath); fs.writeFileSync(lockFilePath, ''); return fn(); } finally { if (fs.existsSync(lockFilePath)) fs.rmSync(lockFilePath, { force: true }); } } export function writeFileWithLock(filePath: string, content: string): void { withFileLock(filePath, () => { fs.writeFileSync(filePath, content); }); } export function readFileWithLock(filePath: string): string { return withFileLock(filePath, () => { return fs.readFileSync(filePath, 'utf8'); }); } export function copyFileWithLock(src: string, dest: string): void { withFileLock(src, () => { withFileLock(dest, () => { fs.copyFileSync(src, dest); }); }); } // endregion