@ps-aux/nodebup 0.10.0 → 0.12.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.
@@ -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",