- Updated all component headers and documentation
- Changed navbar and footer branding
- Updated homepage hero badge
- Modified page title in index.html
- Simplified footer text to 'Built with ❤️'
- Consistent V2 capitalization across all references
275 lines
10 KiB
JavaScript
Executable File
275 lines
10 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
/**
|
|
* We need to run a platform-specific `turbo`. The dependency _should_
|
|
* have already been installed, but it's possible that it has not.
|
|
*/
|
|
|
|
const child_process = require('child_process');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// If we do not find the correct platform binary, should we attempt to install it?
|
|
const SHOULD_INSTALL = true;
|
|
|
|
// If we do not find the correct platform binary, should we trust calling an emulated variant?
|
|
const SHOULD_ATTEMPT_EMULATED = true;
|
|
|
|
// Relies on the fact that each tarball publishes the `package.json`.
|
|
// We can simply cd into the `turbo` directory and install there.
|
|
function installUsingNPM() {
|
|
const turboPath = path.dirname(require.resolve('turbo/package'));
|
|
|
|
// 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 };
|
|
|
|
child_process.execSync(
|
|
`npm install --loglevel=error --prefer-offline --no-audit --progress=false`,
|
|
{ cwd: turboPath, stdio: "pipe", env }
|
|
);
|
|
}
|
|
|
|
// npm has multiple places that we need to look for a package name.
|
|
function hasPackage(sourceObject, packageName) {
|
|
return !!sourceObject[packageName] || !!sourceObject[`node_modules/${packageName}`];
|
|
}
|
|
|
|
// This provides logging messages as it progresses towards calculating the binary path.
|
|
function getBinaryPath() {
|
|
// First we see if the user has configured a particular binary path.
|
|
const TURBO_BINARY_PATH = process.env.TURBO_BINARY_PATH;
|
|
if (TURBO_BINARY_PATH) {
|
|
if (!fs.existsSync(TURBO_BINARY_PATH)) {
|
|
console.error(`Turborepo was unable to find the executable specified by TURBO_BINARY_PATH:\n${TURBO_BINARY_PATH}`);
|
|
console.error();
|
|
console.error(`TURBO_BINARY_PATH is intended for development use-cases. You likely want to unset the environment variable.`);
|
|
process.exit(1);
|
|
} else {
|
|
return TURBO_BINARY_PATH;
|
|
}
|
|
}
|
|
|
|
const availablePlatforms = [
|
|
'darwin',
|
|
'linux',
|
|
'windows',
|
|
];
|
|
|
|
const availableArchs = [
|
|
'64',
|
|
'arm64',
|
|
];
|
|
|
|
// We need to figure out which binary to hand the user.
|
|
// The only place where the binary can be at this point is `require.resolve`-able
|
|
// relative to this package as it should be installed as an optional dependency.
|
|
|
|
let { platform, arch } = process;
|
|
// Node uses `win32` but we want to use `windows` for consistency with
|
|
// our package naming conventions (i.e. `turbo-windows-64`).
|
|
if (platform === "win32") {
|
|
platform = "windows";
|
|
}
|
|
const resolvedArch = arch === 'x64' ? '64' : arch;
|
|
const ext = platform === 'windows' ? '.exe' : '';
|
|
|
|
// Try all places in order until we get a hit.
|
|
|
|
// 1. The package which contains the binary we _should_ be running.
|
|
const correctBinary = availablePlatforms.includes(platform) && availableArchs.includes(resolvedArch) ? `turbo-${platform}-${resolvedArch}/bin/turbo${ext}` : null;
|
|
if (correctBinary !== null) {
|
|
try {
|
|
return require.resolve(`${correctBinary}`);
|
|
} catch (e) {}
|
|
}
|
|
|
|
// 2. Install the binary that they need just in time.
|
|
if (SHOULD_INSTALL && correctBinary !== null) {
|
|
console.warn('Turborepo did not find the correct binary for your platform.');
|
|
console.warn('We will attempt to install it now.');
|
|
|
|
try {
|
|
installUsingNPM();
|
|
const resolvedPath = require.resolve(`${correctBinary}`);
|
|
console.warn('Installation has succeeded.');
|
|
return resolvedPath;
|
|
} catch (e) {
|
|
console.warn('Installation has failed.');
|
|
}
|
|
}
|
|
|
|
// 3. Both Windows and macOS ARM boxes can run x64 binaries. Attempt to run under emulation.
|
|
const alternateBinary = (arch === "arm64" && ['darwin', 'windows'].includes(platform)) ? `turbo-${platform}-64/bin/turbo${ext}` : null;
|
|
if (SHOULD_ATTEMPT_EMULATED && alternateBinary !== null) {
|
|
try {
|
|
const resolvedPath = require.resolve(`${alternateBinary}`);
|
|
console.warn(`Turborepo detected that you're running:\n${platform} ${resolvedArch}.`);
|
|
console.warn(`We were not able to find the binary at:\n${correctBinary}`);
|
|
console.warn(`We found a possibly-compatible binary at:\n${alternateBinary}`);
|
|
console.warn(`We will attempt to run that binary.`);
|
|
return resolvedPath;
|
|
} catch (e) {}
|
|
}
|
|
|
|
// We are not going to run `turbo` this invocation.
|
|
// Let's give the best error message that we can.
|
|
|
|
// Possible error scenarios:
|
|
// - The user is on a platform/arch combination we do not support.
|
|
// - We somehow got detection wrong and never attempted to run the _actual_ `correctBinary` or `alternateBinary`.
|
|
// - The user doesn't have the correct packages installed for their platform.
|
|
|
|
// Explain our detection attempt:
|
|
console.error();
|
|
console.error('***');
|
|
console.error();
|
|
console.error(`Turborepo failed to start.`);
|
|
console.error();
|
|
console.error(`Turborepo detected that you are running:\n${platform} ${resolvedArch}`);
|
|
|
|
// Tell them if we support their platform at all.
|
|
if (!availablePlatforms.includes(platform)) {
|
|
console.error();
|
|
console.error('Turborepo does not presently support your platform.');
|
|
process.exit(1);
|
|
} else if (!availableArchs.includes(resolvedArch)) {
|
|
if (availablePlatforms.includes(platform)) {
|
|
console.error();
|
|
console.error('Turborepo supports your platform, but does not support your processor architecture.');
|
|
process.exit(1);
|
|
} else {
|
|
console.error();
|
|
console.error('Turborepo does not either of your platform or processor architecture.');
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
if (correctBinary !== null) {
|
|
console.error();
|
|
console.error('***');
|
|
console.error();
|
|
console.error(`We were not able to find the binary at:\n${correctBinary}`);
|
|
console.error();
|
|
console.error(`We looked for it at:`);
|
|
console.error(require.resolve.paths(correctBinary).join('\n'));
|
|
}
|
|
if (alternateBinary !== null) {
|
|
console.error();
|
|
console.error('***');
|
|
console.error();
|
|
console.error(`Your platform (${platform}) can sometimes run x86 under emulation.`);
|
|
console.error(`We did not find a possibly-compatible binary at:\n${alternateBinary}`);
|
|
console.error();
|
|
console.error(`We looked for it at:`);
|
|
console.error(require.resolve.paths(alternateBinary).join('\n'));
|
|
}
|
|
|
|
// Investigate other failure modes.
|
|
|
|
// Has the wrong platform's binaries available.
|
|
const availableBinaries = availablePlatforms.map(platform => availableArchs.map(arch => `turbo-${platform}-${arch}/bin/turbo${platform === 'windows' ? '.exe' : ''}`)).flat();
|
|
const definitelyWrongBinaries = availableBinaries.filter(binary => binary !== correctBinary || binary !== correctBinary);;
|
|
const otherInstalled = definitelyWrongBinaries.filter(binaryPath => {
|
|
try {
|
|
return require.resolve(binaryPath);
|
|
} catch (e) {}
|
|
});
|
|
|
|
console.error();
|
|
console.error('***');
|
|
console.error();
|
|
|
|
if (otherInstalled.length > 0) {
|
|
console.error('Turborepo checked to see if binaries for another platform are installed.');
|
|
console.error('This typically indicates an error in sharing of pre-resolved node_modules across platforms.');
|
|
console.error('One common reason for this is copying files to Docker.');
|
|
console.error();
|
|
console.error(`We found these unnecessary binaries:`);
|
|
console.error(otherInstalled.join('\n'));
|
|
} else {
|
|
console.error(`We did not find any binaries on this system.`);
|
|
console.error(`This can happen if you run installation with the --no-optional flag.`);
|
|
}
|
|
|
|
// Check to see if we have partially-populated dependencies in the npm lockfile.
|
|
const MAX_LOOKUPS = 10;
|
|
const availablePackages = availablePlatforms.map(platform => availableArchs.map(arch => `turbo-${platform}-${arch}`)).flat();
|
|
|
|
try {
|
|
// Attempt to find project root.
|
|
const selfPath = require.resolve('turbo/package');
|
|
|
|
let previous = null;
|
|
let current = path.join(selfPath, '..', '..', 'package-lock.json');
|
|
|
|
for (let i = 0; previous !== current && i < MAX_LOOKUPS; i++) {
|
|
try {
|
|
const lockfile = fs.readFileSync(current);
|
|
const parsedLockfile = JSON.parse(lockfile);
|
|
|
|
const sourceObject = parsedLockfile?.dependencies ?? parsedLockfile?.packages ?? {};
|
|
|
|
// If we don't show up in the lockfile it's the wrong lockfile.
|
|
if (hasPackage(sourceObject, 'turbo')) {
|
|
// Check to see if all of `turbo-<PLATFORM>-<ARCH>` is included.
|
|
const hasAllPackages = availablePackages.every(package => hasPackage(sourceObject, package));
|
|
if (!hasAllPackages) {
|
|
console.error();
|
|
console.error('***');
|
|
console.error();
|
|
console.error(`Turborepo detected that your lockfile (${current}) does not enumerate all available platforms.`);
|
|
console.error('This is likely a consequence of an npm issue: https://github.com/npm/cli/issues/4828.');
|
|
|
|
// Let's build their repair command:
|
|
let version = '';
|
|
let environment = '';
|
|
if (parsedLockfile?.packages[""]?.dependencies?.turbo) {
|
|
version = `@${parsedLockfile.packages[""].dependencies.turbo}`;
|
|
environment = ' --save-prod';
|
|
} else if (parsedLockfile?.packages[""]?.devDependencies?.turbo) {
|
|
version = `@${parsedLockfile.packages[""].devDependencies.turbo}`;
|
|
environment = ' --save-dev';
|
|
} else if (parsedLockfile?.packages[""]?.optionalDependencies?.turbo) {
|
|
version = `@${parsedLockfile.packages[""].optionalDependencies.turbo}`;
|
|
environment = ' --save-optional';
|
|
}
|
|
|
|
console.error();
|
|
console.error('To resolve this issue for your repository, run:');
|
|
console.error(`npm install turbo${version} --package-lock-only${environment} && npm install`);
|
|
console.error();
|
|
console.error(`You will need to commit the updated lockfile.`);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
} catch (e) {}
|
|
|
|
let next = path.join(current, '..', '..', 'package-lock.json');
|
|
previous = current;
|
|
current = next;
|
|
}
|
|
} catch (e) {}
|
|
|
|
console.error();
|
|
console.error('***');
|
|
console.error();
|
|
console.error(`If you believe this is an error, please include this message in your report.`);
|
|
|
|
process.exit(1);
|
|
}
|
|
|
|
// Run the binary we got.
|
|
try {
|
|
child_process.execFileSync(
|
|
getBinaryPath(),
|
|
process.argv.slice(2),
|
|
{ stdio: "inherit" }
|
|
);
|
|
} catch (e) {
|
|
if (e && e.status) process.exit(e.status);
|
|
throw e;
|
|
}
|