@datatruck/cli 0.41.3 → 0.41.4

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.
@@ -96,7 +96,6 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
96
96
  log: data.options.verbose,
97
97
  });
98
98
  const result = await restic.snapshots({
99
- json: true,
100
99
  tags: [
101
100
  ...(data.options.ids?.map((id) => ResticRepository.createSnapshotTag(id.length === 8 ? RepositoryAbstract_1.SnapshotTagEnum.SHORT_ID : RepositoryAbstract_1.SnapshotTagEnum.ID, id)) ?? []),
102
101
  ],
@@ -196,7 +195,6 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
196
195
  },
197
196
  });
198
197
  const [lastSnapshot] = await restic.snapshots({
199
- json: true,
200
198
  tags: [packageTag],
201
199
  latest: 1,
202
200
  });
@@ -289,18 +287,14 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
289
287
  if (!snapshot)
290
288
  throw new error_1.AppError(`Snapshot not found`);
291
289
  const restic = new restic_1.Restic({
292
- env: {
293
- ...(await this.buildEnv()),
294
- ...(typeof config.password === "string"
295
- ? { RESTIC_PASSWORD2: config.password }
296
- : { RESTIC_PASSWORD_FILE2: (0, path_1.resolve)(config.password.path) }),
297
- RESTIC_REPOSITORY2: await restic_1.Restic.formatRepository(config.repository),
298
- },
290
+ env: await this.buildEnv(),
299
291
  log: data.options.verbose,
300
292
  });
301
293
  let bytes = 0;
