|
3 | 3 | import type {Manifest} from './types.js'; |
4 | 4 | import type PackageResolver from './package-resolver.js'; |
5 | 5 | import type {Reporter} from './reporters/index.js'; |
6 | | -import type Config from './config.js'; |
| 6 | +import Config from './config.js'; |
7 | 7 | import type {ReporterSetSpinner} from './reporters/types.js'; |
8 | 8 | import executeLifecycleScript from './util/execute-lifecycle-script.js'; |
| 9 | +import * as crypto from './util/crypto.js'; |
9 | 10 | import * as fs from './util/fs.js'; |
| 11 | +import {pack} from './cli/commands/pack.js';Config |
10 | 12 |
|
| 13 | +const fs2 = require('fs'); |
11 | 14 | const invariant = require('invariant'); |
| 15 | +const path = require('path'); |
12 | 16 |
|
13 | 17 | const INSTALL_STAGES = ['preinstall', 'install', 'postinstall']; |
14 | 18 |
|
@@ -137,6 +141,13 @@ export default class PackageInstallScripts { |
137 | 141 | return false; |
138 | 142 | } |
139 | 143 | const ref = pkg._reference; |
| 144 | + if (pkg.prebuiltVariants) { |
| 145 | + for (let variant in pkg.prebuiltVariants) { |
| 146 | + if (pkg._remote && pkg._remote.reference && pkg._remote.reference.includes(variant)) { |
| 147 | + return false; |
| 148 | + } |
| 149 | + } |
| 150 | + } |
140 | 151 | invariant(ref, 'Missing package reference'); |
141 | 152 | if (!ref.fresh && !this.force) { |
142 | 153 | // this package hasn't been touched |
@@ -291,7 +302,53 @@ export default class PackageInstallScripts { |
291 | 302 | await this.saveBuildArtifacts(loc, pkg, beforeFiles, set.spinners[0]); |
292 | 303 | } |
293 | 304 | } |
294 | | - |
295 | 305 | set.end(); |
| 306 | + |
| 307 | + // generate built package as prebuilt one for offline mirror |
| 308 | + for (const pkg of pkgs) { |
| 309 | + if (this.packageCanBeInstalled(pkg)) { |
| 310 | + const filename = PackageInstallScripts.getPrebuiltName(pkg); |
| 311 | + // TODO maybe generated prebuilt packages should be in a subfolder |
| 312 | + const filePath = this.config.getOfflineMirrorPath(filename + '.tgz'); |
| 313 | + if (!filePath) { |
| 314 | + break; |
| 315 | + } |
| 316 | + const ref = pkg._reference; |
| 317 | + invariant(ref, 'expected reference'); |
| 318 | + const loc = this.config.generateHardModulePath(ref); |
| 319 | + const pkgConfig = await Config.create( |
| 320 | + { |
| 321 | + cwd: loc, |
| 322 | + }, |
| 323 | + this.reporter, |
| 324 | + ); |
| 325 | + const stream = await pack(pkgConfig, loc); |
| 326 | + |
| 327 | + const hash = await new Promise((resolve, reject) => { |
| 328 | + console.log("building", pkg.name) |
| 329 | + const validateStream = new crypto.HashStream(); |
| 330 | + stream |
| 331 | + .pipe(validateStream) |
| 332 | + .pipe(fs2.createWriteStream(filePath)) |
| 333 | + .on('error', reject) |
| 334 | + .on('close', () => resolve(validateStream.getHash())); |
| 335 | + }); |
| 336 | + // TODO ! don't run scripts/install/preinstall/postinstall if pkg comes from prebuilt |
| 337 | + // TODO ! don't save artifacts in .yarn-integrity, it is part of the package now |
| 338 | + // TODO ! .yarn-integrity should contain prebuiltPackages array now |
| 339 | + // TODO how does it scale to npm storage? |
| 340 | + pkg.prebuiltVariants = pkg.prebuiltVariants || {}; |
| 341 | + pkg.prebuiltVariants[filename] = hash; |
| 342 | + } |
| 343 | + } |
| 344 | + |
| 345 | + } |
| 346 | + |
| 347 | + static getPrebuiltName(pkg: Manifest): string { |
| 348 | + // TODO support platform variant for linux |
| 349 | + // TODO support hash for all subdependencies that have installs scripts |
| 350 | + const normaliseScope = name => (name[0] === '@' ? name.substr(1).replace('/', '-') : name); |
| 351 | + const suffix = `${process.platform}-${process.arch}-${process.versions.modules || ''}`; |
| 352 | + return `${normaliseScope(pkg.name)}-v${pkg.version}-${suffix}`; |
296 | 353 | } |
297 | 354 | } |
0 commit comments