@datatruck/cli 0.28.0 → 0.29.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.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PruneAction = void 0;
4
4
  const RepositoryFactory_1 = require("../Factory/RepositoryFactory");
5
5
  const snapshot_1 = require("../utils/datatruck/snapshot");
6
+ const date_1 = require("../utils/date");
6
7
  const object_1 = require("../utils/object");
7
8
  const SnapshotsAction_1 = require("./SnapshotsAction");
8
9
  class PruneAction {
@@ -36,43 +37,28 @@ class PruneAction {
36
37
  });
37
38
  const snapshots = await snapshotsAction.exec("prune");
38
39
  const snapshotsDeleted = [];
39
- const reasons = {};
40
- const idFilter = {
41
- id: this.options.ids,
42
- };
43
- const keepFilter = {
44
- last: this.options.keepLast,
45
- lastMinutely: this.options.keepMinutely,
46
- lastHourly: this.options.keepHourly,
47
- lastDaily: this.options.keepDaily,
48
- lastMonthly: this.options.keepMonthly,
49
- lastWeekly: this.options.keepWeekly,
50
- lastYearly: this.options.keepYearly,
51
- };
52
- const hasIdFilter = Object.values(idFilter).some((v) => typeof v !== "undefined");
53
- const hasKeepFilter = Object.values(keepFilter).some((v) => typeof v !== "undefined");
40
+ const hasIdFilter = typeof this.options.ids !== "undefined";
41
+ const keepFilter = (0, date_1.createFilterByLastOptions)(this.options);
42
+ const hasKeepFilter = Object.values(keepFilter).some((v) => typeof v === "number");
54
43
  if (hasIdFilter && hasKeepFilter)
55
44
  throw new Error(`Snapshot id filter can not be used with 'keep' filters`);
56
- const usePrunePolicyConfig = !hasKeepFilter && this.options.groupBy?.includes("packageName");
45
+ const prunePolicy = !hasIdFilter && !hasKeepFilter;
46
+ if (prunePolicy && !this.options.groupBy?.includes("packageName"))
47
+ throw new Error(`Policy config requires groupBy packageName`);
57
48
  const keepSnapshots = hasKeepFilter
