@ps-aux/nodebup 0.10.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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));
@@ -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
+ 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
134
  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
@@ -53,55 +53,63 @@ const restoreOptions = [backupTagOption, {
53
53
  convertCase: true
54
54
  }];
55
55
 
56
- const createApp = () => _nclif.CliApp.of({
57
- commands: {
58
- dir: (0, _nclif.cmdGroup)({
59
- options: singleStorageOptions,
60
- commands: {
61
- backup: (0, _nclif.cmd)({
62
- description: 'Backup a dir to the given storage',
63
- options: backupOptions,
64
- positionals: [{
65
- name: 'path',
66
- required: true
67
- }],
68
- run: (cmd, c) => c.get(_DirBackupController.DirBackupController).backup(cmd)
69
- }),
70
- restore: (0, _nclif.cmd)({
71
- description: 'Restore the storage to the given dir',
72
- options: restoreOptions,
73
- positionals: [{
74
- name: 'path',
75
- required: true
76
- }],
77
- run: (cmd, c) => c.get(_DirBackupController.DirBackupController).restore(cmd)
78
- })
79
- }
80
- }),
81
- aggr: (0, _nclif.cmdGroup)({
82
- commands: {
83
- backup: (0, _nclif.cmd)({
84
- description: 'Run backup',
85
- options: [storageNameOpt],
86
- positionals: [{
87
- name: 'aggregateName',
88
- required: true
89
- }],
90
- run: (a, c) => c.get(_AggregateBackupController.AggregateBackupController).backup(a.aggregateName)
91
- })
92
- }
93
- }),
94
- restic,
95
- pg
96
- }
97
- }).envConfig('NODEBUP').addObjectConfig(pwd => (0, _Config.readConfig)(pwd)).context(({
98
- config,
99
- inputs
100
- }) => (0, _Context.createContext)(config, inputs));
56
+ const createApp = () => {
57
+ const p = _nclif.CliApp.of({
58
+ binName: 'bup',
59
+ description: 'Data backup utility'
60
+ }, {
61
+ commands: {
62
+ dir: (0, _nclif.cmdGroup)({
63
+ options: singleStorageOptions,
64
+ commands: {
65
+ backup: (0, _nclif.cmd)({
66
+ description: 'Backup a dir to the given storage',
67
+ options: backupOptions,
68
+ positionals: [{
69
+ name: 'path',
70
+ required: true
71
+ }],
72
+ run: (cmd, c) => c.get(_DirBackupController.DirBackupController).backup(cmd)
73
+ }),
74
+ restore: (0, _nclif.cmd)({
75
+ description: 'Restore the storage to the given dir',
76
+ options: restoreOptions,
77
+ positionals: [{
78
+ name: 'path',
79
+ required: true
80
+ }],
81
+ run: (cmd, c) => c.get(_DirBackupController.DirBackupController).restore(cmd)
82
+ })
83
+ }
84
+ }),
85
+ aggr: (0, _nclif.cmdGroup)({
86
+ commands: {
87
+ backup: (0, _nclif.cmd)({
88
+ description: 'Run backup',
89
+ options: [storageNameOpt],
90
+ positionals: [{
91
+ name: 'aggregateName',
92
+ required: true
93
+ }],
94
+ run: (a, c) => c.get(_AggregateBackupController.AggregateBackupController).backup(a.aggregateName)
95
+ })
96
+ }
97
+ }),
98
+ restic,
99
+ pg
100
+ }
101
+ }).envConfig('NODEBUP').addObjectConfig(pwd => (0, _Config.readConfig)(pwd)).context(({
102
+ config,
103
+ inputs
104
+ }) => (0, _Context.createContext)(config, inputs));
105
+
106
+ return p;
107
+ };
101
108
 
102
109
  exports.createApp = createApp;
