@datatruck/cli 0.39.0 → 0.39.1

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.
@@ -31,12 +31,11 @@ class RunCommand extends CommandAbstract_1.CommandAbstract {
31
31
  console.error(`error: missing required argument 'jobName' (values: ${jobNames.join(", ")})`);
32
32
  return { exitCode: 1 };
33
33
  }
34
- await (0, job_1.runJob)(job, jobName, {
34
+ const exitCode = await (0, job_1.runJob)(job, jobName, {
35
35
  verbose: verbose,
36
36
  configPath: config.path,
37
- log: "inherit",
38
37
  });
39
- return { exitCode: 0 };
38
+ return { exitCode };
40
39
  }
41
40
  }
42
41
  exports.RunCommand = RunCommand;
@@ -160,7 +160,7 @@ class MariadbTask extends TaskAbstract_1.TaskAbstract {
160
160
  const reloadFiles = async (data = {}) => {
161
161
  if (data.removeFile)
162
162
  removeFiles.push(data.removeFile);
163
- return (files = (await (0, fs_1.readDir)(snapshotPath)).filter((v) => !removeFiles.includes(v)));
163
+ return (files = (await (0, fs_1.safeReaddir)(snapshotPath)).filter((v) => !removeFiles.includes(v)));
164
164
  };
165
165
  await reloadFiles();
166
166
  const absolute = {
@@ -66,7 +66,7 @@ class MssqlTask extends TaskAbstract_1.TaskAbstract {
66
66
  async restore(data) {
67
67
  this.verbose = data.options.verbose;
68
68
  const snapshotPath = data.snapshotPath;
69
- const files = await (0, fs_1.readDir)(snapshotPath);
69
+ const files = await (0, fs_1.safeReaddir)(snapshotPath);
70
70
  for (const file of files) {
71
71
  if (!file.endsWith(MssqlTask.SUFFIX))
72
72
  continue;
@@ -255,7 +255,7 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
255
255
  ...params,
256
256
  database: database.name,
257
257
  });
258
- const [files, compressed] = (0, fs_1.groupFiles)(await (0, fs_1.readDir)(snapshotPath), Object.values(suffix));
258
+ const [files, compressed] = (0, fs_1.groupFiles)(await (0, fs_1.safeReaddir)(snapshotPath), Object.values(suffix));
259
259
  // Database check
260
260
  if (files.some((f) => f.endsWith(suffix.database)) &&
261
261
  !(await sql.isDatabaseEmpty(database.name)))
@@ -168,7 +168,7 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
168
168
  database: database.name,
169
169
  });
170
170
  }
171
- const items = (await (0, fs_1.readDir)(snapshotPath))
171
+ const items = (await (0, fs_1.safeReaddir)(snapshotPath))
172
172
  .map(parseSqlFile)
173
173
  .filter((v) => !!v);
174
174
  // Database check
@@ -21,7 +21,7 @@ function createCrons(jobs, options) {
21
21
  context: name,
22
22
  catch: true,
23
23
  protect: true,
24
- }, () => (0, job_1.runJob)(job, name, options)));
24
+ }, () => (0, job_1.runCronJob)(job, name, options)));
25
25
  }
26
26
  return crons;
27
27
  }
@@ -34,8 +34,10 @@ export type Job = JobAction & {
34
34
  schedule?: JobSchedule;
35
35
  };
36
36
  export type JobConfig = {
37
- log: DatatruckCronServerOptions["log"] | "inherit";
37
+ log: DatatruckCronServerOptions["log"];
38
38
  verbose: boolean;
39
39
  configPath: string;
40
40
  };
41
- export declare function runJob(job: Job, name: string, config: JobConfig): Promise<void>;
41
+ export declare function getJobCliOptions(job: Job): string[];
42
+ export declare function runJob(job: Job, name: string, config: Omit<JobConfig, "log">): Promise<number>;
43
+ export declare function runCronJob(job: Job, name: string, config: JobConfig): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.runJob = void 0;
3
+ exports.runCronJob = exports.runJob = exports.getJobCliOptions = void 0;
4
4
  const async_process_1 = require("../async-process");
