1 | module.exports = runScript
|
2 |
|
3 | var lifecycle = require('./utils/lifecycle.js')
|
4 | var npm = require('./npm.js')
|
5 | var path = require('path')
|
6 | var readJson = require('read-package-json')
|
7 | var log = require('npmlog')
|
8 | var chain = require('slide').chain
|
9 | var usage = require('./utils/usage')
|
10 | var output = require('./utils/output.js')
|
11 | var didYouMean = require('./utils/did-you-mean')
|
12 | var isWindowsShell = require('./utils/is-windows-shell.js')
|
13 |
|
14 | runScript.usage = usage(
|
15 | 'run-script',
|
16 | 'npm run-script <command> [-- <args>...]'
|
17 | )
|
18 |
|
19 | runScript.completion = function (opts, cb) {
|
20 |
|
21 | var argv = opts.conf.argv.remain
|
22 |
|
23 | if (argv.length >= 4) return cb()
|
24 |
|
25 | if (argv.length === 3) {
|
26 |
|
27 |
|
28 | var json = path.join(npm.localPrefix, 'package.json')
|
29 | return readJson(json, function (er, d) {
|
30 | if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er)
|
31 | if (er) d = {}
|
32 | var scripts = Object.keys(d.scripts || {})
|
33 | console.error('local scripts', scripts)
|
34 | if (scripts.indexOf(argv[2]) !== -1) return cb()
|
35 |
|
36 | var pref = npm.config.get('global') ? npm.config.get('prefix')
|
37 | : npm.localPrefix
|
38 | var pkgDir = path.resolve(pref, 'node_modules', argv[2], 'package.json')
|
39 | readJson(pkgDir, function (er, d) {
|
40 | if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er)
|
41 | if (er) d = {}
|
42 | var scripts = Object.keys(d.scripts || {})
|
43 | return cb(null, scripts)
|
44 | })
|
45 | })
|
46 | }
|
47 |
|
48 | readJson(path.join(npm.localPrefix, 'package.json'), function (er, d) {
|
49 | if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er)
|
50 | d = d || {}
|
51 | cb(null, Object.keys(d.scripts || {}))
|
52 | })
|
53 | }
|
54 |
|
55 | function runScript (args, cb) {
|
56 | if (!args.length) return list(cb)
|
57 |
|
58 | var pkgdir = npm.localPrefix
|
59 | var cmd = args.shift()
|
60 |
|
61 | readJson(path.resolve(pkgdir, 'package.json'), function (er, d) {
|
62 | if (er) return cb(er)
|
63 | run(d, pkgdir, cmd, args, cb)
|
64 | })
|
65 | }
|
66 |
|
67 | function list (cb) {
|
68 | var json = path.join(npm.localPrefix, 'package.json')
|
69 | var cmdList = [
|
70 | 'publish',
|
71 | 'install',
|
72 | 'uninstall',
|
73 | 'test',
|
74 | 'stop',
|
75 | 'start',
|
76 | 'restart',
|
77 | 'version'
|
78 | ].reduce(function (l, p) {
|
79 | return l.concat(['pre' + p, p, 'post' + p])
|
80 | }, [])
|
81 | return readJson(json, function (er, d) {
|
82 | if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er)
|
83 | if (er) d = {}
|
84 | var allScripts = Object.keys(d.scripts || {})
|
85 | var scripts = []
|
86 | var runScripts = []
|
87 | allScripts.forEach(function (script) {
|
88 | if (cmdList.indexOf(script) !== -1) scripts.push(script)
|
89 | else runScripts.push(script)
|
90 | })
|
91 |
|
92 | if (log.level === 'silent') {
|
93 | return cb(null, allScripts)
|
94 | }
|
95 |
|
96 | if (npm.config.get('json')) {
|
97 | output(JSON.stringify(d.scripts || {}, null, 2))
|
98 | return cb(null, allScripts)
|
99 | }
|
100 |
|
101 | if (npm.config.get('parseable')) {
|
102 | allScripts.forEach(function (script) {
|
103 | output(script + ':' + d.scripts[script])
|
104 | })
|
105 | return cb(null, allScripts)
|
106 | }
|
107 |
|
108 | var s = '\n '
|
109 | var prefix = ' '
|
110 | if (scripts.length) {
|
111 | output('Lifecycle scripts included in %s:', d.name)
|
112 | }
|
113 | scripts.forEach(function (script) {
|
114 | output(prefix + script + s + d.scripts[script])
|
115 | })
|
116 | if (!scripts.length && runScripts.length) {
|
117 | output('Scripts available in %s via `npm run-script`:', d.name)
|
118 | } else if (runScripts.length) {
|
119 | output('\navailable via `npm run-script`:')
|
120 | }
|
121 | runScripts.forEach(function (script) {
|
122 | output(prefix + script + s + d.scripts[script])
|
123 | })
|
124 | return cb(null, allScripts)
|
125 | })
|
126 | }
|
127 |
|
128 | function run (pkg, wd, cmd, args, cb) {
|
129 | if (!pkg.scripts) pkg.scripts = {}
|
130 |
|
131 | var cmds
|
132 | if (cmd === 'restart' && !pkg.scripts.restart) {
|
133 | cmds = [
|
134 | 'prestop', 'stop', 'poststop',
|
135 | 'restart',
|
136 | 'prestart', 'start', 'poststart'
|
137 | ]
|
138 | } else {
|
139 | if (pkg.scripts[cmd] == null) {
|
140 | if (cmd === 'test') {
|
141 | pkg.scripts.test = 'echo \'Error: no test specified\''
|
142 | } else if (cmd === 'env') {
|
143 | if (isWindowsShell) {
|
144 | log.verbose('run-script using default platform env: SET (Windows)')
|
145 | pkg.scripts[cmd] = 'SET'
|
146 | } else {
|
147 | log.verbose('run-script using default platform env: env (Unix)')
|
148 | pkg.scripts[cmd] = 'env'
|
149 | }
|
150 | } else if (npm.config.get('if-present')) {
|
151 | return cb(null)
|
152 | } else {
|
153 | let suggestions = didYouMean(cmd, Object.keys(pkg.scripts))
|
154 | suggestions = suggestions ? '\n' + suggestions : ''
|
155 | return cb(new Error('missing script: ' + cmd + suggestions))
|
156 | }
|
157 | }
|
158 | cmds = [cmd]
|
159 | }
|
160 |
|
161 | if (!cmd.match(/^(pre|post)/)) {
|
162 | cmds = ['pre' + cmd].concat(cmds).concat('post' + cmd)
|
163 | }
|
164 |
|
165 | log.verbose('run-script', cmds)
|
166 | chain(cmds.map(function (c) {
|
167 |
|
168 | if (pkg.scripts[c] && c === cmd) {
|
169 | pkg.scripts[c] = pkg.scripts[c] + joinArgs(args)
|
170 | }
|
171 |
|
172 |
|
173 | return [lifecycle, pkg, c, wd, { unsafePerm: true }]
|
174 | }), cb)
|
175 | }
|
176 |
|
177 |
|
178 |
|
179 | function joinArgs (args) {
|
180 | var joinedArgs = ''
|
181 | args.forEach(function (arg) {
|
182 | joinedArgs += ' "' + arg.replace(/"/g, '\\"') + '"'
|
183 | })
|
184 | return joinedArgs
|
185 | }
|