-
Notifications
You must be signed in to change notification settings - Fork 0
/
binary.js
119 lines (103 loc) · 4.44 KB
/
binary.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Adapted from the Elm npm installer, licensed under BSD-3-Clause, located at:
// https://github.com/lydell/compiler - original authors were:
// Richard Feldman, Aaron VonderHaar, Evan Czaplicki, Simon Lydell, and others.
// Thank you, all!
var fs = require('fs');
var package = require('./package.json');
var path = require('path');
// This function is used by install.js and by the bin/roc backup script that gets
// run when --ignore-scripts is enabled.
module.exports = function()
{
// figure out package of binary
var version = package.version;
var subPackageName = '@roc-installer-assets/' + process.platform + '_' + process.arch;
verifyPlatform(version, subPackageName);
var fileName = process.platform === 'win32' ? 'roc.exe' : 'roc';
try
{
var subBinaryPath = require.resolve(subPackageName + '/' + fileName);
}
catch (error)
{
if (error && error.code === 'MODULE_NOT_FOUND')
{
exitFailure(version, missingSubPackageHelp(subPackageName));
}
else
{
exitFailure(version, 'I had trouble requiring the binary package for your platform (' + subPackageName + '):\n\n' + error);
}
}
// Yarn 2 and later ("Berry") always invokes `node` (regardless of configuration)
// so we cannot do any optimizations there
var isYarnBerry = /\byarn\/(?!1\.)/.test(process.env.npm_config_user_agent || "");
// as mentioned in bin/roc we cannot do any optimizations on Windows
if (process.platform === 'win32' || isYarnBerry)
{
return subBinaryPath;
}
// figure out where to put the binary
var binaryPath = path.resolve(__dirname, package.bin.roc);
var tmpPath = binaryPath + '.tmp';
// Make sure we don't have a garbage temporary file from an incomplete previous run.
if (fs.existsSync(tmpPath)) {
fs.unlinkSync(tmpPath);
}
// optimize by replacing the JS bin/roc with the native binary directly
try
{
// atomically replace the file with a hard link to the binary
fs.linkSync(subBinaryPath, tmpPath);
fs.renameSync(tmpPath, binaryPath);
}
catch (error)
{
exitFailure(version, 'I had some trouble writing file to disk. It is saying:\n\n' + error);
}
return binaryPath;
}
function verifyPlatform(version, subPackageName)
{
if (subPackageName in package.optionalDependencies) return;
var situation = process.platform + '_' + process.arch;
console.error(
'-- ERROR -----------------------------------------------------------------------\n\n'
+ 'This npm Roc installer does not support your platform (' + situation + ').\n\n'
+ 'You can try to manually download an appropriate binary (if there is one) from:\n\n'
+ '<https://github.com/roc-lang/roc/releases>\n\n'
+ 'You can also get help from friendly people at <https://roc.zulipchat.com>\n\n'
+ '--------------------------------------------------------------------------------\n'
);
process.exit(1);
}
function exitFailure(version, message)
{
console.error(
'-- ERROR -----------------------------------------------------------------------\n\n'
+ message
+ '\n\nNOTE: You can avoid npm entirely by downloading directly from:\n\n'
+ '<https://github.com/roc-lang/roc/releases>\n\n'
+ 'All this package does is to download a file from there.\n\n'
+ '--------------------------------------------------------------------------------\n'
);
process.exit(1);
}
function missingSubPackageHelp(subPackageName)
{
// Instead of giving up, we could try to download it via fetch() in case of --no-optional.
// If we do that, we should download it directly from npm (not from Roc releases),
// so that we avoid introducing another point of failure, and can ensure you're getting
// the same version as everyone else. Apparently the esbuild installer handles a bunch
// of edge cases like this. However, evidently nobody in the Elm community has complained
// about this causing problems, so it doesn't seem urgent to improve.
return (
'I support your platform, but I could not find the binary package (' + subPackageName + ') for it!\n\n'
+ 'This can happen if you use the "--omit=optional" (or "--no-optional") npm flag.\n'
+ 'This package uses the "optionalDependencies" package.json feature install the correct\n'
+ 'binary executable for your current platform. Remove that flag to install Roc.\n\n'
+ 'This can also happen if the "node_modules" folder was copied between two operating systems\n'
+ 'that need different binaries - including "virtual" operating systems like Docker and WSL.\n'
+ 'If so, try installing with npm rather than copying "node_modules".'
);
}