5
5
  const cli_1 = require("../cli");
6
6
  const fs_1 = require("../fs");
@@ -17,26 +17,46 @@ async function createJobLog(config, name) {
17
17
  const tmpLogPath = (0, path_1.join)(dir, `${dt}_${name}.tmp.log`);
18
18
  await (0, promises_1.mkdir)(dir, { recursive: true });
19
19
  return {
20
- type: "file",
21
20
  dt,
22
21
  dir,
23
22
  stream: (0, fs_2.createWriteStream)(tmpLogPath),
24
23
  };
25
24
  }
26
- else if (config === "inherit") {
27
- return {
28
- type: "inherit",
29
- };
30
- }
31
25
  }
26
+ function getJobCliOptions(job) {
27
+ const Command = command_1.datatruckCommands[job.action];
28
+ const command = new Command({ config: { packages: [], repositories: [] } }, {});
29
+ return (0, options_1.stringifyOptions)(command.optionsConfig, job.action === "prune"
30
+ ? ({ ...job.options, confirm: true })
31
+ : job.options);
32
+ }
33
+ exports.getJobCliOptions = getJobCliOptions;
32
34
  async function runJob(job, name, config) {
35
+ const cliOptions = getJobCliOptions(job);
36
+ const [node, bin] = process.argv;
37
+ return await async_process_1.AsyncProcess.exec(node, [
38
+ process.env.DTT_BIN_SCRIPT ?? process.env.pm_exec_path ?? bin,
39
+ "-c",
40
+ config.configPath,
41
+ job.action,
42
+ ...cliOptions,
43
+ ...(config.verbose ? ["-v"] : []),
44
+ ], {
45
+ $exitCode: false,
46
+ $log: { exec: config.verbose },
47
+ env: {
48
+ ...process.env,
49
+ JOB_NAME: name,
50
+ },
51
+ stdio: "inherit",
52
+ });
53
+ }
54
+ exports.runJob = runJob;
55
+ async function runCronJob(job, name, config) {
33
56
  let pid = 0;
34
57
  try {
35
- const Command = command_1.datatruckCommands[job.action];
36
- const command = new Command({ config: { packages: [], repositories: [] } }, {});
37
- const cliOptions = (0, options_1.stringifyOptions)(command.optionsConfig, job.action === "prune"
38
- ? ({ ...job.options, confirm: true })
39
- : job.options);
58
+ const log = await createJobLog(config.log, name);
59
+ const cliOptions = getJobCliOptions(job);
40
60
  const [node, bin] = process.argv;
41
61
  const argv = [
42
62
  process.env.DTT_BIN_SCRIPT ?? process.env.pm_exec_path ?? bin,
@@ -49,24 +69,20 @@ async function runJob(job, name, config) {
49
69
  job.action,
50
70
  ...cliOptions,
51
71
  ];
52
- const log = await createJobLog(config.log, name);
53
- if (log?.type === "file")
54
- log.stream.write(`+ dtt ${argv.join(" ")}\n`);
72
+ log?.stream.write(`+ dtt ${argv.slice(1).join(" ")}\n`);
55
73
  const p = new async_process_1.AsyncProcess(node, argv, {
56
74
  $log: config.verbose,
57
75
  $exitCode: false,
58
76
  env: {
59
77
  ...process.env,
78
+ JOB_NAME: name,
60
79
  COLUMNS: "160",
61
80
  NO_COLOR: "1",
62
- JOB_NAME: name,
63
81
  },
64
- ...(log?.type === "inherit" && {
65
- stdio: "inherit",
66
- }),
67
82
  });
68
83
  pid = p.child.pid || 0;
69
- (0, cli_1.logJson)("job", `'${name}' started`, { pid });
84
+ if (log)
85
+ (0, cli_1.logJson)("job", `'${name}' started`, { pid });
70
86
  const [exitCode] = await Promise.all([
71
87
  p.waitForClose(),
72
88
  ...(log?.stream
@@ -74,21 +90,17 @@ async function runJob(job, name, config) {
74
90
  : []),
75
91
  ]);
76
92
  let logData = {};
77
- if (log?.stream) {
78
- const base = (0, path_1.dirname)(log?.stream.path.toString());
93
+ if (log) {
94
+ const base = (0, path_1.dirname)(log.stream.path.toString());
79
95
  const logPath = (0, path_1.join)(base, `${log.dt}_${name}_${pid}.log`);
80
96
  await (0, fs_1.safeRename)(log?.stream.path.toString(), logPath);
81
97
  logData["log"] = logPath;
82
98
  }
83
- (0, cli_1.logJson)("job", `'${name}' finished`, {
84
- pid,
85
- exitCode,
86
- ...logData,
87
- });
99
+ (0, cli_1.logJson)("job", `'${name}' finished`, { pid, exitCode, ...logData });
88
100
  }
89
101
  catch (error) {
90
102
  (0, cli_1.logJson)("job", `'${name}' failed`, { pid });
91
103
  console.error(error);
92
104
  }
93
105
  }
94
- exports.runJob = runJob;
106
+ exports.runCronJob = runCronJob;
package/lib/utils/fs.d.ts CHANGED
@@ -28,7 +28,8 @@ export declare function parsePackageFile(): {
28
28
  export declare function findFile(sourcePath: string, baseName: string, extensions: string[], errorMessage?: string): Promise<string>;
29
29
  export declare function fastFolderSizeAsync(path: string): Promise<number>;
30
30
  export declare function readPartialFile(path: string, positions: [number, number?]): Promise<string>;
31
- export declare function readDir(path: string, optional?: boolean): Promise<string[]>;
31
+ export declare function safeReaddir(path: string): Promise<string[]>;
32
+ export declare function tryReaddir(path: string): Promise<string[]>;
32
33
  export declare function forEachFile(dirPath: string, cb: (path: string, dir: boolean) => void, includeDir?: boolean): Promise<void>;
33
34
  /**
34
35
  * @experimental
package/lib/utils/fs.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.asFile = exports.groupFiles = exports.ensureFreeDiskSpace = exports.checkFreeDiskSpace = exports.fetchDiskStats = exports.initEmptyDir = exports.tryRm = exports.safeRename = exports.fetchData = exports.countFileLines = exports.createWriteStreamPool = exports.createFileScanner = exports.createProgress = exports.cpy = exports.readTextFile = exports.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.readPartialFile = exports.fastFolderSizeAsync = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.include = exports.parseFileExtensions = exports.writeJSONFile = exports.existsFile = exports.existsDir = exports.safeStat = exports.ensureExistsDir = exports.ensureSingleFile = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isLocalDir = exports.isEmptyDir = exports.isWSLSystem = void 0;
6
+ exports.asFile = exports.groupFiles = exports.ensureFreeDiskSpace = exports.checkFreeDiskSpace = exports.fetchDiskStats = exports.initEmptyDir = exports.tryRm = exports.safeRename = exports.fetchData = exports.countFileLines = exports.createWriteStreamPool = exports.createFileScanner = exports.createProgress = exports.cpy = exports.readTextFile = exports.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.tryReaddir = exports.safeReaddir = exports.readPartialFile = exports.fastFolderSizeAsync = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.include = exports.parseFileExtensions = exports.writeJSONFile = exports.existsFile = exports.existsDir = exports.safeStat = exports.ensureExistsDir = exports.ensureSingleFile = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isLocalDir = exports.isEmptyDir = exports.isWSLSystem = void 0;
7
7
  const pkg_1 = require("../pkg");
8
8
  const bytes_1 = require("./bytes");
9
9
  const error_1 = require("./error");
@@ -58,7 +58,7 @@ async function ensureEmptyDir(path) {
58
58
  }
59
59
  exports.ensureEmptyDir = ensureEmptyDir;
60
60
  async function ensureSingleFile(path) {
61
- const files = await readDir(path);
61
+ const files = await safeReaddir(path);
62
62
  if (files.length !== 1)
63
63
  throw new error_1.AppError(`Dir has not one file: ${files.length}`);
64
64
  const [file] = files;
@@ -171,15 +171,13 @@ async function readPartialFile(path, positions) {
171
171
  });
172
172
  }
173
173
  exports.readPartialFile = readPartialFile;
174
- async function readDir(path, optional) {
174
+ async function safeReaddir(path) {
175
175
  try {
176
176
  return await (0, promises_1.readdir)(path);
177
177
  }
178
178
  catch (anyError) {
179
179
  const nodeError = anyError;
180
180
  if (nodeError.code === "ENOENT") {
181
- if (optional)
182
- return [];
183
181
  const error = new Error(nodeError.message);
184
182
  error.code = nodeError.code;
185
183
  error.errno = nodeError.errno;
@@ -189,9 +187,20 @@ async function readDir(path, optional) {
189
187
  throw anyError;
190
188
  }
191
189
  }
192
- exports.readDir = readDir;
190
+ exports.safeReaddir = safeReaddir;
191
+ async function tryReaddir(path) {
192
+ try {
193
+ return await safeReaddir(path);
194
+ }
195
+ catch (error) {
196
+ if (error.code === "ENOENT")
197
+ return [];
198
+ throw error;
199
+ }
200
+ }
201
+ exports.tryReaddir = tryReaddir;
193
202
  async function forEachFile(dirPath, cb, includeDir) {
194
- const files = await readDir(dirPath);
203
+ const files = await safeReaddir(dirPath);
195
204
  for (const file of files) {
196
205
  const filePath = (0, path_1.join)(dirPath, file);
197
206
  if ((await (0, promises_1.stat)(filePath)).isDirectory()) {
package/lib/utils/git.js CHANGED
@@ -23,7 +23,7 @@ class Git {
23
23
  }
24
24
  async canBeInit(repo) {
25
25
  return ((0, fs_1.isLocalDir)(repo) &&
26
- (!(await (0, fs_1.existsDir)(repo)) || !(await (0, fs_1.readDir)(repo)).length));
26
+ (!(await (0, fs_1.existsDir)(repo)) || !(await (0, fs_1.safeReaddir)(repo)).length));
27
27
  }
28
28
  async clone(options) {
29
29
  await this.exec([
package/lib/utils/logs.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.removeOldLogs = exports.defaultsLogPath = exports.maxAgeToMS = void 0;
4
+ const fs_1 = require("./fs");
4
5
  const promises_1 = require("fs/promises");
5
6
  const os_1 = require("os");
6
7
  const path_1 = require("path");
@@ -29,7 +30,7 @@ async function removeOldLogs(path, inMaxAge) {
29
30
  const hasMaxAge = Object.values(inMaxAge).some((v) => typeof v === "number");
30
31
  if (!hasMaxAge)
31
32
  return [];
32
- const files = (await (0, promises_1.readdir)(path)).filter((file) => file.endsWith(".log"));
33
+ const files = (await (0, fs_1.tryReaddir)(path)).filter((file) => file.endsWith(".log"));
33
34
  const now = Date.now();
34
35
  const paths = [];
35
36
  for (const file of files) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datatruck/cli",
3
- "version": "0.39.0",
3
+ "version": "0.39.1",
4
4
  "description": "Tool for creating and managing backups",
5
5
  "homepage": "https://github.com/swordev/datatruck#readme",
6
6
  "bugs": {