@datatruck/cli 0.35.0 → 0.36.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.
@@ -2073,7 +2073,7 @@
2073
2073
  "const": "prune"
2074
2074
  },
2075
2075
  "options": {
2076
- "$ref": "#/definitions/PruneCommandOptions"
2076
+ "$ref": "#/definitions/Omit<PruneCommandOptions,\"confirm\">"
2077
2077
  }
2078
2078
  },
2079
2079
  "required": [
@@ -2084,62 +2084,59 @@
2084
2084
  }
2085
2085
  ]
2086
2086
  },
2087
- "PruneCommandOptions": {
2088
- "additionalProperties": false,
2087
+ "Omit<PruneCommandOptions,\"confirm\">": {
2089
2088
  "type": "object",
2090
2089
  "properties": {
2091
- "keepLast": {
2092
- "type": "number"
2090
+ "repository": {
2091
+ "type": "string"
2093
2092
  },
2094
- "keepMinutely": {
2093
+ "repositoryType": {
2094
+ "type": "string"
2095
+ },
2096
+ "id": {
2097
+ "type": "string"
2098
+ },
2099
+ "groupBy": {
2100
+ "type": "string"
2101
+ },
2102
+ "dryRun": {
2103
+ "type": "boolean"
2104
+ },
2105
+ "keepDaily": {
2095
2106
  "type": "number"
2096
2107
  },
2097
2108
  "keepHourly": {
2098
2109
  "type": "number"
2099
2110
  },
2100
- "keepDaily": {
2111
+ "keepMinutely": {
2101
2112
  "type": "number"
2102
2113
  },
2103
- "keepWeekly": {
2114
+ "keepLast": {
2104
2115
  "type": "number"
2105
2116
  },
2106
2117
  "keepMonthly": {
2107
2118
  "type": "number"
2108
2119
  },
2109
- "keepYearly": {
2120
+ "keepWeekly": {
2110
2121
  "type": "number"
2111
2122
  },
2112
- "id": {
2113
- "type": "string"
2114
- },
2115
- "longId": {
2116
- "type": "boolean"
2123
+ "keepYearly": {
2124
+ "type": "number"
2117
2125
  },
2118
2126
  "package": {
2119
2127
  "type": "string"
2120
2128
  },
2121
- "repository": {
2122
- "type": "string"
2123
- },
2124
- "repositoryType": {
2125
- "type": "string"
2126
- },
2127
2129
  "tag": {
2128
2130
  "type": "string"
2129
2131
  },
2130
- "groupBy": {
2131
- "type": "string"
2132
- },
2133
- "dryRun": {
2132
+ "longId": {
2134
2133
  "type": "boolean"
2135
2134
  },
2136
2135
  "showAll": {
2137
2136
  "type": "boolean"
2138
- },
2139
- "confirm": {
2140
- "type": "boolean"
2141
2137
  }
2142
- }
2138
+ },
2139
+ "additionalProperties": false
2143
2140
  }
2144
2141
  },
2145
2142
  "$schema": "http://json-schema.org/draft-07/schema#"
@@ -123,6 +123,7 @@ class BackupAction {
123
123
  return await repo.backup({
124
124
  options: this.options,
125
125
  snapshot: data.snapshot,
126
+ hostname: this.config.hostname ?? (0, os_1.hostname)(),
126
127
  package: pkg,
127
128
  packageConfig,
128
129
  onProgress: data.onProgress,
@@ -164,6 +164,7 @@ class CopyAction {
164
164
  if (this.config.minFreeDiskSpace)
165
165
  await mirrorRepo.ensureFreeDiskSpace(mirrorConfig.config, this.config.minFreeDiskSpace);
166
166
  return await mirrorRepo.backup({
167
+ hostname: snapshot.hostname,
167
168
  options: {
168
169
  verbose: this.options.verbose,
169
170
  tags: snapshot.tags,
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.InitAction = void 0;
4
4
  const config_1 = require("../utils/datatruck/config");
5
5
  const repository_1 = require("../utils/datatruck/repository");
6
+ const string_1 = require("../utils/string");
6
7
  class InitAction {
7
8
  config;
8
9
  options;
@@ -12,14 +13,14 @@ class InitAction {
12
13
  }
13
14
  async exec() {
14
15
  const result = [];
16
+ const filterRepo = (0, string_1.createPatternFilter)(this.options.repositoryNames);
17
+ const filterRepoType = (0, string_1.createPatternFilter)(this.options.repositoryTypes);
15
18
  for (const repoConfig of this.config.repositories) {
16
19
  if (!(0, config_1.filterRepositoryByEnabled)(repoConfig, "init"))
17
20
  continue;
18
- if (this.options.repositoryNames &&
19
- !this.options.repositoryNames.includes(repoConfig.name))
21
+ if (!filterRepo(repoConfig.name))
20
22
  continue;
21
- if (this.options.repositoryTypes &&
22
- !this.options.repositoryTypes.includes(repoConfig.type))
23
+ if (!filterRepoType(repoConfig.type))
23
24
  continue;
24
25
  const repo = (0, repository_1.createRepo)(repoConfig, this.options.verbose);
25
26
  let initError = null;
@@ -59,6 +59,7 @@ const error_1 = require("../utils/error");
59
59
  const fs_1 = require("../utils/fs");
60
60
  const list_1 = require("../utils/list");
61
61
  const progress_1 = require("../utils/progress");
62
+ const string_1 = require("../utils/string");
62
63
  const temp_1 = require("../utils/temp");
63
64
  const SnapshotsAction_1 = require("./SnapshotsAction");
64
65
  const assert_1 = require("assert");
@@ -74,12 +75,12 @@ class RestoreAction {
74
75
  }
75
76
  async findSnapshots() {
76
77
  const result = [];
78
+ const filterRepo = (0, string_1.createPatternFilter)(this.options.repositoryNames);
79
+ const filterRepoType = (0, string_1.createPatternFilter)(this.options.repositoryTypes);
77
80
  for (const repository of this.config.repositories) {
78
- if (this.options.repositoryNames &&
79
- !this.options.repositoryNames.includes(repository.name))
81
+ if (!filterRepo(repository.name))
80
82
  continue;
81
- if (this.options.repositoryTypes &&
82
- !this.options.repositoryTypes.includes(repository.type))
83
+ if (!filterRepoType(repository.type))
83
84
  continue;
84
85
  const snapshotsAction = new SnapshotsAction_1.SnapshotsAction(this.config, {
85
86
  repositoryNames: [repository.name],
@@ -4,6 +4,7 @@ import { IfRequireKeys } from "../utils/ts";
4
4
  export type SnapshotGroupByType = keyof Pick<ExtendedSnapshot, "packageName" | "repositoryName" | "repositoryType">;
5
5
  export type SnapshotsActionOptions = {
6
6
  ids?: string[];
7
+ hostnames?: string[];
7
8
  repositoryNames?: string[];
8
9
  packageNames?: string[];
9
10
  packageTaskNames?: string[];
@@ -4,6 +4,7 @@ exports.SnapshotsAction = void 0;
4
4
  const config_1 = require("../utils/datatruck/config");
5
5
  const repository_1 = require("../utils/datatruck/repository");
6
6
  const snapshot_1 = require("../utils/datatruck/snapshot");
7
+ const string_1 = require("../utils/string");
7
8
  class SnapshotsAction {
8
9
  config;
9
10
  options;
@@ -15,14 +16,15 @@ class SnapshotsAction {
15
16
  if (!sourceAction)
16
17
  sourceAction = "snapshots";
17
18
  let result = [];
19
+ const filterHost = (0, string_1.createPatternFilter)(this.options.hostnames);
20
+ const filterRepo = (0, string_1.createPatternFilter)(this.options.repositoryNames);
21
+ const filterRepoType = (0, string_1.createPatternFilter)(this.options.repositoryTypes);
18
22
  for (const repoConfig of this.config.repositories) {
19
23
  if (!(0, config_1.filterRepositoryByEnabled)(repoConfig, sourceAction))
20
24
  continue;
21
- if (this.options.repositoryNames &&
22
- !this.options.repositoryNames.includes(repoConfig.name))
25
+ if (!filterRepo(repoConfig.name))
23
26
  continue;
24
- if (this.options.repositoryTypes &&
25
- !this.options.repositoryTypes.includes(repoConfig.type))
27
+ if (!filterRepoType(repoConfig.type))
26
28
  continue;
27
29
  const repo = await (0, repository_1.createAndInitRepo)(repoConfig, this.options.verbose);
28
30
  const configPackageNames = this.config.packages.map((pkg) => pkg.name);
@@ -35,12 +37,14 @@ class SnapshotsAction {
35
37
  packageNames,
36
38
  },
37
39
  });
38
- const extentedItems = snapshots.map((ss) => ({
40
+ let extentedItems = snapshots.map((ss) => ({
39
41
  ...ss,
40
42
  shortId: ss.id.slice(0, 8),
41
43
  repositoryName: repoConfig.name,
42
44
  repositoryType: repoConfig.type,
43
45
  }));
46
+ if (this.options.hostnames)
47
+ extentedItems = extentedItems.filter((s) => filterHost(s.hostname));
44
48
  result.push(...extentedItems);
45
49
  }
46
50
  result = result.sort((a, b) => b.date.localeCompare(a.date));
@@ -28,6 +28,7 @@ export declare class RestoreCommand extends CommandAbstract<RestoreCommandOption
28
28
  packageName: string;
29
29
  packageTaskName: string | undefined;
30
30
  tags: string[];
31
+ hostname: string;
31
32
  size: number;
32
33
  } & {
33
34
  repositoryName: string;
@@ -4,6 +4,7 @@ import { If } from "../utils/ts";
4
4
  import { CommandAbstract } from "./CommandAbstract";
5
5
  export type SnapshotsCommandOptions<TResolved = false> = {
6
6
  id?: If<TResolved, string[]>;
7
+ host?: If<TResolved, string[]>;
7
8
  package?: If<TResolved, string[]>;
8
9
  packageTask?: If<TResolved, string[]>;
9
10
  packageConfig?: boolean;
@@ -30,6 +30,11 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
30
30
  description: "Filter by identifiers",
31
31
  parser: string_1.parseStringList,
32
32
  },
33
+ host: {
34
+ option: "-h,--host <names>",
35
+ description: "Filter by hostnames",
36
+ parser: string_1.parseStringList,
37
+ },
33
38
  last: {
34
39
  option: "-l,--last <number>",
35
40
  description: "Filter by last snapshots",
@@ -101,6 +106,7 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
101
106
  const config = await ConfigAction_1.ConfigAction.fromGlobalOptions(this.globalOptions);
102
107
  const snapshots = new SnapshotsAction_1.SnapshotsAction(config, {
103
108
  ids: this.options.id,
109
+ hostnames: this.options.host,
104
110
  packageNames: this.options.package,
105
111
  packageTaskNames: this.options.packageTask,
106
112
  packageConfig: this.options.packageConfig,
@@ -125,6 +131,7 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
125
131
  headers: [
126
132
  { value: "Id.", width: (this.options.longId ? 32 : 8) + 2 },
127
133
  { value: "Date", width: 23 + 2 },
134
+ { value: "Host" },
128
135
  { value: "Package" },
129
136
  { value: "Task" },
130
137
  { value: "Size" },
@@ -134,6 +141,7 @@ class SnapshotsCommand extends CommandAbstract_1.CommandAbstract {
134
141
  rows: () => result.map((item) => [
135
142
  this.options.longId ? item.id : item.id.slice(0, 8),
136
143
  item.date.replace("T", " ").replace("Z", ""),
144
+ item.hostname,
137
145
  item.packageName,
138
146
  item.packageTaskName || "",
139
147
  (0, bytes_1.formatBytes)(item.size),
@@ -1,12 +1,6 @@
1
1
  import { CompressOptions } from "../utils/tar";
2
- import { RepositoryAbstract, RepoBackupData, RepoInitData, RepoRestoreData, RepoFetchSnapshotsData, Snapshot, RepoPruneData, RepoCopyData } from "./RepositoryAbstract";
3
- export type MetaData = {
4
- id: string;
5
- date: string;
6
- package: string;
7
- task: string | undefined;
8
- tags: string[];
9
- version: string;
2
+ import { RepositoryAbstract, RepoBackupData, RepoInitData, RepoRestoreData, RepoFetchSnapshotsData, Snapshot, RepoPruneData, RepoCopyData, SnapshotTagObject } from "./RepositoryAbstract";
3
+ export type MetaData = Omit<SnapshotTagObject, "shortId" | "size"> & {
10
4
  size: number;
11
5
  tarStats?: Record<string, {
12
6
  files: number;
@@ -32,7 +26,7 @@ export type DatatruckPackageRepositoryConfig = {
32
26
  export declare const datatruckRepositoryName = "datatruck";
33
27
  export declare class DatatruckRepository extends RepositoryAbstract<DatatruckRepositoryConfig> {
34
28
  static zipBasenameTpl: string;
35
- static buildSnapshotName(snapshot: {
29
+ static createSnapshotName(snapshot: {
36
30
  id: string;
37
31
  date: string;
38
32
  }, pkg: {
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DatatruckRepository = exports.datatruckRepositoryName = void 0;
4
+ const async_1 = require("../utils/async");
4
5
  const cli_1 = require("../utils/cli");
5
6
  const crypto_1 = require("../utils/crypto");
6
7
  const client_1 = require("../utils/datatruck/client");
8
+ const config_1 = require("../utils/datatruck/config");
7
9
  const paths_1 = require("../utils/datatruck/paths");
8
10
  const error_1 = require("../utils/error");
9
11
  const fs_1 = require("../utils/fs");
@@ -14,12 +16,11 @@ const temp_1 = require("../utils/temp");
14
16
  const RepositoryAbstract_1 = require("./RepositoryAbstract");
15
17
  const assert_1 = require("assert");
16
18
  const promises_1 = require("fs/promises");
17
- const micromatch_1 = require("micromatch");
18
19
  const path_1 = require("path");
19
20
  exports.datatruckRepositoryName = "datatruck";
20
21
  class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
21
22
  static zipBasenameTpl = `.*.dd.tar.gz`;
22
- static buildSnapshotName(snapshot, pkg) {
23
+ static createSnapshotName(snapshot, pkg) {
23
24
  const date = snapshot.date.replace(/:/g, "-");
24
25
  const pkgName = encodeURIComponent(pkg.name)
25
26
  .replace(/%40/g, "@")
@@ -54,7 +55,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
54
55
  }
55
56
  async prune(data) {
56
57
  const fs = (0, client_1.createFs)(this.config.backend, this.verbose);
57
- const snapshotName = DatatruckRepository.buildSnapshotName(data.snapshot, {
58
+ const snapshotName = DatatruckRepository.createSnapshotName(data.snapshot, {
58
59
  name: data.snapshot.packageName,
59
60
  });
60
61
  if (data.options.verbose)
@@ -68,23 +69,26 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
68
69
  throw new error_1.AppError(`Repository (${this.repository.name}) out path does not exist: ${fs.resolvePath(".")}`);
69
70
  const snapshots = [];
70
71
  const snapshotNames = await fs.readdir(".");
71
- const packagePatterns = (0, string_1.makePathPatterns)(data.options.packageNames);
72
- const taskPatterns = (0, string_1.makePathPatterns)(data.options.packageTaskNames);
73
- for (const snapshotName of snapshotNames) {
74
- const snapshotNameData = DatatruckRepository.parseSnapshotName(snapshotName);
75
- if (!snapshotNameData)
76
- continue;
77
- if (packagePatterns &&
78
- !(0, micromatch_1.isMatch)(snapshotNameData.packageName, packagePatterns))
79
- continue;
80
- if (data.options.ids &&
81
- !data.options.ids.some((id) => snapshotNameData.snapshotShortId.startsWith(id.slice(0, 8))))
82
- continue;
83
- const metaData = await fs.readFileIfExists(`${snapshotName}/meta.json`);
72
+ const filterPkg = (0, config_1.createPkgFilter)(data.options.packageNames);
73
+ const filterTask = (0, config_1.createTaskFilter)(data.options.packageTaskNames);
74
+ const filterId = (shortId) => !data.options.ids ||
75
+ data.options.ids.some((id) => shortId.startsWith(id.slice(0, 8)));
76
+ const preSnapshots = snapshotNames
77
+ .filter((snapshotName) => {
78
+ const data = DatatruckRepository.parseSnapshotName(snapshotName);
79
+ return (data && filterPkg(data.packageName) && filterId(data.snapshotShortId));
80
+ })
81
+ .map((name) => ({ name }));
82
+ await (0, async_1.runParallel)({
83
+ items: preSnapshots,
84
+ concurrency: 5,
85
+ async onItem({ item }) {
86
+ item.metaData = await fs.readFileIfExists(`${item.name}/meta.json`);
87
+ },
88
+ });
89
+ for (const { name, metaData } of preSnapshots) {
84
90
  const meta = !!metaData && (await DatatruckRepository.parseMetaData(metaData));
85
- if (!meta)
86
- continue;
87
- if (taskPatterns && !(0, string_1.checkMatch)(meta.task, taskPatterns))
91
+ if (!meta || !filterTask(meta.task))
88
92
  continue;
89
93
  if (data.options.ids &&
90
94
  !data.options.ids.some((id) => meta.id.startsWith(id)))
@@ -93,12 +97,13 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
93
97
  !data.options.tags.some((value) => data.options.tags?.includes(value)))
94
98
  continue;
95
99
  snapshots.push({
96
- originalId: snapshotName,
100
+ originalId: name,
97
101
  id: meta.id,
98
102
  date: meta.date,
99
103
  packageName: meta.package,
100
104
  packageTaskName: meta.task,
101
105
  tags: meta.tags,
106
+ hostname: meta.hostname ?? "",
102
107
  size: meta.size || 0,
103
108
  });
104
109
  }
@@ -106,7 +111,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
106
111
  }
107
112
  async backup(data) {
108
113
  const fs = (0, client_1.createFs)(this.config.backend, this.verbose);
109
- const snapshotName = DatatruckRepository.buildSnapshotName(data.snapshot, data.package);
114
+ const snapshotName = DatatruckRepository.createSnapshotName(data.snapshot, data.package);
110
115
  const outPath = fs.isLocal()
111
116
  ? fs.resolvePath(snapshotName)
112
117
  : await (0, temp_1.mkTmpDir)(exports.datatruckRepositoryName, "repo", "backup", "fs-remote");
@@ -209,6 +214,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
209
214
  const nodePkg = (0, fs_1.parsePackageFile)();
210
215
  const meta = {
211
216
  id: data.snapshot.id,
217
+ hostname: data.hostname,
212
218
  date: data.snapshot.date,
213
219
  tags: data.options.tags ?? [],
214
220
  package: data.package.name,
@@ -227,7 +233,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
227
233
  async copy(data) {
228
234
  const sourceFs = (0, client_1.createFs)(this.config.backend, this.verbose);
229
235
  const targetFs = (0, client_1.createFs)(data.mirrorRepositoryConfig.backend, this.verbose);
230
- const snapshotName = DatatruckRepository.buildSnapshotName(data.snapshot, data.package);
236
+ const snapshotName = DatatruckRepository.createSnapshotName(data.snapshot, data.package);
231
237
  if (data.options.verbose)
232
238
  (0, cli_1.logExec)(`Copying backup files to ${data.mirrorRepositoryConfig.backend}`);
233
239
  const tmpSnapshotName = `${snapshotName}_tmp`;
@@ -307,7 +313,7 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
307
313
  });
308
314
  if (!snapshot)
309
315
  throw new error_1.AppError("Snapshot not found");
310
- const snapshotName = DatatruckRepository.buildSnapshotName(snapshot, data.package);
316
+ const snapshotName = DatatruckRepository.createSnapshotName(snapshot, data.package);
311
317
  const meta = await DatatruckRepository.parseMetaData(await fs.readFile(`${snapshotName}/meta.json`));
312
318
  const progress = (0, fs_1.createProgress)({ onProgress: data.onProgress });
313
319
  progress.update("Scanning files");
@@ -9,15 +9,13 @@ export declare class GitRepository extends RepositoryAbstract<GitRepositoryConfi
9
9
  static refPrefix: string;
10
10
  getSource(): string;
11
11
  fetchDiskStats(config: GitRepositoryConfig): Promise<import("../utils/fs").DiskStats | undefined>;
12
- static buildSnapshotTagName(tag: Pick<SnapshotTagObject, SnapshotTagEnum.PACKAGE | SnapshotTagEnum.ID>): string;
13
- static buildSnapshotTag(tag: SnapshotTagObject): {
12
+ static createSnapshotTagName(tag: Pick<SnapshotTagObject, SnapshotTagEnum.PACKAGE | SnapshotTagEnum.ID>): string;
13
+ static createSnapshotTags(tags: SnapshotTagObject): {
14
14
  name: string;
15
15
  message: string;
16
16
  };
17
17
  static isSnapshotTag(name: string): boolean;
18
- static parseSnapshotTag(name: string, message: string): (Omit<SnapshotTagObject, "tags"> & {
19
- tags: string[];
20
- }) | null;
18
+ static parseSnapshotTags(name: string, message: string): SnapshotTagObject | null;
21
19
  static buildBranchName(packageName: string): string;
22
20
  init(data: RepoInitData): Promise<void>;
23
21
  prune(data: RepoPruneData): Promise<void>;
@@ -5,15 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.GitRepository = exports.gitRepositoryName = void 0;
7
7
  const cli_1 = require("../utils/cli");
8
+ const config_1 = require("../utils/datatruck/config");
8
9
  const paths_1 = require("../utils/datatruck/paths");
9
10
  const fs_1 = require("../utils/fs");
10
11
  const git_1 = require("../utils/git");
11
- const string_1 = require("../utils/string");
12
12
  const temp_1 = require("../utils/temp");
13
13
  const RepositoryAbstract_1 = require("./RepositoryAbstract");
14
14
  const fast_glob_1 = __importDefault(require("fast-glob"));
15
15
  const promises_1 = require("fs/promises");
16
- const micromatch_1 = require("micromatch");
17
16
  const path_1 = require("path");
18
17
  exports.gitRepositoryName = "git";
19
18
  class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
@@ -25,19 +24,19 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
25
24
  if ((0, fs_1.isLocalDir)(config.repo))
26
25
  return await (0, fs_1.fetchDiskStats)(config.repo);
27
26
  }
28
- static buildSnapshotTagName(tag) {
27
+ static createSnapshotTagName(tag) {
29
28
  return `${GitRepository.refPrefix}/${tag.package}/${tag.id}`;
30
29
  }
31
- static buildSnapshotTag(tag) {
30
+ static createSnapshotTags(tags) {
32
31
  return {
33
- name: GitRepository.buildSnapshotTagName(tag),
34
- message: JSON.stringify(tag),
32
+ name: GitRepository.createSnapshotTagName(tags),
33
+ message: JSON.stringify(tags),
35
34
  };
36
35
  }
37
36
  static isSnapshotTag(name) {
38
37
  return name.startsWith(`${GitRepository.refPrefix}/`);
39
38
  }
40
- static parseSnapshotTag(name, message) {
39
+ static parseSnapshotTags(name, message) {
41
40
  if (GitRepository.isSnapshotTag(name))
42
41
  return JSON.parse(message);
43
42
  return null;
@@ -104,21 +103,21 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
104
103
  dir: await (0, temp_1.mkTmpDir)(exports.gitRepositoryName, "repo", "snapshots"),
105
104
  log: data.options.verbose,
106
105
  });
107
- const pkgPatterns = (0, string_1.makePathPatterns)(data.options.packageNames);
108
- const pkgTaskPatterns = (0, string_1.makePathPatterns)(data.options.packageTaskNames);
109
106
  await git.clone({ repo: this.config.repo });
110
107
  const tagNames = data.options.ids?.map((id) => `${GitRepository.refPrefix}/*/${id}*`) || [`${GitRepository.refPrefix}/*`];
111
108
  const tags = await git.getTags(tagNames);
109
+ const filterPkg = (0, config_1.createPkgFilter)(data.options.packageNames);
110
+ const filterTask = (0, config_1.createTaskFilter)(data.options.packageTaskNames);
112
111
  return tags
113
112
  .reduce((result, tag) => {
114
113
  const parsedTag = tag.message
115
- ? GitRepository.parseSnapshotTag(tag.name, tag.message)
114
+ ? GitRepository.parseSnapshotTags(tag.name, tag.message)
116
115
  : null;
117
116
  if (!parsedTag)
118
117
  return result;
119
- if (pkgPatterns && !(0, micromatch_1.isMatch)(parsedTag.package, pkgPatterns))
118
+ if (!filterPkg(parsedTag.package))
120
119
  return result;
121
- if (pkgTaskPatterns && !(0, string_1.checkMatch)(parsedTag.task, pkgTaskPatterns))
120
+ if (!filterTask(parsedTag.task))
122
121
  return result;
123
122
  if (data.options.tags &&
124
123
  !parsedTag.tags.some((value) => data.options.tags?.includes(value)))
@@ -130,6 +129,7 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
130
129
  packageName: parsedTag.package,
131
130
  packageTaskName: parsedTag.task,
132
131
  tags: parsedTag.tags,
132
+ hostname: parsedTag.hostname ?? "",
133
133
  size: Number(parsedTag.size) || 0,
134
134
  });
135
135
  return result;
@@ -197,8 +197,9 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
197
197
  const nodePkg = (0, fs_1.parsePackageFile)();
198
198
  const size = (await (0, fs_1.fastFolderSizeAsync)(tmpPath)) -
199
199
  (await (0, fs_1.fastFolderSizeAsync)((0, path_1.join)(tmpPath, ".git")));
200
- const meta = GitRepository.buildSnapshotTag({
200
+ const meta = GitRepository.createSnapshotTags({
201
201
  id: data.snapshot.id,
202
+ hostname: data.hostname,
202
203
  shortId: data.snapshot.id.slice(0, 8),
203
204
  tags: data.options.tags ?? [],
204
205
  date: data.snapshot.date,
@@ -221,7 +222,7 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
221
222
  }
222
223
  async restore(data) {
223
224
  const restorePath = data.snapshotPath;
224
- const tagName = GitRepository.buildSnapshotTagName({
225
+ const tagName = GitRepository.createSnapshotTagName({
225
226
  id: data.snapshot.id,
226
227
  package: data.package.name,
227
228
  });
@@ -13,6 +13,7 @@ export type Snapshot = PreSnapshot & {
13
13
  packageName: string;
14
14
  packageTaskName: string | undefined;
15
15
  tags: string[];
16
+ hostname: string;
16
17
  size: number;
17
18
  };
18
19
  export type RepoInitData = {
@@ -33,6 +34,7 @@ export type RepoCopyData<TRepositoryConfig> = {
33
34
  export type RepoBackupData<TPackageConfig> = {
34
35
  options: BackupActionOptions;
35
36
  snapshot: PreSnapshot;
37
+ hostname: string;
36
38
  package: Omit<PackageConfig, "path"> & {
37
39
  path: string;
38
40
  };
@@ -61,7 +63,8 @@ export declare enum SnapshotTagEnum {
61
63
  TASK = "task",
62
64
  TAGS = "tags",
63
65
  VERSION = "version",
64
- SIZE = "size"
66
+ SIZE = "size",
67
+ HOSTNAME = "hostname"
65
68
  }
66
69
  export type SnapshotTagObject = {
67
70
  [SnapshotTagEnum.ID]: string;
@@ -72,6 +75,7 @@ export type SnapshotTagObject = {
72
75
  [SnapshotTagEnum.TAGS]: string[];
73
76
  [SnapshotTagEnum.VERSION]: string;
74
77
  [SnapshotTagEnum.SIZE]: string;
78
+ [SnapshotTagEnum.HOSTNAME]: string;
75
79
  };
76
80
  export declare abstract class RepositoryAbstract<TConfig> {
77
81
  readonly repository: RepositoryConfig;
@@ -12,6 +12,7 @@ var SnapshotTagEnum;
12
12
  SnapshotTagEnum["TAGS"] = "tags";
13
13
  SnapshotTagEnum["VERSION"] = "version";
14
14
  SnapshotTagEnum["SIZE"] = "size";
15
+ SnapshotTagEnum["HOSTNAME"] = "hostname";
15
16
  })(SnapshotTagEnum || (exports.SnapshotTagEnum = SnapshotTagEnum = {}));
16
17
  class RepositoryAbstract {
17
18
  repository;
@@ -20,14 +20,13 @@ export declare class ResticRepository extends RepositoryAbstract<ResticRepositor
20
20
  RESTIC_PASSWORD_FILE?: string | undefined;
21
21
  RESTIC_REPOSITORY: string;
22
22
  }>;
23
- static buildSnapshotTag(name: SnapshotTagEnum, value: string): string;
23
+ static createSnapshotTag(name: SnapshotTagEnum, value: string): string;
24
+ static createSnapshotTags(object: Omit<SnapshotTagObject, "size">): string[];
24
25
  static parseSnapshotTag(tag: string): {
25
26
  name: SnapshotTagEnum;
26
27
  value: string;
27
28
  } | null;
28
- static parseSnapshotTags(tags: string[]): SnapshotTagObject & {
29
- tags: string[];
30
- };
29
+ static parseSnapshotTags(tags: string[]): SnapshotTagObject;
31
30
  getSource(): string;
32
31
  fetchDiskStats(config: ResticRepositoryConfig): Promise<import("../utils/fs").DiskStats | undefined>;
33
32
  init(data: RepoInitData): Promise<void>;
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.ResticRepository = exports.resticRepositoryName = void 0;
7
7
  const cli_1 = require("../utils/cli");
8
+ const config_1 = require("../utils/datatruck/config");
8
9
  const paths_1 = require("../utils/datatruck/paths");
9
10
  const error_1 = require("../utils/error");
10
11
  const fs_1 = require("../utils/fs");
@@ -15,7 +16,6 @@ const temp_1 = require("../utils/temp");
15
16
  const RepositoryAbstract_1 = require("./RepositoryAbstract");
16
17
  const fast_glob_1 = __importDefault(require("fast-glob"));
17
18
  const promises_1 = require("fs/promises");
18
- const micromatch_1 = require("micromatch");
19
19
  const path_1 = require("path");
20
20
  exports.resticRepositoryName = "restic";
21
21
  class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
@@ -31,9 +31,21 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
31
31
  RESTIC_REPOSITORY: await restic_1.Restic.formatRepository(this.config.repository),
32
32
  });
33
33
  }
34
- static buildSnapshotTag(name, value) {
34
+ static createSnapshotTag(name, value) {
35
35
  return `${ResticRepository.refPrefix}${name}:${value}`;
36
36
  }
37
+ static createSnapshotTags(object) {
38
+ const { tags: inTags, ...otherTags } = object;
39
+ const tags = [...inTags];
40
+ for (const key in otherTags) {
41
+ const value = object[key];
42
+ if (value !== undefined) {
43
+ const tag = ResticRepository.createSnapshotTag(key, value);
44
+ tags.push(tag);
45
+ }
46
+ }
47
+ return tags;
48
+ }
37
49
  static parseSnapshotTag(tag) {
38
50
  for (const metaName in RepositoryAbstract_1.SnapshotTagEnum) {
39
51
  const name = RepositoryAbstract_1.SnapshotTagEnum[metaName];
@@ -83,21 +95,21 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
83
95
  env: await this.buildEnv(),
84
96
  log: data.options.verbose,
85
97
  });
86
- const packagePatterns = (0, string_1.makePathPatterns)(data.options.packageNames);
87
- const taskNamePatterns = (0, string_1.makePathPatterns)(data.options.packageTaskNames);
88
98
  const result = await restic.snapshots({
89
99
  json: true,
90
100
  tags: [
91
- ...(data.options.ids?.map((id) => ResticRepository.buildSnapshotTag(id.length === 8 ? RepositoryAbstract_1.SnapshotTagEnum.SHORT_ID : RepositoryAbstract_1.SnapshotTagEnum.ID, id)) ?? []),
101
+ ...(data.options.ids?.map((id) => ResticRepository.createSnapshotTag(id.length === 8 ? RepositoryAbstract_1.SnapshotTagEnum.SHORT_ID : RepositoryAbstract_1.SnapshotTagEnum.ID, id)) ?? []),
92
102
  ],
93
103
  });
104
+ const filterPkg = (0, config_1.createPkgFilter)(data.options.packageNames);
105
+ const filterTask = (0, config_1.createTaskFilter)(data.options.packageTaskNames);
94
106
  return result.reduce((items, item) => {
95
107
  const tag = ResticRepository.parseSnapshotTags(item.tags ?? []);
96
108
  if (!tag.id)
97
109
  return items;
98
- if (packagePatterns && !(0, micromatch_1.isMatch)(tag.package, packagePatterns))
110
+ if (!filterPkg(tag.package))
99
111
  return items;
100
- if (taskNamePatterns && !(0, string_1.checkMatch)(tag.task, taskNamePatterns))
112
+ if (!filterTask(tag.task))
101
113
  return items;
102
114
  const itemTags = tag.tags ?? [];
103
115
  if (data.options.tags && !itemTags.some((t) => itemTags.includes(t)))
@@ -109,6 +121,7 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
109
121
  date: tag.date,
110
122
  id: tag.id,
111
123
  tags: itemTags,
124
+ hostname: tag.hostname ?? "",
112
125
  size: Number(tag.size) || 0,
113
126
  });
114
127
  return items;
@@ -176,7 +189,7 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
176
189
  }
177
190
  if (data.options.tags?.some((tag) => tag.startsWith(ResticRepository.refPrefix)))
178
191
  throw new error_1.AppError(`Tag prefix is not allowed`);
179
- const packageTag = ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.PACKAGE, data.package.name);
192
+ const packageTag = ResticRepository.createSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.PACKAGE, data.package.name);
180
193
  data.onProgress({
181
194
  relative: {
182
195
  description: "Fetching last snapshot",
@@ -204,19 +217,16 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
204
217
  allowEmptySnapshot: true,
205
218
  excludeFile: gitignorePath ? [gitignorePath] : undefined,
206
219
  parent: lastSnapshot?.id,
207
- tags: [
208
- ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.ID, data.snapshot.id),
209
- ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.SHORT_ID, data.snapshot.id.slice(0, 8)),
210
- ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.DATE, data.snapshot.date),
211
- ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.VERSION, nodePkg.version),
212
- packageTag,
213
- ...(data.package.task?.name
214
- ? [
215
- ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.TASK, data.package.task?.name),
216
- ]
217
- : []),
218
- ...(data.options.tags ?? []),
219
- ],
220
+ tags: ResticRepository.createSnapshotTags({
221
+ id: data.snapshot.id,
222
+ hostname: data.hostname,
223
+ shortId: data.snapshot.id.slice(0, 8),
224
+ date: data.snapshot.date,
225
+ version: nodePkg.version,
226
+ package: data.package.name,
227
+ task: data.package.task?.name,
228
+ tags: data.options.tags || [],
229
+ }),
220
230
  createEmptyDir: async () => await (0, temp_1.mkTmpDir)(exports.resticRepositoryName, "repo", "backup", "empty-dir"),
221
231
  onStream: async (streamData) => {
222
232
  if (streamData.message_type === "status") {
@@ -254,7 +264,7 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
254
264
  throw new error_1.AppError(`Restic snapshot id is is not defined`);
255
265
  if (typeof resticTotalBytes !== "number")
256
266
  throw new error_1.AppError(`Restic snapshot total bytes is not defined`);
257
- const sizeTag = ResticRepository.buildSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.SIZE, resticTotalBytes.toString());
267
+ const sizeTag = ResticRepository.createSnapshotTag(RepositoryAbstract_1.SnapshotTagEnum.SIZE, resticTotalBytes.toString());
258
268
  await restic.exec(["tag", "--add", sizeTag, resticSnapshotId]);
259
269
  data.onProgress({
260
270
  absolute: {
@@ -5,10 +5,10 @@ const async_process_1 = require("../utils/async-process");
5
5
  const config_1 = require("../utils/datatruck/config");
6
6
  const error_1 = require("../utils/error");
7
7
  const fs_1 = require("../utils/fs");
8
+ const string_1 = require("../utils/string");
8
9
  const temp_1 = require("../utils/temp");
9
10
  const TaskAbstract_1 = require("./TaskAbstract");
10
11
  const promises_1 = require("fs/promises");
11
- const micromatch_1 = require("micromatch");
12
12
  const path_1 = require("path");
13
13
  exports.mssqlTaskName = "mssql";
14
14
  class MssqlTask extends TaskAbstract_1.TaskAbstract {
@@ -53,10 +53,10 @@ class MssqlTask extends TaskAbstract_1.TaskAbstract {
53
53
  if (data.package.path)
54
54
  throw new error_1.AppError(`'package.path' is required: ${data.package.path}`);
55
55
  const snapshotPath = await (0, temp_1.mkTmpDir)(exports.mssqlTaskName, "task", "backup", "snapshot");
56
- const databaseNames = (await this.fetchDatabaseNames()).filter((databaseName) => (!this.config.includeDatabases ||
57
- (0, micromatch_1.isMatch)(databaseName, this.config.includeDatabases)) &&
58
- (!this.config.excludeDatabases ||
59
- !(0, micromatch_1.isMatch)(databaseName, this.config.excludeDatabases)));
56
+ const databaseNames = (await this.fetchDatabaseNames()).filter((0, string_1.createPatternFilter)({
57
+ include: this.config.includeDatabases,
58
+ exclude: this.config.excludeDatabases,
59
+ }));
60
60
  for (const databaseName of databaseNames) {
61
61
  const databasePath = (0, path_1.join)(snapshotPath, `${databaseName}${MssqlTask.SUFFIX}`);
62
62
  await this.exec(`BACKUP DATABASE [${databaseName}] TO DISK='${databasePath}' WITH FORMAT`);
@@ -6,11 +6,11 @@ const config_1 = require("../utils/datatruck/config");
6
6
  const error_1 = require("../utils/error");
7
7
  const fs_1 = require("../utils/fs");
8
8
  const math_1 = require("../utils/math");
9
+ const string_1 = require("../utils/string");
9
10
  const temp_1 = require("../utils/temp");
10
11
  const TaskAbstract_1 = require("./TaskAbstract");
11
12
  const assert_1 = require("assert");
12
13
  const promises_1 = require("fs/promises");
13
- const micromatch_1 = require("micromatch");
14
14
  const path_1 = require("path");
15
15
  function serializeSqlFile(input) {
16
16
  if (input.database && input.table) {
@@ -71,13 +71,10 @@ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
71
71
  await (0, fs_1.ensureEmptyDir)(snapshotPath);
72
72
  const config = this.config;
73
73
  const allTableNames = await this.onFetchTableNames(this.config.database);
74
- const tableNames = allTableNames.filter((tableName) => {
75
- if (config.includeTables && !(0, micromatch_1.isMatch)(tableName, config.includeTables))
76
- return false;
77
- if (config.excludeTables && (0, micromatch_1.isMatch)(tableName, config.excludeTables))
78
- return false;
79
- return true;
80
- });
74
+ const tableNames = allTableNames.filter((0, string_1.createPatternFilter)({
75
+ include: config.includeTables,
76
+ exclude: config.excludeTables,
77
+ }));
81
78
  (0, assert_1.ok)(typeof snapshotPath === "string");
82
79
  if (!(await (0, fs_1.existsDir)(snapshotPath)))
83
80
  await (0, promises_1.mkdir)(snapshotPath, { recursive: true });
@@ -3,7 +3,7 @@ type ItemBuffer<T> = Map<T, AbortController>;
3
3
  export declare function runParallel<T>(options: {
4
4
  items: T[];
5
5
  concurrency: number;
6
- onChange: (data: {
6
+ onChange?: (data: {
7
7
  buffer: ItemBuffer<T>;
8
8
  processed: number;
9
9
  proccesing: number;
@@ -12,7 +12,7 @@ async function runParallel(options) {
12
12
  const controller = new AbortController();
13
13
  buffer.set(item, controller);
14
14
  try {
15
- await options.onChange({
15
+ await options.onChange?.({
16
16
  processed,
17
17
  proccesing: buffer.size,
18
18
  buffer,
@@ -37,7 +37,7 @@ async function runParallel(options) {
37
37
  buffer.delete(item);
38
38
  processed++;
39
39
  await options.onFinished?.();
40
- await options.onChange({
40
+ await options.onChange?.({
41
41
  processed,
42
42
  proccesing: buffer.size,
43
43
  buffer,
@@ -1,3 +1,4 @@
1
+ import { Filter } from "../string";
1
2
  import type { Config } from "./config-type";
2
3
  import type { PackageConfig, RepositoryConfigEnabledAction, RepositoryConfig } from "./config-type";
3
4
  export declare function findRepositoryOrFail(config: Config, repositoryName: string): RepositoryConfig;
@@ -99,4 +100,6 @@ export declare const params: {
99
100
  database: string;
100
101
  };
101
102
  };
103
+ export declare function createPkgFilter(patterns: string[] | undefined): Filter;
104
+ export declare function createTaskFilter(patterns: string[] | undefined): Filter<string | undefined>;
102
105
  export {};
@@ -1,10 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.params = exports.dbNameParams = exports.pkgRestorePathParams = exports.pkgExcludeParams = exports.pkgIncludeParams = exports.pkgPathParams = exports.resolvePackages = exports.resolvePackage = exports.resolveDatabaseName = exports.resolvePackagePath = exports.filterPackages = exports.filterRepositoryByEnabled = exports.ensureSameRepositoryType = exports.sortReposByType = exports.filterRepository = exports.findPackageRepositoryConfig = exports.findPackageOrFail = exports.findRepositoryOrFail = void 0;
3
+ exports.createTaskFilter = exports.createPkgFilter = exports.params = exports.dbNameParams = exports.pkgRestorePathParams = exports.pkgExcludeParams = exports.pkgIncludeParams = exports.pkgPathParams = exports.resolvePackages = exports.resolvePackage = exports.resolveDatabaseName = exports.resolvePackagePath = exports.filterPackages = exports.filterRepositoryByEnabled = exports.ensureSameRepositoryType = exports.sortReposByType = exports.filterRepository = exports.findPackageRepositoryConfig = exports.findPackageOrFail = exports.findRepositoryOrFail = void 0;
4
4
  const error_1 = require("../error");
5
5
  const string_1 = require("../string");
6
6
  const temp_1 = require("../temp");
7
- const micromatch_1 = require("micromatch");
8
7
  function findRepositoryOrFail(config, repositoryName) {
9
8
  const repo = config.repositories.find((v) => v.name === repositoryName);
10
9
  if (!repo)
@@ -72,28 +71,26 @@ function filterRepositoryByEnabled(repository, action) {
72
71
  }
73
72
  exports.filterRepositoryByEnabled = filterRepositoryByEnabled;
74
73
  function filterPackages(config, options) {
75
- const packagePatterns = (0, string_1.makePathPatterns)(options.packageNames);
76
- const taskNamePatterns = (0, string_1.makePathPatterns)(options.packageTaskNames);
74
+ const filterRepo = (0, string_1.createPatternFilter)(options.repositoryNames);
75
+ const filterRepoType = (0, string_1.createPatternFilter)(options.repositoryTypes);
76
+ const filterTask = createTaskFilter(options.packageTaskNames);
77
+ const filterPkg = createPkgFilter(options.packageNames);
77
78
  return config.packages
78
79
  .map((pkg) => {
79
80
  pkg = Object.assign({}, pkg);
80
81
  pkg.repositoryNames = (pkg.repositoryNames ?? []).filter((name) => {
81
82
  const repo = findRepositoryOrFail(config, name);
82
- if (!filterRepositoryByEnabled(repo, options?.sourceAction))
83
- return false;
84
- return ((!options.repositoryNames ||
85
- options.repositoryNames.includes(name)) &&
86
- (!options.repositoryTypes ||
87
- options.repositoryTypes.includes(repo.type)));
83
+ return (filterRepositoryByEnabled(repo, options?.sourceAction) &&
84
+ filterRepo(name) &&
85
+ filterRepoType(repo.type));
88
86
  });
89
87
  return pkg;
90
88
  })
91
89
  .filter((pkg) => {
92
- if (taskNamePatterns && !(0, string_1.checkMatch)(pkg.task?.name, taskNamePatterns))
93
- return false;
94
90
  return ((typeof pkg.enabled !== "boolean" || pkg.enabled) &&
95
91
  !!pkg.repositoryNames?.length &&
96
- (!packagePatterns || (0, micromatch_1.isMatch)(pkg.name, packagePatterns)));
92
+ filterTask(pkg.task?.name) &&
93
+ filterPkg(pkg.name));
97
94
  });
98
95
  }
99
96
  exports.filterPackages = filterPackages;
@@ -166,3 +163,22 @@ exports.params = {
166
163
  pkgExclude: exports.pkgExcludeParams,
167
164
  dbName: exports.dbNameParams,
168
165
  };
166
+ function createPkgFilter(patterns) {
167
+ if (patterns === undefined)
168
+ return () => true;
169
+ const map = (v) => (v[0] === "@" && !v.includes("/") ? `${v}/**` : v);
170
+ const { include, exclude } = (0, string_1.splitPatterns)(patterns, map);
171
+ return (subject) => (0, string_1.match)(subject, include, exclude);
172
+ }
173
+ exports.createPkgFilter = createPkgFilter;
174
+ function createTaskFilter(patterns) {
175
+ if (patterns === undefined)
176
+ return () => true;
177
+ const { include, exclude } = (0, string_1.splitPatterns)(patterns);
178
+ return (subject) => {
179
+ if (!subject?.length)
180
+ subject = "<empty>";
181
+ return (0, string_1.match)(subject, include, exclude);
182
+ };
183
+ }
184
+ exports.createTaskFilter = createTaskFilter;
@@ -28,7 +28,7 @@ export type CronAction = {
28
28
  options: CopyCommandOptions;
29
29
  } | {
30
30
  name: "prune";
31
- options: PruneCommandOptions;
31
+ options: Omit<PruneCommandOptions, "confirm">;
32
32
  });
33
33
  export type DatatruckCronServerOptions = {
34
34
  enabled?: boolean;
@@ -31,7 +31,9 @@ function createCronServer(options, config) {
31
31
  try {
32
32
  const Command = command_1.datatruckCommandMap[action.name];
33
33
  const command = new Command({ config: { packages: [], repositories: [] } }, {});
34
- const cliOptions = (0, cli_1.stringifyOptions)(command.optionsConfig(), action.options);
34
+ const cliOptions = (0, cli_1.stringifyOptions)(command.optionsConfig(), action.name === "prune"
35
+ ? ({ ...action.options, confirm: true })
36
+ : action.options);
35
37
  const [node, bin] = process.argv;
36
38
  await async_process_1.AsyncProcess.exec(node, [bin, "-c", config.configPath, action.name, ...cliOptions], { $log: config.verbose });
37
39
  if (config.log)
@@ -85,7 +85,7 @@ async function createMysqlCli(options) {
85
85
  table_name
86
86
  `, [database]))
87
87
  .map((r) => r.table_name)
88
- .filter((0, string_1.createMatchFilter)(include, exclude));
88
+ .filter((0, string_1.createPatternFilter)({ include, exclude }));
89
89
  }
90
90
  async function dump(input) {
91
91
  const process = new async_process_1.AsyncProcess("mysqldump", [
@@ -11,11 +11,18 @@ export type Uri = {
11
11
  path?: string;
12
12
  };
13
13
  export declare function formatUri(input: Uri, hidePassword?: boolean): string;
14
- export declare function makePathPatterns(values: string[] | undefined): string[] | undefined;
14
+ export declare function splitPatterns(patterns: string[], map?: (pattern: string) => string): {
15
+ include: string[] | undefined;
16
+ exclude: string[] | undefined;
17
+ };
15
18
  export declare function match(path: string, include?: string[], exclude?: string[]): boolean;
19
+ export type Filter<V = string> = (subject: V) => boolean;
20
+ export declare function createPatternFilter(patterns: string[] | undefined): Filter;
21
+ export declare function createPatternFilter(patterns: {
22
+ include?: string[];
23
+ exclude?: string[];
24
+ } | undefined): Filter;
16
25
  export declare function endsWith(input: string, patterns: string[]): boolean;
17
- export declare function createMatchFilter(include?: string[], exclude?: string[]): (input: string) => boolean;
18
- export declare function checkMatch(subject: string | undefined, patterns: string[]): boolean;
19
26
  export declare function undefIfEmpty(input: string): string | undefined;
20
27
  export declare function compareJsons(a: any, b: any): boolean;
21
28
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.compareJsons = exports.undefIfEmpty = exports.checkMatch = exports.createMatchFilter = exports.endsWith = exports.match = exports.makePathPatterns = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = void 0;
3
+ exports.compareJsons = exports.undefIfEmpty = exports.endsWith = exports.createPatternFilter = exports.match = exports.splitPatterns = exports.formatUri = exports.parseStringList = exports.render = exports.snakeCase = void 0;
4
4
  const error_1 = require("./error");
5
5
  const micromatch_1 = require("micromatch");
6
6
  function snakeCase(value, char = "_") {
@@ -71,36 +71,44 @@ function formatUri(input, hidePassword) {
71
71
  return uri;
72
72
  }
73
73
  exports.formatUri = formatUri;
74
- function makePathPatterns(values) {
75
- return values?.flatMap((v) => {
76
- if (v === "*" || v === "**" || v === "<empty>" || v === "!<empty>") {
77
- return [v];
74
+ function splitPatterns(patterns, map) {
75
+ const include = [];
76
+ const exclude = [];
77
+ for (const pattern of patterns) {
78
+ if (pattern.startsWith("!")) {
79
+ const includePattern = pattern.slice(1);
80
+ exclude.push(map ? map(includePattern) : includePattern);
78
81
  }
79
82
  else {
80
- return [v, `${v}/**`];
83
+ include.push(map ? map(pattern) : pattern);
81
84
  }
82
- });
85
+ }
86
+ return {
87
+ include: include.length ? include : undefined,
88
+ exclude: exclude.length ? exclude : undefined,
89
+ };
83
90
  }
84
- exports.makePathPatterns = makePathPatterns;
91
+ exports.splitPatterns = splitPatterns;
85
92
  function match(path, include, exclude) {
86
93
  return ((!include || (0, micromatch_1.isMatch)(path, include, { dot: true })) &&
87
94
  (!exclude || !(0, micromatch_1.isMatch)(path, exclude, { dot: true })));
88
95
  }
89
96
  exports.match = match;
97
+ function createPatternFilter(patterns) {
98
+ if (patterns === undefined) {
99
+ return () => true;
100
+ }
101
+ else if (Array.isArray(patterns)) {
102
+ patterns = splitPatterns(patterns);
103
+ }
104
+ const { include, exclude } = patterns;
105
+ return (input) => match(input, include, exclude);
106
+ }
107
+ exports.createPatternFilter = createPatternFilter;
90
108
  function endsWith(input, patterns) {
91
109
  return patterns.some((pattern) => input.endsWith(pattern));
92
110
  }
93
111
  exports.endsWith = endsWith;
94
- function createMatchFilter(include, exclude) {
95
- return (input) => match(input, include, exclude);
96
- }
97
- exports.createMatchFilter = createMatchFilter;
98
- function checkMatch(subject, patterns) {
99
- if (!subject?.length)
100
- subject = "<empty>";
101
- return (0, micromatch_1.isMatch)(subject, patterns);
102
- }
103
- exports.checkMatch = checkMatch;
104
112
  function undefIfEmpty(input) {
105
113
  return input.length ? input : undefined;
106
114
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datatruck/cli",
3
- "version": "0.35.0",
3
+ "version": "0.36.0",
4
4
  "description": "Tool for creating and managing backups",
5
5
  "homepage": "https://github.com/swordev/datatruck#readme",
6
6
  "bugs": {