Comparing version 0.8.5 to 0.9.0-next.0
362
install.js
@@ -1,30 +0,28 @@ | ||
const fs = require('fs') | ||
const os = require('os') | ||
const path = require('path') | ||
const zlib = require('zlib') | ||
const got = require('got') | ||
const https = require('https') | ||
const child_process = require('child_process') | ||
const getAuthToken = require('registry-auth-token') | ||
const version = require('./package.json').version | ||
const binPath = path.join(__dirname, 'bin', 'turbo') | ||
// Most of this file is ripped from esbuild's postinstall script | ||
// @see https://github.com/evanw/esbuild/blob/v0.12.29/lib/npm/install.ts | ||
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 version = require("./package.json").version; | ||
const binPath = path.join(__dirname, "bin", "turbo"); | ||
const TOKEN = process.env.TURBO_TOKEN || process.env.TURBOREPO_TOKEN | ||
async function installBinaryFromPackage(name, fromPath, toPath) { | ||
// Try to install from the cache if possible | ||
// const cachePath = getCachePath(name) | ||
// try { | ||
// // Copy from the cache | ||
// fs.copyFileSync(cachePath, toPath) | ||
// fs.chmodSync(toPath, 0o755) | ||
const cachePath = getCachePath(name); | ||
try { | ||
// Copy from the cache | ||
fs.copyFileSync(cachePath, toPath); | ||
fs.chmodSync(toPath, 0o755); | ||
// // Verify that the binary is the correct version | ||
// validateBinaryVersion(toPath) | ||
// Verify that the binary is the correct version | ||
validateBinaryVersion(toPath); | ||
// // Mark the cache entry as used for LRU | ||
// const now = new Date() | ||
// fs.utimesSync(cachePath, now, now) | ||
// return | ||
// } catch {} | ||
// Mark the cache entry as used for LRU | ||
const now = new Date(); | ||
fs.utimesSync(cachePath, now, now); | ||
return; | ||
} catch (e) {} | ||
@@ -34,13 +32,13 @@ // Next, try to install using npm. This should handle various tricky cases | ||
// there is probably a proxy and/or a custom registry configured instead). | ||
let buffer | ||
let didFail = true | ||
// try { | ||
// buffer = installUsingNPM(name, fromPath) | ||
// } catch (err) { | ||
// didFail = true | ||
// console.error(`Trying to install "${name}" using npm`) | ||
// console.error( | ||
// `Failed to install "${name}" using npm: ${(err && err.message) || err}` | ||
// ) | ||
// } | ||
let buffer; | ||
let didFail = true; | ||
try { | ||
buffer = installUsingNPM(name, fromPath); | ||
} catch (err) { | ||
didFail = true; | ||
console.error(`Trying to install "${name}" using npm`); | ||
console.error( | ||
`Failed to install "${name}" using npm: ${(err && err.message) || err}` | ||
); | ||
} | ||
@@ -50,8 +48,6 @@ // If that fails, the user could have npm configured incorrectly or could not | ||
if (!buffer) { | ||
const { body } = await got(`https://npm.turborepo.com/${name}`) | ||
// https://registry.npmjs.org/@microsoft/task-scheduler/-/task-scheduler-1.0.0.tgz | ||
const url = JSON.parse(body).versions[version].dist.tarball | ||
console.error(`Trying to download ${JSON.stringify(url)}`) | ||
const url = `https://registry.npmjs.org/${name}/-/${name}-${version}.tgz`; | ||
console.error(`Trying to download ${JSON.stringify(url)}`); | ||
try { | ||
buffer = extractFileFromTarGzip(await fetch(url), fromPath) | ||
buffer = extractFileFromTarGzip(await fetch(url), fromPath); | ||
} catch (err) { | ||
@@ -62,3 +58,3 @@ console.error( | ||
}` | ||
) | ||
); | ||
} | ||
@@ -69,12 +65,12 @@ } | ||
if (!buffer) { | ||
console.error(`Install unsuccessful`) | ||
process.exit(1) | ||
console.error(`Install unsuccessful`); | ||
process.exit(1); | ||
} | ||
// Write out the binary executable that was extracted from the package | ||
fs.writeFileSync(toPath, buffer, { mode: 0o755 }) | ||
fs.writeFileSync(toPath, buffer, { mode: 0o755 }); | ||
// Verify that the binary is the correct version | ||
try { | ||
validateBinaryVersion(toPath) | ||
validateBinaryVersion(toPath); | ||
} catch (err) { | ||
@@ -85,18 +81,18 @@ console.error( | ||
}` | ||
) | ||
console.error(`Install unsuccessful`) | ||
process.exit(1) | ||
); | ||
console.error(`Install unsuccessful`); | ||
process.exit(1); | ||
} | ||
// Also try to cache the file to speed up future installs | ||
// try { | ||
// fs.mkdirSync(path.dirname(cachePath), { | ||
// recursive: true, | ||
// mode: 0o700, // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html | ||
// }) | ||
// fs.copyFileSync(toPath, cachePath) | ||
// cleanCacheLRU(cachePath) | ||
// } catch {} | ||
try { | ||
fs.mkdirSync(path.dirname(cachePath), { | ||
recursive: true, | ||
mode: 0o700, // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html | ||
}); | ||
fs.copyFileSync(toPath, cachePath); | ||
cleanCacheLRU(cachePath); | ||
} catch (e) {} | ||
if (didFail) console.error(`Install successful`) | ||
if (didFail) console.error(`Install successful`); | ||
} | ||
@@ -106,9 +102,9 @@ | ||
const stdout = child_process | ||
.execFileSync(binaryPath, ['--version']) | ||
.execFileSync(binaryPath, ["--version"]) | ||
.toString() | ||
.trim() | ||
.trim(); | ||
if (stdout !== version) { | ||
throw new Error( | ||
`Expected ${JSON.stringify(version)} but got ${JSON.stringify(stdout)}` | ||
) | ||
); | ||
} | ||
@@ -118,19 +114,19 @@ } | ||
function getCachePath(name) { | ||
const home = os.homedir() | ||
const common = ['turbo', 'bin', `${name}@${version}`] | ||
if (process.platform === 'darwin') | ||
return path.join(home, 'Library', 'Caches', ...common) | ||
if (process.platform === 'win32') | ||
return path.join(home, 'AppData', 'Local', 'Cache', ...common) | ||
const home = os.homedir(); | ||
const common = ["turbo", "bin", `${name}@${version}`]; | ||
if (process.platform === "darwin") | ||
return path.join(home, "Library", "Caches", ...common); | ||
if (process.platform === "win32") | ||
return path.join(home, "AppData", "Local", "Cache", ...common); | ||
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html | ||
const XDG_CACHE_HOME = process.env.XDG_CACHE_HOME | ||
const XDG_CACHE_HOME = process.env.XDG_CACHE_HOME; | ||
if ( | ||
process.platform === 'linux' && | ||
process.platform === "linux" && | ||
XDG_CACHE_HOME && | ||
path.isAbsolute(XDG_CACHE_HOME) | ||
) | ||
return path.join(XDG_CACHE_HOME, ...common) | ||
return path.join(XDG_CACHE_HOME, ...common); | ||
return path.join(home, '.cache', ...common) | ||
return path.join(home, ".cache", ...common); | ||
} | ||
@@ -140,18 +136,18 @@ | ||
// Gather all entries in the cache | ||
const dir = path.dirname(fileToKeep) | ||
const entries = [] | ||
const dir = path.dirname(fileToKeep); | ||
const entries = []; | ||
for (const entry of fs.readdirSync(dir)) { | ||
const entryPath = path.join(dir, entry) | ||
const entryPath = path.join(dir, entry); | ||
try { | ||
const stats = fs.statSync(entryPath) | ||
entries.push({ path: entryPath, mtime: stats.mtime }) | ||
} catch {} | ||
const stats = fs.statSync(entryPath); | ||
entries.push({ path: entryPath, mtime: stats.mtime }); | ||
} catch (e) {} | ||
} | ||
// Only keep the most recent entries | ||
entries.sort((a, b) => +b.mtime - +a.mtime) | ||
entries.sort((a, b) => +b.mtime - +a.mtime); | ||
for (const entry of entries.slice(5)) { | ||
try { | ||
fs.unlinkSync(entry.path) | ||
} catch {} | ||
fs.unlinkSync(entry.path); | ||
} catch (e) {} | ||
} | ||
@@ -161,35 +157,18 @@ } | ||
function fetch(url) { | ||
let token = TOKEN | ||
try { | ||
const t = getAuthToken('//npm.turborepo.com') | ||
if (t && t.token) { | ||
token = t.token | ||
} | ||
} catch (error) { | ||
console.error('Could not read token from .npmrc') | ||
} | ||
return new Promise((resolve, reject) => { | ||
https | ||
.get( | ||
url, | ||
{ | ||
headers: { | ||
Authorization: 'Bearer ' + token, | ||
}, | ||
}, | ||
(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) | ||
}) | ||
.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); | ||
}); | ||
} | ||
@@ -199,22 +178,22 @@ | ||
try { | ||
buffer = zlib.unzipSync(buffer) | ||
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 | ||
file = `package/${file}` | ||
String.fromCharCode(...buffer.subarray(i, i + n)).replace(/\0.*$/, ""); | ||
let offset = 0; | ||
file = `package/${file}`; | ||
while (offset < buffer.length) { | ||
let name = str(offset, 100) | ||
let size = parseInt(str(offset + 124, 12), 8) | ||
offset += 512 | ||
let name = str(offset, 100); | ||
let size = parseInt(str(offset + 124, 12), 8); | ||
offset += 512; | ||
if (!isNaN(size)) { | ||
if (name === file) return buffer.subarray(offset, offset + size) | ||
offset += (size + 511) & ~511 | ||
if (name === file) return buffer.subarray(offset, offset + size); | ||
offset += (size + 511) & ~511; | ||
} | ||
} | ||
throw new Error(`Could not find ${JSON.stringify(file)} in archive`) | ||
throw new Error(`Could not find ${JSON.stringify(file)} in archive`); | ||
} | ||
@@ -225,32 +204,21 @@ | ||
os.tmpdir(), | ||
'turbo-' + Math.random().toString(36).slice(2) | ||
) | ||
fs.mkdirSync(installDir, { recursive: true }) | ||
fs.writeFileSync(path.join(installDir, 'package.json'), '{}') | ||
try { | ||
fs.copyFileSync( | ||
path.join(process.cwd(), '.npmrc'), | ||
path.join(installDir, '.npmrc') | ||
) | ||
} catch (error) {} | ||
"turbo-" + Math.random().toString(36).slice(2) | ||
); | ||
fs.mkdirSync(installDir, { recursive: true }); | ||
fs.writeFileSync(path.join(installDir, "package.json"), "{}"); | ||
// 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 } | ||
const env = { ...process.env, npm_config_global: undefined }; | ||
child_process.execSync( | ||
`npm install --loglevel=error --prefer-offline --no-audit --progress=false ${name}@${version} --registry=https://npm.turborepo.com`, | ||
{ cwd: installDir, stdio: 'pipe', env } | ||
) | ||
`npm install --loglevel=error --prefer-offline --no-audit --progress=false ${name}@${version}`, | ||
{ cwd: installDir, stdio: "pipe", env } | ||
); | ||
const buffer = fs.readFileSync( | ||
path.join( | ||
installDir, | ||
'node_modules', | ||
'@turborepo', | ||
name.replace('@turborepo/', ''), | ||
file | ||
) | ||
) | ||
path.join(installDir, "node_modules", name, file) | ||
); | ||
try { | ||
removeRecursive(installDir) | ||
removeRecursive(installDir); | ||
} catch (e) { | ||
@@ -265,3 +233,3 @@ // Removing a file or directory can randomly break on Windows, returning | ||
} | ||
return buffer | ||
return buffer; | ||
} | ||
@@ -271,37 +239,43 @@ | ||
for (const entry of fs.readdirSync(dir)) { | ||
const entryPath = path.join(dir, entry) | ||
let stats | ||
const entryPath = path.join(dir, entry); | ||
let stats; | ||
try { | ||
stats = fs.lstatSync(entryPath) | ||
stats = fs.lstatSync(entryPath); | ||
} catch (e) { | ||
continue // Guard against https://github.com/nodejs/node/issues/4760 | ||
continue; // Guard against https://github.com/nodejs/node/issues/4760 | ||
} | ||
if (stats.isDirectory()) removeRecursive(entryPath) | ||
else fs.unlinkSync(entryPath) | ||
if (stats.isDirectory()) removeRecursive(entryPath); | ||
else fs.unlinkSync(entryPath); | ||
} | ||
fs.rmdirSync(dir) | ||
fs.rmdirSync(dir); | ||
} | ||
function isYarnBerryOrNewer() { | ||
const { npm_config_user_agent } = process.env | ||
const { npm_config_user_agent } = process.env; | ||
if (npm_config_user_agent) { | ||
const match = npm_config_user_agent.match(/yarn\/(\d+)/) | ||
const match = npm_config_user_agent.match(/yarn\/(\d+)/); | ||
if (match && match[1]) { | ||
return parseInt(match[1], 10) >= 2 | ||
return parseInt(match[1], 10) >= 2; | ||
} | ||
} | ||
return false | ||
return false; | ||
} | ||
function installDirectly(name) { | ||
if (process.env.TURBO_BIN_PATH_FOR_TESTS) { | ||
fs.unlinkSync(binPath) | ||
fs.symlinkSync(process.env.TURBO_BIN_PATH_FOR_TESTS, binPath) | ||
validateBinaryVersion(process.env.TURBO_BIN_PATH_FOR_TESTS) | ||
if (process.env.TURBO_BINARY_PATH) { | ||
fs.copyFileSync(process.env.TURBO_BINARY_PATH, binPath); | ||
validateBinaryVersion(binPath); | ||
} else { | ||
installBinaryFromPackage(name, 'bin/turbo', binPath).catch((e) => | ||
setImmediate(() => { | ||
throw e | ||
}) | ||
) | ||
// Write to a temporary file, then move the file into place. This is an | ||
// attempt to avoid problems with package managers like pnpm which will | ||
// usually turn each file into a hard link. We don't want to mutate the | ||
// hard-linked file which may be shared with other files. | ||
const tempBinPath = binPath + "__"; | ||
installBinaryFromPackage(name, "bin/turbo", tempBinPath) | ||
.then(() => fs.renameSync(tempBinPath, binPath)) | ||
.catch((e) => | ||
setImmediate(() => { | ||
throw e; | ||
}) | ||
); | ||
} | ||
@@ -320,13 +294,13 @@ } | ||
` | ||
) | ||
const absToPath = path.join(__dirname, toPath) | ||
if (process.env.TURBO_BIN_PATH_FOR_TESTS) { | ||
fs.copyFileSync(process.env.TURBO_BIN_PATH_FOR_TESTS, absToPath) | ||
validateBinaryVersion(process.env.TURBO_BIN_PATH_FOR_TESTS) | ||
); | ||
const absToPath = path.join(__dirname, toPath); | ||
if (process.env.TURBO_BINARY_PATH) { | ||
fs.copyFileSync(process.env.TURBO_BINARY_PATH, absToPath); | ||
validateBinaryVersion(absToPath); | ||
} else { | ||
installBinaryFromPackage(name, fromPath, absToPath).catch((e) => | ||
setImmediate(() => { | ||
throw e | ||
throw e; | ||
}) | ||
) | ||
); | ||
} | ||
@@ -346,5 +320,5 @@ } | ||
if (isYarnBerryOrNewer()) { | ||
installWithWrapper(name, 'bin/turbo', 'turbo') | ||
installWithWrapper(name, "bin/turbo", "turbo"); | ||
} else { | ||
installDirectly(name) | ||
installDirectly(name); | ||
} | ||
@@ -354,31 +328,31 @@ } | ||
function installOnWindows(name) { | ||
installWithWrapper(name, 'turbo.exe', 'turbo.exe') | ||
installWithWrapper(name, "turbo.exe", "turbo.exe"); | ||
} | ||
const platformKey = `${process.platform} ${os.arch()} ${os.endianness()}` | ||
const platformKey = `${process.platform} ${os.arch()} ${os.endianness()}`; | ||
const knownWindowsPackages = { | ||
'win32 ia32 LE': '@turborepo/turbo-windows-32', | ||
'win32 x64 LE': '@turborepo/turbo-windows-64', | ||
} | ||
"win32 ia32 LE": "turbo-windows-32", | ||
"win32 x64 LE": "turbo-windows-64", | ||
}; | ||
const knownUnixlikePackages = { | ||
'darwin x64 LE': '@turborepo/turbo-darwin-64', | ||
'darwin arm64 LE': '@turborepo/turbo-darwin-arm64', | ||
'freebsd arm64 LE': '@turborepo/turbo-freebsd-arm64', | ||
'freebsd x64 LE': '@turborepo/turbo-freebsd-64', | ||
'linux arm LE': '@turborepo/turbo-linux-arm', | ||
'linux arm64 LE': '@turborepo/turbo-linux-arm64', | ||
'linux ia32 LE': '@turborepo/turbo-linux-32', | ||
'linux mips64el LE': '@turborepo/turbo-linux-mips64le', | ||
'linux ppc64 LE': '@turborepo/turbo-linux-ppc64le', | ||
'linux x64 LE': '@turborepo/turbo-linux-64', | ||
} | ||
"darwin x64 LE": "turbo-darwin-64", | ||
"darwin arm64 LE": "turbo-darwin-arm64", | ||
"freebsd arm64 LE": "turbo-freebsd-arm64", | ||
"freebsd x64 LE": "turbo-freebsd-64", | ||
"linux arm LE": "turbo-linux-arm", | ||
"linux arm64 LE": "turbo-linux-arm64", | ||
"linux ia32 LE": "turbo-linux-32", | ||
"linux mips64el LE": "turbo-linux-mips64le", | ||
"linux ppc64 LE": "turbo-linux-ppc64le", | ||
"linux x64 LE": "turbo-linux-64", | ||
}; | ||
// Pick a package to install | ||
if (platformKey in knownWindowsPackages) { | ||
installOnWindows(knownWindowsPackages[platformKey]) | ||
installOnWindows(knownWindowsPackages[platformKey]); | ||
} else if (platformKey in knownUnixlikePackages) { | ||
installOnUnix(knownUnixlikePackages[platformKey]) | ||
installOnUnix(knownUnixlikePackages[platformKey]); | ||
} else { | ||
console.error(`Unsupported platform: ${platformKey}`) | ||
process.exit(1) | ||
console.error(`Unsupported platform: ${platformKey}`); | ||
process.exit(1); | ||
} |
{ | ||
"name": "turbo", | ||
"version": "0.8.5", | ||
"version": "0.9.0-next.0", | ||
"description": "The blazing fast monorepo build system.", | ||
"repository": "https://github.com/turborepo/turbo", | ||
"scripts": { | ||
"postinstall": "node install.js" | ||
}, | ||
"bin": { | ||
@@ -14,6 +11,4 @@ "turbo": "bin/turbo" | ||
"dependencies": { | ||
"got": "^11.8.2", | ||
"registry-auth-token": "^4.2.1", | ||
"zlib": "^1.0.5" | ||
} | ||
} |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
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
Install scripts
Supply chain riskInstall scripts are run when the package is installed. The majority of malware in npm is hidden in install scripts.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
12844
1
4
0
29
0
9
313
5
- Removedgot@^11.8.2
- Removedregistry-auth-token@^4.2.1
- Removed@sindresorhus/is@4.6.0(transitive)
- Removed@szmarczak/http-timer@4.0.6(transitive)
- Removed@types/cacheable-request@6.0.3(transitive)
- Removed@types/http-cache-semantics@4.0.4(transitive)
- Removed@types/keyv@3.1.4(transitive)
- Removed@types/node@22.9.0(transitive)
- Removed@types/responselike@1.0.3(transitive)
- Removedcacheable-lookup@5.0.4(transitive)
- Removedcacheable-request@7.0.4(transitive)
- Removedclone-response@1.0.3(transitive)
- Removeddecompress-response@6.0.0(transitive)
- Removeddeep-extend@0.6.0(transitive)
- Removeddefer-to-connect@2.0.1(transitive)
- Removedend-of-stream@1.4.4(transitive)
- Removedget-stream@5.2.0(transitive)
- Removedgot@11.8.6(transitive)
- Removedhttp-cache-semantics@4.1.1(transitive)
- Removedhttp2-wrapper@1.0.3(transitive)
- Removedini@1.3.8(transitive)
- Removedjson-buffer@3.0.1(transitive)
- Removedkeyv@4.5.4(transitive)
- Removedlowercase-keys@2.0.0(transitive)
- Removedmimic-response@1.0.13.1.0(transitive)
- Removedminimist@1.2.8(transitive)
- Removednormalize-url@6.1.0(transitive)
- Removedonce@1.4.0(transitive)
- Removedp-cancelable@2.1.1(transitive)
- Removedpump@3.0.2(transitive)
- Removedquick-lru@5.1.1(transitive)
- Removedrc@1.2.8(transitive)
- Removedregistry-auth-token@4.2.2(transitive)
- Removedresolve-alpn@1.2.1(transitive)
- Removedresponselike@2.0.1(transitive)
- Removedstrip-json-comments@2.0.1(transitive)
- Removedundici-types@6.19.8(transitive)
- Removedwrappy@1.0.2(transitive)