@ps-aux/nodebup 0.11.1 → 0.12.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.
@@ -5,14 +5,6 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.AggregateBackupController = void 0;
7
7
 
8
- var _FsSyncer = require("../../fs/fssync/FsSyncer");
9
-
10
- var _Gpg = require("../../tools/gpg/Gpg");
11
-
12
- var _Fs = require("../../fs/Fs");
13
-
14
- var _SshKeyManager = require("../../tools/ssh/SshKeyManager");
15
-
16
8
  var _inversify = require("inversify");
17
9
 
18
10
  var _ContextSymbols = require("../../ctx/ContextSymbols");
@@ -25,6 +17,14 @@ var _BackupStorageProvider = require("../../storage/BackupStorageProvider");
25
17
 
26
18
  var _logging = require("../../log/logging");
27
19
 
20
+ var _SshKeyManager = require("../../tools/ssh/SshKeyManager");
21
+
22
+ var _Gpg = require("../../tools/gpg/Gpg");
23
+
24
+ var _Fs = require("../../fs/Fs");
25
+
26
+ var _FsSyncer = require("../../fs/fssync/FsSyncer");
27
+
28
28
  var _dec, _dec2, _dec3, _dec4, _class;
29
29
 
30
30
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
@@ -53,7 +53,7 @@ let AggregateBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = fu
53
53
  } = aggr.sources;
54
54
 
