turbo 1.0.19 → 1.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/turbo CHANGED
@@ -1,11 +1,9 @@
1
1
  #!/usr/bin/env node
2
- throw new Error(`turbo: Failed to install correctly
3
- Make sure you don't have "ignore-scripts" set to true. You can check this with
4
- "npm config get ignore-scripts". If that returns true you can reset it back to
5
- false using "npm config set ignore-scripts false" and then reinstall esbuild.
6
- If you're using npm v7, make sure your package-lock.json file contains either
7
- "lockfileVersion": 1 or the code "hasInstallScript": true. If it doesn't have
8
- either of those, then it is likely the case that a known bug in npm v7 has
9
- corrupted your package-lock.json file. Regenerating your package-lock.json file
10
- should fix this issue.
11
- `)
2
+
3
+ const { generateBinPath } = require("../node-platform");
4
+
5
+ require("child_process").execFileSync(
6
+ generateBinPath(),
7
+ process.argv.slice(2),
8
+ { stdio: "inherit" }
9
+ );
package/install.js CHANGED
@@ -1,148 +1,45 @@
1
- // Most of this file is ripped from esbuild's postinstall script
2
- // @see https://github.com/evanw/esbuild/blob/v0.12.29/lib/npm/install.ts
1
+ // Most of this file is ripped from esbuild
2
+ // @see https://github.com/evanw/esbuild/blob/master/lib/npm/node-install.ts
3
+ // This file is MIT licensed.
4
+
5
+ const nodePlatform = require("./node-platform");
3
6
  const fs = require("fs");
4
7
  const os = require("os");
5
8
  const path = require("path");
6
9
  const zlib = require("zlib");
7
10
  const https = require("https");
8
11
  const child_process = require("child_process");
