Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't re-install cached artifacts. #805

Merged
merged 1 commit into from
Oct 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions __tests__/commands/_install.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ export function runInstall(
name: string,
checkInstalled?: ?(config: Config, reporter: Reporter, install: Install) => ?Promise<void>,
beforeInstall?: ?(cwd: string) => ?Promise<void>,
cleanupAfterInstall: boolean = true,
): Promise<void> {
return run((config, reporter, lockfile): Install => {
return new Install(flags, config, reporter, lockfile);
}, path.join(fixturesLoc, name), checkInstalled, beforeInstall);
}, path.join(fixturesLoc, name), checkInstalled, beforeInstall, cleanupAfterInstall);
}

export async function createLockfile(dir: string): Promise<Lockfile> {
Expand Down Expand Up @@ -54,6 +55,7 @@ export async function run(
dir: string,
checkInstalled: ?(config: Config, reporter: Reporter, install: Install) => ?Promise<void>,
beforeInstall: ?(cwd: string) => ?Promise<void>,
cleanupAfterInstall: boolean,
): Promise<void> {
const cwd = path.join(
os.tmpdir(),
Expand Down Expand Up @@ -110,7 +112,9 @@ export async function run(
}
} finally {
// clean up
await fs.unlink(cwd);
if (cleanupAfterInstall) {
await fs.unlink(cwd);
}
}
} catch (err) {
throw new Error(`${err && err.stack} \nConsole output:\n ${out}`);
Expand Down
3 changes: 2 additions & 1 deletion __tests__/commands/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ function runAdd(
name: string,
checkInstalled?: ?(config: Config, reporter: Reporter) => ?Promise<void>,
beforeInstall?: ?(cwd: string) => ?Promise<void>,
cleanupAfterInstall: boolean = true,
): Promise<void> {
return buildRun((config, reporter, lockfile): Install => {
return new Add(args, flags, config, reporter, lockfile);
}, path.join(fixturesLoc, name), checkInstalled, beforeInstall);
}, path.join(fixturesLoc, name), checkInstalled, beforeInstall, cleanupAfterInstall);
}

test.concurrent('install with arg that has install scripts', (): Promise<void> => {
Expand Down
28 changes: 28 additions & 0 deletions __tests__/commands/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,7 @@ test.concurrent('install should resolve circular dependencies 2', (): Promise<vo
});
});


test('install should respect NODE_ENV=production', (): Promise<void> => {
const env = process.env.NODE_ENV;
process.env.NODE_ENV = 'production';
Expand All @@ -563,6 +564,33 @@ test('install should respect NODE_ENV=production', (): Promise<void> => {
});
});


test.concurrent('install should resolve circular dependencies 2', (): Promise<void> => {
return runInstall({}, 'install-should-circumvent-circular-dependencies-2', async (config, reporter) => {
assert.equal(
await getPackageVersion(config, 'es5-ext'),
'0.10.12',
);
});
});

test.concurrent('install should be idempotent', (): Promise<void> => {
// Install a package twice
runInstall({}, 'install-should-be-idempotent', async (config, reporter) => {
assert.equal(
await getPackageVersion(config, 'dep-a'),
'1.0.0',
);
}, null, false);

return runInstall({}, 'install-should-be-idempotent', async (config, reporter) => {
assert.equal(
await getPackageVersion(config, 'dep-a'),
'1.0.0',
);
});
});

test.concurrent(
'install should add missing deps to yarn and mirror (PR import scenario)',
(): Promise<void> => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
yarn-offline-mirror=./mirror-for-offline
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"dep-a": "1.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
[email protected]:
version "1.0.0"
resolved dep-a-1.0.0.tgz#92820a28fbb001f840326a074a4047d828fe8a8d
2 changes: 0 additions & 2 deletions __tests__/fixtures/install/scripts-order/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ [email protected]:
resolved dep-a-1.0.0.tgz
dependencies:
dep-b "1.0.0"

[email protected]:
version "1.0.0"
resolved dep-b-1.0.0.tgz
dependencies:
dep-c "1.0.0"

[email protected]:
version "1.0.0"
resolved dep-c-1.0.0.tgz
2 changes: 1 addition & 1 deletion __tests__/fixtures/request-cache/GET/localhost/.bin
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
HTTP/1.1 200 OK
Date: Mon, 24 Oct 2016 13:03:20 GMT
Date: Wed, 26 Oct 2016 22:01:42 GMT
Connection: close
Content-Length: 2

Expand Down
1 change: 1 addition & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ export default class Config {
return file;
}
}
return null;
});
}

