@datatruck/cli 0.36.7 → 0.37.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/config.schema.json +87 -79
- package/lib/actions/BackupAction.d.ts +6 -1
- package/lib/actions/BackupAction.js +12 -10
- package/lib/actions/CopyAction.d.ts +6 -1
- package/lib/actions/CopyAction.js +2 -2
- package/lib/actions/RestoreAction.d.ts +6 -1
- package/lib/actions/RestoreAction.js +2 -2
- package/lib/cli.js +75 -21
- package/lib/commands/BackupCommand.d.ts +1 -0
- package/lib/commands/BackupCommand.js +7 -4
- package/lib/commands/CommandAbstract.d.ts +1 -0
- package/lib/commands/CopyCommand.d.ts +1 -0
- package/lib/commands/CopyCommand.js +7 -4
- package/lib/commands/InitCommand.d.ts +1 -0
- package/lib/commands/InitCommand.js +7 -2
- package/lib/commands/RestoreCommand.d.ts +1 -0
- package/lib/commands/RestoreCommand.js +7 -4
- package/lib/commands/RunCommand.d.ts +10 -0
- package/lib/commands/RunCommand.js +35 -0
- package/lib/commands/StartServerCommand.js +12 -12
- package/lib/utils/cli.d.ts +2 -2
- package/lib/utils/cli.js +34 -28
- package/lib/utils/datatruck/command.d.ts +3 -1
- package/lib/utils/datatruck/command.js +2 -0
- package/lib/utils/datatruck/config-type.d.ts +4 -0
- package/lib/utils/datatruck/cron-server.d.ts +8 -39
- package/lib/utils/datatruck/cron-server.js +35 -57
- package/lib/utils/datatruck/job.d.ts +41 -0
- package/lib/utils/datatruck/job.js +77 -0
- package/lib/utils/datatruck/report-list.js +1 -1
- package/lib/utils/datatruck/repository-server.d.ts +4 -0
- package/lib/utils/datatruck/repository-server.js +4 -1
- package/lib/utils/http.d.ts +1 -0
- package/lib/utils/http.js +4 -2
- package/lib/utils/list.d.ts +5 -0
- package/lib/utils/list.js +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RunCommand = void 0;
|
|
4
|
+
const ConfigAction_1 = require("../actions/ConfigAction");
|
|
5
|
+
const job_1 = require("../utils/datatruck/job");
|
|
6
|
+
const error_1 = require("../utils/error");
|
|
7
|
+
const CommandAbstract_1 = require("./CommandAbstract");
|
|
8
|
+
class RunCommand extends CommandAbstract_1.CommandAbstract {
|
|
9
|
+
optionsConfig() {
|
|
10
|
+
return this.castOptionsConfig({
|
|
11
|
+
jobName: {
|
|
12
|
+
description: "Job name",
|
|
13
|
+
required: true,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
async exec() {
|
|
18
|
+
const config = await ConfigAction_1.ConfigAction.fromGlobalOptionsWithPath(this.globalOptions);
|
|
19
|
+
const verbose = !!this.globalOptions.verbose;
|
|
20
|
+
const log = config.data.server?.log ?? true;
|
|
21
|
+
const jobs = config.data.jobs || {};
|
|
22
|
+
const jobName = this.options.jobName;
|
|
23
|
+
const job = jobs[jobName];
|
|
24
|
+
if (!job)
|
|
25
|
+
throw new error_1.AppError(`Job not found: ${jobName}`);
|
|
26
|
+
await (0, job_1.runJob)(job, jobName, {
|
|
27
|
+
log,
|
|
28
|
+
verbose: verbose,
|
|
29
|
+
configPath: config.path,
|
|
30
|
+
logPath: config.data.server?.cron?.logPath,
|
|
31
|
+
});
|
|
32
|
+
return { exitCode: 0 };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.RunCommand = RunCommand;
|
|
@@ -13,13 +13,14 @@ class StartServerCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
13
13
|
}
|
|
14
14
|
async exec() {
|
|
15
15
|
const config = await ConfigAction_1.ConfigAction.fromGlobalOptions(this.globalOptions);
|
|
16
|
+
const configPath = this.configPath;
|
|
16
17
|
const verbose = !!this.globalOptions.verbose;
|
|
17
18
|
const log = config.server?.log ?? true;
|
|
18
19
|
const repositoryOptions = config.server?.repository || {};
|
|
19
20
|
if (repositoryOptions.enabled ?? true) {
|
|
20
21
|
const server = (0, repository_server_1.createDatatruckRepositoryServer)(repositoryOptions, {
|
|
22
|
+
configPath,
|
|
21
23
|
log,
|
|
22
|
-
configPath: this.configPath,
|
|
23
24
|
});
|
|
24
25
|
const port = repositoryOptions.listen?.port ?? 8888;
|
|
25
26
|
const address = repositoryOptions.listen?.address ?? "127.0.0.1";
|
|
@@ -31,24 +32,23 @@ class StartServerCommand extends CommandAbstract_1.CommandAbstract {
|
|
|
31
32
|
server.listen(port, address);
|
|
32
33
|
}
|
|
33
34
|
const cronOptions = config.server?.cron || {};
|
|
34
|
-
const
|
|
35
|
+
const logPath = config.server?.cron?.logPath;
|
|
35
36
|
if (cronOptions.enabled ?? true) {
|
|
36
|
-
if (typeof
|
|
37
|
+
if (typeof configPath !== "string")
|
|
37
38
|
throw new error_1.AppError(`Config path is required by cron server`);
|
|
38
|
-
const server = (0, cron_server_1.createCronServer)(
|
|
39
|
+
const server = await (0, cron_server_1.createCronServer)({
|
|
40
|
+
configPath,
|
|
39
41
|
verbose,
|
|
40
42
|
log,
|
|
41
|
-
|
|
43
|
+
logPath,
|
|
42
44
|
});
|
|
43
45
|
server.start();
|
|
44
|
-
(0, cli_1.logJson)("cron-server", `server started
|
|
45
|
-
jobs: cronJobs.length,
|
|
46
|
-
});
|
|
46
|
+
(0, cli_1.logJson)("cron-server", `server started`);
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return { exitCode
|
|
48
|
+
const exitCode = await new Promise((resolve) => {
|
|
49
|
+
process.on("SIGINT", () => resolve(1)).on("SIGTERM", () => resolve(1));
|
|
50
|
+
});
|
|
51
|
+
return { exitCode };
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
exports.StartServerCommand = StartServerCommand;
|
package/lib/utils/cli.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare const showCursorCommand = "\u001B[?25h";
|
|
|
5
5
|
export declare function renderProgressBar(progress: number, size?: number, subprogress?: number): string;
|
|
6
6
|
export declare function logExec(command: string, argv?: string[], env?: NodeJS.ProcessEnv, logToStderr?: boolean): void;
|
|
7
7
|
export declare function renderResult(error: Error | null | string | boolean | undefined, color?: boolean): string;
|
|
8
|
-
export declare function renderError(error: Error | null | string | undefined,
|
|
8
|
+
export declare function renderError(error: Error | null | string | undefined, index?: number): string;
|
|
9
9
|
export declare function renderListTaskItem<T extends Record<string, any>>(item: Listr3TaskResultEnd<T>, color: boolean | undefined, config: {
|
|
10
10
|
[K in Listr3TaskResultEnd<T>["key"]]: (data: Extract<Listr3TaskResultEnd<T>, {
|
|
11
11
|
key: K;
|
|
@@ -16,7 +16,7 @@ export type OptionsConfig<T1, T2 extends {
|
|
|
16
16
|
[K in keyof T1]: unknown;
|
|
17
17
|
}> = {
|
|
18
18
|
[K in keyof Required<T1>]: {
|
|
19
|
-
option
|
|
19
|
+
option?: string;
|
|
20
20
|
description: string;
|
|
21
21
|
required?: boolean;
|
|
22
22
|
defaults?: Exclude<T1[K], undefined>;
|
package/lib/utils/cli.js
CHANGED
|
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.logJson = exports.colorizeObject = exports.colorizeValue = exports.waitForStdDrain = exports.confirm = exports.stringifyOptions = exports.parseOptions = exports.renderObject = exports.renderListTaskItem = exports.renderError = exports.renderResult = exports.logExec = exports.renderProgressBar = exports.showCursorCommand = void 0;
|
|
7
|
-
const error_1 = require("./error");
|
|
8
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
8
|
const chalk_2 = require("chalk");
|
|
10
9
|
const readline_1 = require("readline");
|
|
@@ -59,20 +58,15 @@ function renderResult(error, color = true) {
|
|
|
59
58
|
: "✓";
|
|
60
59
|
}
|
|
61
60
|
exports.renderResult = renderResult;
|
|
62
|
-
function renderError(error,
|
|
63
|
-
if (!error)
|
|
61
|
+
function renderError(error, index) {
|
|
62
|
+
if (!error)
|
|
64
63
|
return "";
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
const message = error.split(/\r?\n/).shift() ?? "";
|
|
74
|
-
return chalk_1.default.red(message.trim());
|
|
75
|
-
}
|
|
64
|
+
const message = error instanceof Error
|
|
65
|
+
? error.message
|
|
66
|
+
: (error.split(/\r?\n/).shift() ?? "").trim();
|
|
67
|
+
return chalk_1.default.red(typeof index === "number" && index !== -1
|
|
68
|
+
? `${index + 1}. ${message}`
|
|
69
|
+
: message);
|
|
76
70
|
}
|
|
77
71
|
exports.renderError = renderError;
|
|
78
72
|
function renderListTaskItem(item, color, config) {
|
|
@@ -101,10 +95,14 @@ exports.renderObject = renderObject;
|
|
|
101
95
|
function parseOptions(object, options) {
|
|
102
96
|
const result = {};
|
|
103
97
|
for (const key in options) {
|
|
104
|
-
const
|
|
105
|
-
|
|
98
|
+
const opt = options[key].option;
|
|
99
|
+
let defaultsValue;
|
|
100
|
+
let parser = options[key].parser;
|
|
101
|
+
if (typeof opt === "string") {
|
|
102
|
+
const isNegative = opt.startsWith("--no");
|
|
103
|
+
defaultsValue = isNegative ? true : options[key].defaults;
|
|
104
|
+
}
|
|
106
105
|
const value = object?.[key] ?? defaultsValue;
|
|
107
|
-
const parser = options[key].parser;
|
|
108
106
|
if (typeof value !== "undefined") {
|
|
109
107
|
result[key] = parser ? parser(value) : value;
|
|
110
108
|
}
|
|
@@ -114,22 +112,30 @@ function parseOptions(object, options) {
|
|
|
114
112
|
exports.parseOptions = parseOptions;
|
|
115
113
|
function stringifyOptions(options, object) {
|
|
116
114
|
const result = [];
|
|
115
|
+
const prepend = [];
|
|
117
116
|
for (const key in options) {
|
|
118
117
|
const fullOpt = options[key].option;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (
|
|
126
|
-
|
|
118
|
+
if (typeof fullOpt === "string") {
|
|
119
|
+
const [opt] = fullOpt.split(",");
|
|
120
|
+
const isNegative = fullOpt.startsWith("--no");
|
|
121
|
+
const isBool = !fullOpt.includes("<") && !fullOpt.includes("[");
|
|
122
|
+
const defaultsValue = isNegative ? true : options[key].defaults;
|
|
123
|
+
const value = object?.[key] ?? defaultsValue;
|
|
124
|
+
if (isBool) {
|
|
125
|
+
if (object[key])
|
|
126
|
+
result.push(opt);
|
|
127
|
+
}
|
|
128
|
+
else if (value !== undefined) {
|
|
129
|
+
result.push(opt, `${value}`);
|
|
130
|
+
}
|
|
127
131
|
}
|
|
128
|
-
else
|
|
129
|
-
|
|
132
|
+
else {
|
|
133
|
+
const value = object?.[key];
|
|
134
|
+
if (value !== undefined)
|
|
135
|
+
prepend.push(value);
|
|
130
136
|
}
|
|
131
137
|
}
|
|
132
|
-
return result;
|
|
138
|
+
return [...prepend, ...result];
|
|
133
139
|
}
|
|
134
140
|
exports.stringifyOptions = stringifyOptions;
|
|
135
141
|
function confirm(message) {
|
|
@@ -6,6 +6,7 @@ import { CopyCommand } from "../../commands/CopyCommand";
|
|
|
6
6
|
import { InitCommand } from "../../commands/InitCommand";
|
|
7
7
|
import { PruneCommand } from "../../commands/PruneCommand";
|
|
8
8
|
import { RestoreCommand } from "../../commands/RestoreCommand";
|
|
9
|
+
import { RunCommand } from "../../commands/RunCommand";
|
|
9
10
|
import { SnapshotsCommand } from "../../commands/SnapshotsCommand";
|
|
10
11
|
import { StartServerCommand } from "../../commands/StartServerCommand";
|
|
11
12
|
import { StdStreams } from "../stream";
|
|
@@ -16,6 +17,7 @@ export declare const datatruckCommandMap: {
|
|
|
16
17
|
prune: typeof PruneCommand;
|
|
17
18
|
backup: typeof BackupCommand;
|
|
18
19
|
restore: typeof RestoreCommand;
|
|
20
|
+
run: typeof RunCommand;
|
|
19
21
|
copy: typeof CopyCommand;
|
|
20
22
|
cleanCache: typeof CleanCacheCommand;
|
|
21
23
|
startServer: typeof StartServerCommand;
|
|
@@ -23,7 +25,7 @@ export declare const datatruckCommandMap: {
|
|
|
23
25
|
export type DatatruckCommandMap = typeof datatruckCommandMap;
|
|
24
26
|
export type InferDatatruckCommandOptions<T extends keyof DatatruckCommandMap> = InstanceType<DatatruckCommandMap[T]>["inputOptions"];
|
|
25
27
|
export type InferDatatruckCommandResult<T extends keyof DatatruckCommandMap, R = Awaited<ReturnType<InstanceType<DatatruckCommandMap[T]>["exec"]>>> = "result" extends keyof R ? R["result"] : undefined;
|
|
26
|
-
export declare function createCommand<T extends keyof DatatruckCommandMap>(name: T, globalOptions: GlobalOptions<true>, options: InferDatatruckCommandOptions<T>, streams?: Partial<StdStreams>, configPath?: string): BackupCommand | CopyCommand | PruneCommand | CleanCacheCommand | ConfigCommand | InitCommand | RestoreCommand | SnapshotsCommand | StartServerCommand;
|
|
28
|
+
export declare function createCommand<T extends keyof DatatruckCommandMap>(name: T, globalOptions: GlobalOptions<true>, options: InferDatatruckCommandOptions<T>, streams?: Partial<StdStreams>, configPath?: string): BackupCommand | CopyCommand | PruneCommand | CleanCacheCommand | ConfigCommand | InitCommand | RestoreCommand | RunCommand | SnapshotsCommand | StartServerCommand;
|
|
27
29
|
export declare function createCommands(globalOptions: GlobalOptions<true>): {
|
|
28
30
|
[K in keyof DatatruckCommandMap as `${K}`]: (options: InferDatatruckCommandOptions<K>) => Promise<InferDatatruckCommandResult<K>>;
|
|
29
31
|
};
|
|
@@ -8,6 +8,7 @@ const CopyCommand_1 = require("../../commands/CopyCommand");
|
|
|
8
8
|
const InitCommand_1 = require("../../commands/InitCommand");
|
|
9
9
|
const PruneCommand_1 = require("../../commands/PruneCommand");
|
|
10
10
|
const RestoreCommand_1 = require("../../commands/RestoreCommand");
|
|
11
|
+
const RunCommand_1 = require("../../commands/RunCommand");
|
|
11
12
|
const SnapshotsCommand_1 = require("../../commands/SnapshotsCommand");
|
|
12
13
|
const StartServerCommand_1 = require("../../commands/StartServerCommand");
|
|
13
14
|
const error_1 = require("../error");
|
|
@@ -19,6 +20,7 @@ exports.datatruckCommandMap = {
|
|
|
19
20
|
prune: PruneCommand_1.PruneCommand,
|
|
20
21
|
backup: BackupCommand_1.BackupCommand,
|
|
21
22
|
restore: RestoreCommand_1.RestoreCommand,
|
|
23
|
+
run: RunCommand_1.RunCommand,
|
|
22
24
|
copy: CopyCommand_1.CopyCommand,
|
|
23
25
|
cleanCache: CleanCacheCommand_1.CleanCacheCommand,
|
|
24
26
|
startServer: StartServerCommand_1.StartServerCommand,
|
|
@@ -5,6 +5,7 @@ import type { SpawnStep } from "../spawnSteps";
|
|
|
5
5
|
import type { PackageRepositoryConfig, RepositoryConfigEnabledAction, RepositoryConfig } from "./config-repository-type";
|
|
6
6
|
import type { TaskConfig } from "./config-task-type";
|
|
7
7
|
import type { DatatruckCronServerOptions } from "./cron-server";
|
|
8
|
+
import type { Job } from "./job";
|
|
8
9
|
import type { DatatruckRepositoryServerOptions } from "./repository-server";
|
|
9
10
|
export { RepositoryConfig, RepositoryConfigEnabledAction, TaskConfig };
|
|
10
11
|
export type Config = {
|
|
@@ -15,6 +16,9 @@ export type Config = {
|
|
|
15
16
|
repositories: RepositoryConfig[];
|
|
16
17
|
packages: PackageConfig[];
|
|
17
18
|
server?: DatatruckServerOptions;
|
|
19
|
+
jobs?: {
|
|
20
|
+
[name: string]: Job;
|
|
21
|
+
};
|
|
18
22
|
reports?: DatatruckReportConfig[];
|
|
19
23
|
prunePolicy?: DatatruckPolicyConfig;
|
|
20
24
|
};
|
|
@@ -1,44 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { PruneCommandOptions } from "../../commands/PruneCommand";
|
|
4
|
-
export type CronScheduleObject = {
|
|
5
|
-
minute?: number | {
|
|
6
|
-
each: number;
|
|
7
|
-
};
|
|
8
|
-
hour?: number | {
|
|
9
|
-
each: number;
|
|
10
|
-
};
|
|
11
|
-
day?: number | {
|
|
12
|
-
each: number;
|
|
13
|
-
};
|
|
14
|
-
month?: number | {
|
|
15
|
-
each: number;
|
|
16
|
-
};
|
|
17
|
-
weekDay?: number | {
|
|
18
|
-
each: number;
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
export type CronAction = {
|
|
22
|
-
schedule: string | CronScheduleObject;
|
|
23
|
-
} & ({
|
|
24
|
-
name: "backup";
|
|
25
|
-
options: BackupCommandOptions;
|
|
26
|
-
} | {
|
|
27
|
-
name: "copy";
|
|
28
|
-
options: CopyCommandOptions;
|
|
29
|
-
} | {
|
|
30
|
-
name: "prune";
|
|
31
|
-
options: Omit<PruneCommandOptions, "confirm">;
|
|
32
|
-
});
|
|
1
|
+
import { JobConfig } from "./job";
|
|
2
|
+
export declare const defaultsLogPath: string;
|
|
33
3
|
export type DatatruckCronServerOptions = {
|
|
34
4
|
enabled?: boolean;
|
|
35
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @default '/var/logs/datatruck'
|
|
7
|
+
*/
|
|
8
|
+
logPath?: string | boolean;
|
|
36
9
|
};
|
|
37
|
-
export declare function createCronServer(options:
|
|
38
|
-
log: boolean;
|
|
39
|
-
verbose: boolean;
|
|
40
|
-
configPath: string;
|
|
41
|
-
}): {
|
|
10
|
+
export declare function createCronServer(options: JobConfig): Promise<{
|
|
42
11
|
start: () => void;
|
|
43
12
|
stop: () => void;
|
|
44
|
-
}
|
|
13
|
+
}>;
|
|
@@ -1,89 +1,67 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createCronServer = void 0;
|
|
3
|
+
exports.createCronServer = exports.defaultsLogPath = void 0;
|
|
4
4
|
const ConfigAction_1 = require("../../actions/ConfigAction");
|
|
5
|
-
const async_process_1 = require("../async-process");
|
|
6
5
|
const cli_1 = require("../cli");
|
|
7
6
|
const cron_1 = require("../cron");
|
|
8
7
|
const string_1 = require("../string");
|
|
9
8
|
const watcher_1 = require("../watcher");
|
|
10
|
-
const
|
|
9
|
+
const job_1 = require("./job");
|
|
11
10
|
const croner_1 = require("croner");
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
const os_1 = require("os");
|
|
12
|
+
const path_1 = require("path");
|
|
13
|
+
exports.defaultsLogPath = (0, os_1.platform)() === "win32"
|
|
14
|
+
? (0, path_1.join)(process.env.APPDATA ?? `${process.env.HOMEDRIVE ?? "C:"}\\ProgramData`, "datatruck\\logs")
|
|
15
|
+
: "/var/logs/datatruck";
|
|
16
|
+
function createCrons(jobs, options) {
|
|
17
|
+
const crons = [];
|
|
18
|
+
for (const name in jobs) {
|
|
19
|
+
const job = jobs[name];
|
|
20
|
+
if (job.schedule)
|
|
21
|
+
crons.push((0, croner_1.Cron)(typeof job.schedule === "string"
|
|
22
|
+
? job.schedule
|
|
23
|
+
: (0, cron_1.formatCronScheduleObject)(job.schedule), {
|
|
24
|
+
paused: true,
|
|
25
|
+
context: name,
|
|
26
|
+
catch: true,
|
|
27
|
+
protect: true,
|
|
28
|
+
}, () => (0, job_1.runJob)(job, name, options)));
|
|
24
29
|
}
|
|
25
|
-
return
|
|
30
|
+
return crons;
|
|
26
31
|
}
|
|
27
|
-
function createCronServer(options
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const command = new Command({ config: { packages: [], repositories: [] } }, {});
|
|
33
|
-
const cliOptions = (0, cli_1.stringifyOptions)(command.optionsConfig(), action.name === "prune"
|
|
34
|
-
? ({ ...action.options, confirm: true })
|
|
35
|
-
: action.options);
|
|
36
|
-
const [node, bin] = process.argv;
|
|
37
|
-
const p = new async_process_1.AsyncProcess(node, [
|
|
38
|
-
process.env.pm_exec_path ?? bin,
|
|
39
|
-
"-c",
|
|
40
|
-
config.configPath,
|
|
41
|
-
action.name,
|
|
42
|
-
...cliOptions,
|
|
43
|
-
], { $log: config.verbose, $exitCode: false });
|
|
44
|
-
pid = p.child.pid || 0;
|
|
45
|
-
if (config.log)
|
|
46
|
-
(0, cli_1.logJson)("cron-server", `${action.name} started`, { pid });
|
|
47
|
-
const exitCode = await p.waitForClose();
|
|
48
|
-
if (config.log)
|
|
49
|
-
(0, cli_1.logJson)("cron-server", `${action.name} finished`, { pid, exitCode });
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
if (config.log)
|
|
53
|
-
(0, cli_1.logJson)("cron-server", `${action.name} failed`, { pid });
|
|
54
|
-
console.error(error);
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
let jobs = createJobs(options.actions || [], worker);
|
|
32
|
+
async function createCronServer(options) {
|
|
33
|
+
const config = await ConfigAction_1.ConfigAction.fromGlobalOptions({
|
|
34
|
+
config: options.configPath,
|
|
35
|
+
});
|
|
36
|
+
let crons = createCrons(config.jobs || {}, options);
|
|
58
37
|
const watcher = (0, watcher_1.createWatcher)({
|
|
59
|
-
onRead: () => ConfigAction_1.ConfigAction.findAndParseFile(
|
|
38
|
+
onRead: () => ConfigAction_1.ConfigAction.findAndParseFile(options.configPath),
|
|
60
39
|
onCheck: (prev, current) => (0, string_1.compareJsons)(prev, current),
|
|
61
40
|
onError: (error) => {
|
|
62
|
-
if (
|
|
41
|
+
if (options.log) {
|
|
63
42
|
(0, cli_1.logJson)("cron-server", "job update error");
|
|
64
43
|
console.error(error);
|
|
65
44
|
}
|
|
66
45
|
},
|
|
67
46
|
onChange: (data) => {
|
|
68
|
-
if (
|
|
47
|
+
if (options.log)
|
|
69
48
|
(0, cli_1.logJson)("cron-server", "jobs updated");
|
|
70
49
|
handler.stop();
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
jobs = enabled ? createJobs(cron?.actions || [], worker) : [];
|
|
50
|
+
const enabled = data?.server?.cron?.enabled ?? true;
|
|
51
|
+
crons = enabled ? createCrons(data?.jobs || {}, options) : [];
|
|
74
52
|
handler.start();
|
|
75
53
|
},
|
|
76
54
|
});
|
|
77
55
|
const handler = {
|
|
78
56
|
start: () => {
|
|
79
|
-
for (const
|
|
80
|
-
|
|
57
|
+
for (const cron of crons)
|
|
58
|
+
cron.resume();
|
|
81
59
|
watcher.start();
|
|
82
60
|
},
|
|
83
61
|
stop: () => {
|
|
84
62
|
watcher.stop();
|
|
85
|
-
for (const
|
|
86
|
-
|
|
63
|
+
for (const cron of crons)
|
|
64
|
+
cron.stop();
|
|
87
65
|
},
|
|
88
66
|
};
|
|
89
67
|
return handler;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { BackupCommandOptions } from "../../commands/BackupCommand";
|
|
2
|
+
import { CopyCommandOptions } from "../../commands/CopyCommand";
|
|
3
|
+
import { PruneCommandOptions } from "../../commands/PruneCommand";
|
|
4
|
+
export type JobScheduleObject = {
|
|
5
|
+
minute?: number | {
|
|
6
|
+
each: number;
|
|
7
|
+
};
|
|
8
|
+
hour?: number | {
|
|
9
|
+
each: number;
|
|
10
|
+
};
|
|
11
|
+
day?: number | {
|
|
12
|
+
each: number;
|
|
13
|
+
};
|
|
14
|
+
month?: number | {
|
|
15
|
+
each: number;
|
|
16
|
+
};
|
|
17
|
+
weekDay?: number | {
|
|
18
|
+
each: number;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export type JobAction = {
|
|
22
|
+
action: "backup";
|
|
23
|
+
options: BackupCommandOptions;
|
|
24
|
+
} | {
|
|
25
|
+
action: "copy";
|
|
26
|
+
options: CopyCommandOptions;
|
|
27
|
+
} | {
|
|
28
|
+
action: "prune";
|
|
29
|
+
options: Omit<PruneCommandOptions, "confirm">;
|
|
30
|
+
};
|
|
31
|
+
export type JobSchedule = string | JobScheduleObject;
|
|
32
|
+
export type Job = JobAction & {
|
|
33
|
+
schedule?: JobSchedule;
|
|
34
|
+
};
|
|
35
|
+
export type JobConfig = {
|
|
36
|
+
log: boolean;
|
|
37
|
+
logPath: string | boolean | undefined;
|
|
38
|
+
verbose: boolean;
|
|
39
|
+
configPath: string;
|
|
40
|
+
};
|
|
41
|
+
export declare function runJob(job: Job, name: string, config: JobConfig): Promise<void>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runJob = void 0;
|
|
4
|
+
const async_process_1 = require("../async-process");
|
|
5
|
+
const cli_1 = require("../cli");
|
|
6
|
+
const fs_1 = require("../fs");
|
|
7
|
+
const command_1 = require("./command");
|
|
8
|
+
const cron_server_1 = require("./cron-server");
|
|
9
|
+
const fs_2 = require("fs");
|
|
10
|
+
const promises_1 = require("fs/promises");
|
|
11
|
+
const path_1 = require("path");
|
|
12
|
+
async function runJob(job, name, config) {
|
|
13
|
+
let pid = 0;
|
|
14
|
+
try {
|
|
15
|
+
const Command = command_1.datatruckCommandMap[job.action];
|
|
16
|
+
const command = new Command({ config: { packages: [], repositories: [] } }, {});
|
|
17
|
+
const cliOptions = (0, cli_1.stringifyOptions)(command.optionsConfig(), job.action === "prune"
|
|
18
|
+
? ({ ...job.options, confirm: true })
|
|
19
|
+
: job.options);
|
|
20
|
+
const [node, bin] = process.argv;
|
|
21
|
+
const baseLogPath = typeof config.logPath === "string"
|
|
22
|
+
? config.logPath
|
|
23
|
+
: config.logPath === true || config.logPath === undefined
|
|
24
|
+
? cron_server_1.defaultsLogPath
|
|
25
|
+
: config.logPath;
|
|
26
|
+
let stream;
|
|
27
|
+
let logPath;
|
|
28
|
+
const dt = new Date().toISOString().replaceAll(":", "-");
|
|
29
|
+
if (baseLogPath) {
|
|
30
|
+
const tmpLogPath = (0, path_1.join)(baseLogPath, dt) + ".log";
|
|
31
|
+
await (0, promises_1.mkdir)(baseLogPath, { recursive: true });
|
|
32
|
+
stream = (0, fs_2.createWriteStream)(tmpLogPath);
|
|
33
|
+
}
|
|
34
|
+
const p = new async_process_1.AsyncProcess(node, [
|
|
35
|
+
process.env.pm_exec_path ?? bin,
|
|
36
|
+
"--tty",
|
|
37
|
+
"false",
|
|
38
|
+
"--progress",
|
|
39
|
+
"interval:3000",
|
|
40
|
+
"-c",
|
|
41
|
+
config.configPath,
|
|
42
|
+
job.action,
|
|
43
|
+
...cliOptions,
|
|
44
|
+
], {
|
|
45
|
+
$log: config.verbose,
|
|
46
|
+
$exitCode: false,
|
|
47
|
+
env: {
|
|
48
|
+
...process.env,
|
|
49
|
+
COLUMNS: "160",
|
|
50
|
+
NO_COLOR: "1",
|
|
51
|
+
JOB_NAME: name,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
pid = p.child.pid || 0;
|
|
55
|
+
if (config.log)
|
|
56
|
+
(0, cli_1.logJson)("job", `'${name}' started`, { pid });
|
|
57
|
+
const [exitCode] = await Promise.all([
|
|
58
|
+
p.waitForClose(),
|
|
59
|
+
stream && p.stderr.pipe(stream),
|
|
60
|
+
stream && p.stdout.pipe(stream),
|
|
61
|
+
]);
|
|
62
|
+
if (stream)
|
|
63
|
+
await (0, fs_1.safeRename)(stream.path.toString(), (logPath = (0, path_1.join)(stream.path.toString(), `${dt}-${pid}.log`)));
|
|
64
|
+
if (config.log)
|
|
65
|
+
(0, cli_1.logJson)("job", `'${name}' finished`, {
|
|
66
|
+
pid,
|
|
67
|
+
exitCode,
|
|
68
|
+
...(logPath && { log: logPath }),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (config.log)
|
|
73
|
+
(0, cli_1.logJson)("job", `'${name}' failed`, { pid });
|
|
74
|
+
console.error(error);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.runJob = runJob;
|
|
@@ -42,7 +42,7 @@ function createReportListTasks(list, options) {
|
|
|
42
42
|
else if ((0, reportSteps_1.isReportStep)(report.run)) {
|
|
43
43
|
await (0, reportSteps_1.runReportSteps)(report.run, {
|
|
44
44
|
data: {
|
|
45
|
-
title: `[${options.hostname}] DTT ${options.action}`,
|
|
45
|
+
title: `[${options.hostname}] DTT ${process.env.JOB_NAME ?? options.action}`,
|
|
46
46
|
message,
|
|
47
47
|
success,
|
|
48
48
|
},
|
|
@@ -67,6 +67,7 @@ function createDatatruckRepositoryServer(inOptions, config = {}) {
|
|
|
67
67
|
let responseError;
|
|
68
68
|
req.on("error", (error) => (requestError = error));
|
|
69
69
|
res.on("error", (error) => (responseError = error));
|
|
70
|
+
res.setHeader("X-Accel-Buffering", "no");
|
|
70
71
|
try {
|
|
71
72
|
const { repository, action, params } = parseUrl(url);
|
|
72
73
|
if (!repository || !action)
|
|
@@ -93,7 +94,9 @@ function createDatatruckRepositoryServer(inOptions, config = {}) {
|
|
|
93
94
|
else if (action === "download") {
|
|
94
95
|
const [target] = params;
|
|
95
96
|
const path = fs.resolvePath(target);
|
|
96
|
-
await (0, http_1.sendFile)(req, res, path
|
|
97
|
+
await (0, http_1.sendFile)(req, res, path, {
|
|
98
|
+
contentLength: options.contentLength ?? true,
|
|
99
|
+
});
|
|
97
100
|
}
|
|
98
101
|
else if (action === "writeFile") {
|
|
99
102
|
const data = await (0, http_1.readRequestData)(req);
|
package/lib/utils/http.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export declare function fetchJson<T = any>(url: string, options?: RequestInit):
|
|
|
10
10
|
export declare function post(url: string, data: string, options?: Omit<RequestInit, "method" | "body">): Promise<Response>;
|
|
11
11
|
export declare function parseContentLength(value: string | undefined): number;
|
|
12
12
|
export declare function sendFile(req: IncomingMessage, res: ServerResponse, path: string, options?: {
|
|
13
|
+
contentLength?: boolean;
|
|
13
14
|
end?: boolean;
|
|
14
15
|
checksum?: boolean;
|
|
15
16
|
}): Promise<void>;
|
package/lib/utils/http.js
CHANGED
|
@@ -62,7 +62,7 @@ async function sendFile(req, res, path, options = {}) {
|
|
|
62
62
|
try {
|
|
63
63
|
file = (0, fs_1.createReadStream)(path);
|
|
64
64
|
const fileStat = await (0, promises_1.stat)(path);
|
|
65
|
-
res.setHeader("Content-Length", fileStat.size);
|
|
65
|
+
res.setHeader(options.contentLength ?? true ? "Content-Length" : "x-content-length", fileStat.size);
|
|
66
66
|
if (options.checksum)
|
|
67
67
|
res.setHeader("x-checksum", await (0, crypto_1.calcFileHash)(path, "sha1"));
|
|
68
68
|
file.pipe(res);
|
|
@@ -111,7 +111,9 @@ async function downloadFile(url, output, options = {}) {
|
|
|
111
111
|
...fetchOptions,
|
|
112
112
|
signal: AbortSignal.timeout(timeout ?? 3600 * 1000), // 60m
|
|
113
113
|
});
|
|
114
|
-
length.total = parseContentLength(res.headers.get("content-length") ??
|
|
114
|
+
length.total = parseContentLength(res.headers.get("content-length") ??
|
|
115
|
+
res.headers.get("x-content-length") ??
|
|
116
|
+
undefined);
|
|
115
117
|
checksum = res.headers.get("x-checksum") ?? undefined;
|
|
116
118
|
const body = stream_1.Readable.fromWeb(res.body);
|
|
117
119
|
const progress = onProgress &&
|
package/lib/utils/list.d.ts
CHANGED
|
@@ -63,6 +63,11 @@ export declare class Listr3<T extends Listr3Context> extends Listr<void, "defaul
|
|
|
63
63
|
getSummaryResult(): List3SummaryResult;
|
|
64
64
|
getResult(): (List3SummaryResult | Listr3TaskResult<T>)[];
|
|
65
65
|
protected release(): void;
|
|
66
|
+
execAndParse(verbose: boolean | undefined): Promise<{
|
|
67
|
+
result: (List3SummaryResult | Listr3TaskResult<T>)[];
|
|
68
|
+
exitCode: number;
|
|
69
|
+
errors: Error[];
|
|
70
|
+
}>;
|
|
66
71
|
exec(): Promise<(Listr3TaskResult<T> | List3SummaryResult)[]>;
|
|
67
72
|
}
|
|
68
73
|
export {};
|