UNPKG

7.37 kBJavaScriptView Raw
1// On windows, create a .cmd file.
2// Read the #! in the file to see what it uses. The vast majority
3// of the time, this will be either:
4// "#!/usr/bin/env <prog> <args...>"
5// or:
6// "#!<prog> <args...>"
7//
8// Write a binroot/pkg.bin + ".cmd" file that has this line in it:
9// @<prog> <args...> %dp0%<target> %*
10
11module.exports = cmdShim
12cmdShim.ifExists = cmdShimIfExists
13
14var fs = require("graceful-fs")
15
16var mkdir = require("mkdirp")
17 , path = require("path")
18 , toBatchSyntax = require("./lib/to-batch-syntax")
19 , shebangExpr = /^#\!\s*(?:\/usr\/bin\/env)?\s*([^ \t]+=[^ \t]+\s+)*\s*([^ \t]+)(.*)$/
20
21function cmdShimIfExists (from, to, cb) {
22 fs.stat(from, function (er) {
23 if (er) return cb()
24 cmdShim(from, to, cb)
25 })
26}
27
28// Try to unlink, but ignore errors.
29// Any problems will surface later.
30function rm (path, cb) {
31 fs.unlink(path, function(er) {
32 cb()
33 })
34}
35
36function cmdShim (from, to, cb) {
37 fs.stat(from, function (er, stat) {
38 if (er)
39 return cb(er)
40
41 cmdShim_(from, to, cb)
42 })
43}
44
45function cmdShim_ (from, to, cb) {
46 var then = times(3, next, cb)
47 rm(to, then)
48 rm(to + ".cmd", then)
49 rm(to + ".ps1", then)
50
51 function next(er) {
52 writeShim(from, to, cb)
53 }
54}
55
56function writeShim (from, to, cb) {
57 // make a cmd file and a sh script
58 // First, check if the bin is a #! of some sort.
59 // If not, then assume it's something that'll be compiled, or some other
60 // sort of script, and just call it directly.
61 mkdir(path.dirname(to), function (er) {
62 if (er)
63 return cb(er)
64 fs.readFile(from, "utf8", function (er, data) {
65 if (er) return writeShim_(from, to, null, null, null, cb)
66 var firstLine = data.trim().split(/\r*\n/)[0]
67 , shebang = firstLine.match(shebangExpr)
68 if (!shebang) return writeShim_(from, to, null, null, null, cb)
69 var vars = shebang[1] || ""
70 , prog = shebang[2]
71 , args = shebang[3] || ""
72 return writeShim_(from, to, prog, args, vars, cb)
73 })
74 })
75}
76
77
78function writeShim_ (from, to, prog, args, variables, cb) {
79 var shTarget = path.relative(path.dirname(to), from)
80 , target = shTarget.split("/").join("\\")
81 , longProg
82 , shProg = prog && prog.split("\\").join("/")
83 , shLongProg
84 , pwshProg = shProg && "\"" + shProg + "$exe\""
85 , pwshLongProg
86 shTarget = shTarget.split("\\").join("/")
87 args = args || ""
88 variables = variables || ""
89 if (!prog) {
90 prog = "\"%dp0%\\" + target + "\""
91 shProg = "\"$basedir/" + shTarget + "\""
92 pwshProg = shProg
93 args = ""
94 target = ""
95 shTarget = ""
96 } else {
97 longProg = "\"%dp0%\\" + prog + ".exe\""
98 shLongProg = "\"$basedir/" + prog + "\""
99 pwshLongProg = "\"$basedir/" + prog + "$exe\""
100 target = "\"%dp0%\\" + target + "\""
101 shTarget = "\"$basedir/" + shTarget + "\""
102 }
103
104 // @SETLOCAL
105 // @CALL :find_dp0
106 //
107 // @IF EXIST "%dp0%\node.exe" (
108 // @SET "_prog=%dp0%\node.exe"
109 // ) ELSE (
110 // @SET "_prog=node"
111 // @SET PATHEXT=%PATHEXT:;.JS;=;%
112 // )
113 //
114 // "%_prog%" "%dp0%\.\node_modules\npm\bin\npm-cli.js" %*
115 // @ENDLOCAL
116 // @EXIT /b %errorlevel%
117 //
118 // :find_dp0
119 // SET dp0=%~dp0
120 // EXIT /b
121 //
122 // Subroutine trick to fix https://github.com/npm/cmd-shim/issues/10
123 var head = '@ECHO off\r\n' +
124 'SETLOCAL\r\n' +
125 'CALL :find_dp0\r\n'
126 var foot = 'ENDLOCAL\r\n' +
127 'EXIT /b %errorlevel%\r\n' +
128 ':find_dp0\r\n' +
129 'SET dp0=%~dp0\r\n' +
130 'EXIT /b\r\n'
131
132 var cmd
133 if (longProg) {
134 shLongProg = shLongProg.trim();
135 args = args.trim();
136 var variableDeclarationsAsBatch = toBatchSyntax.convertToSetCommands(variables)
137 cmd = head
138 + variableDeclarationsAsBatch
139 + "\r\n"
140 + "IF EXIST " + longProg + " (\r\n"
141 + " SET \"_prog=" + longProg.replace(/(^")|("$)/g, '') + "\"\r\n"
142 + ") ELSE (\r\n"
143 + " SET \"_prog=" + prog.replace(/(^")|("$)/g, '') + "\"\r\n"
144 + " SET PATHEXT=%PATHEXT:;.JS;=;%\r\n"
145 + ")\r\n"
146 + "\r\n"
147 + "\"%_prog%\" " + args + " " + target + " %*\r\n"
148 + foot
149 } else {
150 cmd = head + prog + " " + args + " " + target + " %*\r\n" + foot
151 }
152
153 // #!/bin/sh
154 // basedir=`dirname "$0"`
155 //
156 // case `uname` in
157 // *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
158 // esac
159 //
160 // if [ -x "$basedir/node.exe" ]; then
161 // "$basedir/node.exe" "$basedir/node_modules/npm/bin/npm-cli.js" "$@"
162 // ret=$?
163 // else
164 // node "$basedir/node_modules/npm/bin/npm-cli.js" "$@"
165 // ret=$?
166 // fi
167 // exit $ret
168
169 var sh = "#!/bin/sh\n"
170
171 sh = sh
172 + "basedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")\n"
173 + "\n"
174 + "case `uname` in\n"
175 + " *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w \"$basedir\"`;;\n"
176 + "esac\n"
177 + "\n"
178
179 if (shLongProg) {
180 sh = sh
181 + "if [ -x "+shLongProg+" ]; then\n"
182 + " " + variables + shLongProg + " " + args + " " + shTarget + " \"$@\"\n"
183 + " ret=$?\n"
184 + "else \n"
185 + " " + variables + shProg + " " + args + " " + shTarget + " \"$@\"\n"
186 + " ret=$?\n"
187 + "fi\n"
188 + "exit $ret\n"
189 } else {
190 sh = sh
191 + shProg + " " + args + " " + shTarget + " \"$@\"\n"
192 + "exit $?\n"
193 }
194
195 // #!/usr/bin/env pwsh
196 // $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
197 //
198 // $ret=0
199 // $exe = ""
200 // if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
201 // # Fix case when both the Windows and Linux builds of Node
202 // # are installed in the same directory
203 // $exe = ".exe"
204 // }
205 // if (Test-Path "$basedir/node") {
206 // & "$basedir/node$exe" "$basedir/node_modules/npm/bin/npm-cli.js" $args
207 // $ret=$LASTEXITCODE
208 // } else {
209 // & "node$exe" "$basedir/node_modules/npm/bin/npm-cli.js" $args
210 // $ret=$LASTEXITCODE
211 // }
212 // exit $ret
213 var pwsh = "#!/usr/bin/env pwsh\n"
214 + "$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent\n"
215 + "\n"
216 + "$exe=\"\"\n"
217 + "if ($PSVersionTable.PSVersion -lt \"6.0\" -or $IsWindows) {\n"
218 + " # Fix case when both the Windows and Linux builds of Node\n"
219 + " # are installed in the same directory\n"
220 + " $exe=\".exe\"\n"
221 + "}\n"
222 if (shLongProg) {
223 pwsh = pwsh
224 + "$ret=0\n"
225 + "if (Test-Path " + pwshLongProg + ") {\n"
226 + " & " + pwshLongProg + " " + args + " " + shTarget + " $args\n"
227 + " $ret=$LASTEXITCODE\n"
228 + "} else {\n"
229 + " & " + pwshProg + " " + args + " " + shTarget + " $args\n"
230 + " $ret=$LASTEXITCODE\n"
231 + "}\n"
232 + "exit $ret\n"
233 } else {
234 pwsh = pwsh
235 + "& " + pwshProg + " " + args + " " + shTarget + " $args\n"
236 + "exit $LASTEXITCODE\n"
237 }
238
239 var then = times(3, next, cb)
240 fs.writeFile(to + ".ps1", pwsh, "utf8", then)
241 fs.writeFile(to + ".cmd", cmd, "utf8", then)
242 fs.writeFile(to, sh, "utf8", then)
243 function next () {
244 chmodShim(to, cb)
245 }
246}
247
248function chmodShim (to, cb) {
249 var then = times(3, cb, cb)
250 fs.chmod(to, "0755", then)
251 fs.chmod(to + ".cmd", "0755", then)
252 fs.chmod(to + ".ps1", "0755", then)
253}
254
255function times(n, ok, cb) {
256 var errState = null
257 return function(er) {
258 if (!errState) {
259 if (er)
260 cb(errState = er)
261 else if (--n === 0)
262 ok()
263 }
264 }
265}