Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorScott Santucci <ScottFreeCode@users.noreply.github.com>2017-05-15 23:48:50 +0300
committerRebecca Turner <me@re-becca.org>2017-08-17 21:20:05 +0300
commit0ef320cb40222693b7367b97c60ddffabc2d58c5 (patch)
tree7ed5eebef6c50e7971caffc00587329a6cfd208d /lib
parenta267ab4309883012a9d55934533c5915e9842277 (diff)
build: Check if bin script starts with hashbang
PR-URL: https://github.com/npm/npm/pull/16634 Fixes: #12371 Fixes: #13203 Credit: @ScottFreeCode Reviewed-By: @iarna
Diffstat (limited to 'lib')
-rw-r--r--lib/build.js21
-rw-r--r--lib/utils/convert-line-endings.js49
-rw-r--r--lib/utils/is-hashbang-file.js19
3 files changed, 82 insertions, 7 deletions
diff --git a/lib/build.js b/lib/build.js
index 44ac40a00..6a788bc85 100644
--- a/lib/build.js
+++ b/lib/build.js
@@ -18,6 +18,8 @@ var link = require('./utils/link.js')
var linkIfExists = link.ifExists
var cmdShim = require('cmd-shim')
var cmdShimIfExists = cmdShim.ifExists
+var isHashbangFile = require('./utils/is-hashbang-file.js')
+var dos2Unix = require('./utils/convert-line-endings.js').dos2Unix
var asyncMap = require('slide').asyncMap
var ini = require('ini')
var writeFile = require('write-file-atomic')
@@ -187,13 +189,18 @@ function linkBins (pkg, folder, parent, gtop, cb) {
if (er && er.code === 'ENOENT' && npm.config.get('ignore-scripts')) {
return cb()
}
- if (er || !gtop) return cb(er)
- var dest = path.resolve(binRoot, b)
- var out = npm.config.get('parseable')
- ? dest + '::' + src + ':BINFILE'
- : dest + ' -> ' + src
- if (!npm.config.get('json') && !npm.config.get('parseable')) output(out)
- cb()
+ if (er) return cb(er)
+ isHashbangFile(src).then((isHashbang) => {
+ if (isHashbang) return dos2Unix(src)
+ }).then(() => {
+ if (!gtop) return cb()
+ var dest = path.resolve(binRoot, b)
+ var out = npm.config.get('parseable')
+ ? dest + '::' + src + ':BINFILE'
+ : dest + ' -> ' + src
+ if (!npm.config.get('json') && !npm.config.get('parseable')) output(out)
+ cb()
+ }).catch(cb)
})
}
)
diff --git a/lib/utils/convert-line-endings.js b/lib/utils/convert-line-endings.js
new file mode 100644
index 000000000..b05d328aa
--- /dev/null
+++ b/lib/utils/convert-line-endings.js
@@ -0,0 +1,49 @@
+'use strict'
+
+const Transform = require('stream').Transform
+const Bluebird = require('bluebird')
+const fs = require('graceful-fs')
+const stat = Bluebird.promisify(fs.stat)
+const chmod = Bluebird.promisify(fs.chmod)
+const fsWriteStreamAtomic = require('fs-write-stream-atomic')
+
+module.exports.dos2Unix = dos2Unix
+
+function dos2Unix (file) {
+ return stat(file).then((stats) => {
+ let previousChunkEndedInCR = false
+ return new Bluebird((resolve, reject) => {
+ fs.createReadStream(file)
+ .on('error', reject)
+ .pipe(new Transform({
+ transform: function (chunk, encoding, done) {
+ let data = chunk.toString()
+ if (previousChunkEndedInCR) {
+ data = '\r' + data
+ }
+ if (data[data.length - 1] === '\r') {
+ data = data.slice(0, -1)
+ previousChunkEndedInCR = true
+ } else {
+ previousChunkEndedInCR = false
+ }
+ done(null, data.replace(/\r\n/g, '\n'))
+ },
+ flush: function (done) {
+ if (previousChunkEndedInCR) {
+ this.push('\r')
+ }
+ done()
+ }
+ }))
+ .on('error', reject)
+ .pipe(fsWriteStreamAtomic(file))
+ .on('error', reject)
+ .on('finish', function () {
+ resolve(chmod(file, stats.mode))
+ })
+ })
+ })
+}
+
+// could add unix2Dos and legacy Mac functions if need be
diff --git a/lib/utils/is-hashbang-file.js b/lib/utils/is-hashbang-file.js
new file mode 100644
index 000000000..f1677381f
--- /dev/null
+++ b/lib/utils/is-hashbang-file.js
@@ -0,0 +1,19 @@
+'use strict'
+const Bluebird = require('bluebird')
+const fs = require('graceful-fs')
+const open = Bluebird.promisify(fs.open)
+const close = Bluebird.promisify(fs.close)
+
+module.exports = isHashbangFile
+
+function isHashbangFile (file) {
+ return open(file, 'r').then((fileHandle) => {
+ return new Bluebird((resolve, reject) => {
+ fs.read(fileHandle, new Buffer(new Array(2)), 0, 2, 0, function (err, bytesRead, buffer) {
+ close(fileHandle).then(() => {
+ resolve(!err && buffer.toString() === '#!')
+ }).catch(reject)
+ })
+ })
+ })
+}