55
55
  try {
56
- this.fs.ensureDir(aggrDir);
56
+ await this.fs.ensureDir(aggrDir);
57
57
  file.forEach(f => this.runFileTask(f, aggrDir));
58
58
  sshKey.forEach(k => this.runSshKeyTask(k, aggrDir));
59
59
  gpgKey.forEach(k => this.runGpgKeyTask(k, aggrDir));
@@ -23,22 +23,22 @@ let DirBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.
23
23
 
24
24
  _defineProperty(this, "log", (0, _logging.classObjLog)(this));
25
25
 
26
- _defineProperty(this, "backup", inp => {
26
+ _defineProperty(this, "backup", async inp => {
27
27
  const storage = this.storageProvider.provide();
28
28
 
29
29
  const path = _Path.AbsPath.from(inp.path);
30
30
 
31
31
  this.log.info(`Backing up from ${path} to '${storage}'`);
32
- storage.store(path);
32
+ await storage.store(path);
33
33
  });
34
34
 
35
- _defineProperty(this, "restore", inp => {
35
+ _defineProperty(this, "restore", async inp => {
36
36
  const storage = this.storageProvider.provide();
37
37
 
38
38
  const path = _Path.AbsPath.from(inp.path);
39
39
 
40
40
  this.log.info(`Restoring from '${storage}' to ${path}`);
41
- storage.restore(path);
41
+ await storage.restore(path);
42
42
  });
43
43
  }
44
44
 
@@ -5,8 +5,6 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.PgBackupController = void 0;
7
7
 
8
- var _Fs = require("../../fs/Fs");
9
-
10
8
  var _inversify = require("inversify");
11
9
 
12
10
  var _Shell = require("../../tools/shell/Shell");
@@ -19,6 +17,8 @@ var _Zipper = require("../../tools/compression/Zipper");
19
17
 
20
18
  var _logging = require("../../log/logging");
21
19
 
20
+ var _Fs = require("../../fs/Fs");
21
+
22
22
  var _dec, _dec2, _dec3, _class, _class2, _temp;
23
23
 
24
24
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
@@ -59,61 +59,123 @@ let PgBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.m
59
59
 
60
60
  _defineProperty(this, "getVersion", version => version || PgBackupController.defaultPgVersion);
61
61
 
62
- _defineProperty(this, "outFileName", 'backup.sql');
63
-
64
62
  _defineProperty(this, "backup", async ({
65
63
  pgUrl,
66
- pgVersion
64
+ pgBinDir,
65
+ backupName
67
66
  }) => {
68
67
  const storage = this.storageBackendProvider.provide();
69
- const version = this.getVersion(pgVersion); // TODO validate url
68
+ const connParams = parseConnectionUrl(pgUrl); // TODO validate url
70
69
 
71
- this.log.info(`Backing up Postgres database, version=${version}`);
72
- const connParams = parseConnectionUrl(pgUrl);
73
- const pass = connParams.password; // if (3 > 2)
74
- // return
70
+ this.log.info(`Backing up Postgres database @${connParams.host}`);
75
71
 
76
- await this.fs.inTmpDir('pg-backup', async dir => {
77
- const outputDir = _Path.AbsPath.from(dir);
72
+ const dir = _Path.AbsPath.from(`/var/backup/bup/${backupName}/postgres`); // const dir = AbsPath.from('/var/foo')
78
73
 
79
- this.log.info('Processing Postgres backup');
80
- const bashCmds = [`echo "*:*:*:*:${pass}" > ~/.pgpass`, `chmod 400 ~/.pgpass`, `pg_dumpall -d ${pgUrl}`]; // Don't forget that this itself might be run in docker
74
+
75
+ await this.fs.inNewDir(dir, async () => {
76
+ // const outputDir = AbsPath.from(dir)
77
+ this.log.info('Processing Postgres backup'); // Don't forget that this itself might be run in docker
81
78
  // therefore volume mounts are not usable (will apply to the location at host)
82
79
 
83
- const zipOutPath = outputDir.resolve(`pg-backup-${this.now()}.sql.gz`);
84
- this.log.info(`Dumping database to ${zipOutPath.str()}`);
85
- await this.sh.exec(`docker run --rm --network host ` + `postgres:${version} ` + `bash -c '${bashCmds.join(' && ')}' | gzip> ${zipOutPath.str()}`);
80
+ const file = PgBackupController.dumpFileName;
81
+ this.log.info(`Dumping data into ${file}`);
82
+ let cmd = `pg_dumpall -d ${pgUrl} `;
83
+
84
+ if (pgBinDir) {
85
+ cmd = this.addPgBinDir(cmd, pgBinDir);
86
+ }
87
+
88
+ await this.sh.asyncExec(`${cmd} > ${file}`, {
89
+ env: {
90
+ PGPASSWORD: connParams.password
91
+ },
92
+ cwd: dir.str()
93
+ }, {
94
+ stdout: o => this.log.trace(o),
95
+ stderr: o => this.log.error(o)
96
+ });
97
+ this.log.info(`Compressing ${file}`);
98
+ await this.sh.asyncExec(`gzip -v ${file}`, {
99
+ cwd: dir.str()
100
+ }, {
101
+ stdout: o => this.log.trace('gzip: ' + o),
102
+ stderr: o => this.log.info('gzip: ' + o)
103
+ });
86
104
  this.log.info('Uploading');
87
- storage.store(_Path.AbsPath.from(dir));
105
+ await storage.store(dir);
88
106
  });
89
107
  });
90
108
 
109
+ _defineProperty(this, "dumpFromDockerCmd", (pass, pgUrl, version) => {
110
+ const bashCmds = [`echo "*:*:*:*:${pass}" > ~/.pgpass`, `chmod 400 ~/.pgpass`, `pg_dumpall -d ${pgUrl}`]; // Restore docker command
111
+ // this.sh.exec(
112
+ // `gzip --decompress --stdout ${zipFile.str()} | docker run --network host -i ` +
113
+ // `-e PGPASSWORD=${con.password} ` +
114
+ // `postgres:${version} ` +
115
+ // `psql ${connectionArgs} -v ON_ERROR_STOP=0`
116
+ // )
117
+ // TODO consider pulling the docker images first so the Docke daremon info messages about container pulling are not logged as errors
118
+
119
+ return `docker run --rm --network host postgres:${version} ` + `bash -c '${bashCmds.join(' && ')}'`;
120
+ });
121
+
91
122
  _defineProperty(this, "restore", async ({
92
123
  pgUrl,
93
- pgVersion
124
+ pgBinDir
94
125
  }) => {
95
- const version = this.getVersion(pgVersion);
126
+ // const version = this.getVersion(pgVersion)
96
127
  const storage = this.storageBackendProvider.provide(); // To validate
97
128
 
98
129
  const con = parseConnectionUrl(pgUrl);
99
- this.log.info(`Restoring Postgres database, version=${version}`);
130
+ this.log.info(`Restoring Postgres database`);
100
131
  await this.fs.inTmpDir('pg-restore', async dirStr => {
101
132
  const dir = _Path.AbsPath.from(dirStr);
102
133
 
103
- storage.restore(dir); // TODO check if the dir contains the with the expected name
134
+ await storage.restore(dir); // TODO check if the dir contains the with the expected name
104
135
  // TODO add e2e test for docker
105
136
 
106
- const zipFile = this.fs.listFiles(dir)[0];
107
- this.log.debug('Will run psql import from %s', zipFile.str()); // Database is set to 'postgres' so that also users which don't have db created can use db-less URL
137
+ this.log.info('Backup dir restored');
138
+ const file = PgBackupController.dumpFileName;
139
+ const zipFile = file + '.gz';
140
+ const zipPath = this.fs.listFiles(dir).find(n => n.basename() === zipFile);
141
+ if (!zipPath) throw new Error(`Expected to find file ${zipFile} in the restore data`);
142
+ this.log.info(`Decompressing ${zipFile}`);
143
+ await this.sh.asyncExec(`gzip --decompress -v ${zipFile}`, {
144
+ cwd: dir.str()
145
+ }, {
146
+ stdout: o => this.log.trace('gzip: ' + o),
147
+ stderr: o => this.log.info('gzip: ' + o)
148
+ }); // Database is set to 'postgres' so that also users which don't have db created can use db-less URL
108
149
  // Restoring user needs to have the admin access anyway
109
150
 
110
151
  const connectionArgs = `-h ${con.host} -p ${con.port} -U ${con.username} -d postgres`; // Don't forget that this itself might be run in docker
111
152
  // therefore volume mounts are not usable (will apply to the location at host)
112
153
 
113
- this.sh.exec(`gzip --decompress --stdout ${zipFile.str()} | docker run --network host -i ` + `-e PGPASSWORD=${con.password} ` + `postgres:${version} ` + `psql ${connectionArgs} -v ON_ERROR_STOP=0`);
154
+ let cmd = `psql ${connectionArgs} -v ON_ERROR_STOP=0 < ${file}`;
155
+
156
+ if (pgBinDir) {
157
+ cmd = this.addPgBinDir(cmd, pgBinDir);
158
+ }
159
+
160
+ await this.sh.asyncExec(cmd, {
161
+ cwd: dir.str(),
162
+ env: {
163
+ PGPASSWORD: con.password
164
+ }
165
+ }, {
166
+ stdout: o => this.log.trace(o),
167
+ stderr: o => this.log.error(o)
168
+ });
169
+ this.log.info(`Data successfully inserted into database @${con.host}`);
114
170
  });
115
171
  });
172
+
173
+ _defineProperty(this, "addPgBinDir", (cmd, pgBinDir) => {
174
+ this.log.info(`Using PG bin dir ${pgBinDir}`);
175
+ this.fs.ensureIsDir(_Path.AbsPath.from(pgBinDir));
176
+ return pgBinDir + '/' + cmd;
177
+ });
116
178
  }
117
179
 
118
- }, _defineProperty(_class2, "defaultPgVersion", '14.2'), _temp)) || _class) || _class) || _class);
180
+ }, _defineProperty(_class2, "defaultPgVersion", '14.2'), _defineProperty(_class2, "dumpFileName", 'pg-dump.sql'), _temp)) || _class) || _class) || _class);
119
181
  exports.PgBackupController = PgBackupController;
