Skip to content

Commit dd4bb39

Browse files
committed
WIP: ability to store a built package in offline mirror
1 parent aee005a commit dd4bb39

File tree

7 files changed

+79
-4
lines changed

7 files changed

+79
-4
lines changed

src/cli/commands/pack.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ export function hasWrapper(commander: Object, args: Array<string>): boolean {
148148
return true;
149149
}
150150

151-
export async function run(config: Config, reporter: Reporter, flags: Object, args: Array<string>): Promise<void> {
151+
export async function run(config: Config, reporter: Reporter, flags: {filename?: string}, args?: Array<string>): Promise<void> {
152152
const pkg = await config.readRootManifest();
153153
if (!pkg.name) {
154154
throw new MessageError(reporter.lang('noName'));

src/lockfile/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export type LockManifest = {
2929
permissions: ?{[key: string]: boolean},
3030
optionalDependencies: ?Dependencies,
3131
dependencies: ?Dependencies,
32+
prebuiltVariants: ?{[key: string]: string},
3233
};
3334

3435
type MinimalLockManifest = {
@@ -69,6 +70,7 @@ export function implodeEntry(pattern: string, obj: Object): MinimalLockManifest
6970
dependencies: blankObjectUndefined(obj.dependencies),
7071
optionalDependencies: blankObjectUndefined(obj.optionalDependencies),
7172
permissions: blankObjectUndefined(obj.permissions),
73+
prebuiltVariants: blankObjectUndefined(obj.prebuiltVariants),
7274
};
7375
}
7476

@@ -184,7 +186,6 @@ export default class Lockfile {
184186
}
185187
continue;
186188
}
187-
188189
const obj = implodeEntry(pattern, {
189190
name: pkg.name,
190191
version: pkg.version,
@@ -195,6 +196,7 @@ export default class Lockfile {
195196
peerDependencies: pkg.peerDependencies,
196197
optionalDependencies: pkg.optionalDependencies,
197198
permissions: ref.permissions,
199+
prebuiltVariants: pkg.prebuiltVariants,
198200
});
199201
lockfile[pattern] = obj;
200202

src/package-install-scripts.js

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@
33
import type {Manifest} from './types.js';
44
import type PackageResolver from './package-resolver.js';
55
import type {Reporter} from './reporters/index.js';
6-
import type Config from './config.js';
6+
import Config from './config.js';
77
import type {ReporterSetSpinner} from './reporters/types.js';
88
import executeLifecycleScript from './util/execute-lifecycle-script.js';
9+
import * as crypto from './util/crypto.js';
910
import * as fs from './util/fs.js';
11+
import {pack} from './cli/commands/pack.js';Config
1012

13+
const fs2 = require('fs');
1114
const invariant = require('invariant');
15+
const path = require('path');
1216

1317
const INSTALL_STAGES = ['preinstall', 'install', 'postinstall'];
1418

@@ -137,6 +141,13 @@ export default class PackageInstallScripts {
137141
return false;
138142
}
139143
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+
}
140151
invariant(ref, 'Missing package reference');
141152
if (!ref.fresh && !this.force) {
142153
// this package hasn't been touched
@@ -291,7 +302,53 @@ export default class PackageInstallScripts {
291302
await this.saveBuildArtifacts(loc, pkg, beforeFiles, set.spinners[0]);
292303
}
293304
}
294-
295305
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}`;
296353
}
297354
}

src/package-request.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export default class PackageRequest {
5656
optional: boolean;
5757
foundInfo: ?Manifest;
5858

59+
// TODO is it Manifest?
5960
getLocked(remoteType: string): ?Object {
6061
// always prioritise root lockfile
6162
const shrunk = this.lockfile.getLocked(this.pattern);
@@ -79,6 +80,7 @@ export default class PackageRequest {
7980
},
8081
optionalDependencies: shrunk.optionalDependencies,
8182
dependencies: shrunk.dependencies,
83+
prebuiltVariants: shrunk.prebuiltVariants,
8284
};
8385
} else {
8486
return null;

src/package-resolver.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export default class PackageResolver {
105105
newPkg._remote = ref.remote;
106106
newPkg.name = oldPkg.name;
107107
newPkg.fresh = oldPkg.fresh;
108+
newPkg.prebuiltVariants = oldPkg.prebuiltVariants;
108109

109110
// update patterns
110111
for (const pattern of ref.patterns) {
@@ -118,6 +119,8 @@ export default class PackageResolver {
118119
for (const newPkg of newPkgs) {
119120
if (newPkg._reference) {
120121
for (const pattern of newPkg._reference.patterns) {
122+
const oldPkg = this.patterns[pattern];
123+
newPkg.prebuiltVariants = oldPkg.prebuiltVariants;
121124
this.patterns[pattern] = newPkg;
122125
}
123126
}

src/resolvers/registries/npm-resolver.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import type {Manifest} from '../../types.js';
44
import type Config from '../../config.js';
55
import type PackageRequest from '../../package-request.js';
6+
import PackageInstallScripts from '../../package-install-scripts.js';
67
import {MessageError} from '../../errors.js';
78
import RegistryResolver from './registry-resolver.js';
89
import NpmRegistry, {SCOPE_SEPARATOR} from '../../registries/npm-registry.js';
@@ -176,6 +177,14 @@ export default class NpmResolver extends RegistryResolver {
176177
// lockfile
177178
const shrunk = this.request.getLocked('tarball');
178179
if (shrunk) {
180+
if (shrunk.prebuiltVariants && shrunk._remote) {
181+
const prebuiltName = PackageInstallScripts.getPrebuiltName(shrunk);
182+
if (shrunk.prebuiltVariants[prebuiltName]) {
183+
const filename = this.config.getOfflineMirrorPath(prebuiltName + '.tgz');
184+
shrunk._remote.reference = `file:${filename || ''}`;
185+
shrunk._remote.hash = shrunk.prebuiltVariants[prebuiltName];
186+
}
187+
}
179188
return shrunk;
180189
}
181190

src/types.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ export type Manifest = {
141141
// We need to preserve the flag because we print a list of new packages in
142142
// the end of the add command
143143
fresh?: boolean,
144+
145+
prebuiltVariants?: {[filename: string]: string},
144146
};
145147

146148
//

0 commit comments

Comments
 (0)