feat(core): optimise cache restoration and storing

This commit is contained in:
Victor Savkin 2022-01-09 20:37:40 -05:00 committed by Victor Savkin
parent 630c850ccf
commit 16e9f58f76
8 changed files with 106 additions and 20 deletions

View File

@ -35,7 +35,7 @@ describe('js e2e', () => {
});
}, 120000);
it('xxxshould create libs and apps with js executors (--compiler=tsc)', async () => {
it('should create libs and apps with js executors (--compiler=tsc)', async () => {
const scope = newProject();
const lib = uniq('lib');
runCLI(`generate @nrwl/js:lib ${lib} --buildable --compiler=tsc`);

17
packages/cli/lib/is_ci.ts Normal file
View File

@ -0,0 +1,17 @@
export function isCI() {
return (
process.env.CI === 'true' ||
process.env.TF_BUILD === 'true' ||
process.env['bamboo.buildKey'] ||
process.env.BUILDKITE === 'true' ||
process.env.CIRCLECI === 'true' ||
process.env.CIRRUS_CI === 'true' ||
process.env.CODEBUILD_BUILD_ID ||
process.env.GITHUB_ACTIONS === 'true' ||
process.env.GITLAB_CI ||
process.env.HEROKU_TEST_RUN_ID ||
process.env.BUILD_ID ||
process.env.TEAMCITY_VERSION ||
process.env.TRAVIS === 'true'
);
}

View File

@ -4,6 +4,7 @@
* should be copied here if necessary.
*/
import * as chalk from 'chalk';
import { isCI } from './is_ci';
export interface CLIErrorMessageConfig {
title: string;
@ -34,7 +35,7 @@ export interface CLISuccessMessageConfig {
/**
* Automatically disable styling applied by chalk if CI=true
*/
if (process.env.CI === 'true') {
if (isCI()) {
(chalk as any).Level = 0;
}

View File

@ -11,9 +11,9 @@ import type { AsyncSubscription, Event } from '@parcel/watcher';
import { readFileSync } from 'fs';
import { join, relative } from 'path';
import { FULL_OS_SOCKET_PATH } from '../socket-utils';
import { serverLogger } from '@nrwl/workspace/src/core/project-graph/daemon/server/logger';
import { handleServerProcessTermination } from '@nrwl/workspace/src/core/project-graph/daemon/server/shutdown-utils';
import { Server } from 'net';
import ignore from 'ignore';
/**
* This configures the files and directories which we always want to ignore as part of file watching
@ -59,6 +59,17 @@ export type SubscribeToWorkspaceChangesCallback = (
changeEvents: Event[] | null
) => Promise<void>;
function configureIgnoreObject() {
const ig = ignore();
try {
ig.add(readFileSync(`${appRootPath}/.gitignore`, 'utf-8'));
} catch {}
try {
ig.add(readFileSync(`${appRootPath}/.nxignore`, 'utf-8'));
} catch {}
return ig;
}
export async function subscribeToWorkspaceChanges(
server: Server,
cb: SubscribeToWorkspaceChangesCallback
@ -69,6 +80,7 @@ export async function subscribeToWorkspaceChanges(
* executed by packages which do not have its necessary native binaries available.
*/
const watcher = await import('@parcel/watcher');
const ignoreObj = configureIgnoreObject();
const subscription = await watcher.subscribe(
appRootPath,
@ -105,7 +117,13 @@ export async function subscribeToWorkspaceChanges(
});
}
cb(null, workspaceRelativeEvents);
const nonIgnoredEvents = workspaceRelativeEvents
.filter(({ path }) => !!path)
.filter(({ path }) => !ignoreObj.ignores(path));
if (nonIgnoredEvents && nonIgnoredEvents.length > 0) {
cb(null, nonIgnoredEvents);
}
},
{
ignore: getIgnoredGlobs(),

View File

@ -3,6 +3,7 @@ import { ProjectGraphCache, readCache } from '../nx-deps/nx-deps-cache';
import { buildProjectGraph } from './build-project-graph';
import { readNxJson, workspaceFileName } from '../file-utils';
import { output } from '../../utilities/output';
import { isCI } from '../../utilities/is_ci';
/**
* Synchronously reads the latest cached copy of the workspace's ProjectGraph.
@ -59,8 +60,9 @@ export async function createProjectGraphAsync(
// option=true,env=false => no daemon
// option=false,env=undefined => no daemon
// option=false,env=false => no daemon
// option=true,env=undefined,ci => no daemon
// option=true,env=undefined => daemon
// option=true,env=undefined,!ci => daemon
// option=true,env=true => daemon
// option=false,env=true => daemon
try {
@ -68,7 +70,8 @@ export async function createProjectGraphAsync(
(useDaemonProcessOption === undefined && env === undefined) ||
(useDaemonProcessOption === true && env === 'false') ||
(useDaemonProcessOption === false && env === undefined) ||
(useDaemonProcessOption === false && env === 'false')
(useDaemonProcessOption === false && env === 'false') ||
(useDaemonProcessOption === true && env === undefined && isCI())
) {
return projectGraphAdapter(
'5.0',

View File

@ -13,7 +13,7 @@ import {
} from 'fs-extra';
import { dirname, join, resolve, sep } from 'path';
import { DefaultTasksRunnerOptions } from './default-tasks-runner';
import { spawn } from 'child_process';
import { spawn, exec } from 'child_process';
import { cacheDirectory } from '../utilities/cache-directory';
const util = require('util');
@ -35,6 +35,7 @@ export class Cache {
cachePath = this.createCacheDir();
terminalOutputsDir = this.createTerminalOutputsDir();
latestOutputsHashesDir = this.ensureLatestOutputsHashesDir();
useFsExtraToCopyAndRemove = false;
constructor(private readonly options: DefaultTasksRunnerOptions) {}
@ -89,7 +90,7 @@ export class Cache {
// might be left overs from partially-completed cache invocations
await remove(tdCommit);
await remove(td);
await this.remove(td);
await mkdir(td);
await writeFile(
@ -103,12 +104,9 @@ export class Cache {
const src = join(this.root, f);
if (await existsAsync(src)) {
const cached = join(td, 'outputs', f);
// Ensure parent directory is created if src is a file
const isFile = (await lstatAsync(src)).isFile();
const directory = isFile ? resolve(cached, '..') : cached;
const directory = resolve(cached, '..');
await ensureDir(directory);
await copy(src, cached);
await this.copy(src, directory);
}
})
);
@ -143,14 +141,11 @@ export class Cache {
outputs.map(async (f) => {
const cached = join(cachedResult.outputsPath, f);
if (await existsAsync(cached)) {
const isFile = (await lstatAsync(cached)).isFile();
const src = join(this.root, f);
await remove(src);
// Ensure parent directory is created if src is a file
const directory = isFile ? resolve(src, '..') : src;
await this.remove(src);
const directory = resolve(src, '..');
await ensureDir(directory);
await copy(cached, src);
await this.copy(cached, directory);
}
})
);
@ -187,6 +182,40 @@ export class Cache {
);
}
private copy(src: string, directory: string) {
if (this.useFsExtraToCopyAndRemove) {
return copy(src, directory);
}
return new Promise((res, rej) => {
exec(`cp -a "${src}" "${directory}"`, (error) => {
if (!error) {
res(null);
} else {
this.useFsExtraToCopyAndRemove = true;
copy(src, directory).then(res, rej);
}
});
});
}
private remove(folder: string) {
if (this.useFsExtraToCopyAndRemove) {
return remove(folder);
}
return new Promise((res, rej) => {
exec(`rm -rf "${folder}"`, (error) => {
if (!error) {
res(null);
} else {
this.useFsExtraToCopyAndRemove = true;
remove(folder).then(res, rej);
}
});
});
}
private async recordOutputsHash(
outputs: string[],
hash: string

View File

@ -0,0 +1,17 @@
export function isCI() {
return (
process.env.CI === 'true' ||
process.env.TF_BUILD === 'true' ||
process.env['bamboo.buildKey'] ||
process.env.BUILDKITE === 'true' ||
process.env.CIRCLECI === 'true' ||
process.env.CIRRUS_CI === 'true' ||
process.env.CODEBUILD_BUILD_ID ||
process.env.GITHUB_ACTIONS === 'true' ||
process.env.GITLAB_CI ||
process.env.HEROKU_TEST_RUN_ID ||
process.env.BUILD_ID ||
process.env.TEAMCITY_VERSION ||
process.env.TRAVIS === 'true'
);
}

View File

@ -1,4 +1,5 @@
import * as chalk from 'chalk';
import { isCI } from './is_ci';
export interface CLIErrorMessageConfig {
title: string;
@ -31,7 +32,7 @@ export enum TaskCacheStatus {
/**
* Automatically disable styling applied by chalk if CI=true
*/
if (process.env.CI === 'true') {
if (isCI()) {
(chalk as any).level = 0;
}