Refactor linkBins()

This commit is contained in:
Rico Sta. Cruz
2016-01-28 22:05:39 +08:00
parent d4e36e2367
commit 5cedc4089f
2 changed files with 82 additions and 54 deletions

View File

@@ -1,15 +1,14 @@
var Promise = require('./promise')
var debug = require('debug')('pnpm:install')
var npa = require('npm-package-arg')
var config = require('./config')
var join = require('path').join
var mkdirp = require('./mkdirp')
var fetch = require('./fetch')
var resolve = require('./resolve')
var getUuid = require('node-uuid')
var symlink = require('./force_symlink')
var linkBins = require('./install/link_bins')
var fs = require('mz/fs')
var basename = require('path').basename
/*
* Installs a package.
@@ -49,8 +48,9 @@ module.exports = function install (ctx, pkg, modules, options) {
var log = ctx.log(pkgSpec) // function
var tmp = join(ctx.tmp, getUuid()) // 'node_modules/.tmp/000-11...'
return fs.stat(join(modules, pkgSpec.name))
return fs.stat(join(modules, pkgSpec.name, 'package.json'))
.catch((err) => {
if (err.code !== 'ENOENT') throw err
return resolve(pkgSpec)
.then(set)
.then(_ => log('resolved', pkgData))
@@ -63,7 +63,6 @@ module.exports = function install (ctx, pkg, modules, options) {
.then(_ => log('downloading'))
.then(_ => mkdirp(store))
.then(_ => mkdirp(tmp))
// TODO: check for existence of target
.then(_ => fetch(tmp, dist.tarball, dist.shasum, log))
.then(_ => linkBins(modules, tmp, fullname))
.then(_ => log('dependencies'))
@@ -76,7 +75,7 @@ module.exports = function install (ctx, pkg, modules, options) {
.then(_ => unlock(ctx, target))
})
.then(_ => mkdirp(modules))
.then(_ => doSymlink())
.then(_ => symlinkToModules(fullname, name, modules, depth))
})
.then(_ => log('done'))
.catch((err) => {
@@ -92,17 +91,6 @@ module.exports = function install (ctx, pkg, modules, options) {
name = res.name
dist = res.dist
}
// perform the final symlinking of ./.store/x@1.0.0 => ./x.
function doSymlink () {
if (depth === 0) {
return symlink(join('.store', fullname), join(modules, name))
} else {
// we'll go back to ..../.store here so the same module will act the same
// on node_modules/.tmp
return symlink(join('..', '..', '..', '.store', fullname), join(modules, name))
}
}
}
function lock (ctx, path) {
@@ -119,7 +107,7 @@ function isLocked (ctx, path) {
}
/*
* symlink a package into its own node_modules. this way, babel-runtime@5 can
* Symlink a package into its own node_modules. this way, babel-runtime@5 can
* require('babel-runtime') within itself.
*/
@@ -135,45 +123,20 @@ function symlinkSelf (target, name, depth) {
}
/*
* Links executables into `node_modules/.bin`
* Perform the final symlinking of ./.store/x@1.0.0 -> ./x.
*
* module = 'project/node_modules'
* target = 'project/node_modules/.tmp/a1b3c56...'
* linkBins(module, target, 'rimraf@2.5.1')
*
* // node_modules/.bin/rimraf -> ../.store/rimraf@2.5.1/cmd.js
* fullname = 'lodash@4.0.0'
* name = 'lodash'
* modules = './node_modules'
* symlinkToModules(fullname, name, modules, 0)
*/
function linkBins (module, target, fullname) {
var pkg = tryRequire(join(target, 'package.json'))
if (!pkg || !pkg.bin) return
var bins = binify(pkg)
return Object.keys(bins).map((bin) => {
var actualBin = bins[bin]
return Promise.resolve()
.then(_ => fs.chmod(join(target, actualBin), 0o755))
.then(_ => mkdirp(join(module, '.bin')))
.then(_ => symlink(
join('..', '.store', fullname, actualBin),
join(module, '.bin', bin)))
})
}
function binify (pkg) {
if (typeof pkg.bin === 'string') {
var obj = {}
obj[pkg.name] = pkg.bin
return obj
function symlinkToModules (fullname, name, modules, depth) {
if (depth === 0) {
return symlink(join('.store', fullname), join(modules, name))
} else {
// we'll go back to ..../.store here so the same module will act the same
// on node_modules/.tmp
return symlink(join('..', '..', '..', '.store', fullname), join(modules, name))
}
return pkg.bin
}
function tryRequire (path) {
try {
return require(path)
} catch (e) { }
}

65
lib/install/link_bins.js Normal file
View File

@@ -0,0 +1,65 @@
var join = require('path').join
var symlink = require('../force_symlink')
var fs = require('mz/fs')
var mkdirp = require('../mkdirp')
/*
* Links executables into `node_modules/.bin`.
*
* - `modules` (String) - the node_modlules path
* - `target` (String) - where the module is now; read package.json from here
* - `fullname` (String) - fullname of the module (`rimraf@2.5.1`)
*
* module = 'project/node_modules'
* target = 'project/node_modules/.tmp/a1b3c56...'
* linkBins(module, target, 'rimraf@2.5.1')
*
* // node_modules/.bin/rimraf -> ../.store/rimraf@2.5.1/cmd.js
*/
module.exports = function linkBins (modules, target, fullname) {
var pkg = tryRequire(join(target, 'package.json'))
if (!pkg || !pkg.bin) return
var bins = binify(pkg)
return Object.keys(bins).map((bin) => {
var actualBin = bins[bin]
return Promise.resolve()
.then(_ => fs.chmod(join(target, actualBin), 0o755))
.then(_ => mkdirp(join(modules, '.bin')))
.then(_ => symlink(
join('..', '.store', fullname, actualBin),
join(modules, '.bin', bin)))
})
}
/*
* Like `require()`, but returns `undefined` when it fails
*/
function tryRequire (path) {
try { return require(path) } catch (e) { }
}
/*
* Returns bins for a package in a standard object format. This normalizes
* between npm's string and object formats.
*
* binify({ name: 'rimraf', bin: 'cmd.js' })
* => { rimraf: 'cmd.js' }
*
* binify({ name: 'rmrf', bin: { rmrf: 'cmd.js' } })
* => { rmrf: 'cmd.js' }
*/
function binify (pkg) {
if (typeof pkg.bin === 'string') {
var obj = {}
obj[pkg.name] = pkg.bin
return obj
}
return pkg.bin
}