aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/packages/turbo
diff options
context:
space:
mode:
author简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:44 +0800
committer简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:44 +0800
commitdd84b9d64fb98746a230cd24233ff50a562c39c9 (patch)
treeb583261ef00b3afe72ec4d6dacb31e57779a6faf /packages/turbo
parent0b46fcd72ac34382387b2bcf9095233efbcc52f4 (diff)
downloadHydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.tar.gz
HydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.zip
Diffstat (limited to 'packages/turbo')
-rw-r--r--packages/turbo/.dev-mode3
-rw-r--r--packages/turbo/README.md54
-rw-r--r--packages/turbo/bin/turbo14
-rw-r--r--packages/turbo/bump-version.js21
-rw-r--r--packages/turbo/install.js331
-rw-r--r--packages/turbo/node-platform.js257
-rw-r--r--packages/turbo/package.json29
7 files changed, 709 insertions, 0 deletions
diff --git a/packages/turbo/.dev-mode b/packages/turbo/.dev-mode
new file mode 100644
index 0000000..c25642e
--- /dev/null
+++ b/packages/turbo/.dev-mode
@@ -0,0 +1,3 @@
+DO NOT DELETE OR NPM PUBLISH THIS FILE.
+
+Its existence is used by `install.js` to determine if it should attempt to replace the binary with the native executable.
diff --git a/packages/turbo/README.md b/packages/turbo/README.md
new file mode 100644
index 0000000..97557bc
--- /dev/null
+++ b/packages/turbo/README.md
@@ -0,0 +1,54 @@
+<p align="center">
+ <a href="https://turbo.build/repo">
+ <picture>
+ <source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/4060187/196936123-f6e1db90-784d-4174-b774-92502b718836.png">
+ <img src="https://user-images.githubusercontent.com/4060187/196936104-5797972c-ab10-4834-bd61-0d1e5f442c9c.png" height="128">
+ </picture>
+ <h1 align="center">Turborepo</h1>
+ </a>
+</p>
+
+<p align="center">
+ <a aria-label="Vercel logo" href="https://vercel.com/">
+ <img src="https://img.shields.io/badge/MADE%20BY%20Vercel-000000.svg?style=for-the-badge&logo=Vercel&labelColor=000">
+ </a>
+ <a aria-label="NPM version" href="https://www.npmjs.com/package/turbo">
+ <img alt="" src="https://img.shields.io/npm/v/turbo.svg?style=for-the-badge&labelColor=000000">
+ </a>
+ <a aria-label="License" href="https://github.com/vercel/turbo/blob/main/LICENSE">
+ <img alt="" src="https://img.shields.io/npm/l/turbo.svg?style=for-the-badge&labelColor=000000&color=">
+ </a>
+ <a aria-label="Join the community on GitHub" href="https://github.com/vercel/turbo/discussions">
+ <img alt="" src="https://img.shields.io/badge/Join%20the%20community-blueviolet.svg?style=for-the-badge&logo=turborepo&labelColor=000000&logoWidth=20&logoColor=white">
+ </a>
+</p>
+
+## Getting Started
+
+Visit https://turbo.build/repo/docs to get started with Turborepo and read the documentation.
+
+## Community
+
+The Turborepo community can be found on [GitHub Discussions](https://github.com/vercel/turbo/discussions), where you can ask questions, voice ideas, and share your projects.
+
+To chat with other community members, you can join the [Turborepo Discord](https://turbo.build/discord)
+
+Our [Code of Conduct](https://github.com/vercel/turbo/blob/main/CODE_OF_CONDUCT.md) applies to all Turborepo community channels.
+
+## Who is using Turbo?
+
+Turbo is used by the world's leading companies. Check out the [Turbo Showcase](https://turbo.build/showcase) to learn more.
+
+## Updates
+
+Follow [@turborepo](https://twitter.com/turborepo) on Twitter and for project updates
+
+## Author
+
+- Jared Palmer ([@jaredpalmer](https://twitter.com/jaredpalmer))
+
+## Security
+
+If you believe you have found a security vulnerability in Turbo, we encourage you to responsibly disclose this and not open a public issue. We will investigate all legitimate reports. Email `security@vercel.com` to disclose any security vulnerabilities.
+
+https://vercel.com/security
diff --git a/packages/turbo/bin/turbo b/packages/turbo/bin/turbo
new file mode 100644
index 0000000..d998261
--- /dev/null
+++ b/packages/turbo/bin/turbo
@@ -0,0 +1,14 @@
+#!/usr/bin/env node
+
+const { generateBinPath } = require("../node-platform");
+
+try {
+ require("child_process").execFileSync(
+ generateBinPath(),
+ process.argv.slice(2),
+ { stdio: "inherit" }
+ );
+} catch(e) {
+ if(e && e.status) process.exit(e.status);
+ throw e;
+}
diff --git a/packages/turbo/bump-version.js b/packages/turbo/bump-version.js
new file mode 100644
index 0000000..d3d48d1
--- /dev/null
+++ b/packages/turbo/bump-version.js
@@ -0,0 +1,21 @@
+#!/usr/bin/env node
+
+const fs = require("fs");
+const {
+ knownUnixlikePackages,
+ knownWindowsPackages,
+} = require("./node-platform");
+
+const pkg = require("./package.json");
+const file = require.resolve("./package.json");
+
+pkg.optionalDependencies = Object.fromEntries(
+ Object.values({
+ ...knownWindowsPackages,
+ ...knownUnixlikePackages,
+ })
+ .sort()
+ .map((x) => [x, pkg.version])
+);
+
+fs.writeFileSync(file, JSON.stringify(pkg, null, 2) + "\n");
diff --git a/packages/turbo/install.js b/packages/turbo/install.js
new file mode 100644
index 0000000..8b939c4
--- /dev/null
+++ b/packages/turbo/install.js
@@ -0,0 +1,331 @@
+// Most of this file is ripped from esbuild
+// @see https://github.com/evanw/esbuild/blob/master/lib/npm/node-install.ts
+// This file is MIT licensed.
+
+const nodePlatform = require("./node-platform");
+const fs = require("fs");
+const os = require("os");
+const path = require("path");
+const zlib = require("zlib");
+const https = require("https");
+const child_process = require("child_process");
+const {
+ downloadedBinPath,
+ TURBO_BINARY_PATH,
+ pkgAndSubpathForCurrentPlatform,
+} = nodePlatform;
+const TURBO_VERSION = require("./package.json").version;
+
+const toPath = path.join(__dirname, "bin", "turbo");
+const goToPath = path.join(__dirname, "bin", "go-turbo");
+let isToPathJS = true;
+
+function validateBinaryVersion(...command) {
+ command.push("--version");
+ // Make sure that we get the version of the binary that was just installed
+ command.push("--skip-infer");
+ const stdout = child_process
+ .execFileSync(command.shift(), command, {
+ // Without this, this install script strangely crashes with the error
+ // "EACCES: permission denied, write" but only on Ubuntu Linux when node is
+ // installed from the Snap Store. This is not a problem when you download
+ // the official version of node. The problem appears to be that stderr
+ // (i.e. file descriptor 2) isn't writable?
+ //
+ // More info:
+ // - https://snapcraft.io/ (what the Snap Store is)
+ // - https://nodejs.org/dist/ (download the official version of node)
+ // - https://github.com/evanw/esbuild/issues/1711#issuecomment-1027554035
+ //
+ stdio: "pipe",
+ })
+ .toString()
+ .trim();
+ if (stdout !== TURBO_VERSION) {
+ throw new Error(
+ `Expected ${JSON.stringify(TURBO_VERSION)} but got ${JSON.stringify(
+ stdout
+ )}`
+ );
+ }
+}
+
+function isYarn() {
+ const { npm_config_user_agent } = process.env;
+ if (npm_config_user_agent) {
+ return /\byarn\//.test(npm_config_user_agent);
+ }
+ return false;
+}
+
+function fetch(url) {
+ return new Promise((resolve, reject) => {
+ https
+ .get(url, (res) => {
+ if (
+ (res.statusCode === 301 || res.statusCode === 302) &&
+ res.headers.location
+ )
+ return fetch(res.headers.location).then(resolve, reject);
+ if (res.statusCode !== 200)
+ return reject(new Error(`Server responded with ${res.statusCode}`));
+ let chunks = [];
+ res.on("data", (chunk) => chunks.push(chunk));
+ res.on("end", () => resolve(Buffer.concat(chunks)));
+ })
+ .on("error", reject);
+ });
+}
+
+function extractFileFromTarGzip(buffer, subpath) {
+ try {
+ buffer = zlib.unzipSync(buffer);
+ } catch (err) {
+ throw new Error(
+ `Invalid gzip data in archive: ${(err && err.message) || err}`
+ );
+ }
+ let str = (i, n) =>
+ String.fromCharCode(...buffer.subarray(i, i + n)).replace(/\0.*$/, "");
+ let offset = 0;
+ subpath = `package/${subpath}`;
+ while (offset < buffer.length) {
+ let name = str(offset, 100);
+ let size = parseInt(str(offset + 124, 12), 8);
+ offset += 512;
+ if (!isNaN(size)) {
+ if (name === subpath) return buffer.subarray(offset, offset + size);
+ offset += (size + 511) & ~511;
+ }
+ }
+ throw new Error(`Could not find ${JSON.stringify(subpath)} in archive`);
+}
+
+function installUsingNPM(pkg, subpath, binPath) {
+ // Erase "npm_config_global" so that "npm install --global turbo" works.
+ // Otherwise this nested "npm install" will also be global, and the install
+ // will deadlock waiting for the global installation lock.
+ const env = { ...process.env, npm_config_global: undefined };
+
+ // Create a temporary directory inside the "turbo" package with an empty
+ // "package.json" file. We'll use this to run "npm install" in.
+ const turboLibDir = path.dirname(require.resolve("turbo"));
+ const installDir = path.join(turboLibDir, "npm-install");
+ fs.mkdirSync(installDir);
+ try {
+ fs.writeFileSync(path.join(installDir, "package.json"), "{}");
+
+ // Run "npm install" in the temporary directory which should download the
+ // desired package. Try to avoid unnecessary log output. This uses the "npm"
+ // command instead of a HTTP request so that it hopefully works in situations
+ // where HTTP requests are blocked but the "npm" command still works due to,
+ // for example, a custom configured npm registry and special firewall rules.
+ child_process.execSync(
+ `npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${TURBO_VERSION}`,
+ { cwd: installDir, stdio: "pipe", env }
+ );
+
+ // Move the downloaded binary executable into place. The destination path
+ // is the same one that the JavaScript API code uses so it will be able to
+ // find the binary executable here later.
+ const installedBinPath = path.join(
+ installDir,
+ "node_modules",
+ pkg,
+ subpath
+ );
+ fs.renameSync(installedBinPath, binPath);
+ } finally {
+ // Try to clean up afterward so we don't unnecessarily waste file system
+ // space. Leaving nested "node_modules" directories can also be problematic
+ // for certain tools that scan over the file tree and expect it to have a
+ // certain structure.
+ try {
+ removeRecursive(installDir);
+ } catch {
+ // Removing a file or directory can randomly break on Windows, returning
+ // EBUSY for an arbitrary length of time. I think this happens when some
+ // other program has that file or directory open (e.g. an anti-virus
+ // program). This is fine on Unix because the OS just unlinks the entry
+ // but keeps the reference around until it's unused. There's nothing we
+ // can do in this case so we just leave the directory there.
+ }
+ }
+}
+
+function removeRecursive(dir) {
+ for (const entry of fs.readdirSync(dir)) {
+ const entryPath = path.join(dir, entry);
+ let stats;
+ try {
+ stats = fs.lstatSync(entryPath);
+ } catch {
+ continue; // Guard against https://github.com/nodejs/node/issues/4760
+ }
+ if (stats.isDirectory()) removeRecursive(entryPath);
+ else fs.unlinkSync(entryPath);
+ }
+ fs.rmSync(dir);
+}
+
+function maybeOptimizePackage(binPath) {
+ // Everything else that this installation does is fine, but the optimization
+ // step rewrites existing files. We need to make sure that this does not
+ // happen during development. We determine that by looking for a file in
+ // the package that is not published in the `npm` registry.
+ if (fs.existsSync(path.join(__dirname, ".dev-mode"))) {
+ return;
+ }
+
+ // This package contains a "bin/turbo" JavaScript file that finds and runs
+ // the appropriate binary executable. However, this means that running the
+ // "turbo" command runs another instance of "node" which is way slower than
+ // just running the binary executable directly.
+ //
+ // Here we optimize for this by replacing the JavaScript file with the binary
+ // executable at install time. This optimization does not work on Windows
+ // because on Windows the binary executable must be called "turbo.exe"
+ // instead of "turbo".
+ //
+ // This also doesn't work with Yarn both because of lack of support for binary
+ // files in Yarn 2+ (see https://github.com/yarnpkg/berry/issues/882) and
+ // because Yarn (even Yarn 1?) may run the same install scripts in the same
+ // place multiple times from different platforms, especially when people use
+ // Docker. Avoid idempotency issues by just not optimizing when using Yarn.
+ //
+ // This optimization also doesn't apply when npm's "--ignore-scripts" flag is
+ // used since in that case this install script will not be run.
+ if (os.platform() !== "win32" && !isYarn()) {
+ const optimizeBin = (from, to, temp) => {
+ const tempPath = path.join(__dirname, temp);
+ try {
+ // First link the binary with a temporary file. If this fails and throws an
+ // error, then we'll just end up doing nothing. This uses a hard link to
+ // avoid taking up additional space on the file system.
+ fs.linkSync(from, tempPath);
+
+ // Then use rename to atomically replace the target file with the temporary
+ // file. If this fails and throws an error, then we'll just end up leaving
+ // the temporary file there, which is harmless.
+ fs.renameSync(tempPath, to);
+
+ // If we get here, then we know that the target location is now a binary
+ // executable instead of a JavaScript file.
+ isToPathJS = false;
+
+ // If this install script is being re-run, then "renameSync" will fail
+ // since the underlying inode is the same (it just returns without doing
+ // anything, and without throwing an error). In that case we should remove
+ // the file manually.
+ fs.unlinkSync(tempPath);
+ } catch {
+ // Ignore errors here since this optimization is optional
+ }
+ };
+ const goBinPath = path.join(path.dirname(binPath), "go-turbo");
+ optimizeBin(goBinPath, goToPath, "bin-go-turbo");
+ optimizeBin(binPath, toPath, "bin-turbo");
+ }
+}
+
+async function downloadDirectlyFromNPM(pkg, subpath, binPath) {
+ // If that fails, the user could have npm configured incorrectly or could not
+ // have npm installed. Try downloading directly from npm as a last resort.
+ const url = `https://registry.npmjs.org/${pkg}/-/${pkg}-${TURBO_VERSION}.tgz`;
+ console.error(`[turbo] Trying to download ${JSON.stringify(url)}`);
+ try {
+ fs.writeFileSync(
+ binPath,
+ extractFileFromTarGzip(await fetch(url), subpath)
+ );
+ fs.chmodSync(binPath, 0o755);
+ } catch (e) {
+ console.error(
+ `[turbo] Failed to download ${JSON.stringify(url)}: ${
+ (e && e.message) || e
+ }`
+ );
+ throw e;
+ }
+}
+
+async function checkAndPreparePackage() {
+ // This feature was added to give external code a way to modify the binary
+ // path without modifying the code itself. Do not remove this because
+ // external code relies on this (in addition to turbo's own test suite).
+ if (TURBO_BINARY_PATH) {
+ return;
+ }
+
+ const { pkg, subpath } = pkgAndSubpathForCurrentPlatform();
+
+ let binPath;
+ try {
+ // First check for the binary package from our "optionalDependencies". This
+ // package should have been installed alongside this package at install time.
+ binPath = require.resolve(`${pkg}/${subpath}`);
+ } catch (e) {
+ console.error(`[turbo] Failed to find package "${pkg}" on the file system
+
+This can happen if you use the "--no-optional" flag. The "optionalDependencies"
+package.json feature is used by turbo to install the correct binary executable
+for your current platform. This install script will now attempt to work around
+this. If that fails, you need to remove the "--no-optional" flag to use turbo.
+`);
+
+ // If that didn't work, then someone probably installed turbo with the
+ // "--no-optional" flag. Attempt to compensate for this by downloading the
+ // package using a nested call to "npm" instead.
+ //
+ // THIS MAY NOT WORK. Package installation uses "optionalDependencies" for
+ // a reason: manually downloading the package has a lot of obscure edge
+ // cases that fail because people have customized their environment in
+ // some strange way that breaks downloading. This code path is just here
+ // to be helpful but it's not the supported way of installing turbo.
+ binPath = downloadedBinPath(pkg, subpath);
+ try {
+ console.error(`[turbo] Trying to install package "${pkg}" using npm`);
+ installUsingNPM(pkg, subpath, binPath);
+ } catch (e2) {
+ console.error(
+ `[turbo] Failed to install package "${pkg}" using npm: ${
+ (e2 && e2.message) || e2
+ }`
+ );
+
+ // If that didn't also work, then something is likely wrong with the "npm"
+ // command. Attempt to compensate for this by manually downloading the
+ // package from the npm registry over HTTP as a last resort.
+ try {
+ await downloadDirectlyFromNPM(pkg, subpath, binPath);
+ } catch (e3) {
+ throw new Error(`Failed to install package "${pkg}"`);
+ }
+ }
+ }
+
+ maybeOptimizePackage(binPath);
+}
+
+checkAndPreparePackage().then(() => {
+ try {
+ if (isToPathJS) {
+ // We need "node" before this command since it's a JavaScript file
+ validateBinaryVersion("node", toPath);
+ } else {
+ // This is no longer a JavaScript file so don't run it using "node"
+ validateBinaryVersion(toPath);
+ }
+ } catch (err) {
+ if (
+ process.platform === "linux" &&
+ err.message &&
+ err.message.includes("ENOENT")
+ ) {
+ console.error(
+ `Error: Failed to run turbo binary, you may need to install glibc compat\nSee https://turbo.build/repo/docs/getting-started/existing-monorepo#install-turbo`
+ );
+ }
+ throw err;
+ }
+});
diff --git a/packages/turbo/node-platform.js b/packages/turbo/node-platform.js
new file mode 100644
index 0000000..f65a662
--- /dev/null
+++ b/packages/turbo/node-platform.js
@@ -0,0 +1,257 @@
+// Most of this file is ripped from esbuild
+// @see https://github.com/evanw/esbuild/blob/master/lib/npm/node-install.ts
+// This file is MIT licensed.
+
+const fs = require("fs");
+const os = require("os");
+const path = require("path");
+
+// This feature was added to give external code a way to modify the binary
+// path without modifying the code itself. Do not remove this because
+// external code relies on this.
+const TURBO_BINARY_PATH = process.env.TURBO_BINARY_PATH;
+
+const packageDarwin_arm64 = "turbo-darwin-arm64";
+const packageDarwin_x64 = "turbo-darwin-64";
+
+const knownWindowsPackages = {
+ "win32 arm64 LE": "turbo-windows-arm64",
+ "win32 x64 LE": "turbo-windows-64",
+};
+
+const knownUnixlikePackages = {
+ "darwin arm64 LE": packageDarwin_arm64,
+ "darwin x64 LE": packageDarwin_x64,
+ "linux arm64 LE": "turbo-linux-arm64",
+ "linux x64 LE": "turbo-linux-64",
+};
+
+function pkgAndSubpathForCurrentPlatform() {
+ let pkg;
+ let subpath;
+ let platformKey = `${process.platform} ${os.arch()} ${os.endianness()}`;
+
+ if (platformKey in knownWindowsPackages) {
+ pkg = knownWindowsPackages[platformKey];
+ subpath = "bin/turbo.exe";
+ } else if (platformKey in knownUnixlikePackages) {
+ pkg = knownUnixlikePackages[platformKey];
+ subpath = "bin/turbo";
+ } else {
+ throw new Error(`Unsupported platform: ${platformKey}`);
+ }
+ return { pkg, subpath };
+}
+
+function downloadedBinPath(pkg, subpath) {
+ const turboLibDir = path.dirname(require.resolve("turbo"));
+ return path.join(turboLibDir, `downloaded-${pkg}-${path.basename(subpath)}`);
+}
+
+function pkgForSomeOtherPlatform() {
+ const libMainJS = require.resolve("turbo");
+ const nodeModulesDirectory = path.dirname(
+ path.dirname(path.dirname(libMainJS))
+ );
+ if (path.basename(nodeModulesDirectory) === "node_modules") {
+ for (const unixKey in knownUnixlikePackages) {
+ try {
+ const pkg = knownUnixlikePackages[unixKey];
+ if (fs.existsSync(path.join(nodeModulesDirectory, pkg))) return pkg;
+ } catch {}
+ }
+ for (const windowsKey in knownWindowsPackages) {
+ try {
+ const pkg = knownWindowsPackages[windowsKey];
+ if (fs.existsSync(path.join(nodeModulesDirectory, pkg))) return pkg;
+ } catch {}
+ }
+ }
+ return null;
+}
+
+function generateBinPath() {
+ // This feature was added to give external code a way to modify the binary
+ // path without modifying the code itself. Do not remove this because
+ // external code relies on this (in addition to turbo's own test suite).
+ if (TURBO_BINARY_PATH) {
+ if (!fs.existsSync(TURBO_BINARY_PATH)) {
+ console.warn(
+ `[turbo] Ignoring bad configuration: TURBO_BINARY_PATH=${TURBO_BINARY_PATH}`
+ );
+ } else {
+ return TURBO_BINARY_PATH;
+ }
+ }
+
+ const { pkg, subpath } = pkgAndSubpathForCurrentPlatform();
+ let binPath;
+
+ try {
+ // First check for the binary package from our "optionalDependencies". This
+ // package should have been installed alongside this package at install time.
+ binPath = require.resolve(`${pkg}/${subpath}`);
+ } catch (e) {
+ // If that didn't work, then someone probably installed turbo with the
+ // "--no-optional" flag. Our install script attempts to compensate for this
+ // by manually downloading the package instead. Check for that next.
+ binPath = downloadedBinPath(pkg, subpath);
+ if (!fs.existsSync(binPath)) {
+ // If that didn't work too, check to see whether the package is even there
+ // at all. It may not be (for a few different reasons).
+ try {
+ require.resolve(pkg);
+ } catch {
+ // If we can't find the package for this platform, then it's possible
+ // that someone installed this for some other platform and is trying
+ // to use it without reinstalling. That won't work of course, but
+ // people do this all the time with systems like Docker. Try to be
+ // helpful in that case.
+ const otherPkg = pkgForSomeOtherPlatform();
+ if (otherPkg) {
+ let suggestions = `
+Specifically the "${otherPkg}" package is present but this platform
+needs the "${pkg}" package instead. People often get into this
+situation by installing turbo on Windows or macOS and copying "node_modules"
+into a Docker image that runs Linux, or by copying "node_modules" between
+Windows and WSL environments.
+If you are installing with npm, you can try not copying the "node_modules"
+directory when you copy the files over, and running "npm ci" or "npm install"
+on the destination platform after the copy. Or you could consider using yarn
+instead of npm which has built-in support for installing a package on multiple
+platforms simultaneously.
+If you are installing with yarn, you can try listing both this platform and the
+other platform in your ".yarnrc.yml" file using the "supportedArchitectures"
+feature: https://yarnpkg.com/configuration/yarnrc/#supportedArchitectures
+Keep in mind that this means multiple copies of turbo will be present.
+`;
+
+ // Use a custom message for macOS-specific architecture issues
+ if (
+ (pkg === packageDarwin_x64 && otherPkg === packageDarwin_arm64) ||
+ (pkg === packageDarwin_arm64 && otherPkg === packageDarwin_x64)
+ ) {
+ suggestions = `
+Specifically the "${otherPkg}" package is present but this platform
+needs the "${pkg}" package instead. People often get into this
+situation by installing turbo with npm running inside of Rosetta 2 and then
+trying to use it with node running outside of Rosetta 2, or vice versa (Rosetta
+2 is Apple's on-the-fly x86_64-to-arm64 translation service).
+If you are installing with npm, you can try ensuring that both npm and node are
+not running under Rosetta 2 and then reinstalling turbo. This likely involves
+changing how you installed npm and/or node. For example, installing node with
+the universal installer here should work: https://nodejs.org/en/download/. Or
+you could consider using yarn instead of npm which has built-in support for
+installing a package on multiple platforms simultaneously.
+If you are installing with yarn, you can try listing both "arm64" and "x64"
+in your ".yarnrc.yml" file using the "supportedArchitectures" feature:
+https://yarnpkg.com/configuration/yarnrc/#supportedArchitectures
+Keep in mind that this means multiple copies of turbo will be present.
+`;
+ }
+
+ throw new Error(`
+You installed turbo for another platform than the one you're currently using.
+This won't work because turbo is written with native code and needs to
+install a platform-specific binary executable.
+${suggestions}
+Another alternative is to use the "turbo-wasm" package instead, which works
+the same way on all platforms. But it comes with a heavy performance cost and
+can sometimes be 10x slower than the "turbo" package, so you may also not
+want to do that.
+`);
+ }
+
+ // If that didn't work too, then maybe someone installed turbo with
+ // both the "--no-optional" and the "--ignore-scripts" flags. The fix
+ // for this is to just not do that. We don't attempt to handle this
+ // case at all.
+ //
+ // In that case we try to have a nice error message if we think we know
+ // what's happening. Otherwise we just rethrow the original error message.
+ throw new Error(`The package "${pkg}" could not be found, and is needed by turbo.
+If you are installing turbo with npm, make sure that you don't specify the
+"--no-optional" or "--omit=optional" flags. The "optionalDependencies" feature
+of "package.json" is used by turbo to install the correct binary executable
+for your current platform.`);
+ }
+ throw e;
+ }
+ }
+
+ // This code below guards against the unlikely case that the user is using
+ // Yarn 2+ in PnP mode and that version is old enough that it doesn't support
+ // the "preferUnplugged" setting. If that's the case, then the path to the
+ // binary executable that we got above isn't actually a real path. Instead
+ // it's a path to a zip file with some extra stuff appended to it.
+ //
+ // Yarn's PnP mode tries hard to patch Node's file system APIs to pretend
+ // that these fake paths are real. So we can't check whether it's a real file
+ // or not by using Node's file system APIs (e.g. "fs.existsSync") because
+ // they have been patched to lie. But we can't return this fake path because
+ // Yarn hasn't patched "child_process.execFileSync" to work with fake paths,
+ // so attempting to execute the binary will fail.
+ //
+ // As a hack, we use Node's file system APIs to copy the file from the fake
+ // path to a real path. This will cause Yarn's hacked file system to extract
+ // the binary executable from the zip file and turn it into a real file that
+ // we can execute.
+ //
+ // This is only done when both ".zip/" is present in the path and the
+ // "pnpapi" package is present, which is a strong indication that Yarn PnP is
+ // being used. There is no API at all for telling whether something is a real
+ // file or not as far as I can tell. Even Yarn's own code just checks for
+ // whether ".zip/" is present in the path or not.
+ //
+ // Note to self: One very hacky way to tell if a path is under the influence
+ // of Yarn's file system hacks is to stat the file and check for the "crc"
+ // property in the result. If that's present, then the file is inside a zip
+ // file. However, I haven't done that here because it's not intended to be
+ // used that way. Who knows what Yarn versions it does or does not work on
+ // (including future versions).
+ if (/\.zip\//.test(binPath)) {
+ let pnpapi;
+ try {
+ pnpapi = require("pnpapi");
+ } catch (e) {}
+ if (pnpapi) {
+ // Copy the executable to ".cache/turbo". The official recommendation
+ // of the Yarn team is to use the directory "node_modules/.cache/turbo":
+ // https://yarnpkg.com/advanced/rulebook/#packages-should-never-write-inside-their-own-folder-outside-of-postinstall
+ // People that use Yarn in PnP mode find this really annoying because they
+ // don't like seeing the "node_modules" directory. These people should
+ // either work with Yarn to change their recommendation, or upgrade their
+ // version of Yarn, since newer versions of Yarn shouldn't stick turbo's
+ // binary executables in a zip file due to the "preferUnplugged" setting.
+ const root = pnpapi.getPackageInformation(
+ pnpapi.topLevel
+ ).packageLocation;
+ const binTargetPath = path.join(
+ root,
+ "node_modules",
+ ".cache",
+ "turbo",
+ `pnpapi-${pkg.replace("/", "-")}-${TURBO_VERSION}-${path.basename(
+ subpath
+ )}`
+ );
+ if (!fs.existsSync(binTargetPath)) {
+ fs.mkdirSync(path.dirname(binTargetPath), { recursive: true });
+ fs.copyFileSync(binPath, binTargetPath);
+ fs.chmodSync(binTargetPath, 0o755);
+ }
+ return binTargetPath;
+ }
+ }
+
+ return binPath;
+}
+
+module.exports = {
+ knownUnixlikePackages,
+ knownWindowsPackages,
+ generateBinPath,
+ downloadedBinPath,
+ pkgAndSubpathForCurrentPlatform,
+ TURBO_BINARY_PATH,
+};
diff --git a/packages/turbo/package.json b/packages/turbo/package.json
new file mode 100644
index 0000000..4627a33
--- /dev/null
+++ b/packages/turbo/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "turbo",
+ "version": "1.9.4-canary.2",
+ "description": "Turborepo is a high-performance build system for JavaScript and TypeScript codebases.",
+ "repository": "https://github.com/vercel/turbo",
+ "bugs": "https://github.com/vercel/turbo/issues",
+ "homepage": "https://turbo.build/repo",
+ "license": "MPL-2.0",
+ "scripts": {
+ "postversion": "node bump-version.js",
+ "postinstall": "node install.js"
+ },
+ "bin": {
+ "turbo": "./bin/turbo"
+ },
+ "files": [
+ "bin",
+ "node-platform.js",
+ "install.js"
+ ],
+ "optionalDependencies": {
+ "turbo-darwin-64": "1.9.4-canary.2",
+ "turbo-darwin-arm64": "1.9.4-canary.2",
+ "turbo-linux-64": "1.9.4-canary.2",
+ "turbo-linux-arm64": "1.9.4-canary.2",
+ "turbo-windows-64": "1.9.4-canary.2",
+ "turbo-windows-arm64": "1.9.4-canary.2"
+ }
+}