Skip to content

Commit 48fd811

Browse files
committed
promisification
1 parent c5f9b8e commit 48fd811

File tree

3 files changed

+55
-125
lines changed

3 files changed

+55
-125
lines changed

README.md

+6-16
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ On Unix systems, you should use a symbolic link instead.
77

88
[![Build Status](https://img.shields.io/travis/npm/cmd-shim/master.svg)](https://travis-ci.org/npm/cmd-shim)
99
[![Dependency Status](https://img.shields.io/david/npm/cmd-shim.svg)](https://david-dm.org/npm/cmd-shim)
10-
[![NPM version](https://img.shields.io/npm/v/cmd-shim.svg)](https://www.npmjs.com/package/cmd-shim)
10+
[![npm version](https://img.shields.io/npm/v/cmd-shim.svg)](https://www.npmjs.com/package/cmd-shim)
1111

1212
## Installation
1313

@@ -17,28 +17,18 @@ npm install cmd-shim
1717

1818
## API
1919

20-
### cmdShim(from, to, cb)
20+
### cmdShim(from, to) -> Promise
2121

2222
Create a cmd shim at `to` for the command line program at `from`.
2323
e.g.
2424

2525
```javascript
2626
var cmdShim = require('cmd-shim');
27-
cmdShim(__dirname + '/cli.js', '/usr/bin/command-name', function (err) {
28-
if (err) throw err;
29-
});
27+
cmdShim(__dirname + '/cli.js', '/usr/bin/command-name').then(() => {
28+
// shims are created!
29+
})
3030
```
3131

32-
### cmdShim.ifExists(from, to, cb)
32+
### cmdShim.ifExists(from, to) -> Promise
3333

3434
The same as above, but will just continue if the file does not exist.
35-
Source:
36-
37-
```javascript
38-
function cmdShimIfExists (from, to, cb) {
39-
fs.stat(from, function (er) {
40-
if (er) return cb()
41-
cmdShim(from, to, cb)
42-
})
43-
}
44-
```

index.js

+36-58
Original file line numberDiff line numberDiff line change
@@ -8,64 +8,55 @@
88
// Write a binroot/pkg.bin + ".cmd" file that has this line in it:
99
// @<prog> <args...> %dp0%<target> %*
1010

11+
const {promisify} = require('util')
1112
const fs = require('fs')
13+
const writeFile = promisify(fs.writeFile)
14+
const readFile = promisify(fs.readFile)
15+
const chmod = promisify(fs.chmod)
16+
const stat = promisify(fs.stat)
17+
const unlink = promisify(fs.unlink)
1218

19+
const {dirname, relative} = require('path')
1320
const mkdir = require('mkdirp')
14-
const path = require('path')
1521
const toBatchSyntax = require('./lib/to-batch-syntax')
1622
const shebangExpr = /^#\!\s*(?:\/usr\/bin\/env)?\s*([^ \t]+=[^ \t]+\s+)*\s*([^ \t]+)(.*)$/
1723

18-
const cmdShimIfExists = (from, to, cb) => {
19-
fs.stat(from, er => {
20-
if (er) return cb()
21-
cmdShim(from, to, cb)
22-
})
23-
}
24+
const cmdShimIfExists = (from, to) =>
25+
stat(from).then(() => cmdShim(from, to), () => {})
2426

2527
// Try to unlink, but ignore errors.
2628
// Any problems will surface later.
27-
const rm = (path, cb) => fs.unlink(path, () => cb())
28-
29-
const cmdShim = (from, to, cb) => {
30-
fs.stat(from, (er, stat) => {
31-
if (er)
32-
return cb(er)
29+
const rm = path => unlink(path).catch(() => {})
3330

34-
cmdShim_(from, to, cb)
35-
})
36-
}
31+
const cmdShim = (from, to) =>
32+
stat(from).then(() => cmdShim_(from, to))
3733

38-
const cmdShim_ = (from, to, cb) => {
39-
const next = () => writeShim(from, to, cb)
40-
const then = times(3, next, cb)
41-
42-
rm(to, then)
43-
rm(to + '.cmd', then)
44-
rm(to + '.ps1', then)
45-
}
34+
const cmdShim_ = (from, to) => Promise.all([
35+
rm(to),
36+
rm(to + '.cmd'),
37+
rm(to + '.ps1'),
38+
]).then(() => writeShim(from, to))
4639

47-
const writeShim = (from, to, cb) => {
40+
const writeShim = (from, to) =>
4841
// make a cmd file and a sh script
4942
// First, check if the bin is a #! of some sort.
5043
// If not, then assume it's something that'll be compiled, or some other
5144
// sort of script, and just call it directly.
52-
mkdir(path.dirname(to)).then(() => {
53-
fs.readFile(from, 'utf8', (er, data) => {
54-
if (er) return writeShim_(from, to, null, null, null, cb)
45+
mkdir(dirname(to))
46+
.then(() => readFile(from, 'utf8'))
47+
.then(data => {
5548
const firstLine = data.trim().split(/\r*\n/)[0]
5649
const shebang = firstLine.match(shebangExpr)
57-
if (!shebang) return writeShim_(from, to, null, null, null, cb)
50+
if (!shebang) return writeShim_(from, to)
5851
const vars = shebang[1] || ''
5952
const prog = shebang[2]
6053
const args = shebang[3] || ''
61-
return writeShim_(from, to, prog, args, vars, cb)
62-
})
63-
}, cb)
64-
}
54+
return writeShim_(from, to, prog, args, vars)
55+
}, er => writeShim_(from, to))
6556

6657

67-
const writeShim_ = (from, to, prog, args, variables, cb) => {
68-
let shTarget = path.relative(path.dirname(to), from)
58+
const writeShim_ = (from, to, prog, args, variables) => {
59+
let shTarget = relative(dirname(to), from)
6960
let target = shTarget.split('/').join('\\')
7061
let longProg
7162
let shProg = prog && prog.split('\\').join('/')
@@ -225,31 +216,18 @@ const writeShim_ = (from, to, prog, args, variables, cb) => {
225216
+ 'exit $LASTEXITCODE\n'
226217
}
227218

228-
const next = () => chmodShim(to, cb)
229-
const then = times(3, next, cb)
230-
fs.writeFile(to + '.ps1', pwsh, 'utf8', then)
231-
fs.writeFile(to + '.cmd', cmd, 'utf8', then)
232-
fs.writeFile(to, sh, 'utf8', then)
233-
}
234-
235-
const chmodShim = (to, cb) => {
236-
const then = times(3, cb, cb)
237-
fs.chmod(to, 0o755, then)
238-
fs.chmod(to + '.cmd', 0o755, then)
239-
fs.chmod(to + '.ps1', 0o755, then)
219+
return Promise.all([
220+
writeFile(to + '.ps1', pwsh, 'utf8'),
221+
writeFile(to + '.cmd', cmd, 'utf8'),
222+
writeFile(to, sh, 'utf8'),
223+
]).then(() => chmodShim(to))
240224
}
241225

242-
const times = (n, ok, cb) => {
243-
let errState = null
244-
return er => {
245-
if (!errState) {
246-
if (er)
247-
cb(errState = er)
248-
else if (--n === 0)
249-
ok()
250-
}
251-
}
252-
}
226+
const chmodShim = to => Promise.all([
227+
chmod(to, 0o755),
228+
chmod(to + '.cmd', 0o755),
229+
chmod(to + '.ps1', 0o755),
230+
])
253231

254232
module.exports = cmdShim
255233
cmdShim.ifExists = cmdShimIfExists

test/basic.js

+13-51
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,17 @@ var cmdShim = require('../')
1212
test('no shebang', function (t) {
1313
var from = path.resolve(fixtures, 'from.exe')
1414
var to = path.resolve(fixtures, 'exe.shim')
15-
cmdShim(from, to, function(er) {
16-
if (er)
17-
throw er
15+
return cmdShim(from, to).then(() => {
1816
matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
1917
matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
2018
matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
21-
t.end()
2219
})
2320
})
2421

2522
test('if exists (it does exist)', function (t) {
2623
var from = path.resolve(fixtures, 'from.exe')
2724
var to = path.resolve(fixtures, 'exe.shim')
28-
cmdShim.ifExists(from, to, function(er) {
29-
if (er)
30-
throw er
25+
return cmdShim.ifExists(from, to).then(() => {
3126
matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
3227
matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
3328
matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
@@ -38,9 +33,7 @@ test('if exists (it does exist)', function (t) {
3833
test('if exists (it does not exist)', function (t) {
3934
var from = path.resolve(fixtures, 'argle bargle we like to sparkle')
4035
var to = path.resolve(fixtures, 'argle-bargle-shim')
41-
cmdShim.ifExists(from, to, function(er) {
42-
if (er)
43-
throw er
36+
return cmdShim.ifExists(from, to).then(() => {
4437
t.throws(() => fs.statSync(to))
4538
t.throws(() => fs.statSync(to + '.cmd'))
4639
t.throws(() => fs.statSync(to + '.ps1'))
@@ -51,112 +44,81 @@ test('if exists (it does not exist)', function (t) {
5144
test('fails if from doesnt exist', t => {
5245
var from = path.resolve(fixtures, 'argle bargle we like to sparkle')
5346
var to = path.resolve(fixtures, 'argle-bargle-shim')
54-
cmdShim(from, to, function(er) {
55-
t.match(er, { code: 'ENOENT' })
56-
t.end()
57-
})
47+
return t.rejects(cmdShim(from, to), { code: 'ENOENT' })
5848
})
5949

6050
test('fails if mkdir fails', t => {
6151
var from = path.resolve(fixtures, 'from.env')
6252
var to = path.resolve(fixtures, 'from.env/a/b/c')
63-
cmdShim(from, to, er => {
64-
t.match(er, { code: /^(ENOTDIR|EEXIST)$/ })
65-
t.end()
66-
})
53+
return t.rejects(cmdShim(from, to), { code: /^(ENOTDIR|EEXIST)$/ })
6754
})
6855

6956
test('fails if to is a dir', t => {
7057
var from = path.resolve(fixtures, 'from.env')
7158
var to = path.resolve(fixtures)
72-
cmdShim(from, to, er => {
73-
t.match(er, { code: 'EISDIR' })
59+
t.teardown(() => {
7460
rimraf.sync(to + '.cmd')
7561
rimraf.sync(to + '.ps1')
76-
t.end()
7762
})
63+
return t.rejects(cmdShim(from, to), { code: 'EISDIR' })
7864
})
7965

8066
test('just proceed if reading fails', t => {
8167
var from = fixtures
8268
var to = path.resolve(fixtures, 'env.shim')
83-
cmdShim(from, to, er => {
84-
if (er)
85-
throw er
86-
69+
return cmdShim(from, to).then(() => {
8770
matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
8871
matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
8972
matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
90-
t.end()
9173
})
9274
})
9375

9476
test('env shebang', function (t) {
9577
var from = path.resolve(fixtures, 'from.env')
9678
var to = path.resolve(fixtures, 'env.shim')
97-
cmdShim(from, to, function(er) {
98-
if (er)
99-
throw er
100-
79+
return cmdShim(from, to).then(() => {
10180
matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
10281
matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
10382
matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
104-
t.end()
10583
})
10684
})
10785

10886
test('env shebang with args', function (t) {
10987
var from = path.resolve(fixtures, 'from.env.args')
11088
var to = path.resolve(fixtures, 'env.args.shim')
111-
cmdShim(from, to, function(er) {
112-
if (er)
113-
throw er
114-
89+
return cmdShim(from, to).then(() => {
11590
matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
11691
matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
11792
matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
118-
t.end()
11993
})
12094
})
12195

12296
test('env shebang with variables', function (t) {
12397
var from = path.resolve(fixtures, 'from.env.variables')
12498
var to = path.resolve(fixtures, 'env.variables.shim')
125-
cmdShim(from, to, function(er) {
126-
if (er)
127-
throw er
128-
99+
return cmdShim(from, to).then(() => {
129100
matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
130101
matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
131102
matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
132-
t.end()
133103
})
134104
})
135105

136106
test('explicit shebang', function (t) {
137107
var from = path.resolve(fixtures, 'from.sh')
138108
var to = path.resolve(fixtures, 'sh.shim')
139-
cmdShim(from, to, function(er) {
140-
if (er)
141-
throw er
142-
109+
return cmdShim(from, to).then(() => {
143110
matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
144111
matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
145112
matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
146-
t.end()
147113
})
148114
})
149115

150116
test('explicit shebang with args', function (t) {
151117
var from = path.resolve(fixtures, 'from.sh.args')
152118
var to = path.resolve(fixtures, 'sh.args.shim')
153-
cmdShim(from, to, function(er) {
154-
if (er)
155-
throw er
156-
119+
return cmdShim(from, to).then(() => {
157120
matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell')
158121
matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd')
159122
matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1')
160-
t.end()
161123
})
162124
})

0 commit comments

Comments
 (0)