58
- ? (0, snapshot_1.groupAndFilter)(snapshots, this.options.groupBy, usePrunePolicyConfig
59
- ? (groupedSnapshots) => {
60
- const [firstSnapshot] = groupedSnapshots;
61
- const packageName = firstSnapshot.packageName;
49
+ ? (0, snapshot_1.groupAndFilter)(snapshots, this.options.groupBy, keepFilter)
50
+ : prunePolicy
51
+ ? (0, snapshot_1.groupAndFilter)(snapshots, this.options.groupBy, (groups) => {
52
+ const [snapshot] = groups;
53
+ const packageName = snapshot.packageName;
62
54
  const config = this.config.packages.find((pkg) => pkg.name === packageName);
63
- const prunePolicy = config?.prunePolicy ?? {};
64
- return {
65
- last: prunePolicy.keepLast,
66
- lastMinutely: prunePolicy.keepMinutely,
67
- lastHourly: prunePolicy.keepHourly,
68
- lastDaily: prunePolicy.keepDaily,
69
- lastMonthly: prunePolicy.keepMonthly,
70
- lastWeekly: prunePolicy.keepWeekly,
71
- lastYearly: prunePolicy.keepYearly,
72
- };
73
- }
74
- : keepFilter, reasons)
75
- : [];
55
+ const prunePolicy = config?.prunePolicy ?? this.config.prunePolicy ?? {};
56
+ const hasPrunePolicy = Object.values(prunePolicy).some((v) => typeof v === "number");
57
+ return hasPrunePolicy
58
+ ? (0, date_1.createFilterByLastOptions)(prunePolicy)
59
+ : "no-policy";
60
+ })
61
+ : [];
76
62
  const result = {
77
63
  total: snapshots.length,
78
64
  prune: 0,
@@ -80,13 +66,14 @@ class PruneAction {
80
66
  };
81
67
  let snapshotIndex = 0;
82
68
  for (const snapshot of snapshots) {
83
- const prune = !keepSnapshots.includes(snapshot);
69
+ const keepSnapshot = keepSnapshots.find(({ item }) => item === snapshot);
70
+ const prune = !keepSnapshot;
84
71
  if (prune)
85
72
  result.prune++;
86
73
  if (prune || this.options.returnsAll)
87
74
  snapshotsDeleted.push({
88
75
  ...snapshot,
89
- exclusionReasons: reasons[snapshotIndex],
76
+ exclusionReasons: keepSnapshot?.reasons || [],
90
77
  });
91
78
  snapshotIndex++;
92
79
  }
@@ -17,7 +17,7 @@ export type RestoreActionOptions = {
17
17
  repositoryNames?: string[];
18
18
  repositoryTypes?: string[];
19
19
  verbose?: boolean;
20
- restorePath?: boolean;
20
+ initial?: boolean;
21
21
  tty?: "auto" | boolean;
22
22
  progress?: "auto" | "interval" | boolean;
23
23
  progressInterval?: number;
@@ -69,7 +69,7 @@ class RestoreAction {
69
69
  let { snapshot, pkg, task } = data;
70
70
  const repoConfig = (0, config_1.findRepositoryOrFail)(this.config, snapshot.repositoryName);
71
71
  const repo = (0, RepositoryFactory_1.createRepo)(repoConfig);
72
- if (!this.options.restorePath)
72
+ if (this.options.initial)
73
73
  pkg = { ...pkg, restorePath: pkg.path };
74
74
  let snapshotPath = pkg.restorePath ?? pkg.path;
75
75
  await data.gc.cleanupIfFail(async () => {
@@ -101,7 +101,7 @@ class RestoreAction {
101
101
  let title = item.key.slice(0, 1).toUpperCase() + item.key.slice(1);
102
102
  return item.key === "restore" && color ? chalk_1.default.cyan(title) : title;
103
103
  };
104
- const renderData = (item, color) => {
104
+ const renderData = (item, color, result = []) => {
105
105
  const g = (v) => (color ? `${chalk_1.default.gray(`(${v})`)}` : `(${v})`);
106
106
  return item.key === "snapshots"
107
107
  ? `${item.data.id.slice(0, 8)} ${g(`${item.data.packages} packages`)}`
@@ -109,7 +109,13 @@ class RestoreAction {
109
109
  ? `${item.data.packageName} ${g(item.data.taskName)}`
110
110
  : item.key === "restore"
111
111
  ? `${item.data.packageName} ${g(item.data.repositoryName)}`
112
- : "";
112
+ : item.key === "summary"
113
+ ? (0, cli_1.renderObject)({
114
+ errors: item.data.errors,
115
+ restores: result.filter((r) => !r.error && r.key === "restore")
116
+ .length,
117
+ })
118
+ : "";
113
119
  };
114
120
  return new DataFormat_1.DataFormat({
115
121
  streams: options.streams,
@@ -123,11 +129,11 @@ class RestoreAction {
123
129
  { value: "Error", width: 50 },
124
130
  ],
125
131
  rows: () => result.map((item) => [
126
- (0, cli_1.resultColumn)(item.error),
132
+ (0, cli_1.renderResult)(item.error),
127
133
  renderTitle(item, true),
128
- renderData(item, true),
134
+ renderData(item, true, result),
129
135
  (0, date_1.duration)(item.elapsed),
130
- (0, cli_1.errorColumn)(item.error, options.verbose),
136
+ (0, cli_1.renderError)(item.error, options.verbose),
131
137
  ]),
132
138
  },
133
139
  });
@@ -173,10 +179,10 @@ class RestoreAction {
173
179
  keyIndex: snapshot.packageName,
174
180
  data: snapshot,
175
181
  title: {
176
- initial: `Restore ${snapshot.packageName} snapshot`,
177
- started: `Restoring ${snapshot.packageName} snapshot`,
178
- completed: `Snapshot restored: ${snapshot.packageName}`,
179
- failed: `Snapshot restore failed: ${snapshot.packageName}`,
182
+ initial: `Restore snapshot: ${snapshot.packageName} (${snapshot.repositoryName})`,
183
+ started: `Restoring snapshot: ${snapshot.packageName} (${snapshot.repositoryName})`,
184
+ completed: `Snapshot restored: ${snapshot.packageName} (${snapshot.repositoryName})`,
185
+ failed: `Snapshot restore failed: ${snapshot.packageName} (${snapshot.repositoryName})`,
180
186
  },
181
187
  exitOnError: false,
182
188
  run: async (listTask) => {
@@ -201,10 +207,10 @@ class RestoreAction {
201
207
  keyIndex: pkg.name,
202
208
  data: { taskName: pkg.task.name, packageName: pkg.name },
203
209
  title: {
204
- initial: `Execute ${pkg.task?.name} task`,
205
- started: `Executing ${pkg.task?.name} task`,
206
- completed: `Task executed: ${pkg.task?.name}`,
207
- failed: `Task execute failed: ${pkg.task?.name}`,
210
+ initial: `Execute task: ${pkg.name} (${pkg.task.name})`,
211
+ started: `Executing task: ${pkg.name} (${pkg.task.name})`,
212
+ completed: `Task executed: ${pkg.name} (${pkg.task.name})`,
213
+ failed: `Task execute failed: ${pkg.name} (${pkg.task.name})`,
208
214
  },
209
215
  exitOnError: false,
210
216
  runWrapper: gc.cleanup.bind(gc),
@@ -44,7 +44,7 @@ class SnapshotsAction {
44
44
  result.push(...extentedItems);
45
45
  }
46
46
  result = result.sort((a, b) => b.date.localeCompare(a.date));
47
- return (0, snapshot_1.groupAndFilter)(result, this.options.groupBy, this.options);
47
+ return (0, snapshot_1.groupAndFilter)(result, this.options.groupBy, this.options).map(({ item }) => item);
48
48
  }
49
49
  }
50
50
  exports.SnapshotsAction = SnapshotsAction;
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # @datatruck/cli
2
2
 
3
+ ## 0.29.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`34900c5`](https://github.com/swordev/datatruck/commit/34900c5ba9f323d491f2f6865c566386a4812c08) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix texts
8
+
9
+ ## 0.29.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [`363fc0d`](https://github.com/swordev/datatruck/commit/363fc0d8158aba6ae6a171769ef01dcd0fd2de08) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `--prune` option to the backup command
14
+
15
+ - [`e47ed46`](https://github.com/swordev/datatruck/commit/e47ed46c47fc93d7d5f3b76935d425c6b42ae9a5) Thanks [@juanrgm](https://github.com/juanrgm)! - Add `--last` option to the copy command
16
+
17
+ - [`0a760a2`](https://github.com/swordev/datatruck/commit/0a760a2038ff77966936b3a9a0a8e865f4dae4c4) Thanks [@juanrgm](https://github.com/juanrgm)! - Add global prune policy to the config
18
+
19
+ ### Patch Changes
20
+
21
+ - [`1c5084d`](https://github.com/swordev/datatruck/commit/1c5084dab2058ab9699f1a908f2581cd03da0468) Thanks [@juanrgm](https://github.com/juanrgm)! - Rename `--no-restore-path` to `--initial`
22
+
23
+ - [`5fe3e91`](https://github.com/swordev/datatruck/commit/5fe3e91e994238cf901e570c9b9ef8254d79afa1) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix prune policy
24
+
25
+ - [`bd4d42e`](https://github.com/swordev/datatruck/commit/bd4d42e0261f79bdb69dd55abc30ef8bb0bfdcd7) Thanks [@juanrgm](https://github.com/juanrgm)! - Fix reports
26
+
3
27
  ## 0.28.0
4
28
 
5
29
  ### Minor Changes
@@ -10,6 +10,7 @@ export type BackupCommandOptions<TResolved = false> = {
10
10
  tag?: If<TResolved, string[]>;
11
11
  dryRun?: boolean;
12
12
  date?: string;
13
+ prune?: boolean;
13
14
  };
14
15
  export type BackupCommandResult = Unwrap<BackupAction["exec"]>;
15
16
  export declare class BackupCommand extends CommandAbstract<BackupCommandOptions<false>, BackupCommandOptions<true>> {
@@ -41,6 +41,10 @@ class BackupCommand extends CommandAbstract_1.CommandAbstract {
41
41
  description: "Date time (ISO)",
42
42
  option: "--date <value>",
43
43
  },
44
+ prune: {
45
+ description: "Prune backups",
46
+ option: "--prune",
47
+ },
44
48
  });
45
49
  }
46
50
  async onExec() {
@@ -59,6 +63,7 @@ class BackupCommand extends CommandAbstract_1.CommandAbstract {
59
63
  progress: this.globalOptions.progress,
60
64
  progressInterval: this.globalOptions.progressInterval,
61
65
  streams: this.streams,
66
+ prune: this.options.prune,
62
67
  });
63
68
  const result = await backup.exec();
64
69
  if (this.globalOptions.outputFormat)
@@ -2,7 +2,8 @@ import { CopyAction } from "../Action/CopyAction";
2
2
  import { If, Unwrap } from "../utils/ts";
3
3
  import { CommandAbstract } from "./CommandAbstract";
4
4
  export type CopyCommandOptionsType<TResolved = false> = {
5
- id: If<TResolved, string[]>;
5
+ id?: If<TResolved, string[]>;
6
+ last?: number;
6
7
  package?: If<TResolved, string[]>;
7
8
  packageTask?: If<TResolved, string[]>;
8
9
  repository: string;
@@ -11,9 +11,13 @@ class CopyCommand extends CommandAbstract_1.CommandAbstract {
11
11
  id: {
12
12
  option: "-i,--id <ids>",
13
13
  description: "Filter by identifiers",
14
- required: true,
15
14
  parser: string_1.parseStringList,
16
15
  },
16
+ last: {
17
+ option: "-l,--last <amount>",
18
+ description: "Last snapshots",
19
+ parser: Number,
20
+ },
17
21
  package: {
18
22
  option: "-p,--package <names>",
19
23
  description: "Filter by package names",
@@ -41,6 +45,7 @@ class CopyCommand extends CommandAbstract_1.CommandAbstract {
41
45
  const config = await ConfigAction_1.ConfigAction.fromGlobalOptions(this.globalOptions);
42
46
  const copy = new CopyAction_1.CopyAction(config, {
43
47
  ids: this.options.id,
48
+ last: this.options.last,
44
49
  packageNames: this.options.package,
45
50
  packageTaskNames: this.options.packageTask,
46
51
  repositoryName: this.options.repository,
@@ -43,11 +43,11 @@ class InitCommand extends CommandAbstract_1.CommandAbstract {
43
43
  { value: "Error", width: 50 },
44
44
  ],
45
45
  rows: () => response.map((item) => [
46
- (0, cli_1.resultColumn)(item.error),
46
+ (0, cli_1.renderResult)(item.error),
47
47
  item.repositoryName,
48
48
  item.repositoryType,
49
49
  item.repositorySource,
50
- (0, cli_1.errorColumn)(item.error, verbose),
50
+ (0, cli_1.renderError)(item.error, verbose),
51
51
  ]),
52
52
  },
53
53
  });
@@ -1,21 +1,15 @@
1
1
  import { SnapshotGroupByType } from "../Action/SnapshotsAction";
2
2
  import { RepositoryConfigType } from "../Config/RepositoryConfig";
3
+ import { KeepObject } from "../utils/date";
3
4
  import { If } from "../utils/ts";
4
5
  import { CommandAbstract } from "./CommandAbstract";
5
- export type PruneCommandOptions<TResolved = false> = {
6
+ export type PruneCommandOptions<TResolved = false> = KeepObject & {
6
7
  id?: If<TResolved, string[]>;
7
8
  longId?: boolean;
8
9
  package?: If<TResolved, string[]>;
9
10
  repository?: If<TResolved, string[]>;
10
11
  repositoryType?: If<TResolved, RepositoryConfigType["type"][]>;
11
12
  tag?: If<TResolved, string[]>;
12
- keepLast?: number;
13
- keepMinutely?: number;
14
- keepHourly?: number;
15
- keepDaily?: number;
16
- keepWeekly?: number;
17
- keepMonthly?: number;
18
- keepYearly?: number;
19
13
  groupBy?: If<TResolved, SnapshotGroupByType[]>;
20
14
  dryRun?: boolean;
21
15
  showAll?: boolean;
@@ -9,7 +9,7 @@ export type RestoreCommandOptionsType<TResolved = false> = {
9
9
  repository?: If<TResolved, string[]>;
10
10
  repositoryType?: If<TResolved, RepositoryConfigType["type"][]>;
11
11
  tag?: If<TResolved, string[]>;
12
- restorePath?: boolean;
12
+ initial?: boolean;
13
13
  };
14
14
  export declare class RestoreCommand extends CommandAbstract<RestoreCommandOptionsType<false>, RestoreCommandOptionsType<true>> {
15
15
  onOptions(): import("../utils/cli").OptionsType<RestoreCommandOptionsType<false>, RestoreCommandOptionsType<true>>;
@@ -18,9 +18,9 @@ class RestoreCommand extends CommandAbstract_1.CommandAbstract {
18
18
  option: "-p,--package <values>",
19
19
  parser: string_1.parseStringList,
20
20
  },
21
- restorePath: {
22
- description: "Disable restore path",
23
- option: "--no-restore-path",
21
+ initial: {
22
+ description: "Initial restoring (disables restore path)",
23
+ option: "--initial",
24
24
  },
25
25
  packageTask: {
26
26
  description: "Filter by package task names",
@@ -60,7 +60,7 @@ class RestoreCommand extends CommandAbstract_1.CommandAbstract {
60
60
  repositoryTypes: this.options.repositoryType,
61
61
  tags: this.options.tag,
62
62
  verbose: verbose > 0,
63
- restorePath: this.options.restorePath,
63
+ initial: this.options.initial,
64
64
  tty: this.globalOptions.tty,
65
65
  progress: this.globalOptions.progress,
66
66
  progressInterval: this.globalOptions.progressInterval,
@@ -2,6 +2,7 @@ import { FormatType } from "../utils/DataFormat";
2
2
  import { DatatruckServerOptions } from "../utils/datatruck/server";
3
3
  import { Step } from "../utils/steps";
4
4
  import { PackageConfigType } from "./PackageConfig";
5
+ import { PrunePolicyConfigType } from "./PrunePolicyConfig";
5
6
  import { RepositoryConfigType } from "./RepositoryConfig";
6
7
  import type { JSONSchema7 } from "json-schema";
7
8
  export type ConfigType = {
@@ -11,6 +12,7 @@ export type ConfigType = {
11
12
  packages: PackageConfigType[];
12
13
  server?: DatatruckServerOptions;
13
14
  reports?: ReportConfig[];
15
+ prunePolicy?: PrunePolicyConfigType;
14
16
  };
15
17
  export type ReportConfig = {
16
18
  when?: "success" | "error";
package/Config/Config.js CHANGED
@@ -60,5 +60,6 @@ exports.configDefinition = {
60
60
  },
61
61
  },
62
62
  },
63
+ prunePolicy: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.prunePolicy),
63
64
  },
64
65
  };
@@ -12,6 +12,7 @@ export type MetaDataType = {
12
12
  tarStats?: Record<string, {
13
13
  files: number;
14
14
  size: number;
15
+ checksum: string;
15
16
  }>;
16
17
  };
17
18
  export type DatatruckRepositoryConfigType = {
@@ -4,6 +4,7 @@ exports.DatatruckRepository = exports.datatruckPackageRepositoryDefinition = exp
4
4
  const AppError_1 = require("../Error/AppError");
5
5
  const DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
6
6
  const cli_1 = require("../utils/cli");
7
+ const crypto_1 = require("../utils/crypto");
7
8
  const client_1 = require("../utils/datatruck/client");
8
9
  const paths_1 = require("../utils/datatruck/paths");
9
10
  const fs_1 = require("../utils/fs");
@@ -213,6 +214,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
213
214
  tarStats[packBasename] = {
214
215
  files: stream.lines(packIndex),
215
216
  size: 0,
217
+ checksum: "",
216
218
  };
217
219
  const tarPath = (0, path_1.join)(outPath, packBasename);
218
220
  await (0, tar_1.createTar)({
@@ -223,8 +225,11 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
223
225
  output: tarPath,
224
226
  onEntry: async (data) => scanner.progress(pack.compress ? "Compressing" : "Packing", data.path),
225
227
  });
228
+ scanner.progress("Fetching tar stats", (0, path_1.basename)(tarPath), false);
229
+ tarStats[packBasename].checksum = await (0, crypto_1.calcFileHash)(tarPath, "sha1");
226
230
  tarStats[packBasename].size = (await (0, promises_1.stat)(tarPath)).size;
227
231
  if (!fs.isLocal()) {
232
+ scanner.progress("Uploading tar", (0, path_1.basename)(tarPath), false);
228
233
  await fs.upload(tarPath, `${snapshotName}/${packBasename}`);
229
234
  await (0, promises_1.rm)(tarPath);
230
235
  }
@@ -36,12 +36,6 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
36
36
  async backup(data) {
37
37
  const compressAndClean = this.config.compress
38
38
  ? async (path) => {
39
- data.onProgress({
40
- relative: {
41
- description: "Compressing",
42
- payload: (0, path_1.basename)(path),
43
- },
44
- });
45
39
  await (0, tar_1.createTar)({
46
40
  include: [(0, path_1.relative)(snapshotPath, path)],
47
41
  output: `${path}.tar.gz`,
@@ -123,7 +117,7 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
123
117
  items: [tableName],
124
118
  database: this.config.database,
125
119
  onSpawn: (p) => (controller.stop = () => p.kill()),
126
- ...(concurrency !== 1 && {
120
+ ...(concurrency === 1 && {
127
121
  onProgress(progress) {
128
122
  data.onProgress({
129
123
  relative: {
@@ -207,7 +201,7 @@ class MysqlDumpTask extends TaskAbstract_1.TaskAbstract {
207
201
  const database = {
208
202
  name: (0, config_1.resolveDatabaseName)(this.config.database, params),
209
203
  };
210
- if (this.config.targetDatabase && data.options.restorePath)
204
+ if (this.config.targetDatabase && !data.options.initial)
211
205
  database.name = (0, config_1.resolveDatabaseName)(this.config.targetDatabase.name, {
212
206
  ...params,
213
207
  database: database.name,
@@ -204,7 +204,7 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
204
204
  database: undefined,
205
205
  }),
206
206
  };
207
- if (this.config.targetDatabase && data.options.restorePath) {
207
+ if (this.config.targetDatabase && !data.options.initial) {
208
208
  database.name = (0, config_1.resolveDatabaseName)(this.config.targetDatabase.name, {
209
209
  packageName: data.package.name,
210
210
  snapshotId: data.options.snapshotId,
@@ -1079,6 +1079,9 @@
1079
1079
  }
1080
1080
  }
1081
1081
  }
1082
+ },
1083
+ "prunePolicy": {
1084
+ "$ref": "#/definitions/prune-policy"
1082
1085
  }
1083
1086
  }
1084
1087
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datatruck/cli",
3
- "version": "0.28.0",
3
+ "version": "0.29.1",
4
4
  "dependencies": {
5
5
  "@supercharge/promise-pool": "^3.1.0",
6
6
  "ajv": "^8.12.0",
package/utils/cli.d.ts CHANGED
@@ -2,8 +2,9 @@
2
2
  export declare const showCursorCommand = "\u001B[?25h";
3
3
  export declare function renderProgressBar(progress: number, size?: number, subprogress?: number): string;
4
4
  export declare function logExec(command: string, argv?: string[], env?: NodeJS.ProcessEnv, logToStderr?: boolean): void;
5
- export declare function resultColumn(error: Error | null | string | boolean | undefined, color?: boolean): string;
6
- export declare function errorColumn(error: Error | null | string | undefined, verbose?: number): string;
5
+ export declare function renderResult(error: Error | null | string | boolean | undefined, color?: boolean): string;
6
+ export declare function renderError(error: Error | null | string | undefined, verbose?: number): string;
7
+ export declare function renderObject(object: Record<string, any>): string;
7
8
  export type OptionsType<T1, T2 extends {
8
9
  [K in keyof T1]: unknown;
9
10
  }> = {
package/utils/cli.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.confirm = exports.parseOptions = exports.errorColumn = exports.resultColumn = exports.logExec = exports.renderProgressBar = exports.showCursorCommand = void 0;
6
+ exports.confirm = exports.parseOptions = exports.renderObject = exports.renderError = exports.renderResult = exports.logExec = exports.renderProgressBar = exports.showCursorCommand = void 0;
7
7
  const chalk_1 = __importDefault(require("chalk"));
8
8
  const chalk_2 = require("chalk");
9
9
  const readline_1 = require("readline");
@@ -48,7 +48,7 @@ function logExec(command, argv = [], env, logToStderr) {
48
48
  : console.info(text);
49
49
  }
50
50
  exports.logExec = logExec;
51
- function resultColumn(error, color = true) {
51
+ function renderResult(error, color = true) {
52
52
  return error
53
53
  ? color
54
54
  ? chalk_1.default.red("Χ")
@@ -57,8 +57,8 @@ function resultColumn(error, color = true) {
57
57
  ? chalk_1.default.green("✓")
58
58
  : "✓";
59
59
  }
60
- exports.resultColumn = resultColumn;
61
- function errorColumn(error, verbose) {
60
+ exports.renderResult = renderResult;
61
+ function renderError(error, verbose) {
62
62
  let message = null;
63
63
  if (typeof error === "string") {
64
64
  message = error;
@@ -74,7 +74,14 @@ function errorColumn(error, verbose) {
74
74
  }
75
75
  return chalk_1.default.red(message.trim());
76
76
  }
77
- exports.errorColumn = errorColumn;
77
+ exports.renderError = renderError;
78
+ function renderObject(object) {
79
+ const values = [];
80
+ for (const key in object)
81
+ values.push(`${key}: ${(0, chalk_2.grey)(object[key])}`);
82
+ return values.join(` `);
83
+ }
84
+ exports.renderObject = renderObject;
78
85
  function parseOptions(object, options) {
79
86
  const result = {};
80
87
  for (const key in options) {
@@ -0,0 +1 @@
1
+ export declare function calcFileHash(path: string, algorithm: string): Promise<string>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calcFileHash = void 0;
4
+ const crypto_1 = require("crypto");
5
+ const fs_1 = require("fs");
6
+ function calcFileHash(path, algorithm) {
7
+ return new Promise((resolve, reject) => {
8
+ const hash = (0, crypto_1.createHash)(algorithm);
9
+ (0, fs_1.createReadStream)(path)
10
+ .on("error", reject)
11
+ .on("data", (chunk) => hash.update(chunk))
12
+ .on("end", () => resolve(hash.digest("hex")));
13
+ });
14
+ }
15
+ exports.calcFileHash = calcFileHash;
@@ -1,4 +1,7 @@
1
1
  import { SnapshotGroupByType } from "../../Action/SnapshotsAction";
2
2
  import { Snapshot } from "../../Repository/RepositoryAbstract";
3
3
  import { FilterByLastOptionsType } from "../date";
4
- export declare function groupAndFilter<TSnapshot extends Snapshot>(snapshots: TSnapshot[], groupByKey?: SnapshotGroupByType[], filter?: FilterByLastOptionsType | ((groupedSnapshots: TSnapshot[]) => FilterByLastOptionsType), reasons?: Record<number, string[]>): TSnapshot[];
4
+ export declare function groupAndFilter<TSnapshot extends Snapshot>(snapshots: TSnapshot[], groupKeys?: SnapshotGroupByType[], inFilter?: FilterByLastOptionsType | ((group: TSnapshot[]) => FilterByLastOptionsType | string)): {
5
+ item: TSnapshot;
6
+ reasons: string[];
7
+ }[];
@@ -3,29 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.groupAndFilter = void 0;
4
4
  const date_1 = require("../date");
5
5
  const object_1 = require("../object");
6
- function groupAndFilter(snapshots, groupByKey, filter, reasons) {
7
- const grouped = groupByKey?.length
8
- ? (0, object_1.groupBy)(snapshots, groupByKey)
6
+ function groupAndFilter(snapshots, groupKeys, inFilter) {
7
+ const groups = groupKeys?.length
8
+ ? (0, object_1.groupBy)(snapshots, groupKeys)
9
9
  : { "": snapshots };
10
- const result = [];
11
- for (const key in grouped) {
12
- if (filter) {
13
- const groupReasons = reasons
14
- ? {}
15
- : undefined;
16
- result.push(...(0, date_1.filterByLast)(grouped[key], typeof filter === "function" ? filter(grouped[key]) : filter, groupReasons));
17
- if (groupReasons && reasons) {
18
- for (const groupItemIndex in groupReasons) {
19
- const snapshot = grouped[key][groupItemIndex];
20
- const snapshotIndex = snapshots.indexOf(snapshot);
21
- reasons[snapshotIndex] = groupReasons[groupItemIndex];
22
- }
23
- }
24
- }
25
- else {
26
- result.push(...grouped[key]);
27
- }
10
+ const keep = [];
11
+ for (const key in groups) {
12
+ const filter = typeof inFilter === "function" ? inFilter(groups[key]) : inFilter || {};
13
+ keep.push(...(typeof filter === "string"
14
+ ? groups[key].map((item) => ({ item, reasons: [filter] }))
15
+ : (0, date_1.filterByLast)(groups[key], filter)));
28
16
  }
29
- return snapshots.filter((snapshot) => result.includes(snapshot));
17
+ return snapshots
18
+ .map((snapshot) => keep.find((v) => v.item === snapshot))
19
+ .filter((v) => !!v);
30
20
  }
31
21
  exports.groupAndFilter = groupAndFilter;
package/utils/date.d.ts CHANGED
@@ -7,9 +7,22 @@ export type FilterByLastOptionsType = {
7
7
  lastMonthly?: number;
8
8
  lastYearly?: number;
9
9
  };
10
+ export type KeepObject = {
11
+ keepLast?: number;
12
+ keepMinutely?: number;
13
+ keepHourly?: number;
14
+ keepDaily?: number;
15
+ keepWeekly?: number;
16
+ keepMonthly?: number;
17
+ keepYearly?: number;
18
+ };
19
+ export declare function createFilterByLastOptions(keep: KeepObject): FilterByLastOptionsType;
10
20
  export declare function filterByLast<TItem extends {
11
21
  date: string;
12
- }>(items: TItem[], options: FilterByLastOptionsType, reasons?: Record<number, string[]>): TItem[];
22
+ }>(items: TItem[], options: FilterByLastOptionsType): {
23
+ item: TItem;
24
+ reasons: string[];
25
+ }[];
13
26
  export type Timer = {
14
27
  reset: (min?: number) => boolean;
15
28
  check: (min: number) => boolean;