index.js 7.2 KB

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