From 7e12f30188d52f15b97125c4593849d73bc129f5 Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Sun, 10 Jul 2016 17:22:06 +0300 Subject: [PATCH 1/2] Preserve symlinks on Node.js>=v6.3.0 close #244 --- lib/install/link_bins.js | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/lib/install/link_bins.js b/lib/install/link_bins.js index a90872497a..d3e7a67f0c 100644 --- a/lib/install/link_bins.js +++ b/lib/install/link_bins.js @@ -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,47 @@ 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)) + } + + proxy(externalBinPath, join(pkg.name, actualBin)) + return makeExecutable(externalBinPath) + }) }) } +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') +} + /* * Like `require()`, but returns `undefined` when it fails */ From a33869e441a12c980a22e694d138153ab12dd432 Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Mon, 11 Jul 2016 23:28:12 +0300 Subject: [PATCH 2/2] create command and sh files on windows to link bin files --- lib/install/link_bins.js | 45 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/lib/install/link_bins.js b/lib/install/link_bins.js index d3e7a67f0c..39c7669227 100644 --- a/lib/install/link_bins.js +++ b/lib/install/link_bins.js @@ -63,8 +63,11 @@ function linkBins (modules, target) { externalBinPath)) } - proxy(externalBinPath, join(pkg.name, actualBin)) - return makeExecutable(externalBinPath) + var targetPath = join(pkg.name, actualBin) + if (process.platform !== 'win32') { + return proxy(externalBinPath, targetPath) + } + return cmdShim(externalBinPath, targetPath) }) }) } @@ -80,6 +83,44 @@ function proxy (proxyPath, targetPath) { "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) + ]) } /*