Merge pull request #245 from zkochan/issue244

Preserve symlinks on Node.js >=v6.3.0
This commit is contained in:
Rico Sta. Cruz
2016-07-12 11:39:55 +08:00
committed by GitHub

View File

@@ -1,11 +1,14 @@
var join = require('path').join
var basename = require('path').basename
var semver = require('semver')
var relSymlink = require('../fs/rel_symlink')
var fs = require('mz/fs')
var mkdirp = require('../fs/mkdirp')
var debug = require('debug')('pnpm:link_bins')
var requireJson = require('../fs/require_json')
var preserveSymlinks = semver.satisfies(process.version, '>=6.3.0')
module.exports = function linkAllBins (modules) {
getDirectories(modules)
.reduce((pkgDirs, dir) => pkgDirs.concat(isScopedPkgsDir(dir) ? getDirectories(dir) : dir), [])
@@ -38,25 +41,88 @@ function isScopedPkgsDir (dirPath) {
function linkBins (modules, target) {
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]
var externalBinPath = join(modules, '.bin', bin)
return Promise.resolve()
.then(_ => fs.chmod(join(target, actualBin), 0o755))
.then(_ => mkdirp(join(modules, '.bin')))
.then(_ => debug('linking %s -> %s',
join(target, actualBin),
join(modules, '.bin', bin)))
.then(_ => relSymlink(
join(target, actualBin),
join(modules, '.bin', bin)))
.then(_ => {
if (!preserveSymlinks) {
return makeExecutable(join(target, actualBin))
.then(_ => debug('linking %s -> %s',
join(target, actualBin),
externalBinPath))
.then(_ => relSymlink(
join(target, actualBin),
externalBinPath))
}
var targetPath = join(pkg.name, actualBin)
if (process.platform !== 'win32') {
return proxy(externalBinPath, targetPath)
}
return cmdShim(externalBinPath, targetPath)
})
})
}
function makeExecutable (filePath) {
return fs.chmod(filePath, 0o755)
}
function proxy (proxyPath, targetPath) {
var proxyContent = [
'#!/bin/sh',
'":" //# comment; exec /usr/bin/env node --preserve-symlinks "$0" "$@"',
"require('../" + targetPath + "')"
].join('\n')
fs.writeFileSync(proxyPath, proxyContent, 'utf8')
return makeExecutable(proxyPath)
}
function cmdShim (proxyPath, targetPath) {
var cmdContent = [
'@IF EXIST "%~dp0\\node.exe" (',
' "%~dp0\\node.exe --preserve-symlinks" "%~dp0/../' + targetPath + '" %*',
') ELSE (',
' @SETLOCAL',
' @SET PATHEXT=%PATHEXT:;.JS;=;%',
' node --preserve-symlinks "%~dp0/../' + targetPath + '" %*',
')'
].join('\n')
fs.writeFileSync(proxyPath + '.cmd', cmdContent, 'utf8')
var shContent = [
'#!/bin/sh',
'basedir=$(dirname "$(echo "$0" | sed -e \'s,\\,/,g\')")',
'',
'case `uname` in',
' *CYGWIN*) basedir=`cygpath -w "$basedir"`;;',
'esac',
'',
'if [ -x "$basedir/node" ]; then',
' "$basedir/node --preserve-symlinks" "$basedir/../' + targetPath + '" "$@"',
' ret=$?',
'else ',
' node --preserve-symlinks "$basedir/../' + targetPath + '" "$@"',
' ret=$?',
'fi',
'exit $ret',
''
].join('\n')
fs.writeFileSync(proxyPath, shContent, 'utf8')
return Promise.all([
makeExecutable(proxyPath + '.cmd'),
makeExecutable(proxyPath)
])
}
/*
* Like `require()`, but returns `undefined` when it fails
*/