302
294
  await restic.copy({
303
- id: snapshot.originalId,
295
+ ids: [snapshot.originalId],
296
+ fromRepo: await restic_1.Restic.formatRepository(config.repository),
297
+ fromRepoPassword: config.password,
304
298
  onStream(data) {
305
299
  if (data.message_type === "status") {
306
300
  bytes = data.total_bytes;
@@ -40,16 +40,24 @@ export type ResticBackupStream = {
40
40
  export declare class Restic {
41
41
  readonly options: {
42
42
  log?: boolean;
43
- env: Record<string, string>;
43
+ env: {
44
+ RESTIC_REPOSITORY: string;
45
+ RESTIC_PASSWORD?: string;
46
+ RESTIC_PASSWORD_FILE?: string;
47
+ };
44
48
  };
45
49
  constructor(options: {
46
50
  log?: boolean;
47
- env: Record<string, string>;
51
+ env: {
52
+ RESTIC_REPOSITORY: string;
53
+ RESTIC_PASSWORD?: string;
54
+ RESTIC_PASSWORD_FILE?: string;
55
+ };
48
56
  });
49
57
  static formatRepository(input: ResticRepositoryUri, hidePassword?: boolean): Promise<string>;
50
58
  private createProcess;
51
59
  exec(args: string[], options?: AsyncProcessOptions): Promise<number>;
52
- private stdout;
60
+ json<T>(args: string[], options?: AsyncProcessOptions): Promise<T>;
53
61
  checkRepository(): Promise<boolean>;
54
62
  forget(options: {
55
63
  snapshotId?: string;
@@ -63,13 +71,16 @@ export declare class Restic {
63
71
  keepTag?: string[];
64
72
  tag?: string[];
65
73
  prune?: boolean;
74
+ args?: string[];
66
75
  }): Promise<void>;
67
76
  snapshots(options: {
77
+ ids?: string[];
68
78
  tags?: string[];
69
79
  paths?: string[];
70
80
  latest?: number;
71
81
  json?: boolean;
72
- snapshotIds?: string[];
82
+ group?: ("path" | "tags" | "host")[];
83
+ args?: string[];
73
84
  }): Promise<{
74
85
  time: string;
75
86
  tree: string;
@@ -92,10 +103,16 @@ export declare class Restic {
92
103
  allowEmptySnapshot?: boolean;
93
104
  onStream?: (data: ResticBackupStream) => void;
94
105
  createEmptyDir?: () => Promise<string>;
106
+ args?: string[];
95
107
  }): Promise<void>;
96
108
  copy(options: {
97
- id: string;
109
+ ids: string[];
110
+ fromRepo?: string;
111
+ fromRepoPassword?: string | {
112
+ path: string;
113
+ };
98
114
  onStream?: (data: ResticBackupStream) => void;
115
+ args?: string[];
99
116
  }): Promise<void>;
100
117
  restore(options: {
101
118
  id: string;
@@ -105,5 +122,6 @@ export declare class Restic {
105
122
  */
106
123
  progressInterval?: number | false;
107
124
  onStream?: (data: ResticBackupStream) => void;
125
+ args?: string[];
108
126
  }): Promise<AsyncProcess>;
109
127
  }
@@ -1,9 +1,62 @@
1
1
  "use strict";
2
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
3
+ if (value !== null && value !== void 0) {
4
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
5
+ var dispose, inner;
6
+ if (async) {
7
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
8
+ dispose = value[Symbol.asyncDispose];
9
+ }
10
+ if (dispose === void 0) {
11
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
12
+ dispose = value[Symbol.dispose];
13
+ if (async) inner = dispose;
14
+ }
15
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
16
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
17
+ env.stack.push({ value: value, dispose: dispose, async: async });
18
+ }
19
+ else if (async) {
20
+ env.stack.push({ async: true });
21
+ }
22
+ return value;
23
+ };
24
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
25
+ return function (env) {
26
+ function fail(e) {
27
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
28
+ env.hasError = true;
29
+ }
30
+ var r, s = 0;
31
+ function next() {
32
+ while (r = env.stack.pop()) {
33
+ try {
34
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
35
+ if (r.dispose) {
36
+ var result = r.dispose.call(r.value);
37
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
38
+ }
39
+ else s |= 1;
40
+ }
41
+ catch (e) {
42
+ fail(e);
43
+ }
44
+ }
45
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
46
+ if (env.hasError) throw env.error;
47
+ }
48
+ return next();
49
+ };
50
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
51
+ var e = new Error(message);
52
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
53
+ });
2
54
  Object.defineProperty(exports, "__esModule", { value: true });
3
55
  exports.Restic = void 0;
4
56
  const async_process_1 = require("./async-process");
5
57
  const fs_1 = require("./fs");
6
58
  const string_1 = require("./string");
59
+ const temp_1 = require("./temp");
7
60
  const promises_1 = require("fs/promises");
8
61
  const path_1 = require("path");
9
62
  const emptySnapshotTag = "empty-snapshot";
@@ -31,7 +84,8 @@ class Restic {
31
84
  createProcess(args, options) {
32
85
  return new async_process_1.AsyncProcess("restic", args, {
33
86
  stdio: ["ignore", "pipe", "pipe"],
34
- env: { ...process.env, ...this.options.env },
87
+ ...(options ?? {}),
88
+ env: { ...process.env, ...this.options.env, ...options?.env },
35
89
  $log: this.options.log
36
90
  ? {
37
91
  exec: true,
@@ -46,14 +100,14 @@ class Restic {
46
100
  ],
47
101
  }
48
102
  : {},
49
- ...(options ?? {}),
50
103
  });
51
104
  }
52
105
  async exec(args, options) {
53
106
  return await this.createProcess(args, options).waitForClose();
54
107
  }
55
- async stdout(args, options) {
56
- return await this.createProcess(args, options).stdout.fetch();
108
+ async json(args, options) {
109
+ const stdout = await this.createProcess(args, options).stdout.fetch();
110
+ return JSON.parse(stdout);
57
111
  }
58
112
  async checkRepository() {
59
113
  return ((await this.exec(["cat", "config"], {
@@ -87,19 +141,22 @@ class Restic {
87
141
  : []),
88
142
  ...(options.tag ? options.tag.flatMap((v) => ["--tag", v]) : []),
89
143
  ...(options.prune ? ["--prune"] : []),
144
+ ...(options.args || []),
90
145
  ...(options.snapshotId ? [options.snapshotId] : []),
91
146
  ]);
92
147
  }
93
148
  async snapshots(options) {
94
- const json = await this.stdout([
149
+ const json = options.json ?? true;
150
+ return await this.json([
95
151
  "snapshots",
152
+ ...(json ? ["--json"] : []),
96
153
  ...(options.tags?.flatMap((tag) => [`--tag`, tag]) ?? []),
97
- ...(options.json ? ["--json"] : []),
98
154
  ...(options.paths?.flatMap((path) => ["--path", path]) ?? []),
155
+ ...(options.group ? ["--group-by", options.group.join(",")] : []),
99
156
  ...(options.latest ? ["--latest", options.latest.toString()] : []),
100
- ...(options.snapshotIds || []),
157
+ ...(options.args || []),
158
+ ...(options.ids || []),
101
159
  ]);
102
- return JSON.parse(json);
103
160
  }
104
161
  async backup(options) {
105
162
  try {
@@ -111,6 +168,7 @@ class Restic {
111
168
  ...(options.tags?.flatMap((v) => ["--tag", v]) ?? []),
112
169
  ...(options.setPaths?.flatMap((v) => ["--set-path", v]) ?? []),
113
170
  ...(options.parent ? ["--parent", options.parent] : []),
171
+ ...(options.args || []),
114
172
  ...options.paths,
115
173
  ], { cwd: options.cwd });
116
174
  if (options.onStream) {
@@ -151,16 +209,51 @@ class Restic {
151
209
  }
152
210
  }
153
211
  async copy(options) {
154
- const copy = this.createProcess(["copy", "--json", options.id]);
155
- if (options.onStream) {
156
- await copy.stdout.parseLines((line) => {
157
- if (line.startsWith("{") && line.endsWith("}")) {
158
- options.onStream?.(JSON.parse(line));
159
- }
212
+ const env_1 = { stack: [], error: void 0, hasError: false };
213
+ try {
214
+ const rawPassword = typeof options.fromRepoPassword === "string"
215
+ ? options.fromRepoPassword
216
+ : undefined;
217
+ const fromPasswordDir = __addDisposableResource(env_1, rawPassword
218
+ ? await (0, temp_1.useTempDir)("restic-copy")
219
+ : undefined, true);
220
+ const fromPasswordFile = fromPasswordDir
221
+ ? (0, path_1.join)(fromPasswordDir.path, "password.txt")
222
+ : !!options.fromRepoPassword &&
223
+ typeof options.fromRepoPassword !== "string"
224
+ ? options.fromRepoPassword.path
225
+ : undefined;
226
+ if (fromPasswordFile && rawPassword)
227
+ await (0, promises_1.writeFile)(fromPasswordFile, rawPassword);
228
+ const copy = this.createProcess([
229
+ "copy",
230
+ "--json",
231
+ ...(fromPasswordFile ? ["--from-password-file", fromPasswordFile] : []),
232
+ ...(options.fromRepo ? ["--from-repo", options.fromRepo] : []),
233
+ ...(options.args || []),
234
+ ...options.ids,
235
+ ], {
236
+ env: {},
160
237
  });
238
+ if (options.onStream) {
239
+ await copy.stdout.parseLines((line) => {
240
+ if (line.startsWith("{") && line.endsWith("}")) {
241
+ options.onStream?.(JSON.parse(line));
242
+ }
243
+ });
244
+ }
245
+ else {
246
+ await copy.waitForClose();
247
+ }
248
+ }
249
+ catch (e_1) {
250
+ env_1.error = e_1;
251
+ env_1.hasError = true;
161
252
  }
162
- else {
163
- await copy.waitForClose();
253
+ finally {
254
+ const result_1 = __disposeResources(env_1);
255
+ if (result_1)
256
+ await result_1;
164
257
  }
165
258
  }
166
259
  async restore(options) {
@@ -180,8 +273,7 @@ class Restic {
180
273
  }
181
274
  }
182
275
  const snapshots = await this.snapshots({
183
- snapshotIds: [options.id],
184
- json: true,
276
+ ids: [options.id],
185
277
  });
186
278
  if (typeof progressInterval === "number")
187
279
  progressRutine();
@@ -192,6 +284,7 @@ class Restic {
192
284
  options.id,
193
285
  "--target",
194
286
  options.target,
287
+ ...(options.args || []),
195
288
  ]);
196
289
  if (options.onStream) {
197
290
  await result.stdout.parseLines((line) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datatruck/cli",
3
- "version": "0.41.3",
3
+ "version": "0.41.4",
4
4
  "description": "Tool for creating and managing backups",
5
5
  "homepage": "https://github.com/swordev/datatruck#readme",
6
6
  "bugs": {