package/lib/cli/app.js CHANGED
@@ -45,6 +45,7 @@ const singleStorageOptions = [storageNameOpt, {
45
45
  }];
46
46
  const backupTagOption = {
47
47
  name: 'backup-tag',
48
+ fromConfig: 'backup.tag',
48
49
  convertCase: true
49
50
  };
50
51
  const backupOptions = [backupTagOption];
@@ -117,6 +118,17 @@ const restic = (0, _nclif.cmdGroup)({
117
118
  snapshots: (0, _nclif.cmd)({
118
119
  run: (_, c, p) => c.get(_ResticController.ResticController).listSnapshots(p.stdout)
119
120
  }),
121
+ env: (0, _nclif.cmd)({
122
+ run: ({
123
+ export: doExport
124
+ }, c) => c.get(_ResticController.ResticController).printEnv(doExport),
125
+ options: [{
126
+ name: 'export',
127
+ type: 'boolean',
128
+ description: 'Add "export" statement to each env variable inoutput',
129
+ convertCase: true
130
+ }]
131
+ }),
120
132
  cmd: (0, _nclif.cmd)({
121
133
  positionals: [{
122
134
  name: 'cmd',
@@ -132,18 +144,30 @@ const pg = (0, _nclif.cmdGroup)({
132
144
  description: 'Postgres backup commands',
133
145
  options: [...singleStorageOptions, {
134
146
  name: 'pg-url',
147
+ description: 'Postgres URL',
135
148
  convertCase: true,
136
149
  fromConfig: 'pg.url',
137
150
  required: true
138
151
  }, {
139
- name: 'pg-version',
152
+ name: 'pg-bin-dir',
153
+ description: 'A directory with Postgres binaries (if the ones on the path should not be used)',
140
154
  convertCase: true,
141
- fromConfig: 'pg.version',
142
- description: `Postgres version - default is ${_PgBackupController.PgBackupController.defaultPgVersion}`
143
- }],
155
+ fromConfig: 'pg.bin-dir'
156
+ } // {
157
+ // name: 'pg-version',
158
+ // convertCase: true,
159
+ // fromConfig: 'pg.version',
160
+ // description: `Postgres version - default is ${PgBackupController.defaultPgVersion}`
161
+ // }
162
+ ],
144
163
  commands: {
145
164
  backup: (0, _nclif.cmd)({
146
- options: backupOptions,
165
+ options: [...backupOptions, {
166
+ name: 'backup-name',
167
+ convertCase: true,
168
+ fromConfig: 'backup.name',
169
+ required: true
170
+ }],
147
171
  run: (inp, c) => c.get(_PgBackupController.PgBackupController).backup(inp)
148
172
  }),
149
173
  restore: (0, _nclif.cmd)({
@@ -5,16 +5,16 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.readConfig = void 0;
7
7
 
8
+ var _expandAndCreatePath = require("./expandAndCreatePath");
9
+
10
+ var _Fs = require("../fs/Fs");
11
+
8
12
  var _Path = require("../fs/path/Path");
9
13
 
10
14
  var _readYaml = require("../fs/readYaml");
11
15
 
12
16
  var _validateConfigAgainstSchema = require("./validateConfigAgainstSchema");
13
17
 
14
- var _expandAndCreatePath = require("./expandAndCreatePath");
15
-
16
- var _Fs = require("../fs/Fs");
17
-
18
18
  const expandPaths = (cfg, exp) => {
19
19
  cfg.aggregates.forEach(a => {
20
20
  a.sources.file.forEach(f => {
@@ -37,7 +37,8 @@ const readFromFile = cwd => {
37
37
  const cfg = fs.exists(cfgPath) ? (0, _readYaml.readYaml)(cfgPath.str()) : {
38
38
  aggregates: [],
39
39
  storage: []
40
- };
40
+ }; // eslint-disable-next-line no-undef
41
+
41
42
  (0, _validateConfigAgainstSchema.validateConfigAgainstSchema)(cfg);
42
43
  return cfg;
43
44
  };
@@ -5,12 +5,12 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.expandStrPath = exports.expandAndCreatePath = void 0;
7
7
 
8
- var _Path = require("../fs/path/Path");
9
-
10
8
  var _os = _interopRequireDefault(require("os"));
11
9
 
12
10
  var _path = _interopRequireDefault(require("path"));
13
11
 
12
+ var _Path = require("../fs/path/Path");
13
+
14
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
15
 
16
16
  const expandStrPath = (path, pwd) => {
@@ -5,16 +5,6 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.createContext = void 0;
7
7
 
8
- var _Shell = require("../tools/shell/Shell");
9
-
10
- var _FsSyncer = require("../fs/fssync/FsSyncer");
11
-
12
- var _Gpg = require("../tools/gpg/Gpg");
13
-
14
- var _Fs = require("../fs/Fs");
15
-
16
- var _SshKeyManager = require("../tools/ssh/SshKeyManager");
17
-
18
8
  var _inversify = require("inversify");
19
9
 
20
10
  var _ContextSymbols = require("./ContextSymbols");
@@ -39,6 +29,16 @@ var _PgBackupController = require("../bup/pg/PgBackupController");
39
29
 
40
30
  var _Zipper = require("../tools/compression/Zipper");
41
31
 
32
+ var _FsSyncer = require("../fs/fssync/FsSyncer");
33
+
34
+ var _Gpg = require("../tools/gpg/Gpg");
35
+
36
+ var _Shell = require("../tools/shell/Shell");
37
+
38
+ var _Fs = require("../fs/Fs");
39
+
40
+ var _SshKeyManager = require("../tools/ssh/SshKeyManager");
41
+
42
42
  const createContext = (cfg, inp) => {
43
43
  const c = new _inversify.Container();
44
44
  c.bind(_ContextSymbols.AppConfig_).toConstantValue(cfg);
package/lib/fs/Fs.js CHANGED
@@ -7,9 +7,9 @@ exports.Fs = void 0;
7
7
 
8
8
  var _fs = _interopRequireDefault(require("fs"));
9
9
 
10
- var _path = _interopRequireDefault(require("path"));
10
+ var _promises = _interopRequireDefault(require("fs/promises"));
11
11
 
12
- var _Path = require("./path/Path");
12
+ var _path = _interopRequireDefault(require("path"));
13
13
 
14
14
  var _inversify = require("inversify");
15
15
 
@@ -19,6 +19,8 @@ var _os = _interopRequireDefault(require("os"));
19
19
 
20
20
  var _logging = require("../log/logging");
21
21
 
22
+ var _Path = require("./path/Path");
23
+
22
24
  var _dec, _dec2, _dec3, _class;
23
25
 
24
26
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -73,10 +75,23 @@ let Fs = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:
73
75
  try {
74
76
  await withDir(dir);
75
77
  } finally {
78
+ // TODO handle if not exists?
76
79
  this.rmDir(_Path.AbsPath.from(dir));
77
80
  }
78
81
  });
79
82
 
83
+ _defineProperty(this, "inNewDir", async (path, withDir) => {
84
+ let created = false;
85
+
86
+ try {
87
+ await this.ensureDir(path, true);
88
+ created = true;
89
+ await withDir();
90
+ } finally {
91
+ if (created) this.rmDir(path);
92
+ }
93
+ });
94
+
80
95
  _defineProperty(this, "mkTmpDir", name => {
81
96
  const dir = _fs.default.mkdtempSync(_path.default.resolve(_os.default.tmpdir(), name));
82
97
 
@@ -97,7 +112,7 @@ let Fs = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:
97
112
  return JSON.parse(file);
98
113
  });
99
114
 
100
- _defineProperty(this, "ensureDir", path => {
115
+ _defineProperty(this, "ensureDir", async (path, mustBeEmpty = false) => {
101
116
  if (!this.exists(path)) {
102
117
  this.log.trace('Dir %s does not exist. Wil be created', path.str());
103
118
 
@@ -106,13 +121,18 @@ let Fs = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:
106
121
  });
107
122
  } else {
108
123
  if (this.isFile(path)) throw new Error(`${path.str()} exists and is not a directory`);
124
+
125
+ if (mustBeEmpty) {
126
+ const content = await _promises.default.readdir(path.str());
127
+ if (content.length) throw new Error(`${path.str()} exists but is not empty`);
128
+ }
109
129
  }
110
130
  });
111
131
 
112
- _defineProperty(this, "ensureParentDir", path => {
132
+ _defineProperty(this, "ensureParentDir", async path => {
113
133
  const parent = path.parent();
114
134
  if (this.exists(parent)) return;
115
- this.ensureDir(parent);
135
+ await this.ensureDir(parent);
116
136
  });
117
137
 
118
138
  _defineProperty(this, "exists", path => _fs.default.existsSync(path.str()));
@@ -34,7 +34,7 @@ let FsSyncer = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("d
34
34
  if (this.fs.isFile(from)) this.syncFile(from, to);else this.syncDirs(from, to);
35
35
  });
36
36
 
37
- _defineProperty(this, "syncDirs", (from, to) => {
37
+ _defineProperty(this, "syncDirs", async (from, to) => {
38
38
  this.fs.ensureIsDir(from);
39
39
  this.log.info('Syncing dir', from.str(), '==>', to.str());
40
40
  const fromPath = toUnixDirString(from);
@@ -12,15 +12,15 @@ class BackupStorage {
12
12
  this.backend = backend;
13
13
  this.props = props;
14
14
 
15
- _defineProperty(this, "store", from => {
15
+ _defineProperty(this, "store", async from => {
16
16
  const {
17
17
  tag
18
18
  } = this.props;
19
19
  const tags = tag ? [tag] : undefined;
20
- this.backend.backup(from, tags);
20
+ await this.backend.backup(from, tags);
21
21
  });
22
22
 
23
- _defineProperty(this, "restore", to => {
23
+ _defineProperty(this, "restore", async to => {
24
24
  const {
25
25
  snapshotId
26
26
  } = this.props;
@@ -17,7 +17,7 @@ class RcloneBackupBackend {
17
17
 
18
18
  _defineProperty(this, "log", (0, _logging.classObjLog)(this));
19
19
 
20
- _defineProperty(this, "backup", (from, tags) => {
20
+ _defineProperty(this, "backup", async (from, tags) => {
21
21
  if (tags) throw new _nclif.InvalidInputError(`Rclone does not support tags`);
22
22
  this.log.info('Performing backup', {
23
23
  from
@@ -25,14 +25,14 @@ class RcloneBackupBackend {
25
25
  this.rclone.backup(from);
26
26
  });
27
27
 
28
- _defineProperty(this, "restoreLatest", to => {
28
+ _defineProperty(this, "restoreLatest", async to => {
29
29
  this.log.info('Restoring', {
30
30
  to
31
31
  });
32
32
  this.rclone.restore(to);
33
33
  });
34
34
 
35
- _defineProperty(this, "restoreSnapshot", (to, snapshotId) => {
35
+ _defineProperty(this, "restoreSnapshot", async (to, snapshotId) => {
36
36
  throw new _nclif.InvalidInputError(`Rclone does not support snaphosts`);
37
37
  });
38
38
  }
@@ -15,11 +15,12 @@ var _b2TestConfig = require("../../../test/b2TestConfig");
15
15
  var _testHelper = require("../../../test/testHelper");
16
16
 
17
17
  describe('RcloneClient', () => {
18
- const getRestoreDir = (0, _test.testdataDirBuilder)('b2/restore');
18
+ // TODO clean up dir locations more
19
+ const testData = (0, _test.testdataDirBuilder)('rclone');
19
20
  describe('local', () => {
20
21
  const backupDir = (0, _test.testDir)('backup/1');
21
- const restoreDir = getRestoreDir('local');
22
- const storeDir = (0, _test.testdataDir)('b2/store');
22
+ const restoreDir = testData('local');
23
+ const storeDir = testData('store');
23
24
  const cfg = {
24
25
  type: 'local',
25
26
  location: (0, _test.testdataDir)(storeDir),
@@ -68,11 +69,11 @@ describe('RcloneClient', () => {
68
69
  password: 'foo123'
69
70
  }
70
71
  }, new _Shell.Shell());
71
- const restoreDir = getRestoreDir('b2');
72
+ const restoreDir = testData('b2');
72
73
  afterAll(() => {
73
74
  (0, _testHelper.cleanDir)(restoreDir);
74
75
  });
75
- it('push adn restore data', () => {
76
+ it('push and restore data', () => {
76
77
  sut.backup(_Path.AbsPath.from(backupDir));
77
78
  sut.restore(_Path.AbsPath.from(restoreDir));
78
79
  const res = (0, _dirCompare.compareSync)(backupDir, restoreDir);
@@ -17,18 +17,18 @@ class ResticBackupBackend {
17
17
 
18
18
  _defineProperty(this, "log", (0, _logging.classObjLog)(this));
19
19
 
20
- _defineProperty(this, "backup", (from, tags = []) => {
20
+ _defineProperty(this, "backup", async (from, tags = []) => {
21
21
  this.log.info(`Performing backup from=${from}, tags=${tags}`);
22
- this.restic.backup(from, _Path.RelativePath.from('.'), tags);
22
+ await this.restic.backup(from, _Path.RelativePath.from('.'), tags);
23
23
  this.restic.forget();
24
24
  });
25
25
 
26
- _defineProperty(this, "restoreLatest", to => {
26
+ _defineProperty(this, "restoreLatest", async to => {
27
27
  this.log.info(`Restoring latest snapshot to=${to}`);
28
28
  this.restic.restore(to);
29
29
  });
30
30
 
31
- _defineProperty(this, "restoreSnapshot", (to, snapshotId) => {
31
+ _defineProperty(this, "restoreSnapshot", async (to, snapshotId) => {
32
32
  this.log.info(`Restoring snapshot '${snapshotId}'`, {
33
33
  to
34
34
  });
@@ -30,10 +30,13 @@ class ResticClient {
30
30
 
31
31
  _defineProperty(this, "log", (0, _logging.classObjLog)(this));
32
32
 
33
- _defineProperty(this, "prepareRepo", () => {
33
+ _defineProperty(this, "prepareRepo", async () => {
34
34
  this.log.info('Preparing a restic repo at %s', this.url);
35
- this.shell.exec(`restic init`, {
35
+ await this.shell.asyncExec(`restic init`, {
36
36
  env: this.env()
37
+ }, {
38
+ stdout: o => this.log.trace(o),
39
+ stderr: o => this.log.error(o)
37
40
  });
38
41
  });
39
42
 
@@ -43,15 +46,18 @@ class ResticClient {
43
46
  });
44
47
  });
45
48
 
46
- _defineProperty(this, "backup", (cwd, from, tags = []) => {
49
+ _defineProperty(this, "backup", async (cwd, from, tags = []) => {
47
50
  this.log.debug('Running backup for repo=%s', this.url);
48
51
  let cmd = `restic backup ${from.str()}`;
49
52
  tags.forEach(t => {
50
53
  cmd += ` --tag=${t}`;
51
54
  });
52
- this.shell.exec(cmd, {
55
+ await this.shell.asyncExec(cmd, {
53
56
  cwd: cwd.str(),
54
57
  env: this.env()
58
+ }, {
59
+ stdout: o => this.log.trace(o),
60
+ stderr: o => this.log.error(o)
55
61
  });
56
62
  });
57
63
 
@@ -77,14 +83,17 @@ class ResticClient {
77
83
  });
78
84
 
79
85
  _defineProperty(this, "snapshots", () => {
80
- this.log.debug('Listing snapshots of repo=%', this.url);
86
+ this.log.debug(`Listing snapshots of repo=${this.url}`);
81
87
  const out = this.shell.execAndReturnString(`restic snapshots --json`, {
82
88
  env: this.env()
83
89
  });
84
90
  const res = JSON.parse(out);
85
91
  return res.map(r => ({
86
92
  id: r.id,
93
+ short_id: r.short_id,
87
94
  time: new Date(r.time),
95
+ paths: r.paths,
96
+ hostname: r.hostname,
88
97
  tags: r.tags
89
98
  }));
90
99
  });
@@ -30,8 +30,9 @@ describe('ResticClient', () => {
30
30
  (0, _testHelper.cleanDir)(repoDir);
31
31
  (0, _testHelper.cleanDir)(restoreDir);
32
32
  });
33
- it('create repo', () => {
34
- sut.prepareRepo();
33
+ it('create repo', async () => {
34
+ await sut.prepareRepo();
35
+ console.log('repo created');
35
36
  });
36
37
  it('push data & forget', () => {
37
38
  const from = _Path.AbsPath.from(backupDir);
@@ -76,7 +77,7 @@ describe('ResticClient', () => {
76
77
  afterAll(() => {
77
78
  (0, _testHelper.cleanDir)(restoreDir);
78
79
  });
79
- it('push adn restore data', () => {
80
+ it('push and restore data', () => {
80
81
  // sut.prepareRepo()
81
82
  sut.backup(_Path.AbsPath.from(backupDir), _Path.RelativePath.from('.'));
82
83
  sut.restore(_Path.AbsPath.from(restoreDir));
@@ -39,10 +39,11 @@ let ResticController = (_dec = (0, _inversify.injectable)(), _dec2 = function (t
39
39
  return this.restFact.createClient(props);
40
40
  });
41
41
 
42
- _defineProperty(this, "initRepo", () => {
42
+ _defineProperty(this, "initRepo", async () => {
43
43
  const props = this.storageConfigProvider.provide();
44
44
  this.log.info(`Initializing Restic repo ${props.repo}`);
45
- this.client().prepareRepo();
45
+ await this.client().prepareRepo();
46
+ this.log.info('Repo initialized');
46
47
  });
47
48
 
48
49
  _defineProperty(this, "listSnapshots", print => {
@@ -54,6 +55,15 @@ let ResticController = (_dec = (0, _inversify.injectable)(), _dec2 = function (t
54
55
  const res = this.client().runCmd(cmd);
55
56
  print(res.toString());
56
57
  });
58
+
59
+ _defineProperty(this, "printEnv", (doExport = false) => {
60
+ const env = this.client().env();
61
+ const out = Object.entries(env).map(([k, v]) => `${k}=${v}`).map(line => {
62
+ if (!doExport) return line;
63
+ return `export ${line}`;
64
+ }).join('\n');
65
+ console.log(out);
66
+ });
57
67
  }
58
68
 
59
69
  }) || _class) || _class) || _class) || _class);
@@ -48,7 +48,7 @@ let Shell = (_dec = (0, _inversify.injectable)(), _dec(_class = class Shell {
48
48
  });
49
49
  });
50
50
 
51
- _defineProperty(this, "asyncExec", (cmd, onStdout, ops = {}) => {
51
+ _defineProperty(this, "asyncExec", (cmd, ops = {}, on) => {
52
52
  let onDone;
53
53
  let onError;
54
54
  const p = new Promise((res, rej) => {
@@ -60,8 +60,8 @@ let Shell = (_dec = (0, _inversify.injectable)(), _dec(_class = class Shell {
60
60
  cwd: ops.cwd,
61
61
  env: ops.env
62
62
  });
63
- r.stdout.on('data', onStdout);
64
- r.stderr.on('data', data => console.error(data.toString()));
63
+ r.stdout.on('data', o => on.stdout(o.toString()));
64
+ r.stderr.on('data', o => on.stderr(o.toString()));
65
65
  r.on('exit', status => {
66
66
  if (status === 0) onDone();else onError(new Error('Exited with non zero return code: ' + status));
67
67
  });
@@ -14,8 +14,13 @@ it.skip('execAndReturnStream', async () => {
14
14
  expect(() => sh.execAndReturnString(bigStdOutCme())).toThrow('spawnSync /bin/sh ENOBUFS'); //
15
15
 
16
16
  let out = '';
17
- await sh.asyncExec(bigStdOutCme(), data => {
18
- out = data.toString().trim();
17
+ await sh.asyncExec(bigStdOutCme(), {}, {
18
+ stdout: data => {
19
+ out = data.toString().trim();
20
+ },
21
+ stderr: data => {
22
+ console.error(data);
23
+ }
19
24
  });
20
25
  expect(out).toEndWith('Done');
21
26
  }, 5000_000);
@@ -5,14 +5,14 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.SshKeyManager = void 0;
7
7
 
8
- var _Fs = require("../../fs/Fs");
9
-
10
- var _Path = require("../../fs/path/Path");
11
-
12
8
  var _os = _interopRequireDefault(require("os"));
13
9
 
14
10
  var _inversify = require("inversify");
15
11
 
12
+ var _Fs = require("../../fs/Fs");
13
+
14
+ var _Path = require("../../fs/path/Path");
15
+
16
16
  var _dec, _dec2, _dec3, _class;
17
17
 
18
18
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@ps-aux/nodebup",
3
- "version": "0.11.1",
3
+ "version": "0.12.1",
4
4
  "description": "",
5
5
  "module": "lib/index.js",
6
6
  "main": "lib/index.js",
7
7
  "scripts": {
8
+ "run": "ts-node ./src/cli/bin.ts",
8
9
  "build": "rm -rf build && babel --extensions '.ts,.js,.md' src -d lib src",
9
10
  "publish:local": "npm run build && chmod +x lib/cli/bin.js && npm link",
10
11
  "pub": "npm publish --access public",
11
- "test": "jest",
12
- "test:ci": "jest --group=-no-ci",
12
+ "test": "jest --runInBand",
13
+ "test:ci": "jest --group=-no-ci --runInBand",
13
14
  "tc": "tsc --noEmit",
14
15
  "format": "prettier \"**/*.{js,ts,tsx}\" --write",
15
16
  "build-n-run": "npm run build && ",
@@ -68,6 +69,7 @@
68
69
  "pg": "^8.7.3",
69
70
  "prettier": "^2.5.1",
70
71
  "ts-jest": "^27.1.2",
72
+ "ts-node": "^10.9.2",
71
73
  "typescript": "^4.5.4"
72
74
  },
73
75
  "lint-staged": {