@yarnpkg/fslib
Advanced tools
Comparing version 2.0.0-rc.3 to 2.0.0-rc.4
@@ -239,6 +239,30 @@ "use strict"; | ||
async lockPromise(affectedPath, callback) { | ||
const lockPath = `${affectedPath}.lock`; | ||
const lockPath = `${affectedPath}.flock`; | ||
const interval = 1000 / 60; | ||
const timeout = Date.now() + 60 * 1000; | ||
const startTime = Date.now(); | ||
let fd = null; | ||
// Even when we detect that a lock file exists, we still look inside to see | ||
// whether the pid that created it is still alive. It's not foolproof | ||
// (there are false positive), but there are no false negative and that's | ||
// all that matters in 99% of the cases. | ||
const isAlive = async () => { | ||
let pid; | ||
try { | ||
([pid] = await this.readJsonPromise(lockPath)); | ||
} | ||
catch (error) { | ||
// If we can't read the file repeatedly, we assume the process was | ||
// aborted before even writing finishing writing the payload. | ||
return Date.now() - startTime < 500; | ||
} | ||
try { | ||
// "As a special case, a signal of 0 can be used to test for the | ||
// existence of a process" - so we check whether it's alive. | ||
process.kill(pid, 0); | ||
return true; | ||
} | ||
catch (error) { | ||
return false; | ||
} | ||
}; | ||
while (fd === null) { | ||
@@ -250,3 +274,13 @@ try { | ||
if (error.code === `EEXIST`) { | ||
if (Date.now() < timeout) { | ||
if (!await isAlive()) { | ||
try { | ||
await this.unlinkPromise(lockPath); | ||
continue; | ||
} | ||
catch (error) { | ||
// No big deal if we can't remove it. Just fallback to wait for | ||
// it to be eventually released by its owner. | ||
} | ||
} | ||
if (Date.now() - startTime < 60 * 1000) { | ||
await new Promise(resolve => setTimeout(resolve, interval)); | ||
@@ -263,2 +297,3 @@ } | ||
} | ||
await this.writePromise(fd, JSON.stringify([process.pid])); | ||
try { | ||
@@ -265,0 +300,0 @@ return await callback(); |
@@ -9,5 +9,6 @@ import { FakeFS } from './FakeFS'; | ||
constructor(factory: LazyFSFactory<P>, pathUtils: PathUtils<P>); | ||
protected readonly baseFs: FakeFS<P>; | ||
protected get baseFs(): FakeFS<P>; | ||
protected set baseFs(value: FakeFS<P>); | ||
protected mapFromBase(p: P): P; | ||
protected mapToBase(p: P): P; | ||
} |
@@ -15,2 +15,5 @@ "use strict"; | ||
} | ||
set baseFs(value) { | ||
this.instance = value; | ||
} | ||
mapFromBase(p) { | ||
@@ -17,0 +20,0 @@ return p; |
@@ -9,2 +9,9 @@ "use strict"; | ||
class VirtualFS extends ProxiedFS_1.ProxiedFS { | ||
constructor(virtual, { baseFs = new NodeFS_1.NodeFS() } = {}) { | ||
super(path_1.ppath); | ||
this.baseFs = baseFs; | ||
this.target = path_1.ppath.dirname(virtual); | ||
this.virtual = virtual; | ||
this.mapToBaseRegExp = new RegExp(`^(${escapeRegexp(this.virtual)})((?:/([^\/]+)(?:/([^/]+))?)?((?:/.*)?))$`); | ||
} | ||
static makeVirtualPath(base, component, to) { | ||
@@ -22,9 +29,2 @@ // Obtains the relative distance between the virtual path and its actual target | ||
} | ||
constructor(virtual, { baseFs = new NodeFS_1.NodeFS() } = {}) { | ||
super(path_1.ppath); | ||
this.baseFs = baseFs; | ||
this.target = path_1.ppath.dirname(virtual); | ||
this.virtual = virtual; | ||
this.mapToBaseRegExp = new RegExp(`^(${escapeRegexp(this.virtual)})((?:/([^\/]+)(?:/([^/]+))?)?((?:/.*)?))$`); | ||
} | ||
getRealPath() { | ||
@@ -31,0 +31,0 @@ return this.pathUtils.resolve(this.baseFs.getRealPath(), this.target); |
{ | ||
"name": "@yarnpkg/fslib", | ||
"version": "2.0.0-rc.3", | ||
"version": "2.0.0-rc.4", | ||
"main": "./lib/index.js", | ||
@@ -10,9 +10,5 @@ "sideEffects": false, | ||
}, | ||
"devDependencies": { | ||
"@yarnpkg/pnpify": "2.0.0-rc.3", | ||
"typescript": "^3.5.3" | ||
}, | ||
"scripts": { | ||
"postpack": "rm -rf lib", | ||
"prepack": "mkdir -p lib && rsync -a --exclude '*.ts' sources/ lib/ && pnpify tsc", | ||
"prepack": "mkdir -p lib && rsync -a --exclude '*.ts' sources/ lib/ && run build:compile packages/yarnpkg-fslib", | ||
"release": "yarn npm publish", | ||
@@ -19,0 +15,0 @@ "test:fslib": "run test:unit packages/yarnpkg-fslib", |
132706
0
3222