Comparing version 1.6.3 to 1.10.12
@@ -7,3 +7,2 @@ // Most of this file is ripped from esbuild | ||
const fs = require("fs"); | ||
const os = require("os"); | ||
const path = require("path"); | ||
@@ -25,2 +24,4 @@ const zlib = require("zlib"); | ||
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 | ||
@@ -52,10 +53,2 @@ .execFileSync(command.shift(), command, { | ||
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) { | ||
@@ -171,57 +164,2 @@ return new Promise((resolve, reject) => { | ||
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 tempPath = path.join(__dirname, "bin-turbo"); | ||
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(binPath, 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, toPath); | ||
// 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 | ||
} | ||
} | ||
} | ||
async function downloadDirectlyFromNPM(pkg, subpath, binPath) { | ||
@@ -302,14 +240,25 @@ // If that fails, the user could have npm configured incorrectly or could not | ||
} | ||
maybeOptimizePackage(binPath); | ||
} | ||
checkAndPreparePackage().then(() => { | ||
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); | ||
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; | ||
} | ||
}); |
@@ -14,2 +14,5 @@ // Most of this file is ripped from esbuild | ||
const packageDarwin_arm64 = "turbo-darwin-arm64"; | ||
const packageDarwin_x64 = "turbo-darwin-64"; | ||
const knownWindowsPackages = { | ||
@@ -21,4 +24,4 @@ "win32 arm64 LE": "turbo-windows-arm64", | ||
const knownUnixlikePackages = { | ||
"darwin arm64 LE": "turbo-darwin-arm64", | ||
"darwin x64 LE": "turbo-darwin-64", | ||
"darwin arm64 LE": packageDarwin_arm64, | ||
"darwin x64 LE": packageDarwin_x64, | ||
"linux arm64 LE": "turbo-linux-arm64", | ||
@@ -50,2 +53,24 @@ "linux x64 LE": "turbo-linux-64", | ||
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() { | ||
@@ -56,3 +81,9 @@ // This feature was added to give external code a way to modify the binary | ||
if (TURBO_BINARY_PATH) { | ||
return 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; | ||
} | ||
} | ||
@@ -73,16 +104,79 @@ | ||
if (!fs.existsSync(binPath)) { | ||
// If that didn't work too, then we're out of options. This can happen | ||
// when someone installs turbo with both the "--no-optional" and the | ||
// "--ignore-scripts" flags. The fix for this is to just not do that. | ||
// | ||
// 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. | ||
// 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" flag. The "optionalDependencies" package.json feature is used | ||
by turbo to install the correct binary executable for your current platform.`); | ||
"--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.`); | ||
} | ||
@@ -93,23 +187,67 @@ throw e; | ||
// The turbo binary executable can't be used in Yarn 2 in PnP mode because | ||
// it's inside a virtual file system and the OS needs it in the real file | ||
// system. So we need to copy the file out of the virtual file system into | ||
// the real file system. | ||
let isYarnPnP = false; | ||
try { | ||
require("pnpapi"); | ||
isYarnPnP = true; | ||
} catch (e) {} | ||
if (isYarnPnP) { | ||
const turboLibDir = path.dirname(require.resolve("turbo/package.json")); | ||
const binTargetPath = path.join( | ||
turboLibDir, | ||
`pnpapi-${pkg}-${path.basename(subpath)}` | ||
); | ||
if (!fs.existsSync(binTargetPath)) { | ||
fs.copyFileSync(binPath, binTargetPath); | ||
fs.chmodSync(binTargetPath, 0o755); | ||
// 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 binTargetPath; | ||
} | ||
return binPath; | ||
@@ -116,0 +254,0 @@ } |
{ | ||
"name": "turbo", | ||
"version": "1.6.3", | ||
"version": "1.10.12", | ||
"description": "Turborepo is a high-performance build system for JavaScript and TypeScript codebases.", | ||
@@ -9,6 +9,3 @@ "repository": "https://github.com/vercel/turbo", | ||
"license": "MPL-2.0", | ||
"scripts": { | ||
"postversion": "node bump-version.js", | ||
"postinstall": "node install.js" | ||
}, | ||
"main": "./bin/turbo", | ||
"bin": { | ||
@@ -23,9 +20,13 @@ "turbo": "./bin/turbo" | ||
"optionalDependencies": { | ||
"turbo-darwin-64": "1.6.3", | ||
"turbo-darwin-arm64": "1.6.3", | ||
"turbo-linux-64": "1.6.3", | ||
"turbo-linux-arm64": "1.6.3", | ||
"turbo-windows-64": "1.6.3", | ||
"turbo-windows-arm64": "1.6.3" | ||
"turbo-darwin-64": "1.10.12", | ||
"turbo-darwin-arm64": "1.10.12", | ||
"turbo-linux-64": "1.10.12", | ||
"turbo-linux-arm64": "1.10.12", | ||
"turbo-windows-64": "1.10.12", | ||
"turbo-windows-arm64": "1.10.12" | ||
}, | ||
"scripts": { | ||
"postversion": "node bump-version.js", | ||
"postinstall": "node install.js" | ||
} | ||
} |
@@ -28,8 +28,4 @@ <p align="center"> | ||
Visit https://turbo.build/repo/docs/getting-started to get started with Turborepo. | ||
Visit https://turbo.build/repo/docs to get started with Turborepo and read the documentation. | ||
## Documentation | ||
Visit https://turbo.build/repo/docs to view the full documentation. | ||
## Community | ||
@@ -36,0 +32,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
40981
6
480
8
55