9
- const version = require("./package.json").version;
10
- const binPath = path.join(__dirname, "bin", "turbo");
11
-
12
- async function installBinaryFromPackage(name, fromPath, toPath) {
13
- // Try to install from the cache if possible
14
- const cachePath = getCachePath(name);
15
- try {
16
- // Copy from the cache
17
- fs.copyFileSync(cachePath, toPath);
18
- fs.chmodSync(toPath, 0o755);
19
-
20
- // Verify that the binary is the correct version
21
- validateBinaryVersion(toPath);
22
-
23
- // Mark the cache entry as used for LRU
24
- const now = new Date();
25
- fs.utimesSync(cachePath, now, now);
26
- return;
27
- } catch (e) {}
28
-
29
- // Next, try to install using npm. This should handle various tricky cases
30
- // such as environments where requests to npmjs.org will hang (in which case
31
- // there is probably a proxy and/or a custom registry configured instead).
32
- let buffer;
33
- let didFail = true;
34
- try {
35
- buffer = installUsingNPM(name, fromPath);
36
- } catch (err) {
37
- didFail = true;
38
- console.error(`Trying to install "${name}" using npm`);
39
- console.error(
40
- `Failed to install "${name}" using npm: ${(err && err.message) || err}`
41
- );
42
- }
43
-
44
- // If that fails, the user could have npm configured incorrectly or could not
45
- // have npm installed. Try downloading directly from npm as a last resort.
46
- if (!buffer) {
47
- const url = `https://registry.npmjs.org/${name}/-/${name}-${version}.tgz`;
48
- console.error(`Trying to download ${JSON.stringify(url)}`);
49
- try {
50
- buffer = extractFileFromTarGzip(await fetch(url), fromPath);
51
- } catch (err) {
52
- console.error(
53
- `Failed to download ${JSON.stringify(url)}: ${
54
- (err && err.message) || err
55
- }`
56
- );
57
- }
58
- }
59
-
60
- // Give up if none of that worked
61
- if (!buffer) {
62
- console.error(`Install unsuccessful`);
63
- process.exit(1);
64
- }
12
+ const {
13
+ downloadedBinPath,
14
+ TURBO_BINARY_PATH,
15
+ pkgAndSubpathForCurrentPlatform,
16
+ } = nodePlatform;
17
+ const TURBO_VERSION = require("./package.json").version;
65
18
 
66
- // Write out the binary executable that was extracted from the package
67
- fs.writeFileSync(toPath, buffer, { mode: 0o755 });
19
+ const toPath = path.join(__dirname, "bin", "turbo");
20
+ let isToPathJS = true;
68
21
 
69
- // Verify that the binary is the correct version
70
- try {
71
- validateBinaryVersion(toPath);
72
- } catch (err) {
73
- console.error(
74
- `The version of the downloaded binary is incorrect: ${
75
- (err && err.message) || err
76
- }`
77
- );
78
- console.error(`Install unsuccessful`);
79
- process.exit(1);
80
- }
81
-
82
- // Also try to cache the file to speed up future installs
83
- try {
84
- fs.mkdirSync(path.dirname(cachePath), {
85
- recursive: true,
86
- mode: 0o700, // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
87
- });
88
- fs.copyFileSync(toPath, cachePath);
89
- cleanCacheLRU(cachePath);
90
- } catch (e) {}
91
-
92
- if (didFail) console.error(`Install successful`);
93
- }
94
-
95
- function validateBinaryVersion(binaryPath) {
22
+ function validateBinaryVersion(...command) {
23
+ command.push("--version");
96
24
  const stdout = child_process
97
- .execFileSync(binaryPath, ["--version"])
25
+ .execFileSync(command.shift(), command)
98
26
  .toString()
99
27
  .trim();
100
- if (stdout !== version) {
28
+ if (stdout !== TURBO_VERSION) {
101
29
  throw new Error(
102
- `Expected ${JSON.stringify(version)} but got ${JSON.stringify(stdout)}`
30
+ `Expected ${JSON.stringify(TURBO_VERSION)} but got ${JSON.stringify(
31
+ stdout
32
+ )}`
103
33
  );
104
34
  }
105
35
  }
106
36
 
107
- function getCachePath(name) {
108
- const home = os.homedir();
109
- const common = ["turbo", "bin", `${name}@${version}`];
110
- if (process.platform === "darwin")
111
- return path.join(home, "Library", "Caches", ...common);
112
- if (process.platform === "win32")
113
- return path.join(home, "AppData", "Local", "Cache", ...common);
114
-
115
- // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
116
- const XDG_CACHE_HOME = process.env.XDG_CACHE_HOME;
117
- if (
118
- process.platform === "linux" &&
119
- XDG_CACHE_HOME &&
120
- path.isAbsolute(XDG_CACHE_HOME)
121
- )
122
- return path.join(XDG_CACHE_HOME, ...common);
123
-
124
- return path.join(home, ".cache", ...common);
125
- }
126
-
127
- function cleanCacheLRU(fileToKeep) {
128
- // Gather all entries in the cache
129
- const dir = path.dirname(fileToKeep);
130
- const entries = [];
131
- for (const entry of fs.readdirSync(dir)) {
132
- const entryPath = path.join(dir, entry);
133
- try {
134
- const stats = fs.statSync(entryPath);
135
- entries.push({ path: entryPath, mtime: stats.mtime });
136
- } catch (e) {}
137
- }
138
-
139
- // Only keep the most recent entries
140
- entries.sort((a, b) => +b.mtime - +a.mtime);
141
- for (const entry of entries.slice(5)) {
142
- try {
143
- fs.unlinkSync(entry.path);
144
- } catch (e) {}
37
+ function isYarn() {
38
+ const { npm_config_user_agent } = process.env;
39
+ if (npm_config_user_agent) {
40
+ return /\byarn\//.test(npm_config_user_agent);
145
41
  }
42
+ return false;
146
43
  }
147
44
 
148
45
  function fetch(url) {
@@ -164,7 +61,7 @@ function fetch(url) {
164
61
  });
165
62
  }
166
63
 
167
- function extractFileFromTarGzip(buffer, file) {
64
+ function extractFileFromTarGzip(buffer, subpath) {
168
65
  try {
169
66
  buffer = zlib.unzipSync(buffer);
170
67
  } catch (err) {
@@ -175,51 +72,69 @@ function extractFileFromTarGzip(buffer, file) {
175
72
  let str = (i, n) =>
176
73
  String.fromCharCode(...buffer.subarray(i, i + n)).replace(/\0.*$/, "");
177
74
  let offset = 0;
178
- file = `package/${file}`;
75
+ subpath = `package/${subpath}`;
179
76
  while (offset < buffer.length) {
180
77
  let name = str(offset, 100);
181
78
  let size = parseInt(str(offset + 124, 12), 8);
182
79
  offset += 512;
183
80
  if (!isNaN(size)) {
184
- if (name === file) return buffer.subarray(offset, offset + size);
81
+ if (name === subpath) return buffer.subarray(offset, offset + size);
185
82
  offset += (size + 511) & ~511;
186
83
  }
187
84
  }
188
- throw new Error(`Could not find ${JSON.stringify(file)} in archive`);
85
+ throw new Error(`Could not find ${JSON.stringify(subpath)} in archive`);
189
86
  }
190
87
 
191
- function installUsingNPM(name, file) {
192
- const installDir = path.join(
193
- os.tmpdir(),
194
- "turbo-" + Math.random().toString(36).slice(2)
195
- );
196
- fs.mkdirSync(installDir, { recursive: true });
197
- fs.writeFileSync(path.join(installDir, "package.json"), "{}");
198
-
88
+ function installUsingNPM(pkg, subpath, binPath) {
199
89
  // Erase "npm_config_global" so that "npm install --global turbo" works.
200
90
  // Otherwise this nested "npm install" will also be global, and the install
201
91
  // will deadlock waiting for the global installation lock.
202
92
  const env = { ...process.env, npm_config_global: undefined };
203
93
 
204
- child_process.execSync(
205
- `npm install --loglevel=error --prefer-offline --no-audit --progress=false ${name}@${version}`,
206
- { cwd: installDir, stdio: "pipe", env }
207
- );
208
- const buffer = fs.readFileSync(
209
- path.join(installDir, "node_modules", name, file)
210
- );
94
+ // Create a temporary directory inside the "turbo" package with an empty
95
+ // "package.json" file. We'll use this to run "npm install" in.
96
+ const turboLibDir = path.dirname(require.resolve("turbo"));
97
+ const installDir = path.join(turboLibDir, "npm-install");
98
+ fs.mkdirSync(installDir);
211
99
  try {
212
- removeRecursive(installDir);
213
- } catch (e) {
214
- // Removing a file or directory can randomly break on Windows, returning
215
- // EBUSY for an arbitrary length of time. I think this happens when some
216
- // other program has that file or directory open (e.g. an anti-virus
217
- // program). This is fine on Unix because the OS just unlinks the entry
218
- // but keeps the reference around until it's unused. In this case we just
219
- // ignore errors because this directory is in a temporary directory, so in
220
- // theory it should get cleaned up eventually anyway.
100
+ fs.writeFileSync(path.join(installDir, "package.json"), "{}");
101
+
102
+ // Run "npm install" in the temporary directory which should download the
103
+ // desired package. Try to avoid unnecessary log output. This uses the "npm"
104
+ // command instead of a HTTP request so that it hopefully works in situations
105
+ // where HTTP requests are blocked but the "npm" command still works due to,
106
+ // for example, a custom configured npm registry and special firewall rules.
107
+ child_process.execSync(
108
+ `npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${TURBO_VERSION}`,
109
+ { cwd: installDir, stdio: "pipe", env }
110
+ );
111
+
112
+ // Move the downloaded binary executable into place. The destination path
113
+ // is the same one that the JavaScript API code uses so it will be able to
114
+ // find the binary executable here later.
115
+ const installedBinPath = path.join(
116
+ installDir,
117
+ "node_modules",
118
+ pkg,
119
+ subpath
120
+ );
121
+ fs.renameSync(installedBinPath, binPath);
122
+ } finally {
123
+ // Try to clean up afterward so we don't unnecessarily waste file system
124
+ // space. Leaving nested "node_modules" directories can also be problematic
125
+ // for certain tools that scan over the file tree and expect it to have a
126
+ // certain structure.
127
+ try {
128
+ removeRecursive(installDir);
129
+ } catch {
130
+ // Removing a file or directory can randomly break on Windows, returning
131
+ // EBUSY for an arbitrary length of time. I think this happens when some
132
+ // other program has that file or directory open (e.g. an anti-virus
133
+ // program). This is fine on Unix because the OS just unlinks the entry
134
+ // but keeps the reference around until it's unused. There's nothing we
135
+ // can do in this case so we just leave the directory there.
136
+ }
221
137
  }
222
- return buffer;
223
138
  }
224
139
 
225
140
  function removeRecursive(dir) {
@@ -228,7 +143,7 @@ function removeRecursive(dir) {
228
143
  let stats;
229
144
  try {
230
145
  stats = fs.lstatSync(entryPath);
231
- } catch (e) {
146
+ } catch {
232
147
  continue; // Guard against https://github.com/nodejs/node/issues/4760
233
148
  }
234
149
  if (stats.isDirectory()) removeRecursive(entryPath);
@@ -237,106 +152,155 @@ function removeRecursive(dir) {
237
152
  fs.rmdirSync(dir);
238
153
  }
239
154
 
240
- function isYarnBerryOrNewer() {
241
- const { npm_config_user_agent } = process.env;
242
- if (npm_config_user_agent) {
243
- const match = npm_config_user_agent.match(/yarn\/(\d+)/);
244
- if (match && match[1]) {
245
- return parseInt(match[1], 10) >= 2;
246
- }
247
- }
248
- return false;
155
+ function applyManualBinaryPathOverride(overridePath) {
156
+ // Patch the CLI use case (the "turbo" command)
157
+ const pathString = JSON.stringify(overridePath);
158
+ fs.writeFileSync(
159
+ toPath,
160
+ `#!/usr/bin/env node\n` +
161
+ `require('child_process').execFileSync(${pathString}, process.argv.slice(2), { stdio: 'inherit' });\n`
162
+ );
163
+
164
+ // Not needed for turbo
165
+ // // Patch the JS API use case (the "require('turbo')" workflow)
166
+ // const libMain = path.join(__dirname, "lib", "main.js");
167
+ // const code = fs.readFileSync(libMain, "utf8");
168
+ // fs.writeFileSync(libMain, `var TURBO_BINARY_PATH = ${pathString};\n${code}`);
249
169
  }
250
170
 
251
- function installDirectly(name) {
252
- if (process.env.TURBO_BINARY_PATH) {
253
- fs.copyFileSync(process.env.TURBO_BINARY_PATH, binPath);
254
- validateBinaryVersion(binPath);
255
- } else {
256
- // Write to a temporary file, then move the file into place. This is an
257
- // attempt to avoid problems with package managers like pnpm which will
258
- // usually turn each file into a hard link. We don't want to mutate the
259
- // hard-linked file which may be shared with other files.
260
- const tempBinPath = binPath + "__";
261
- installBinaryFromPackage(name, "bin/turbo", tempBinPath)
262
- .then(() => fs.renameSync(tempBinPath, binPath))
263
- .catch((e) =>
264
- setImmediate(() => {
265
- throw e;
266
- })
267
- );
171
+ function maybeOptimizePackage(binPath) {
172
+ // This package contains a "bin/turbo" JavaScript file that finds and runs
173
+ // the appropriate binary executable. However, this means that running the
174
+ // "turbo" command runs another instance of "node" which is way slower than
175
+ // just running the binary executable directly.
176
+ //
177
+ // Here we optimize for this by replacing the JavaScript file with the binary
178
+ // executable at install time. This optimization does not work on Windows
179
+ // because on Windows the binary executable must be called "turbo.exe"
180
+ // instead of "turbo".
181
+ //
182
+ // This also doesn't work with Yarn both because of lack of support for binary
183
+ // files in Yarn 2+ (see https://github.com/yarnpkg/berry/issues/882) and
184
+ // because Yarn (even Yarn 1?) may run the same install scripts in the same
185
+ // place multiple times from different platforms, especially when people use
186
+ // Docker. Avoid idempotency issues by just not optimizing when using Yarn.
187
+ //
188
+ // This optimization also doesn't apply when npm's "--ignore-scripts" flag is
189
+ // used since in that case this install script will not be run.
190
+ if (os.platform() !== "win32" && !isYarn()) {
191
+ const tempPath = path.join(__dirname, "bin-turbo");
192
+ try {
193
+ // First link the binary with a temporary file. If this fails and throws an
194
+ // error, then we'll just end up doing nothing. This uses a hard link to
195
+ // avoid taking up additional space on the file system.
196
+ fs.linkSync(binPath, tempPath);
197
+
198
+ // Then use rename to atomically replace the target file with the temporary
199
+ // file. If this fails and throws an error, then we'll just end up leaving
200
+ // the temporary file there, which is harmless.
201
+ fs.renameSync(tempPath, toPath);
202
+
203
+ // If we get here, then we know that the target location is now a binary
204
+ // executable instead of a JavaScript file.
205
+ isToPathJS = false;
206
+
207
+ // If this install script is being re-run, then "renameSync" will fail
208
+ // since the underlying inode is the same (it just returns without doing
209
+ // anything, and without throwing an error). In that case we should remove
210
+ // the file manually.
211
+ fs.unlinkSync(tempPath);
212
+ } catch {
213
+ // Ignore errors here since this optimization is optional
214
+ }
268
215
  }
269
216
  }
270
217
 
271
- function installWithWrapper(name, fromPath, toPath) {
272
- fs.writeFileSync(
273
- binPath,
274
- `#!/usr/bin/env node
275
- const path = require('path');
276
- const turbo_exe = path.join(__dirname, '..', ${JSON.stringify(toPath)});
277
- const child_process = require('child_process');
278
- const { status } = child_process.spawnSync(turbo_exe, process.argv.slice(2), { stdio: 'inherit' });
279
- process.exitCode = status === null ? 1 : status;
280
- `
281
- );
282
- const absToPath = path.join(__dirname, toPath);
283
- if (process.env.TURBO_BINARY_PATH) {
284
- fs.copyFileSync(process.env.TURBO_BINARY_PATH, absToPath);
285
- validateBinaryVersion(absToPath);
286
- } else {
287
- installBinaryFromPackage(name, fromPath, absToPath).catch((e) =>
288
- setImmediate(() => {
289
- throw e;
290
- })
218
+ async function downloadDirectlyFromNPM(pkg, subpath, binPath) {
219
+ // If that fails, the user could have npm configured incorrectly or could not
220
+ // have npm installed. Try downloading directly from npm as a last resort.
221
+ const url = `https://registry.npmjs.org/${pkg}/-/${pkg}-${TURBO_VERSION}.tgz`;
222
+ console.error(`[turbo] Trying to download ${JSON.stringify(url)}`);
223
+ try {
224
+ fs.writeFileSync(
225
+ binPath,
226
+ extractFileFromTarGzip(await fetch(url), subpath)
227
+ );
228
+ fs.chmodSync(binPath, 0o755);
229
+ } catch (e) {
230
+ console.error(
231
+ `[turbo] Failed to download ${JSON.stringify(url)}: ${
232
+ (e && e.message) || e
233
+ }`
291
234
  );
235
+ throw e;
292
236
  }
293
237
  }
294
238
 
295
- function installOnUnix(name) {
296
- // Yarn 2 is deliberately incompatible with binary modules because the
297
- // developers of Yarn 2 don't think they should be used. See this thread for
298
- // details: https://github.com/yarnpkg/berry/issues/882.
299
- //
300
- // We want to avoid slowing down turbo for everyone just because of this
301
- // decision by the Yarn 2 developers, so we explicitly detect if turbo is
302
- // being installed using Yarn 2 and install a compatability shim only for
303
- // Yarn 2. Normal package managers can just run the binary directly for
304
- // maximum speed.
305
- if (isYarnBerryOrNewer()) {
306
- installWithWrapper(name, "bin/turbo", "turbo");
307
- } else {
308
- installDirectly(name);
239
+ async function checkAndPreparePackage() {
240
+ // This feature was added to give external code a way to modify the binary
241
+ // path without modifying the code itself. Do not remove this because
242
+ // external code relies on this (in addition to turbo's own test suite).
243
+ if (TURBO_BINARY_PATH) {
244
+ applyManualBinaryPathOverride(TURBO_BINARY_PATH);
245
+ return;
309
246
  }
310
- }
311
247
 
312
- function installOnWindows(name) {
313
- installWithWrapper(name, "turbo.exe", "turbo.exe");
314
- }
248
+ const { pkg, subpath } = pkgAndSubpathForCurrentPlatform();
315
249
 
316
- const platformKey = `${process.platform} ${os.arch()} ${os.endianness()}`;
317
- const knownWindowsPackages = {
318
- "win32 ia32 LE": "turbo-windows-32",
319
- "win32 x64 LE": "turbo-windows-64",
320
- };
321
- const knownUnixlikePackages = {
322
- "darwin x64 LE": "turbo-darwin-64",
323
- "darwin arm64 LE": "turbo-darwin-arm64",
324
- "freebsd arm64 LE": "turbo-freebsd-arm64",
325
- "freebsd x64 LE": "turbo-freebsd-64",
326
- "linux arm LE": "turbo-linux-arm",
327
- "linux arm64 LE": "turbo-linux-arm64",
328
- "linux ia32 LE": "turbo-linux-32",
329
- "linux mips64el LE": "turbo-linux-mips64le",
330
- "linux ppc64 LE": "turbo-linux-ppc64le",
331
- "linux x64 LE": "turbo-linux-64",
332
- };
250
+ let binPath;
251
+ try {
252
+ // First check for the binary package from our "optionalDependencies". This
253
+ // package should have been installed alongside this package at install time.
254
+ binPath = require.resolve(`${pkg}/${subpath}`);
255
+ } catch (e) {
256
+ console.error(`[turbo] Failed to find package "${pkg}" on the file system
333
257
 
334
- // Pick a package to install
335
- if (platformKey in knownWindowsPackages) {
336
- installOnWindows(knownWindowsPackages[platformKey]);
337
- } else if (platformKey in knownUnixlikePackages) {
338
- installOnUnix(knownUnixlikePackages[platformKey]);
339
- } else {
340
- console.error(`Unsupported platform: ${platformKey}`);
341
- process.exit(1);
258
+ This can happen if you use the "--no-optional" flag. The "optionalDependencies"
259
+ package.json feature is used by turbo to install the correct binary executable
260
+ for your current platform. This install script will now attempt to work around
261
+ this. If that fails, you need to remove the "--no-optional" flag to use turbo.
262
+ `);
263
+
264
+ // If that didn't work, then someone probably installed turbo with the
265
+ // "--no-optional" flag. Attempt to compensate for this by downloading the
266
+ // package using a nested call to "npm" instead.
267
+ //
268
+ // THIS MAY NOT WORK. Package installation uses "optionalDependencies" for
269
+ // a reason: manually downloading the package has a lot of obscure edge
270
+ // cases that fail because people have customized their environment in
271
+ // some strange way that breaks downloading. This code path is just here
272
+ // to be helpful but it's not the supported way of installing turbo.
273
+ binPath = downloadedBinPath(pkg, subpath);
274
+ try {
275
+ console.error(`[turbo] Trying to install package "${pkg}" using npm`);
276
+ installUsingNPM(pkg, subpath, binPath);
277
+ } catch (e2) {
278
+ console.error(
279
+ `[turbo] Failed to install package "${pkg}" using npm: ${
280
+ (e2 && e2.message) || e2
281
+ }`
282
+ );
283
+
284
+ // If that didn't also work, then something is likely wrong with the "npm"
285
+ // command. Attempt to compensate for this by manually downloading the
286
+ // package from the npm registry over HTTP as a last resort.
287
+ try {
288
+ await downloadDirectlyFromNPM(pkg, subpath, binPath);
289
+ } catch (e3) {
290
+ throw new Error(`Failed to install package "${pkg}"`);
291
+ }
292
+ }
293
+ }
294
+
295
+ maybeOptimizePackage(binPath);
342
296
  }
297
+
298
+ checkAndPreparePackage().then(() => {
299
+ if (isToPathJS) {
300
+ // We need "node" before this command since it's a JavaScript file
301
+ validateBinaryVersion("node", toPath);
302
+ } else {
303
+ // This is no longer a JavaScript file so don't run it using "node"
304
+ validateBinaryVersion(toPath);
305
+ }
306
+ });
@@ -0,0 +1,130 @@
1
+ // Most of this file is ripped from esbuild
2
+ // @see https://github.com/evanw/esbuild/blob/master/lib/npm/node-install.ts
3
+ // This file is MIT licensed.
4
+
5
+ const fs = require("fs");
6
+ const os = require("os");
7
+ const path = require("path");
8
+
9
+ // This feature was added to give external code a way to modify the binary
10
+ // path without modifying the code itself. Do not remove this because
11
+ // external code relies on this.
12
+ const TURBO_BINARY_PATH = process.env.TURBO_BINARY_PATH;
13
+
14
+ const knownWindowsPackages = {
15
+ // "win32 arm64 LE": "turbo-windows-arm64",
16
+ "win32 ia32 LE": "turbo-windows-32",
17
+ "win32 x64 LE": "turbo-windows-64",
18
+ };
19
+
20
+ const knownUnixlikePackages = {
21
+ // "android arm64 LE": "turbo-android-arm64",
22
+ "darwin arm64 LE": "turbo-darwin-arm64",
23
+ "darwin x64 LE": "turbo-darwin-64",
24
+ "freebsd arm64 LE": "turbo-freebsd-arm64",
25
+ "freebsd x64 LE": "turbo-freebsd-64",
26
+ "linux arm LE": "turbo-linux-arm",
27
+ "linux arm64 LE": "turbo-linux-arm64",
28
+ "linux ia32 LE": "turbo-linux-32",
29
+ "linux mips64el LE": "turbo-linux-mips64le",
30
+ "linux ppc64 LE": "turbo-linux-ppc64le",
31
+ // "linux s390x BE": "turbo-linux-s390x",
32
+ "linux x64 LE": "turbo-linux-64",
33
+ // "netbsd x64 LE": "turbo-netbsd-64",
34
+ // "openbsd x64 LE": "turbo-openbsd-64",
35
+ // "sunos x64 LE": "turbo-sunos-64",
36
+ };
37
+
38
+ function pkgAndSubpathForCurrentPlatform() {
39
+ let pkg;
40
+ let subpath;
41
+ let platformKey = `${process.platform} ${os.arch()} ${os.endianness()}`;
42
+
43
+ if (platformKey in knownWindowsPackages) {
44
+ pkg = knownWindowsPackages[platformKey];
45
+ subpath = "turbo.exe";
46
+ } else if (platformKey in knownUnixlikePackages) {
47
+ pkg = knownUnixlikePackages[platformKey];
48
+ subpath = "bin/turbo";
49
+ } else {
50
+ throw new Error(`Unsupported platform: ${platformKey}`);
51
+ }
52
+ return { pkg, subpath };
53
+ }
54
+
55
+ function downloadedBinPath(pkg, subpath) {
56
+ const turboLibDir = path.dirname(require.resolve("turbo"));
57
+ return path.join(turboLibDir, `downloaded-${pkg}-${path.basename(subpath)}`);
58
+ }
59
+
60
+ function generateBinPath() {
61
+ // This feature was added to give external code a way to modify the binary
62
+ // path without modifying the code itself. Do not remove this because
63
+ // external code relies on this (in addition to turbo's own test suite).
64
+ if (TURBO_BINARY_PATH) {
65
+ return TURBO_BINARY_PATH;
66
+ }
67
+
68
+ const { pkg, subpath } = pkgAndSubpathForCurrentPlatform();
69
+ let binPath;
70
+
71
+ try {
72
+ // First check for the binary package from our "optionalDependencies". This
73
+ // package should have been installed alongside this package at install time.
74
+ binPath = require.resolve(`${pkg}/${subpath}`);
75
+ } catch (e) {
76
+ // If that didn't work, then someone probably installed turbo with the
77
+ // "--no-optional" flag. Our install script attempts to compensate for this
78
+ // by manually downloading the package instead. Check for that next.
79
+ binPath = downloadedBinPath(pkg, subpath);
80
+ if (!fs.existsSync(binPath)) {
81
+ // If that didn't work too, then we're out of options. This can happen
82
+ // when someone installs turbo with both the "--no-optional" and the
83
+ // "--ignore-scripts" flags. The fix for this is to just not do that.
84
+ //
85
+ // In that case we try to have a nice error message if we think we know
86
+ // what's happening. Otherwise we just rethrow the original error message.
87
+ try {
88
+ require.resolve(pkg);
89
+ } catch {
90
+ throw new Error(`The package "${pkg}" could not be found, and is needed by turbo.
91
+
92
+ If you are installing turbo with npm, make sure that you don't specify the
93
+ "--no-optional" flag. The "optionalDependencies" package.json feature is used
94
+ by turbo to install the correct binary executable for your current platform.`);
95
+ }
96
+ throw e;
97
+ }
98
+ }
99
+
100
+ // The turbo binary executable can't be used in Yarn 2 in PnP mode because
101
+ // it's inside a virtual file system and the OS needs it in the real file
102
+ // system. So we need to copy the file out of the virtual file system into
103
+ // the real file system.
104
+ let isYarnPnP = false;
105
+ try {
106
+ require("pnpapi");
107
+ isYarnPnP = true;
108
+ } catch (e) {}
109
+ if (isYarnPnP) {
110
+ const turboLibDir = path.dirname(require.resolve("turbo"));
111
+ const binTargetPath = path.join(
112
+ turboLibDir,
113
+ `pnpapi-${pkg}-${path.basename(subpath)}`
114
+ );
115
+ if (!fs.existsSync(binTargetPath)) {
116
+ fs.copyFileSync(binPath, binTargetPath);
117
+ fs.chmodSync(binTargetPath, 0o755);
118
+ }
119
+ return binTargetPath;
120
+ }
121
+ return binPath;
122
+ }
123
+
124
+ module.exports = {
125
+ knownUnixlikePackages,
126
+ knownWindowsPackages,
127
+ generateBinPath,
128
+ pkgAndSubpathForCurrentPlatform,
129
+ TURBO_BINARY_PATH,
130
+ };
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "turbo",
3
- "version": "1.0.19",
3
+ "version": "1.0.20",
4
4
  "description": "The blazing fast monorepo build system.",
5
5
  "repository": "https://github.com/vercel/turborepo",
6
6
  "bugs": "https://github.com/vercel/turborepo/issues",
7
7
  "homepage": "https://turborepo.org",
8
+ "license": "MPL-2.0",
8
9
  "scripts": {
9
10
  "postinstall": "node install.js"
10
11
  },
@@ -13,8 +14,21 @@
13
14
  },
14
15
  "files": [
15
16
  "bin",
16
- "install.js",
17
- "login.js"
17
+ "node-platform.js",
18
+ "install.js"
18
19
  ],
19
- "license": "MPL-2.0"
20
- }
20
+ "optionalDependencies": {
21
+ "turbo-darwin-64": "1.0.20",
22
+ "turbo-darwin-arm64": "1.0.20",
23
+ "turbo-freebsd-64": "1.0.20",
24
+ "turbo-freebsd-arm64": "1.0.20",
25
+ "turbo-linux-32": "1.0.20",
26
+ "turbo-linux-64": "1.0.20",
27
+ "turbo-linux-arm": "1.0.20",
28
+ "turbo-linux-arm64": "1.0.20",
29
+ "turbo-linux-mips64le": "1.0.20",
30
+ "turbo-linux-ppc64le": "1.0.20",
31
+ "turbo-windows-32": "1.0.20",
32
+ "turbo-windows-64": "1.0.20"
33
+ }
34
+ }