Expand Down
1 change: 1 addition & 0 deletions src/fetchers/base-fetcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export default class BaseFetcher {
hash,
dest,
package: pkg,
cached: false,
};
});
}
Expand Down
5 changes: 5 additions & 0 deletions src/package-fetcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default class PackageFetcher {
resolved: await fetcher.getResolvedFromCached(hash),
hash,
dest,
cached: true,
};
}

Expand Down Expand Up @@ -91,6 +92,10 @@ export default class PackageFetcher {
if (res.resolved) {
ref.remote.resolved = res.resolved;
}

if (res.cached) {
ref.cached = true;
}
}

if (newPkg) {
Expand Down
52 changes: 33 additions & 19 deletions src/package-install-scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,12 @@ export default class PackageInstallScripts {
return mtimes;
}

async wrapCopyBuildArtifacts<T>(
async copyBuildArtifacts(
loc: string,
pkg: Manifest,
beforeFiles: Map<string, number>,
spinner: ReporterSetSpinner,
factory: () => Promise<T>,
): Promise<T> {
const beforeFiles = await this.walk(loc);
const res = await factory();
): Promise<void> {
const afterFiles = await this.walk(loc);

// work out what files have been created/modified
Expand All @@ -84,7 +82,7 @@ export default class PackageInstallScripts {

if (!removedFiles.length && !buildArtifacts.length) {
// nothing else to do here since we have no build side effects
return res;
return;
}

// if the process is killed while copying over build artifacts then we'll leave
Expand Down Expand Up @@ -119,23 +117,21 @@ export default class PackageInstallScripts {
});
await fs.writeFile(cachedMetadataLoc, cachedMetadata);
}

return res;
}

async install(cmds: Array<[string, string]>, pkg: Manifest, spinner: ReporterSetSpinner): Promise<void> {
const loc = this.config.generateHardModulePath(pkg._reference);
const ref = pkg._reference;
invariant(ref, 'expected reference');
const loc = this.config.generateHardModulePath(ref);
if (ref.cached) {
// This package is fetched directly from installed cache with build artifacts
// No need to rebuild
return;
}
try {
await this.wrapCopyBuildArtifacts(
loc,
pkg,
spinner,
async (): Promise<void> => {
for (const [stage, cmd] of cmds) {
await executeLifecycleScript(stage, this.config, loc, cmd, spinner);
}
},
);
for (const [stage, cmd] of cmds) {
await executeLifecycleScript(stage, this.config, loc, cmd, spinner);
}
} catch (err) {
err.message = `${loc}: ${err.message}`;

Expand Down Expand Up @@ -269,8 +265,14 @@ export default class PackageInstallScripts {
const installed = new Set();
const pkgs = this.resolver.getTopologicalManifests(seedPatterns);
let installablePkgs = 0;
// A map to keep track of what files exist before installation
const beforeFilesMap = new Map();
for (const pkg of pkgs) {
if (this.packageCanBeInstalled(pkg)) {
const ref = pkg._reference;
invariant(ref, 'expected reference');
const loc = this.config.generateHardModulePath(ref);
beforeFilesMap.set(loc, await this.walk(loc));
installablePkgs += 1;
}
workQueue.add(pkg);
Expand All @@ -289,6 +291,18 @@ export default class PackageInstallScripts {

await Promise.all(workers);

// cache all build artifacts
for (const pkg of pkgs) {
if (this.packageCanBeInstalled(pkg)) {
const ref = pkg._reference;
invariant(ref, 'expected reference');
const loc = this.config.generateHardModulePath(ref);
const beforeFiles = beforeFilesMap.get(loc);
invariant(beforeFiles, 'files before installation should always be recorded');
await this.copyBuildArtifacts(loc, pkg, beforeFiles, set.spinners[0]);
}
}

set.end();
}
}
4 changes: 3 additions & 1 deletion src/package-reference.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default class PackageReference {
this.ignore = false;
this.fresh = false;
this.location = null;

this.cached = false;
this.addRequest(request);
}

Expand All @@ -59,6 +59,8 @@ export default class PackageReference {
optional: ?boolean;
visibility: {[action: string]: number};
ignore: boolean;
// whether or not this package is fetched from cache
cached: boolean;
fresh: boolean;
dependencies: Array<string>;
patterns: Array<string>;
Expand Down
1 change: 1 addition & 0 deletions src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export type FetchedMetadata = {
resolved: ?string,
hash: string,
dest: string,
cached: boolean,
};
export type FetchedOverride = {
hash: string,
Expand Down