on master help sign in
document all the weird facts about Windows
commitf632e0518923f3d5e4b363508d5925b02e315104 authorEvan Czaplicki <evancz@users.noreply.github.com> dateFri 30 Aug 2019, 17:19 (7 years ago) parentd52457c
5 files changed+54−50
installers/npm/bin/elm+46 installers/npm/bin/elm.exe−40 installers/npm/download.js+6−2 installers/npm/install.js+1−7 installers/npm/package.json+1−1
installers/npm/bin/elmnew file+46
@@ -0,0 +1,46 @@
1+#!/usr/bin/env node
2+
3+var child_process = require('child_process');
4+var path = require('path');
5+var fs = require('fs');
6+
7+
8+// Some npm users enable --ignore-scripts (a good security measure)
9+// They do not run the post-install hook, so install.js does not run.
10+//
11+// On Mac and Linux, we download the elm executable into the exact same
12+// location as this file. Since npm uses symlinks on these platforms,
13+// that means that the first run will invoke this file and subsequent
14+// runs will call the elm binary directly.
15+//
16+// On Windows, we must download a file named elm.exe for it to run properly.
17+// Instead of symlinks, they create two files:
18+//
19+// - node_modules/.bin/elm (a bash file)
20+// - node_modules/.bin/elm.cmd (a batch file)
21+//
22+// Both files specifically invoke `node` to run the file listed at package.bin,
23+// so there is no way around instantiating node for no reason on Windows. So
24+// the existsSync check is needed so that it is not downloaded more than once.
25+
26+
27+// figure out where to put the binary (calls path.resolve() to get path separators right on Windows)
28+//
29+var binaryPath = path.resolve(__dirname, package.bin) + (process.platform === 'win32' ? '.exe' : '');
30+
31+// Run the command directly if possible, otherwise download and then run.
32+// This check is important for Windows where this file will be run all the time.
33+//
34+fs.existsSync(binaryPath)
35+ ? runCommand()
36+ : require('../download.js')(runCommand);
37+
38+
39+function runCommand()
40+{
41+ // Need double quotes and { shell: true } when there are spaces in the path on windows:
42+ // https://github.com/nodejs/node/issues/7367#issuecomment-229721296
43+ child_process
44+ .spawn('"' + binaryPath + '"', process.argv.slice(2), { stdio: 'inherit', shell: true })
45+ .on('exit', process.exit);
46+}
installers/npm/bin/elm.exedeleted−40
@@ -1,40 +0,0 @@
1−#!/usr/bin/env node
2−
3−var child_process = require('child_process');
4−var download = require('../download.js');
5−var fs = require('fs');
6−
7−
8−// Some npm users enable --ignore-scripts (a good security measure)
9−//
10−// They do not run the post-install hook, so install.js does not run.
11−//
12−// This file pretends to be the downloaded binary. It then downloads
13−// the real binary over itself. So in that case, the first run would
14−// also make an HTTPS request to fetch the real binary. From there,
15−// it calls the binary it downloaded on each run.
16−//
17−// It needs a .exe extension for Windows users. That file extension
18−// should allow this file to run both as a JS script and after it is
19−// replaced by the real Elm binary. The file extension does not appear
20−// to matter on Mac or Linux since it is hidden by the symlink at
21−// node_modules/.bin/elm that most people would refer to.
22−
23−
24−// Make sure we get the right path even if we're executing from the symlinked
25−// node_modules/.bin/ executable
26−var targetPath = fs.realpathSync(process.argv[1]);
27−
28−download(targetPath, runOriginalCommandWithDownloadedBinary);
29−
30−
31−// If the binary downloads successfully, try to run the original command.
32−function runOriginalCommandWithDownloadedBinary()
33−{
34− // Need double quotes and { shell: true } when there are spaces in the path on windows:
35− // https://github.com/nodejs/node/issues/7367#issuecomment-229721296
36− //
37− child_process
38− .spawn('"' + targetPath + '"', process.argv.slice(2), { stdio: 'inherit', shell: true })
39− .on('exit', process.exit);
40−}
installers/npm/download.js+6−2
@@ -1,5 +1,6 @@
11var fs = require('fs');
22var package = require('./package.json');
3+var path = require('path');
34var request = require('request');
45var zlib = require('zlib');
56
@@ -11,7 +12,7 @@ var zlib = require('zlib');
1112// called when --ignore-scripts is enabled. That's why install.js is so weird.
1213
1314
14−module.exports = function(destinationPath, callback)
15+module.exports = function(callback)
1516{
1617 // figure out URL of binary
1718 var version = package.version.replace(/^(\d+\.\d+\.\d+).*$/, '$1'); // turn '1.2.3-alpha' into '1.2.3'
@@ -19,6 +20,9 @@ module.exports = function(destinationPath, callback)
1920 var arch = { 'x64': '64-bit', 'ia32': '32-bit' }[process.arch];
2021 var url = 'https://github.com/elm/compiler/releases/download/' + version + '/binary-for-' + os + '-' + arch + '.gz';
2122
23+ // figure out where to put the binary (calls path.resolve() to get path separators right on Windows)
24+ var binaryPath = path.resolve(__dirname, package.bin) + (process.platform === 'win32' ? '.exe' : '');
25+
2226 // set up handler for request failure
2327 function reportDownloadFailure(error)
2428 {
@@ -31,7 +35,7 @@ module.exports = function(destinationPath, callback)
3135 });
3236
3337 // set up file write pipe
34− var write = fs.createWriteStream(destinationPath, {
38+ var write = fs.createWriteStream(binaryPath, {
3539 encoding: 'binary',
3640 mode: 0o755
3741 }).on('finish', callback).on('error', function(error) {
installers/npm/install.js+1−7
@@ -1,10 +1,4 @@
11
22var download = require('./download.js');
3−var package = require('./package.json');
4−var path = require('path');
53
6−
7−// get slashes right for Windows
8−var targetPath = path.resolve(__dirname, package.bin);
9−
10−download(targetPath, function() {});
4+download(function() {});
installers/npm/package.json+1−1
@@ -35,7 +35,7 @@
3535 "install",
3636 "installer"
3737 ],
38− "bin": "bin/elm.exe",
38+ "bin": "bin/elm",
3939 "dependencies": {
4040 "request": "^2.88.0"
4141 }