@nrwl/workspace 12.10.0-beta.3 → 12.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -5
- package/src/command-line/nx-commands.js +4 -4
- package/src/command-line/nx-commands.js.map +1 -1
- package/src/core/dep-graph/index.html +2 -1
- package/src/core/dep-graph/main.es5.js +1 -1
- package/src/core/dep-graph/main.esm.js +1 -1
- package/src/core/hasher/file-hasher.d.ts +12 -8
- package/src/core/hasher/file-hasher.js +18 -11
- package/src/core/hasher/file-hasher.js.map +1 -1
- package/src/core/hasher/git-hasher.d.ts +1 -0
- package/src/core/hasher/git-hasher.js +2 -1
- package/src/core/hasher/git-hasher.js.map +1 -1
- package/src/core/project-graph/daemon/{server.d.ts → client/client.d.ts} +6 -9
- package/src/core/project-graph/daemon/client/client.js +181 -0
- package/src/core/project-graph/daemon/client/client.js.map +1 -0
- package/src/core/project-graph/daemon/server/server.d.ts +8 -0
- package/src/core/project-graph/daemon/server/server.js +284 -0
- package/src/core/project-graph/daemon/server/server.js.map +1 -0
- package/src/core/project-graph/daemon/{exec → server}/start.d.ts +0 -0
- package/src/core/project-graph/daemon/{exec → server}/start.js +1 -1
- package/src/core/project-graph/daemon/server/start.js.map +1 -0
- package/src/core/project-graph/daemon/{exec → server}/stop.d.ts +0 -0
- package/src/core/project-graph/daemon/{exec → server}/stop.js +1 -1
- package/src/core/project-graph/daemon/server/stop.js.map +1 -0
- package/src/core/project-graph/daemon/server/watcher.d.ts +10 -0
- package/src/core/project-graph/daemon/server/watcher.js +138 -0
- package/src/core/project-graph/daemon/server/watcher.js.map +1 -0
- package/src/core/project-graph/daemon/socket-utils.d.ts +3 -0
- package/src/core/project-graph/daemon/socket-utils.js +29 -0
- package/src/core/project-graph/daemon/socket-utils.js.map +1 -0
- package/src/core/project-graph/operators.js +1 -1
- package/src/core/project-graph/operators.js.map +1 -1
- package/src/core/project-graph/project-graph.js +4 -6
- package/src/core/project-graph/project-graph.js.map +1 -1
- package/src/utils/versions.js +1 -1
- package/src/core/project-graph/daemon/exec/index.d.ts +0 -3
- package/src/core/project-graph/daemon/exec/index.js +0 -89
- package/src/core/project-graph/daemon/exec/index.js.map +0 -1
- package/src/core/project-graph/daemon/exec/start.js.map +0 -1
- package/src/core/project-graph/daemon/exec/stop.js.map +0 -1
- package/src/core/project-graph/daemon/server.js +0 -345
- package/src/core/project-graph/daemon/server.js.map +0 -1
|
@@ -17,16 +17,20 @@ export declare class FileHasher {
|
|
|
17
17
|
init(): Map<string, string>;
|
|
18
18
|
/**
|
|
19
19
|
* This method is used in cases where we do not want to fully tear down the
|
|
20
|
-
* known state of file hashes, and instead only want to hash
|
|
21
|
-
*
|
|
20
|
+
* known state of file hashes, and instead only want to hash an updated Map
|
|
21
|
+
* of files which are provided to the method.
|
|
22
22
|
*
|
|
23
|
-
* For example, the daemon server
|
|
24
|
-
*
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
* For example, the daemon server performs file-watching and knows at a granular
|
|
24
|
+
* level what needs to be rehashed in order to accurately update the overall state.
|
|
25
|
+
*/
|
|
26
|
+
incrementalUpdate(updatedHashes: Map<string, string>): void;
|
|
27
|
+
/**
|
|
28
|
+
* In the case of the daemon server, because it performs file-watching, it
|
|
29
|
+
* knows when one or more files have been deleted from the workspace and can
|
|
30
|
+
* therefore precisely update the source of truth for file hashes and workspace
|
|
31
|
+
* files.
|
|
28
32
|
*/
|
|
29
|
-
|
|
33
|
+
removeFiles(deletedFiles: string[]): void;
|
|
30
34
|
hashFile(path: string): string;
|
|
31
35
|
ensureInitialized(): void;
|
|
32
36
|
private applyFileHashes;
|
|
@@ -36,19 +36,15 @@ class FileHasher {
|
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
38
|
* This method is used in cases where we do not want to fully tear down the
|
|
39
|
-
* known state of file hashes, and instead only want to hash
|
|
40
|
-
*
|
|
39
|
+
* known state of file hashes, and instead only want to hash an updated Map
|
|
40
|
+
* of files which are provided to the method.
|
|
41
41
|
*
|
|
42
|
-
* For example, the daemon server
|
|
43
|
-
*
|
|
44
|
-
* SHA is unchanged.
|
|
45
|
-
*
|
|
46
|
-
* @returns The Map of filenames to hashes returned by getUntrackedAndUncommittedFileHashes()
|
|
42
|
+
* For example, the daemon server performs file-watching and knows at a granular
|
|
43
|
+
* level what needs to be rehashed in order to accurately update the overall state.
|
|
47
44
|
*/
|
|
48
|
-
incrementalUpdate() {
|
|
45
|
+
incrementalUpdate(updatedHashes) {
|
|
49
46
|
perf_hooks_1.performance.mark('incremental hashing:start');
|
|
50
|
-
|
|
51
|
-
untrackedAndUncommittedFileHashes.forEach((hash, filename) => {
|
|
47
|
+
updatedHashes.forEach((hash, filename) => {
|
|
52
48
|
this.fileHashes[filename] = hash;
|
|
53
49
|
/**
|
|
54
50
|
* we have to store it separately because fileHashes can be modified
|
|
@@ -58,7 +54,18 @@ class FileHasher {
|
|
|
58
54
|
});
|
|
59
55
|
perf_hooks_1.performance.mark('incremental hashing:end');
|
|
60
56
|
perf_hooks_1.performance.measure('incremental hashing', 'incremental hashing:start', 'incremental hashing:end');
|
|
61
|
-
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* In the case of the daemon server, because it performs file-watching, it
|
|
60
|
+
* knows when one or more files have been deleted from the workspace and can
|
|
61
|
+
* therefore precisely update the source of truth for file hashes and workspace
|
|
62
|
+
* files.
|
|
63
|
+
*/
|
|
64
|
+
removeFiles(deletedFiles) {
|
|
65
|
+
for (const deletedFile of deletedFiles) {
|
|
66
|
+
delete this.fileHashes[deletedFile];
|
|
67
|
+
this.workspaceFiles.delete(deletedFile);
|
|
68
|
+
}
|
|
62
69
|
}
|
|
63
70
|
hashFile(path) {
|
|
64
71
|
this.ensureInitialized();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-hasher.js","sourceRoot":"","sources":["../../../../../../packages/workspace/src/core/hasher/file-hasher.ts"],"names":[],"mappings":";;;AAAA,2DAA2D;AAC3D,2CAAyC;AACzC,6CAGsB;AACtB,iDAA6D;AAE7D,MAAa,UAAU;IAMrB,YAA6B,OAAoB;QAApB,YAAO,GAAP,OAAO,CAAa;QALjD,eAAU,GAA+B,EAAE,CAAC;QAC5C,mBAAc,GAAG,IAAI,GAAG,EAAU,CAAC;QACnC,sBAAiB,GAAG,KAAK,CAAC;QAClB,kBAAa,GAAG,KAAK,CAAC;IAEsB,CAAC;IAErD,KAAK;QACH,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;QACrB,IAAI,CAAC,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;QACxC,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,IAAI;QACF,wBAAW,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,MAAM,mBAAmB,GAAG,0BAAa,CAAC,sBAAW,CAAC,CAAC;QACvD,IAAI,CAAC,eAAe,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,CAAC,iBAAiB,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QACjE,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAE1B,wBAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACrC,wBAAW,CAAC,OAAO,CACjB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,CACnB,CAAC;QAEF,OAAO,mBAAmB,CAAC,yBAAyB,CAAC;IACvD,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"file-hasher.js","sourceRoot":"","sources":["../../../../../../packages/workspace/src/core/hasher/file-hasher.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getUntrackedAndUncommittedFileHashes = exports.getFileHashes = exports.gitRevParseHead = void 0;
|
|
3
|
+
exports.getUntrackedAndUncommittedFileHashes = exports.getFileHashes = exports.gitRevParseHead = exports.getGitHashForFiles = void 0;
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
5
|
const path_1 = require("path");
|
|
6
6
|
const spawn_process_1 = require("./spawn-process");
|
|
@@ -67,6 +67,7 @@ function getGitHashForFiles(filesToHash, path) {
|
|
|
67
67
|
}
|
|
68
68
|
return changes;
|
|
69
69
|
}
|
|
70
|
+
exports.getGitHashForFiles = getGitHashForFiles;
|
|
70
71
|
function gitLsTree(path) {
|
|
71
72
|
return parseGitLsTree(spawn_process_1.spawnProcess('git', ['ls-tree', 'HEAD', '-r', '-z'], path));
|
|
72
73
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-hasher.js","sourceRoot":"","sources":["../../../../../../packages/workspace/src/core/hasher/git-hasher.ts"],"names":[],"mappings":";;;AAAA,2BAA8B;AAC9B,+BAA4B;AAC5B,mDAA+C;AAE/C,SAAS,cAAc,CAAC,MAAc;IACpC,MAAM,OAAO,GAAwB,IAAI,GAAG,EAAkB,CAAC;IAC/D,IAAI,MAAM,EAAE;QACV,MAAM,QAAQ,GAAW,kDAAkD,CAAC;QAC5E,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YAClC,IAAI,IAAI,EAAE;gBACR,MAAM,OAAO,GAA4B,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBAC9D,IAAI,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE;oBACvC,MAAM,IAAI,GAAW,OAAO,CAAC,CAAC,CAAC,CAAC;oBAChC,MAAM,QAAQ,GAAW,OAAO,CAAC,CAAC,CAAC,CAAC;oBACpC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;iBAC7B;qBAAM;oBACL,MAAM,IAAI,KAAK,CAAC,oCAAoC,IAAI,GAAG,CAAC,CAAC;iBAC9D;aACF;QACH,CAAC,CAAC,CAAC;KACJ;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,MAAM,MAAM,GAAG,4BAAY,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;IAC5E,MAAM,OAAO,GAAwB,IAAI,GAAG,EAAkB,CAAC;IAC/D,IAAI,CAAC,MAAM,EAAE;QACX,OAAO,OAAO,CAAC;KAChB;IAED,iEAAiE;IACjE,8DAA8D;IAC9D,MAAM,MAAM,GAAG,4BAAY,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,CAAC;IAEzE,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACtC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,KAAK,CAAC,MAAM,EAAE;YAChB,wCAAwC;YACxC,yDAAyD;YACzD,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1E,IAAI,CAAC,KAAK,GAAG,EAAE;gBACb,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aAC/B;YACD,0DAA0D;YAC1D,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;SAC/B;KACF;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"git-hasher.js","sourceRoot":"","sources":["../../../../../../packages/workspace/src/core/hasher/git-hasher.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import { ProjectGraph } from '@nrwl/devkit';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
export declare function startServer({ serverLogOutputFile, }: StartServerOptions): Promise<Server>;
|
|
8
|
-
export declare function stopServer(): Promise<void>;
|
|
9
|
-
export declare function killSocketOrPath(): void;
|
|
2
|
+
export declare function startInBackground(): Promise<void>;
|
|
3
|
+
export declare function startInCurrentProcess(): void;
|
|
4
|
+
export declare function stop(): void;
|
|
10
5
|
/**
|
|
11
6
|
* As noted in the comments above the createServer() call, in order to reliably (meaning it works
|
|
12
7
|
* cross-platform) check whether or not the server is availabe to request a project graph from we
|
|
@@ -22,6 +17,8 @@ export declare function isServerAvailable(): Promise<boolean>;
|
|
|
22
17
|
*
|
|
23
18
|
* All logs are performed by the devkit logger because this logic does not
|
|
24
19
|
* run "on the server" per se and therefore does not write to its log output.
|
|
20
|
+
*
|
|
21
|
+
* TODO: Gracefully handle a server shutdown (for whatever reason) while a client
|
|
22
|
+
* is connecting and querying it.
|
|
25
23
|
*/
|
|
26
24
|
export declare function getProjectGraphFromServer(): Promise<ProjectGraph>;
|
|
27
|
-
export {};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getProjectGraphFromServer = exports.isServerAvailable = exports.stop = exports.startInCurrentProcess = exports.startInBackground = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const devkit_1 = require("@nrwl/devkit");
|
|
6
|
+
const app_root_1 = require("@nrwl/tao/src/utils/app-root");
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const fs_extra_1 = require("fs-extra");
|
|
9
|
+
const path_1 = require("path");
|
|
10
|
+
const tmp_1 = require("tmp");
|
|
11
|
+
const cache_1 = require("../cache");
|
|
12
|
+
const net_1 = require("net");
|
|
13
|
+
const socket_utils_1 = require("../socket-utils");
|
|
14
|
+
const perf_hooks_1 = require("perf_hooks");
|
|
15
|
+
const fs_1 = require("fs");
|
|
16
|
+
function startInBackground() {
|
|
17
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
18
|
+
/**
|
|
19
|
+
* For now, while the daemon is an opt-in feature, we will log to stdout when
|
|
20
|
+
* starting the server, as well as providing a reference to where any subsequent
|
|
21
|
+
* log files can be found.
|
|
22
|
+
*/
|
|
23
|
+
const tmpDirPrefix = `nx-daemon--${devkit_1.normalizePath(app_root_1.appRootPath).replace(
|
|
24
|
+
// Replace the occurrences of / in the unix-style normalized path with a -
|
|
25
|
+
new RegExp(escapeRegExp('/'), 'g'), '-')}`;
|
|
26
|
+
const serverLogOutputDir = tmp_1.dirSync({
|
|
27
|
+
prefix: tmpDirPrefix,
|
|
28
|
+
}).name;
|
|
29
|
+
const serverLogOutputFile = path_1.join(serverLogOutputDir, 'nx-daemon.log');
|
|
30
|
+
fs_extra_1.ensureFileSync(serverLogOutputFile);
|
|
31
|
+
// Clean up any existing orphaned background process before creating a new one
|
|
32
|
+
const cachedDaemonJson = yield cache_1.readDaemonJsonCache();
|
|
33
|
+
if (cachedDaemonJson) {
|
|
34
|
+
if (cachedDaemonJson.backgroundProcessId) {
|
|
35
|
+
process.kill(cachedDaemonJson.backgroundProcessId);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
devkit_1.logger.info(`NX Daemon Server - Starting in a background process...`);
|
|
39
|
+
devkit_1.logger.log(` Logs from the Daemon process can be found here: ${serverLogOutputFile}\n`);
|
|
40
|
+
try {
|
|
41
|
+
const backgroundProcess = child_process_1.spawn(process.execPath, ['../server/start.js', serverLogOutputFile], {
|
|
42
|
+
cwd: __dirname,
|
|
43
|
+
stdio: 'ignore',
|
|
44
|
+
detached: true,
|
|
45
|
+
});
|
|
46
|
+
backgroundProcess.unref();
|
|
47
|
+
// Persist metadata about the background process so that it can be cleaned up later if needed
|
|
48
|
+
const daemonJson = {
|
|
49
|
+
backgroundProcessId: backgroundProcess.pid,
|
|
50
|
+
serverLogOutputFile: serverLogOutputFile,
|
|
51
|
+
};
|
|
52
|
+
yield cache_1.writeDaemonJsonCache(daemonJson);
|
|
53
|
+
/**
|
|
54
|
+
* Ensure the server is actually available to connect to via IPC before resolving
|
|
55
|
+
*/
|
|
56
|
+
return new Promise((resolve) => {
|
|
57
|
+
const id = setInterval(() => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
if (yield isServerAvailable()) {
|
|
59
|
+
clearInterval(id);
|
|
60
|
+
resolve();
|
|
61
|
+
}
|
|
62
|
+
}), 500);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
devkit_1.logger.error(err);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
exports.startInBackground = startInBackground;
|
|
72
|
+
function startInCurrentProcess() {
|
|
73
|
+
devkit_1.logger.info(`NX Daemon Server - Starting in the current process...`);
|
|
74
|
+
child_process_1.spawnSync(process.execPath, ['./start.js'], {
|
|
75
|
+
cwd: __dirname,
|
|
76
|
+
stdio: 'inherit',
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
exports.startInCurrentProcess = startInCurrentProcess;
|
|
80
|
+
function stop() {
|
|
81
|
+
devkit_1.logger.info(`NX Daemon Server - Stopping...`);
|
|
82
|
+
child_process_1.spawnSync(process.execPath, ['../server/stop.js'], {
|
|
83
|
+
cwd: __dirname,
|
|
84
|
+
stdio: 'inherit',
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
exports.stop = stop;
|
|
88
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
|
|
89
|
+
function escapeRegExp(string) {
|
|
90
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* As noted in the comments above the createServer() call, in order to reliably (meaning it works
|
|
94
|
+
* cross-platform) check whether or not the server is availabe to request a project graph from we
|
|
95
|
+
* need to actually attempt connecting to it.
|
|
96
|
+
*
|
|
97
|
+
* Because of the behavior of named pipes on Windows, we cannot simply treat them as a file and
|
|
98
|
+
* check for their existence on disk (unlike with Unix Sockets).
|
|
99
|
+
*/
|
|
100
|
+
function isServerAvailable() {
|
|
101
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
102
|
+
try {
|
|
103
|
+
const socket = net_1.connect(socket_utils_1.FULL_OS_SOCKET_PATH);
|
|
104
|
+
return new Promise((resolve) => {
|
|
105
|
+
socket.on('connect', () => {
|
|
106
|
+
socket.destroy();
|
|
107
|
+
resolve(true);
|
|
108
|
+
});
|
|
109
|
+
socket.on('error', () => {
|
|
110
|
+
resolve(false);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch (_a) {
|
|
115
|
+
return Promise.resolve(false);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
exports.isServerAvailable = isServerAvailable;
|
|
120
|
+
/**
|
|
121
|
+
* Establishes a client connection to the daemon server for use in project graph
|
|
122
|
+
* creation utilities.
|
|
123
|
+
*
|
|
124
|
+
* All logs are performed by the devkit logger because this logic does not
|
|
125
|
+
* run "on the server" per se and therefore does not write to its log output.
|
|
126
|
+
*
|
|
127
|
+
* TODO: Gracefully handle a server shutdown (for whatever reason) while a client
|
|
128
|
+
* is connecting and querying it.
|
|
129
|
+
*/
|
|
130
|
+
function getProjectGraphFromServer() {
|
|
131
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
132
|
+
return new Promise((resolve, reject) => {
|
|
133
|
+
perf_hooks_1.performance.mark('getProjectGraphFromServer-start');
|
|
134
|
+
const socket = net_1.connect(socket_utils_1.FULL_OS_SOCKET_PATH);
|
|
135
|
+
socket.on('error', (err) => {
|
|
136
|
+
let errorMessage;
|
|
137
|
+
if (err.message.startsWith('connect ENOENT')) {
|
|
138
|
+
errorMessage = 'Error: The Daemon Server is not running';
|
|
139
|
+
}
|
|
140
|
+
if (err.message.startsWith('connect ECONNREFUSED')) {
|
|
141
|
+
// If somehow the file descriptor had not been released during a previous shut down.
|
|
142
|
+
if (fs_1.existsSync(socket_utils_1.FULL_OS_SOCKET_PATH)) {
|
|
143
|
+
errorMessage = `Error: A server instance had not been fully shut down. Please try running the command again.`;
|
|
144
|
+
socket_utils_1.killSocketOrPath();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
devkit_1.logger.error(`NX Daemon Client - ${errorMessage || err}`);
|
|
148
|
+
return reject(new Error(errorMessage) || err);
|
|
149
|
+
});
|
|
150
|
+
/**
|
|
151
|
+
* Immediately after connecting to the server we send it the known project graph creation
|
|
152
|
+
* request payload. See the notes above createServer() for more context as to why we explicitly
|
|
153
|
+
* request the graph from the client like this.
|
|
154
|
+
*/
|
|
155
|
+
socket.on('connect', () => {
|
|
156
|
+
socket.write('REQUEST_PROJECT_GRAPH_PAYLOAD');
|
|
157
|
+
let serializedProjectGraph = '';
|
|
158
|
+
socket.on('data', (data) => {
|
|
159
|
+
serializedProjectGraph += data.toString();
|
|
160
|
+
});
|
|
161
|
+
socket.on('end', () => {
|
|
162
|
+
try {
|
|
163
|
+
perf_hooks_1.performance.mark('json-parse-start');
|
|
164
|
+
const projectGraph = JSON.parse(serializedProjectGraph);
|
|
165
|
+
perf_hooks_1.performance.mark('json-parse-end');
|
|
166
|
+
perf_hooks_1.performance.measure('deserialize graph on the client', 'json-parse-start', 'json-parse-end');
|
|
167
|
+
devkit_1.logger.info('NX Daemon Client - Resolved ProjectGraph');
|
|
168
|
+
perf_hooks_1.performance.measure('total for getProjectGraphFromServer()', 'getProjectGraphFromServer-start', 'json-parse-end');
|
|
169
|
+
return resolve(projectGraph);
|
|
170
|
+
}
|
|
171
|
+
catch (_a) {
|
|
172
|
+
devkit_1.logger.error('NX Daemon Client - Error: Could not deserialize the ProjectGraph');
|
|
173
|
+
return reject(new Error('Could not deserialize the ProjectGraph'));
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
exports.getProjectGraphFromServer = getProjectGraphFromServer;
|
|
181
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../../../../../../packages/workspace/src/core/project-graph/daemon/client/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Server } from 'net';
|
|
3
|
+
interface StartServerOptions {
|
|
4
|
+
serverLogOutputFile?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function startServer({ serverLogOutputFile, }: StartServerOptions): Promise<Server>;
|
|
7
|
+
export declare function stopServer(): Promise<void>;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stopServer = exports.startServer = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const devkit_1 = require("@nrwl/devkit");
|
|
6
|
+
const app_root_1 = require("@nrwl/tao/src/utils/app-root");
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const net_1 = require("net");
|
|
9
|
+
const perf_hooks_1 = require("perf_hooks");
|
|
10
|
+
const file_hasher_1 = require("../../../hasher/file-hasher");
|
|
11
|
+
const git_hasher_1 = require("../../../hasher/git-hasher");
|
|
12
|
+
const project_graph_1 = require("../../project-graph");
|
|
13
|
+
const socket_utils_1 = require("../socket-utils");
|
|
14
|
+
const watcher_1 = require("./watcher");
|
|
15
|
+
/**
|
|
16
|
+
* We have two different use-cases for the "daemon" server:
|
|
17
|
+
* 1) Running in a background process so that the daemon is purely an implementation detail.
|
|
18
|
+
* 2) Running in the main process in order to aid with development/debugging (technically, of course, in this case
|
|
19
|
+
* it isn't actually a daemon server at all, but for simplicity we stick with the same general name as its primary
|
|
20
|
+
* reason for existence is to be run in a background process).
|
|
21
|
+
*
|
|
22
|
+
* For (1) we do not want to log things from the daemon server to stdout/stderr, so we instead write to a file.
|
|
23
|
+
*
|
|
24
|
+
* This file location will be set by the `./exec/index.ts` utilities when starting the server so that we can
|
|
25
|
+
* provide feedback to the user as to its location via stdout on the parent process and still not cause the child
|
|
26
|
+
* process to be "undetachable".
|
|
27
|
+
*
|
|
28
|
+
* For (2) we simply log to stdout.
|
|
29
|
+
*/
|
|
30
|
+
let _serverLogOutputFile;
|
|
31
|
+
function serverLog(...s) {
|
|
32
|
+
/**
|
|
33
|
+
* If _serverLogOutputFile has not be set when starting the server, it means we are
|
|
34
|
+
* running it in the current process and we should log to stdout.
|
|
35
|
+
*/
|
|
36
|
+
if (!_serverLogOutputFile) {
|
|
37
|
+
console.log(formatLogMessage(`${s.join(' ')}`));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
fs_1.appendFileSync(_serverLogOutputFile, formatLogMessage(`${s.join(' ')}\n`));
|
|
41
|
+
}
|
|
42
|
+
function formatLogMessage(message) {
|
|
43
|
+
return `[NX Daemon Server] - ${new Date().toISOString()} - ${message}`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* To improve the overall readibility of the logs, we categorize things by "trigger":
|
|
47
|
+
*
|
|
48
|
+
* - [REQUEST] meaning that the current set of actions were triggered by a client request to the server
|
|
49
|
+
* - [WATCHER] meaning the the current set of actions were triggered by handling changes to the workspace files
|
|
50
|
+
*
|
|
51
|
+
* We keep those two "triggers" left aligned at the top level and then indent subsequent logs so that there is a
|
|
52
|
+
* logical hierarchy/grouping.
|
|
53
|
+
*/
|
|
54
|
+
function requestLog(...s) {
|
|
55
|
+
serverLog(`[REQUEST]: ${s.join(' ')}`);
|
|
56
|
+
}
|
|
57
|
+
function watcherLog(...s) {
|
|
58
|
+
serverLog(`[WATCHER]: ${s.join(' ')}`);
|
|
59
|
+
}
|
|
60
|
+
function nestedLog(...s) {
|
|
61
|
+
serverLog(` ${s.join(' ')}`);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* We cache the latest known HEAD value so that we can potentially skip some initialization work.
|
|
65
|
+
*/
|
|
66
|
+
let cachedGitHead;
|
|
67
|
+
/**
|
|
68
|
+
* We cache the latest copy of the serialized project graph itself in memory so that in the
|
|
69
|
+
* best case scenario we can skip all graph construction and serialization work entirely.
|
|
70
|
+
*/
|
|
71
|
+
let cachedSerializedProjectGraph;
|
|
72
|
+
function createAndSerializeProjectGraph() {
|
|
73
|
+
perf_hooks_1.performance.mark('create-project-graph-start');
|
|
74
|
+
const projectGraph = project_graph_1.createProjectGraph(undefined, undefined, undefined, '4.0');
|
|
75
|
+
perf_hooks_1.performance.mark('create-project-graph-end');
|
|
76
|
+
perf_hooks_1.performance.measure('total execution time for createProjectGraph()', 'create-project-graph-start', 'create-project-graph-end');
|
|
77
|
+
perf_hooks_1.performance.mark('json-stringify-start');
|
|
78
|
+
const serializedProjectGraph = JSON.stringify(projectGraph);
|
|
79
|
+
perf_hooks_1.performance.mark('json-stringify-end');
|
|
80
|
+
perf_hooks_1.performance.measure('serialize graph', 'json-stringify-start', 'json-stringify-end');
|
|
81
|
+
return serializedProjectGraph;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* File watcher subscription.
|
|
85
|
+
*/
|
|
86
|
+
let watcherSubscription;
|
|
87
|
+
/**
|
|
88
|
+
* We need to make sure that we instantiate the PerformanceObserver only once, otherwise
|
|
89
|
+
* we will end up with duplicate entries in the server logs.
|
|
90
|
+
*/
|
|
91
|
+
let performanceObserver;
|
|
92
|
+
const server = net_1.createServer((socket) => {
|
|
93
|
+
if (!performanceObserver) {
|
|
94
|
+
performanceObserver = new perf_hooks_1.PerformanceObserver((list) => {
|
|
95
|
+
const entry = list.getEntries()[0];
|
|
96
|
+
// Slight indentation to improve readability of the overall log file
|
|
97
|
+
nestedLog(`Time taken for '${entry.name}'`, `${entry.duration}ms`);
|
|
98
|
+
});
|
|
99
|
+
performanceObserver.observe({ entryTypes: ['measure'], buffered: false });
|
|
100
|
+
}
|
|
101
|
+
socket.on('data', (data) => {
|
|
102
|
+
/**
|
|
103
|
+
* If anything other than the known project graph creation request payload is sent to
|
|
104
|
+
* the server, we throw an error.
|
|
105
|
+
*/
|
|
106
|
+
const payload = data.toString();
|
|
107
|
+
if (payload !== 'REQUEST_PROJECT_GRAPH_PAYLOAD') {
|
|
108
|
+
throw new Error(`Unsupported payload sent to daemon server: ${payload}`);
|
|
109
|
+
}
|
|
110
|
+
perf_hooks_1.performance.mark('server-connection');
|
|
111
|
+
requestLog('Client Request for Project Graph Received');
|
|
112
|
+
const currentGitHead = git_hasher_1.gitRevParseHead(app_root_1.appRootPath);
|
|
113
|
+
let serializedProjectGraph;
|
|
114
|
+
/**
|
|
115
|
+
* Cached HEAD has changed, we must perform full file-hashing initialization work and
|
|
116
|
+
* recompute the project graph
|
|
117
|
+
*/
|
|
118
|
+
if (currentGitHead !== cachedGitHead) {
|
|
119
|
+
cachedSerializedProjectGraph = undefined;
|
|
120
|
+
nestedLog(`Cached HEAD does not match current (${currentGitHead}), performing full file hash init and recomputing project graph...`);
|
|
121
|
+
file_hasher_1.defaultFileHasher.init();
|
|
122
|
+
cachedGitHead = currentGitHead;
|
|
123
|
+
serializedProjectGraph = createAndSerializeProjectGraph();
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
/**
|
|
127
|
+
* We know at this point that the cached HEAD has not changed so now there are two possibilities:
|
|
128
|
+
*
|
|
129
|
+
* 1) We have not computed the project graph and cached it for the untracked and uncommitted changes
|
|
130
|
+
* and need to ask git for this information (slower)
|
|
131
|
+
*
|
|
132
|
+
* 2) We already have a cached serialized project graph (which we trust has been kept up to date
|
|
133
|
+
* by the file watching logic) so we can immediately resolve it to the client (faster)
|
|
134
|
+
*/
|
|
135
|
+
if (cachedSerializedProjectGraph) {
|
|
136
|
+
nestedLog(`State unchanged since last request, resolving in-memory cached project graph...`);
|
|
137
|
+
serializedProjectGraph = cachedSerializedProjectGraph;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// Update the file-hasher's knowledge of the untracked and uncommitted changes in order to recompute the project graph
|
|
141
|
+
file_hasher_1.defaultFileHasher.incrementalUpdate(git_hasher_1.getUntrackedAndUncommittedFileHashes(app_root_1.appRootPath));
|
|
142
|
+
nestedLog(`Unknown untracked/uncommitted file state, recomputing project graph...`);
|
|
143
|
+
serializedProjectGraph = createAndSerializeProjectGraph();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Cache the latest version of the project graph in memory so that we can potentially skip a lot
|
|
148
|
+
* of expensive work on the next client request.
|
|
149
|
+
*
|
|
150
|
+
* For reference, on the very large test repo https://github.com/vsavkin/interstellar the project
|
|
151
|
+
* graph nxdeps.json file is about 32MB, so memory utilization should not be a huge concern.
|
|
152
|
+
*/
|
|
153
|
+
cachedSerializedProjectGraph = serializedProjectGraph;
|
|
154
|
+
perf_hooks_1.performance.mark('serialized-project-graph-ready');
|
|
155
|
+
perf_hooks_1.performance.measure('total for creating and serializing project graph', 'server-connection', 'serialized-project-graph-ready');
|
|
156
|
+
socket.write(serializedProjectGraph, () => {
|
|
157
|
+
perf_hooks_1.performance.mark('serialized-project-graph-written-to-client');
|
|
158
|
+
perf_hooks_1.performance.measure('write project graph to socket', 'serialized-project-graph-ready', 'serialized-project-graph-written-to-client');
|
|
159
|
+
/**
|
|
160
|
+
* Close the connection once all data has been written to the socket so that the client
|
|
161
|
+
* knows when to read it.
|
|
162
|
+
*/
|
|
163
|
+
socket.end();
|
|
164
|
+
perf_hooks_1.performance.measure('total for server response', 'server-connection', 'serialized-project-graph-written-to-client');
|
|
165
|
+
const bytesWritten = Buffer.byteLength(serializedProjectGraph, 'utf-8');
|
|
166
|
+
nestedLog(`Closed Connection to Client (${bytesWritten} bytes transferred)`);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
/**
|
|
171
|
+
* Server process termination clean up and logging.
|
|
172
|
+
*/
|
|
173
|
+
function handleServerProcessTermination() {
|
|
174
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
175
|
+
server.close();
|
|
176
|
+
/**
|
|
177
|
+
* Tear down any file watchers that may be running.
|
|
178
|
+
*/
|
|
179
|
+
if (watcherSubscription) {
|
|
180
|
+
yield watcherSubscription.unsubscribe();
|
|
181
|
+
watcherLog(`Unsubscribed from changes within: ${app_root_1.appRootPath}`);
|
|
182
|
+
}
|
|
183
|
+
serverLog('Server Stopped');
|
|
184
|
+
devkit_1.logger.info('NX Daemon Server - Stopped');
|
|
185
|
+
process.exit(0);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
process
|
|
189
|
+
.on('SIGINT', handleServerProcessTermination)
|
|
190
|
+
.on('SIGTERM', handleServerProcessTermination)
|
|
191
|
+
.on('SIGHUP', handleServerProcessTermination);
|
|
192
|
+
/**
|
|
193
|
+
* When applicable files in the workspaces are changed (created, updated, deleted),
|
|
194
|
+
* we need to recompute the cached serialized project graph so that it is readily
|
|
195
|
+
* available for the next client request to the server.
|
|
196
|
+
*/
|
|
197
|
+
const handleWorkspaceChanges = (err, changeEvents) => {
|
|
198
|
+
/**
|
|
199
|
+
* We know that something must have happened in the workspace so it makes sense
|
|
200
|
+
* to proactively destroy any previous knowledge of the project graph at this point.
|
|
201
|
+
*/
|
|
202
|
+
cachedSerializedProjectGraph = undefined;
|
|
203
|
+
if (err || !changeEvents || !changeEvents.length) {
|
|
204
|
+
watcherLog('Unexpected Error');
|
|
205
|
+
console.error(err);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
watcherLog(watcher_1.convertChangeEventsToLogMessage(changeEvents));
|
|
209
|
+
/**
|
|
210
|
+
* Update the file-hasher's knowledge of the non-deleted changed files in order to
|
|
211
|
+
* recompute and cache the project graph in memory.
|
|
212
|
+
*/
|
|
213
|
+
try {
|
|
214
|
+
const filesToHash = [];
|
|
215
|
+
const deletedFiles = [];
|
|
216
|
+
for (const event of changeEvents) {
|
|
217
|
+
if (event.type === 'delete') {
|
|
218
|
+
deletedFiles.push(event.path);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
filesToHash.push(event.path);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
perf_hooks_1.performance.mark('hash-watched-changes-start');
|
|
225
|
+
const updatedHashes = git_hasher_1.getGitHashForFiles(filesToHash, app_root_1.appRootPath);
|
|
226
|
+
perf_hooks_1.performance.mark('hash-watched-changes-end');
|
|
227
|
+
perf_hooks_1.performance.measure('hash changed files from watcher', 'hash-watched-changes-start', 'hash-watched-changes-end');
|
|
228
|
+
file_hasher_1.defaultFileHasher.incrementalUpdate(updatedHashes);
|
|
229
|
+
file_hasher_1.defaultFileHasher.removeFiles(deletedFiles);
|
|
230
|
+
nestedLog(`Updated file-hasher based on watched changes, recomputing project graph...`);
|
|
231
|
+
cachedSerializedProjectGraph = createAndSerializeProjectGraph();
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
serverLog(`Unexpected Error`);
|
|
235
|
+
console.error(err);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
function startServer({ serverLogOutputFile, }) {
|
|
239
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
240
|
+
_serverLogOutputFile = serverLogOutputFile;
|
|
241
|
+
// See notes above on OS differences regarding clean up of existings connections.
|
|
242
|
+
if (!socket_utils_1.isWindows) {
|
|
243
|
+
socket_utils_1.killSocketOrPath();
|
|
244
|
+
}
|
|
245
|
+
return new Promise((resolve) => {
|
|
246
|
+
server.listen(socket_utils_1.FULL_OS_SOCKET_PATH, () => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
247
|
+
serverLog(`Started listening on: ${socket_utils_1.FULL_OS_SOCKET_PATH}`);
|
|
248
|
+
if (!watcherSubscription) {
|
|
249
|
+
watcherSubscription = yield watcher_1.subscribeToWorkspaceChanges(handleWorkspaceChanges);
|
|
250
|
+
watcherLog(`Subscribed to changes within: ${app_root_1.appRootPath}`);
|
|
251
|
+
}
|
|
252
|
+
return resolve(server);
|
|
253
|
+
}));
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
exports.startServer = startServer;
|
|
258
|
+
function stopServer() {
|
|
259
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
260
|
+
return new Promise((resolve, reject) => {
|
|
261
|
+
server.close((err) => {
|
|
262
|
+
if (err) {
|
|
263
|
+
/**
|
|
264
|
+
* If the server is running in a detached background process then server.close()
|
|
265
|
+
* will throw this error even if server is actually alive. We therefore only reject
|
|
266
|
+
* in case of any other unexpected errors.
|
|
267
|
+
*/
|
|
268
|
+
if (!err.message.startsWith('Server is not running')) {
|
|
269
|
+
return reject(err);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
socket_utils_1.killSocketOrPath();
|
|
273
|
+
/**
|
|
274
|
+
* The distinction regarding background process or not is not relevant for stopping the server,
|
|
275
|
+
* always pretty print the message to stdout.
|
|
276
|
+
*/
|
|
277
|
+
devkit_1.logger.info('NX Daemon Server - Stopped');
|
|
278
|
+
return resolve();
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
exports.stopServer = stopServer;
|
|
284
|
+
//# sourceMappingURL=server.js.map
|