@memlab/cli 1.0.5 → 1.0.8
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/bin/{memlab → memlab.js} +9 -2
- package/dist/CommandLoader.d.ts +7 -6
- package/dist/CommandLoader.js +7 -0
- package/dist/Dispatcher.d.ts +7 -2
- package/dist/Dispatcher.js +12 -5
- package/dist/commands/GetVersionCommand.d.ts +18 -0
- package/dist/commands/GetVersionCommand.js +69 -0
- package/dist/commands/heap/CheckLeakCommand.js +6 -0
- package/dist/commands/heap/interactive/InteractiveCommandLoader.d.ts +16 -0
- package/dist/commands/heap/interactive/InteractiveCommandLoader.js +33 -0
- package/dist/commands/heap/interactive/InteractiveHeapCommand.d.ts +23 -0
- package/dist/commands/heap/interactive/InteractiveHeapCommand.js +127 -0
- package/dist/commands/helper/HelperCommand.js +16 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.js +22 -0
- package/dist/options/MLClusteringLinkageMaxDistanceOption.d.ts +18 -0
- package/dist/options/MLClusteringLinkageMaxDistanceOption.js +47 -0
- package/dist/options/MLClusteringMaxDFOption.d.ts +18 -0
- package/dist/options/MLClusteringMaxDFOption.js +47 -0
- package/dist/options/MLClusteringOption.d.ts +18 -0
- package/dist/options/MLClusteringOption.js +37 -0
- package/dist/options/heap/leak-filter/examples/large-object-as-leak.example.js +0 -1
- package/package.json +6 -6
package/bin/{memlab → memlab.js}
RENAMED
|
@@ -10,5 +10,12 @@
|
|
|
10
10
|
* @format
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
cli
|
|
13
|
+
// eslint-disable-next-line no-var
|
|
14
|
+
var cli = require('../dist/index');
|
|
15
|
+
|
|
16
|
+
// register the `@memlab/cli` package info
|
|
17
|
+
// so that `memlab version` get use the info
|
|
18
|
+
// eslint-disable-next-line fb-www/promise-termination
|
|
19
|
+
cli.registerPackage().then(() => {
|
|
20
|
+
cli.run();
|
|
21
|
+
});
|
package/dist/CommandLoader.d.ts
CHANGED
|
@@ -9,14 +9,15 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import BaseCommand from './BaseCommand';
|
|
11
11
|
export default class CommandLoader {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
protected isLoaded: boolean;
|
|
13
|
+
protected OSSModules: Map<string, BaseCommand>;
|
|
14
|
+
protected modules: Map<string, BaseCommand>;
|
|
15
|
+
protected modulePaths: Map<string, string>;
|
|
16
16
|
getModules(): Map<string, BaseCommand>;
|
|
17
17
|
getModulePaths(): Map<string, string>;
|
|
18
18
|
registerCommands(): void;
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
protected shouldRegisterCommand(command: BaseCommand): boolean;
|
|
20
|
+
protected registerCommandsFromDir(modulesDir: string): void;
|
|
21
|
+
protected postRegistration(): void;
|
|
21
22
|
}
|
|
22
23
|
//# sourceMappingURL=CommandLoader.d.ts.map
|
package/dist/CommandLoader.js
CHANGED
|
@@ -41,6 +41,10 @@ class CommandLoader {
|
|
|
41
41
|
this.registerCommandsFromDir(modulesDir);
|
|
42
42
|
this.postRegistration();
|
|
43
43
|
}
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
45
|
+
shouldRegisterCommand(command) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
44
48
|
registerCommandsFromDir(modulesDir) {
|
|
45
49
|
const moduleFiles = fs_1.default.readdirSync(modulesDir);
|
|
46
50
|
for (const moduleFile of moduleFiles) {
|
|
@@ -61,6 +65,9 @@ class CommandLoader {
|
|
|
61
65
|
if (!(moduleInstance instanceof BaseCommand_1.default)) {
|
|
62
66
|
core_1.utils.haltOrThrow('loading a command that does not extend BaseCommand');
|
|
63
67
|
}
|
|
68
|
+
if (!this.shouldRegisterCommand(moduleInstance)) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
64
71
|
const commandName = moduleInstance.getCommandName();
|
|
65
72
|
const loadingOssCommand = !core_1.fileManager.isWithinInternalDirectory(modulePath);
|
|
66
73
|
// reigster OSS commands
|
package/dist/Dispatcher.d.ts
CHANGED
|
@@ -10,16 +10,21 @@
|
|
|
10
10
|
import type { ParsedArgs } from 'minimist';
|
|
11
11
|
import type { AnyRecord, MemLabConfig } from '@memlab/core';
|
|
12
12
|
import BaseCommand from './BaseCommand';
|
|
13
|
+
import CommandLoader from './CommandLoader';
|
|
13
14
|
declare type RunCommandOptions = {
|
|
14
15
|
isPrerequisite?: boolean;
|
|
15
16
|
commandIndex?: number;
|
|
16
17
|
configFromOptions: AnyRecord;
|
|
17
18
|
};
|
|
18
|
-
declare
|
|
19
|
+
declare type CommandDispatcherOptions = {
|
|
20
|
+
commandLoader?: CommandLoader;
|
|
21
|
+
};
|
|
22
|
+
export declare class CommandDispatcher {
|
|
19
23
|
private modules;
|
|
20
24
|
private executedCommands;
|
|
21
25
|
private executingCommandStack;
|
|
22
|
-
constructor();
|
|
26
|
+
constructor(options?: CommandDispatcherOptions);
|
|
27
|
+
protected resetData(): void;
|
|
23
28
|
dispatch(args: ParsedArgs): Promise<void>;
|
|
24
29
|
parseOptions(command: BaseCommand, config: MemLabConfig, args: ParsedArgs): Promise<AnyRecord>;
|
|
25
30
|
private runCommand;
|
package/dist/Dispatcher.js
CHANGED
|
@@ -21,21 +21,27 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
21
21
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
22
|
};
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.CommandDispatcher = void 0;
|
|
24
25
|
const core_1 = require("@memlab/core");
|
|
25
26
|
const HelperCommand_1 = __importDefault(require("./commands/helper/HelperCommand"));
|
|
26
27
|
const UniversalOptions_1 = __importDefault(require("./options/lib/UniversalOptions"));
|
|
27
28
|
const CommandLoader_1 = __importDefault(require("./CommandLoader"));
|
|
28
29
|
const helperCommand = new HelperCommand_1.default();
|
|
29
30
|
class CommandDispatcher {
|
|
30
|
-
constructor() {
|
|
31
|
-
|
|
32
|
-
this.
|
|
31
|
+
constructor(options = {}) {
|
|
32
|
+
var _a;
|
|
33
|
+
this.resetData();
|
|
33
34
|
// auto load all command modules
|
|
34
|
-
const commandLoader = new CommandLoader_1.default();
|
|
35
|
+
const commandLoader = (_a = options.commandLoader) !== null && _a !== void 0 ? _a : new CommandLoader_1.default();
|
|
35
36
|
this.modules = commandLoader.getModules();
|
|
36
37
|
}
|
|
38
|
+
resetData() {
|
|
39
|
+
this.executedCommands = new Set();
|
|
40
|
+
this.executingCommandStack = [];
|
|
41
|
+
}
|
|
37
42
|
dispatch(args) {
|
|
38
43
|
return __awaiter(this, void 0, void 0, function* () {
|
|
44
|
+
this.resetData();
|
|
39
45
|
// triggered by `memlab` (without specific command)
|
|
40
46
|
if (!args._ || !(args._.length >= 1)) {
|
|
41
47
|
core_1.info.error('\n command argument missing');
|
|
@@ -121,7 +127,7 @@ class CommandDispatcher {
|
|
|
121
127
|
const subCommands = command.getSubCommands();
|
|
122
128
|
for (const subCommand of subCommands) {
|
|
123
129
|
if (subCommand.getCommandName() === args._[subCommandIndex]) {
|
|
124
|
-
this.runCommand(subCommand, args, runCmdOpt);
|
|
130
|
+
yield this.runCommand(subCommand, args, runCmdOpt);
|
|
125
131
|
return;
|
|
126
132
|
}
|
|
127
133
|
}
|
|
@@ -140,4 +146,5 @@ class CommandDispatcher {
|
|
|
140
146
|
});
|
|
141
147
|
}
|
|
142
148
|
}
|
|
149
|
+
exports.CommandDispatcher = CommandDispatcher;
|
|
143
150
|
exports.default = new CommandDispatcher();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
import type { CLIOptions } from '@memlab/core';
|
|
11
|
+
import BaseCommand from '../BaseCommand';
|
|
12
|
+
export default class GetVersionCommand extends BaseCommand {
|
|
13
|
+
getCommandName(): string;
|
|
14
|
+
getDescription(): string;
|
|
15
|
+
private loadDepencyPackageInfo;
|
|
16
|
+
run(options: CLIOptions): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=GetVersionCommand.d.ts.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
+
};
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
25
|
+
const BaseCommand_1 = __importDefault(require("../BaseCommand"));
|
|
26
|
+
const core_1 = require("@memlab/core");
|
|
27
|
+
const api_1 = require("@memlab/api");
|
|
28
|
+
const core_2 = require("@memlab/core");
|
|
29
|
+
const heap_analysis_1 = require("@memlab/heap-analysis");
|
|
30
|
+
const e2e_1 = require("@memlab/e2e");
|
|
31
|
+
class GetVersionCommand extends BaseCommand_1.default {
|
|
32
|
+
getCommandName() {
|
|
33
|
+
return 'version';
|
|
34
|
+
}
|
|
35
|
+
getDescription() {
|
|
36
|
+
return 'Show the versions of all memlab packages installed';
|
|
37
|
+
}
|
|
38
|
+
loadDepencyPackageInfo() {
|
|
39
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
40
|
+
// require all sub-packages to register package information
|
|
41
|
+
// memlab and cli packages already registered in the bin file
|
|
42
|
+
// the following sub-packages are registered here lazily to
|
|
43
|
+
// avoid too many file operations
|
|
44
|
+
return Promise.all([
|
|
45
|
+
(0, api_1.registerPackage)(),
|
|
46
|
+
(0, core_2.registerPackage)(),
|
|
47
|
+
(0, heap_analysis_1.registerPackage)(),
|
|
48
|
+
(0, e2e_1.registerPackage)(),
|
|
49
|
+
]);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
53
|
+
run(options) {
|
|
54
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
yield this.loadDepencyPackageInfo();
|
|
56
|
+
const packages = [...core_1.config.packageInfo].sort((p1, p2) => p1.name < p2.name ? 1 : -1);
|
|
57
|
+
core_1.info.topLevel('');
|
|
58
|
+
for (const pkg of packages) {
|
|
59
|
+
const version = chalk_1.default.grey(`@${pkg.version}`);
|
|
60
|
+
core_1.info.topLevel(` ${pkg.name}${version}`);
|
|
61
|
+
if (core_1.config.verbose && pkg.packageLocation) {
|
|
62
|
+
core_1.info.lowLevel(` ${pkg.packageLocation}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
core_1.info.topLevel('');
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.default = GetVersionCommand;
|
|
@@ -58,6 +58,9 @@ const LogTraceAsClusterOption_1 = __importDefault(require("../../options/heap/Lo
|
|
|
58
58
|
const CleanLoggerDataCommand_1 = __importDefault(require("../CleanLoggerDataCommand"));
|
|
59
59
|
const LeakFilterFileOption_1 = __importDefault(require("../../options/heap/leak-filter/LeakFilterFileOption"));
|
|
60
60
|
const LeakClusterSizeThresholdOption_1 = __importDefault(require("../../options/heap/LeakClusterSizeThresholdOption"));
|
|
61
|
+
const MLClusteringOption_1 = __importDefault(require("../../options/MLClusteringOption"));
|
|
62
|
+
const MLClusteringLinkageMaxDistanceOption_1 = __importDefault(require("../../options/MLClusteringLinkageMaxDistanceOption"));
|
|
63
|
+
const MLClusteringMaxDFOption_1 = __importDefault(require("../../options/MLClusteringMaxDFOption"));
|
|
61
64
|
class CheckLeakCommand extends BaseCommand_1.default {
|
|
62
65
|
getCommandName() {
|
|
63
66
|
return 'find-leaks';
|
|
@@ -83,6 +86,9 @@ class CheckLeakCommand extends BaseCommand_1.default {
|
|
|
83
86
|
new LeakClusterSizeThresholdOption_1.default(),
|
|
84
87
|
new TraceAllObjectsOption_1.default(),
|
|
85
88
|
new LogTraceAsClusterOption_1.default(),
|
|
89
|
+
new MLClusteringOption_1.default(),
|
|
90
|
+
new MLClusteringLinkageMaxDistanceOption_1.default(),
|
|
91
|
+
new MLClusteringMaxDFOption_1.default(),
|
|
86
92
|
];
|
|
87
93
|
}
|
|
88
94
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
import BaseCommand from '../../../BaseCommand';
|
|
11
|
+
import CommandLoader from '../../../CommandLoader';
|
|
12
|
+
export default class InteractiveCommandLoader extends CommandLoader {
|
|
13
|
+
protected shouldRegisterCommand(command: BaseCommand): boolean;
|
|
14
|
+
protected postRegistration(): void;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=InteractiveCommandLoader.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const CommandLoader_1 = __importDefault(require("../../../CommandLoader"));
|
|
16
|
+
const HelperCommand_1 = __importDefault(require("../../helper/HelperCommand"));
|
|
17
|
+
const GetRetainerTraceCommand_1 = __importDefault(require("../GetRetainerTraceCommand"));
|
|
18
|
+
const HeapAnalysisCommand_1 = __importDefault(require("../HeapAnalysisCommand"));
|
|
19
|
+
const commandToInclude = new Set([
|
|
20
|
+
HeapAnalysisCommand_1.default,
|
|
21
|
+
GetRetainerTraceCommand_1.default,
|
|
22
|
+
HelperCommand_1.default,
|
|
23
|
+
]);
|
|
24
|
+
class InteractiveCommandLoader extends CommandLoader_1.default {
|
|
25
|
+
shouldRegisterCommand(command) {
|
|
26
|
+
const constructor = command.constructor;
|
|
27
|
+
return commandToInclude.has(constructor);
|
|
28
|
+
}
|
|
29
|
+
postRegistration() {
|
|
30
|
+
// do nothing
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.default = InteractiveCommandLoader;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
import { CLIOptions } from '@memlab/core';
|
|
11
|
+
import BaseCommand, { CommandCategory } from '../../../BaseCommand';
|
|
12
|
+
import { BaseOption } from '@memlab/core';
|
|
13
|
+
export default class InteractiveHeapCommand extends BaseCommand {
|
|
14
|
+
getCommandName(): string;
|
|
15
|
+
getDescription(): string;
|
|
16
|
+
getCategory(): CommandCategory;
|
|
17
|
+
getExamples(): string[];
|
|
18
|
+
getOptions(): BaseOption[];
|
|
19
|
+
private printPromptInfo;
|
|
20
|
+
private startInteractiveCLI;
|
|
21
|
+
run(options: CLIOptions): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=InteractiveHeapCommand.d.ts.map
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
35
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
36
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
37
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
38
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
39
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
40
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
44
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
45
|
+
};
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
const core_1 = require("@memlab/core");
|
|
48
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
49
|
+
const readline_1 = __importDefault(require("readline"));
|
|
50
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
51
|
+
const minimist_1 = __importDefault(require("minimist"));
|
|
52
|
+
const BaseCommand_1 = __importStar(require("../../../BaseCommand"));
|
|
53
|
+
const core_2 = require("@memlab/core");
|
|
54
|
+
const SnapshotFileOption_1 = __importDefault(require("../../../options/heap/SnapshotFileOption"));
|
|
55
|
+
const JSEngineOption_1 = __importDefault(require("../../../options/heap/JSEngineOption"));
|
|
56
|
+
const core_3 = require("@memlab/core");
|
|
57
|
+
const heap_analysis_1 = require("@memlab/heap-analysis");
|
|
58
|
+
const Dispatcher_1 = require("../../../Dispatcher");
|
|
59
|
+
const InteractiveCommandLoader_1 = __importDefault(require("./InteractiveCommandLoader"));
|
|
60
|
+
class InteractiveHeapCommand extends BaseCommand_1.default {
|
|
61
|
+
getCommandName() {
|
|
62
|
+
return 'heap';
|
|
63
|
+
}
|
|
64
|
+
getDescription() {
|
|
65
|
+
return 'interactive command to explore a single heap snapshot';
|
|
66
|
+
}
|
|
67
|
+
getCategory() {
|
|
68
|
+
return BaseCommand_1.CommandCategory.COMMON;
|
|
69
|
+
}
|
|
70
|
+
getExamples() {
|
|
71
|
+
return ['--snapshot <HEAP_SNAPSHOT_FILE>'];
|
|
72
|
+
}
|
|
73
|
+
getOptions() {
|
|
74
|
+
return [new SnapshotFileOption_1.default(), new JSEngineOption_1.default()];
|
|
75
|
+
}
|
|
76
|
+
printPromptInfo() {
|
|
77
|
+
core_2.info.topLevel(`Heap Snapshot Loaded: ${chalk_1.default.grey(heap_analysis_1.heapConfig.currentHeapFile)}`);
|
|
78
|
+
}
|
|
79
|
+
startInteractiveCLI() {
|
|
80
|
+
const rl = readline_1.default.createInterface({
|
|
81
|
+
input: process.stdin,
|
|
82
|
+
output: process.stdout,
|
|
83
|
+
prompt: 'memlab > ',
|
|
84
|
+
});
|
|
85
|
+
// the interactive cli only supports a subset of memlab commands
|
|
86
|
+
const dispatcher = new Dispatcher_1.CommandDispatcher({
|
|
87
|
+
commandLoader: new InteractiveCommandLoader_1.default(),
|
|
88
|
+
});
|
|
89
|
+
// do not halt execution when running the interactive command
|
|
90
|
+
core_2.config.errorHandling = core_1.ErrorHandling.Throw;
|
|
91
|
+
// start the interactive prompt
|
|
92
|
+
this.printPromptInfo();
|
|
93
|
+
rl.prompt();
|
|
94
|
+
// start interpreting interactive commands
|
|
95
|
+
rl.on('line', (line) => __awaiter(this, void 0, void 0, function* () {
|
|
96
|
+
try {
|
|
97
|
+
// "memlab <command>" -> "<command>"
|
|
98
|
+
const command = line.trim().startsWith('memlab ')
|
|
99
|
+
? line.substring('memlab '.length)
|
|
100
|
+
: line;
|
|
101
|
+
const args = command.match(/("[^"]+")|('[^']+')|(\S+)/g);
|
|
102
|
+
const parsedArgs = (0, minimist_1.default)(args);
|
|
103
|
+
yield dispatcher.dispatch(parsedArgs);
|
|
104
|
+
}
|
|
105
|
+
catch (ex) {
|
|
106
|
+
const error = core_2.utils.getError(ex);
|
|
107
|
+
core_2.info.topLevel(error.message);
|
|
108
|
+
}
|
|
109
|
+
core_2.info.topLevel('');
|
|
110
|
+
this.printPromptInfo();
|
|
111
|
+
rl.prompt();
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
run(options) {
|
|
115
|
+
var _a;
|
|
116
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
117
|
+
const workDir = (_a = options.configFromOptions) === null || _a === void 0 ? void 0 : _a.workDir;
|
|
118
|
+
const reportOutDir = core_3.fileManager.getReportOutDir({ workDir });
|
|
119
|
+
fs_extra_1.default.emptyDirSync(reportOutDir);
|
|
120
|
+
// load single heap snapshot
|
|
121
|
+
heap_analysis_1.heapConfig.isCliInteractiveMode = true;
|
|
122
|
+
yield (0, heap_analysis_1.loadHeapSnapshot)({ args: options.cliArgs });
|
|
123
|
+
this.startInteractiveCLI();
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
exports.default = InteractiveHeapCommand;
|
|
@@ -51,6 +51,7 @@ const core_1 = require("@memlab/core");
|
|
|
51
51
|
const CommandOrder_1 = __importDefault(require("./lib/CommandOrder"));
|
|
52
52
|
const BaseCommand_1 = __importStar(require("../../BaseCommand"));
|
|
53
53
|
const UniversalOptions_1 = __importDefault(require("../../options/lib/UniversalOptions"));
|
|
54
|
+
const heap_analysis_1 = require("@memlab/heap-analysis");
|
|
54
55
|
class HelperCommand extends BaseCommand_1.default {
|
|
55
56
|
constructor() {
|
|
56
57
|
super(...arguments);
|
|
@@ -81,7 +82,11 @@ class HelperCommand extends BaseCommand_1.default {
|
|
|
81
82
|
printCommandCategories(options) {
|
|
82
83
|
for (const category in BaseCommand_1.CommandCategory) {
|
|
83
84
|
const item = CommandOrder_1.default.find(item => item.category === category);
|
|
84
|
-
const commandsToPrintFirst =
|
|
85
|
+
const commandsToPrintFirst = heap_analysis_1.heapConfig.isCliInteractiveMode
|
|
86
|
+
? []
|
|
87
|
+
: item
|
|
88
|
+
? item.commands
|
|
89
|
+
: [];
|
|
85
90
|
this.printCategory(category, commandsToPrintFirst, options);
|
|
86
91
|
}
|
|
87
92
|
}
|
|
@@ -93,13 +98,13 @@ class HelperCommand extends BaseCommand_1.default {
|
|
|
93
98
|
core_1.info.topLevel('');
|
|
94
99
|
}
|
|
95
100
|
printCategory(category, commandsToPrintFirst, options) {
|
|
96
|
-
|
|
101
|
+
const commandsToPrint = [];
|
|
97
102
|
for (const command of commandsToPrintFirst) {
|
|
98
103
|
const name = command.getCommandName();
|
|
99
104
|
if (this.printedCommand.has(name)) {
|
|
100
105
|
continue;
|
|
101
106
|
}
|
|
102
|
-
|
|
107
|
+
commandsToPrint.push(command);
|
|
103
108
|
this.printedCommand.add(name);
|
|
104
109
|
}
|
|
105
110
|
// print other commands in this category
|
|
@@ -115,9 +120,16 @@ class HelperCommand extends BaseCommand_1.default {
|
|
|
115
120
|
if (this.printedCommand.has(name)) {
|
|
116
121
|
continue;
|
|
117
122
|
}
|
|
118
|
-
|
|
123
|
+
commandsToPrint.push(command);
|
|
119
124
|
this.printedCommand.add(name);
|
|
120
125
|
}
|
|
126
|
+
if (commandsToPrint.length === 0) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
this.printCategoryHeader(category, options);
|
|
130
|
+
for (const command of commandsToPrint) {
|
|
131
|
+
this.printCommand(command, options.indent);
|
|
132
|
+
}
|
|
121
133
|
core_1.info.topLevel('');
|
|
122
134
|
}
|
|
123
135
|
getCommandOptionsSummary(command, indent = '') {
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -22,5 +22,27 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
|
|
|
22
22
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
23
23
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
24
24
|
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
25
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.registerPackage = void 0;
|
|
39
|
+
const path_1 = __importDefault(require("path"));
|
|
40
|
+
const core_1 = require("@memlab/core");
|
|
41
|
+
/** @internal */
|
|
42
|
+
function registerPackage() {
|
|
43
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
44
|
+
return core_1.PackageInfoLoader.registerPackage(path_1.default.join(__dirname, '..'));
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
exports.registerPackage = registerPackage;
|
|
26
48
|
__exportStar(require("./runner"), exports);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
import type { ParsedArgs } from 'minimist';
|
|
11
|
+
import { MemLabConfig } from '@memlab/core';
|
|
12
|
+
import { BaseOption } from '@memlab/core';
|
|
13
|
+
export default class MLClusteringLinkageMaxDistanceOption extends BaseOption {
|
|
14
|
+
getOptionName(): string;
|
|
15
|
+
getDescription(): string;
|
|
16
|
+
parse(config: MemLabConfig, args: ParsedArgs): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=MLClusteringLinkageMaxDistanceOption.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const core_1 = require("@memlab/core");
|
|
22
|
+
const core_2 = require("@memlab/core");
|
|
23
|
+
class MLClusteringLinkageMaxDistanceOption extends core_2.BaseOption {
|
|
24
|
+
getOptionName() {
|
|
25
|
+
return 'ml-linkage-max-dist';
|
|
26
|
+
}
|
|
27
|
+
getDescription() {
|
|
28
|
+
return 'set linkage max distance value for clustering. The value should be between [0, 1] inclusive.';
|
|
29
|
+
}
|
|
30
|
+
parse(config, args) {
|
|
31
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
32
|
+
if (args['ml-linkage-max-dist']) {
|
|
33
|
+
const linkageMaxDist = args['ml-linkage-max-dist'];
|
|
34
|
+
const linkageMaxDistNum = parseFloat(linkageMaxDist);
|
|
35
|
+
if (!isNaN(linkageMaxDistNum) &&
|
|
36
|
+
linkageMaxDistNum >= 0 &&
|
|
37
|
+
linkageMaxDistNum <= 1) {
|
|
38
|
+
config.mlClusteringLinkageMaxDistance = linkageMaxDistNum;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
core_1.utils.haltOrThrow(`ml-linkage-max-dist is not number between [0, 1]. ml-linkage-max-dist=${linkageMaxDist}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.default = MLClusteringLinkageMaxDistanceOption;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
import type { ParsedArgs } from 'minimist';
|
|
11
|
+
import { MemLabConfig } from '@memlab/core';
|
|
12
|
+
import { BaseOption } from '@memlab/core';
|
|
13
|
+
export default class MLClusteringMaxDFOption extends BaseOption {
|
|
14
|
+
getOptionName(): string;
|
|
15
|
+
getDescription(): string;
|
|
16
|
+
parse(config: MemLabConfig, args: ParsedArgs): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=MLClusteringMaxDFOption.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const core_1 = require("@memlab/core");
|
|
22
|
+
const core_2 = require("@memlab/core");
|
|
23
|
+
class MLClusteringMaxDFOption extends core_2.BaseOption {
|
|
24
|
+
getOptionName() {
|
|
25
|
+
return 'ml-clustering-max-df';
|
|
26
|
+
}
|
|
27
|
+
getDescription() {
|
|
28
|
+
return 'set percentage based max document frequency for limiting the terms that appear too often';
|
|
29
|
+
}
|
|
30
|
+
parse(config, args) {
|
|
31
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
32
|
+
if (args['ml-clustering-max-df']) {
|
|
33
|
+
const clusteringMaxDFStr = args['ml-clustering-max-df'];
|
|
34
|
+
const clusteringMaxDF = parseFloat(clusteringMaxDFStr);
|
|
35
|
+
if (!isNaN(clusteringMaxDF) &&
|
|
36
|
+
clusteringMaxDF >= 0 &&
|
|
37
|
+
clusteringMaxDF <= 1) {
|
|
38
|
+
config.mlMaxDF = clusteringMaxDF;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
core_1.utils.haltOrThrow(`ml-clustering-max-df is not number between [0, 1]. ml-clustering-max-df=${clusteringMaxDF}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.default = MLClusteringMaxDFOption;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
import type { ParsedArgs } from 'minimist';
|
|
11
|
+
import type { MemLabConfig } from '@memlab/core';
|
|
12
|
+
import { BaseOption } from '@memlab/core';
|
|
13
|
+
export default class MLClusteringOption extends BaseOption {
|
|
14
|
+
getOptionName(): string;
|
|
15
|
+
getDescription(): string;
|
|
16
|
+
parse(config: MemLabConfig, args: ParsedArgs): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=MLClusteringOption.d.ts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const core_1 = require("@memlab/core");
|
|
22
|
+
class MLClusteringOption extends core_1.BaseOption {
|
|
23
|
+
getOptionName() {
|
|
24
|
+
return 'ml-clustering';
|
|
25
|
+
}
|
|
26
|
+
getDescription() {
|
|
27
|
+
return 'use machine learning algorithms for clustering leak traces (by default, traces are clustered by heuristics)';
|
|
28
|
+
}
|
|
29
|
+
parse(config, args) {
|
|
30
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
+
if (args['ml-clustering']) {
|
|
32
|
+
config.isMLClustering = true;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.default = MLClusteringOption;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memlab/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "command line interface for memlab",
|
|
6
6
|
"author": "Liang Gong <lgong@fb.com>",
|
|
@@ -18,16 +18,16 @@
|
|
|
18
18
|
"dist"
|
|
19
19
|
],
|
|
20
20
|
"bin": {
|
|
21
|
-
"memlab": "bin/memlab"
|
|
21
|
+
"memlab": "bin/memlab.js"
|
|
22
22
|
},
|
|
23
23
|
"publishConfig": {
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@memlab/api": "^1.0.
|
|
28
|
-
"@memlab/core": "^1.
|
|
29
|
-
"@memlab/e2e": "^1.0.
|
|
30
|
-
"@memlab/heap-analysis": "^1.0.
|
|
27
|
+
"@memlab/api": "^1.0.6",
|
|
28
|
+
"@memlab/core": "^1.1.6",
|
|
29
|
+
"@memlab/e2e": "^1.0.7",
|
|
30
|
+
"@memlab/heap-analysis": "^1.0.5",
|
|
31
31
|
"ansi": "^0.3.1",
|
|
32
32
|
"babar": "^0.2.0",
|
|
33
33
|
"chalk": "^4.0.0",
|