mirror of
https://github.com/pnpm/pnpm.git
synced 2026-03-31 13:32:18 -04:00
67 lines
1.7 KiB
TypeScript
67 lines
1.7 KiB
TypeScript
import logger from 'pnpm-logger'
|
|
import path = require('path')
|
|
import lockfile = require('proper-lockfile')
|
|
import mkdirp = require('mkdirp-promise')
|
|
import crypto = require('crypto')
|
|
|
|
async function delay(ms: number) {
|
|
return new Promise(resolve => setTimeout(resolve, ms))
|
|
}
|
|
|
|
async function lock(
|
|
lockFilename: string,
|
|
opts: {firstTime: boolean, stale: number}
|
|
): Promise<{}> {
|
|
const promise = new Promise((resolve, reject) => {
|
|
lockfile.lock(
|
|
lockFilename,
|
|
{realpath: false, stale: opts.stale},
|
|
async (err: Error & {code: string}) => {
|
|
if (err && err.code === 'ELOCKED') {
|
|
if (opts.firstTime) {
|
|
logger.warn('waiting for another installation to complete...')
|
|
}
|
|
await delay(200)
|
|
await lock(lockFilename, {firstTime: false, stale: opts.stale})
|
|
resolve()
|
|
} else if (err) {
|
|
reject(err)
|
|
} else {
|
|
resolve()
|
|
}
|
|
})
|
|
})
|
|
return promise as Promise<{}>
|
|
}
|
|
|
|
async function unlock(lockFilename: string): Promise<{}> {
|
|
const promise = new Promise(resolve =>
|
|
lockfile.unlock(
|
|
lockFilename,
|
|
{realpath: false},
|
|
resolve))
|
|
return promise as Promise<{}>
|
|
}
|
|
|
|
export default async function withLock<T> (
|
|
dir: string,
|
|
fn: () => Promise<T>,
|
|
opts: {
|
|
stale: number,
|
|
locks: string,
|
|
}
|
|
): Promise<T> {
|
|
dir = path.resolve(dir)
|
|
await mkdirp(opts.locks)
|
|
const lockFilename = path.join(opts.locks, crypto.createHash('sha1').update(dir).digest('hex'))
|
|
await lock(lockFilename, {firstTime: true, stale: opts.stale})
|
|
try {
|
|
const result = await fn()
|
|
await unlock(lockFilename)
|
|
return result
|
|
} catch (err) {
|
|
await unlock(lockFilename)
|
|
throw err;
|
|
}
|
|
}
|