mirror of
https://github.com/pnpm/pnpm.git
synced 2026-05-18 22:02:53 -04:00
Merge pull request #17 from rstacruz/improve-atomicness
Improve atomicness
This commit is contained in:
23
lib/fs/obliterate.js
Normal file
23
lib/fs/obliterate.js
Normal file
@@ -0,0 +1,23 @@
|
||||
require('../promise')
|
||||
var rimraf = require('thenify')(require('rimraf'))
|
||||
var fs = require('mz/fs')
|
||||
|
||||
/*
|
||||
* Removes `path`.
|
||||
* If it's a symlink, remove its destination as well.
|
||||
*/
|
||||
|
||||
module.exports = function obliterate (path) {
|
||||
return fs.lstat(path)
|
||||
.then(stat => {
|
||||
if (stat.isSymbolicLink()) {
|
||||
return fs.readlink(path)
|
||||
.then(realpath => rimraf(realpath))
|
||||
} else {
|
||||
return rimraf(path)
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
if (err !== 'ENOENT') throw err
|
||||
})
|
||||
}
|
||||
@@ -12,6 +12,7 @@ var relSymlink = require('./rel_symlink')
|
||||
var linkBins = require('./install/link_bins')
|
||||
var linkBundledDeps = require('./install/link_bundled_deps')
|
||||
var fs = require('mz/fs')
|
||||
var obliterate = require('./fs/obliterate')
|
||||
|
||||
/*
|
||||
* Installs a package.
|
||||
@@ -78,12 +79,11 @@ module.exports = function install (ctx, pkgSpec, modules, options) {
|
||||
|
||||
var log = ctx.log(pkg.spec) // function
|
||||
|
||||
return make(join(modules, pkg.spec.name), _ =>
|
||||
return make(join(modules, pkg.spec.name), false, _ =>
|
||||
resolve(pkg.spec)
|
||||
.then(saveResolution)
|
||||
.then(_ => log('resolved', pkg.data))
|
||||
.then(_ => make(paths.target, _ =>
|
||||
buildToStoreCached(ctx, paths, pkg, log)))
|
||||
.then(_ => buildToStoreCached(ctx, paths, pkg, log))
|
||||
.then(_ => mkdirp(paths.modules))
|
||||
.then(_ => symlinkToModules(paths.target, pkg.spec, paths.modules)))
|
||||
.then(_ => log('done'))
|
||||
@@ -111,8 +111,9 @@ function buildToStoreCached (ctx, paths, pkg, log) {
|
||||
if (isCircular(pkg)) {
|
||||
return Promise.resolve()
|
||||
} else {
|
||||
return memoize(ctx.builds, pkg.fullname, _ =>
|
||||
buildToStore(ctx, paths, pkg, log))
|
||||
return make(paths.target, ctx.builds[pkg.fullname], _ =>
|
||||
memoize(ctx.builds, pkg.fullname, _ =>
|
||||
buildToStore(ctx, paths, pkg, log)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +136,7 @@ function buildToStore (ctx, paths, pkg, log) {
|
||||
.then(_ => log('downloading'))
|
||||
.then(_ => mkdirp(paths.store))
|
||||
.then(_ => mkdirp(paths.tmp))
|
||||
.then(_ => fs.writeFile(join(paths.tmp, '.pnpm_inprogress'), '', 'utf-8'))
|
||||
.then(_ => fetch(paths.tmp, pkg.dist.tarball, pkg.dist.shasum, log))
|
||||
|
||||
// update pkg.fulldata; to be used later
|
||||
@@ -156,6 +158,7 @@ function buildToStore (ctx, paths, pkg, log) {
|
||||
.then(_ => symlinkSelf(paths.tmp, pkg.data, pkg.keypath.length))
|
||||
|
||||
// move to .store/lodash@4.0.0; remove the stub done earlier
|
||||
.then(_ => fs.unlink(join(paths.tmp, '.pnpm_inprogress')))
|
||||
.then(_ => fs.unlink(paths.target))
|
||||
.then(_ => fs.rename(paths.tmp, paths.target))
|
||||
}
|
||||
@@ -208,12 +211,19 @@ function isCircular (pkg) {
|
||||
}
|
||||
|
||||
/*
|
||||
* If `path` exists, don't do anything; otherwise invoke `fn()`.
|
||||
* Kinda like how makefiles work.
|
||||
* If `path` doesn't exist, run `fn()`.
|
||||
* If it exists and is not in progress, don't do anything.
|
||||
* If it's in progress, check if we're working on it. If we're not,
|
||||
* obliterate it and run `fn()`.
|
||||
*/
|
||||
|
||||
function make (path, fn) {
|
||||
function make (path, isWorking, fn) {
|
||||
return fs.stat(path)
|
||||
.then(_ => {
|
||||
return fs.stat(join(path, '.pnpm_inprogress'))
|
||||
.then(_ => { if (!isWorking) return obliterate(path).then(fn) })
|
||||
.catch(err => { if (err.code !== 'ENOENT') throw err })
|
||||
})
|
||||
.catch(err => {
|
||||
if (err.code !== 'ENOENT') throw err
|
||||
return fn()
|
||||
|
||||
Reference in New Issue
Block a user