103
110
  const restic = (0, _nclif.cmdGroup)({
104
111
  options: singleStorageOptions,
112
+ description: 'Restic commands',
105
113
  commands: {
106
114
  'init-repo': (0, _nclif.cmd)({
107
115
  run: (_, c) => c.get(_ResticController.ResticController).initRepo()
@@ -109,6 +117,17 @@ const restic = (0, _nclif.cmdGroup)({
109
117
  snapshots: (0, _nclif.cmd)({
110
118
  run: (_, c, p) => c.get(_ResticController.ResticController).listSnapshots(p.stdout)
111
119
  }),
120
+ env: (0, _nclif.cmd)({
121
+ run: ({
122
+ export: doExport
123
+ }, c) => c.get(_ResticController.ResticController).printEnv(doExport),
124
+ options: [{
125
+ name: 'export',
126
+ type: 'boolean',
127
+ description: 'Add "export" statement to each env variable inoutput',
128
+ convertCase: true
129
+ }]
130
+ }),
112
131
  cmd: (0, _nclif.cmd)({
113
132
  positionals: [{
114
133
  name: 'cmd',
@@ -121,20 +140,32 @@ const restic = (0, _nclif.cmdGroup)({
121
140
  }
122
141
  });
123
142
  const pg = (0, _nclif.cmdGroup)({
143
+ description: 'Postgres backup commands',
124
144
  options: [...singleStorageOptions, {
125
145
  name: 'pg-url',
146
+ description: 'Postgres URL',
126
147
  convertCase: true,
127
148
  fromConfig: 'pg.url',
128
149
  required: true
129
150
  }, {
130
- name: 'pg-version',
151
+ name: 'pg-bin-dir',
152
+ description: 'A directory with Postgres binaries (if the ones on the path should not be used)',
131
153
  convertCase: true,
132
- fromConfig: 'pg.version',
133
- description: `Postgres version - default is ${_PgBackupController.PgBackupController.defaultPgVersion}`
134
- }],
154
+ fromConfig: 'pg.bin-dir'
155
+ } // {
156
+ // name: 'pg-version',
157
+ // convertCase: true,
158
+ // fromConfig: 'pg.version',
159
+ // description: `Postgres version - default is ${PgBackupController.defaultPgVersion}`
160
+ // }
161
+ ],
135
162
  commands: {
136
163
  backup: (0, _nclif.cmd)({
137
- options: backupOptions,
164
+ options: [...backupOptions, {
165
+ name: 'backup-name',
166
+ convertCase: true,
167
+ required: true
168
+ }],
138
169
  run: (inp, c) => c.get(_PgBackupController.PgBackupController).backup(inp)
139
170
  }),
140
171
  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);
@@ -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);
@@ -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
 
@@ -77,14 +80,17 @@ class ResticClient {
77
80
  });
78
81
 
79
82
  _defineProperty(this, "snapshots", () => {
80
- this.log.debug('Listing snapshots of repo=%', this.url);
83
+ this.log.debug(`Listing snapshots of repo=${this.url}`);
81
84
  const out = this.shell.execAndReturnString(`restic snapshots --json`, {
82
85
  env: this.env()
83
86
  });
84
87
  const res = JSON.parse(out);
85
88
  return res.map(r => ({
86
89
  id: r.id,
90
+ short_id: r.short_id,
87
91
  time: new Date(r.time),
92
+ paths: r.paths,
93
+ hostname: r.hostname,
88
94
  tags: r.tags
89
95
  }));
90
96
  });
@@ -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.10.0",
3
+ "version": "0.12.0",
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": {
@@ -78,7 +80,7 @@
78
80
  },
79
81
  "dependencies": {
80
82
  "@hapi/joi": "^17.1.1",
81
- "@ps-aux/nclif": "^0.0.7-alpha.1",
83
+ "@ps-aux/nclif": "^0.9.0-alpha5",
82
84
  "@types/hapi__joi": "^17.1.8",
83
85
  "axios": "^0.24.0",
84
86
  "handlebars": "^4.7.7",