@ps-aux/nodebup 0.5.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -0,0 +1 @@
1
+
@@ -5,25 +5,25 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.AggregateBackupController = void 0;
7
7
 
8
- var _FsSyncer = require("../fs/fssync/FsSyncer");
8
+ var _FsSyncer = require("../../fs/fssync/FsSyncer");
9
9
 
10
- var _Gpg = require("../tools/gpg/Gpg");
10
+ var _Gpg = require("../../tools/gpg/Gpg");
11
11
 
12
- var _Fs = require("../fs/Fs");
12
+ var _Fs = require("../../fs/Fs");
13
13
 
14
- var _SshKeyManager = require("../tools/ssh/SshKeyManager");
14
+ var _SshKeyManager = require("../../tools/ssh/SshKeyManager");
15
15
 
16
16
  var _inversify = require("inversify");
17
17
 
18
- var _ContextSymbols = require("../ctx/ContextSymbols");
18
+ var _ContextSymbols = require("../../ctx/ContextSymbols");
19
19
 
20
- var _AppLogger = require("../log/AppLogger");
20
+ var _AppLogger = require("../../log/AppLogger");
21
21
 
22
- var _Path = require("../fs/path/Path");
22
+ var _Path = require("../../fs/path/Path");
23
23
 
24
- var _config = require("../config");
24
+ var _config = require("../../config");
25
25
 
26
- var _BackupController = require("./BackupController");
26
+ var _StorageBackendProvider = require("../../storage/StorageBackendProvider");
27
27
 
28
28
  var _dec, _dec2, _dec3, _dec4, _class;
29
29
 
@@ -31,17 +31,17 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
31
31
 
32
32
  let AggregateBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = function (target, key) {
33
33
  return (0, _inversify.inject)(_ContextSymbols.AppConfig_)(target, undefined, 6);
34
- }, _dec3 = Reflect.metadata("design:type", Function), _dec4 = Reflect.metadata("design:paramtypes", [typeof _Gpg.Gpg === "undefined" ? Object : _Gpg.Gpg, typeof _SshKeyManager.SshKeyManager === "undefined" ? Object : _SshKeyManager.SshKeyManager, typeof _Fs.Fs === "undefined" ? Object : _Fs.Fs, typeof _FsSyncer.FsSyncer === "undefined" ? Object : _FsSyncer.FsSyncer, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof _BackupController.BackupController === "undefined" ? Object : _BackupController.BackupController, typeof _config.Config === "undefined" ? Object : _config.Config]), _dec(_class = _dec2(_class = _dec3(_class = _dec4(_class = class AggregateBackupController {
35
- constructor(gpg, ssh, fs, fsSyncer, log, backupController, cfg) {
34
+ }, _dec3 = Reflect.metadata("design:type", Function), _dec4 = Reflect.metadata("design:paramtypes", [typeof _Gpg.Gpg === "undefined" ? Object : _Gpg.Gpg, typeof _SshKeyManager.SshKeyManager === "undefined" ? Object : _SshKeyManager.SshKeyManager, typeof _Fs.Fs === "undefined" ? Object : _Fs.Fs, typeof _FsSyncer.FsSyncer === "undefined" ? Object : _FsSyncer.FsSyncer, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof _StorageBackendProvider.StorageBackendProvider === "undefined" ? Object : _StorageBackendProvider.StorageBackendProvider, typeof _config.Config === "undefined" ? Object : _config.Config]), _dec(_class = _dec2(_class = _dec3(_class = _dec4(_class = class AggregateBackupController {
35
+ constructor(gpg, ssh, fs, fsSyncer, log, storageProvider, cfg) {
36
36
  this.gpg = gpg;
37
37
  this.ssh = ssh;
38
38
  this.fs = fs;
39
39
  this.fsSyncer = fsSyncer;
40
40
  this.log = log;
41
- this.backupController = backupController;
41
+ this.storageProvider = storageProvider;
42
42
  this.cfg = cfg;
43
43
 
44
- _defineProperty(this, "backup", async (aggrName, storage) => {
44
+ _defineProperty(this, "backup", async aggrName => {
45
45
  const aggrDir = this.cfg.pwd.resolve('.aggr');
46
46
  const aggr = this.cfg.aggregates.find(a => a.name === aggrName);
47
47
  if (!aggr) throw new Error(`No backup aggregate with name '${aggrName}'`);
@@ -56,7 +56,7 @@ let AggregateBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = fu
56
56
  file.forEach(f => this.runFileTask(f, aggrDir));
57
57
  sshKey.forEach(k => this.runSshKeyTask(k, aggrDir));
58
58
  gpgKey.forEach(k => this.runGpgKeyTask(k, aggrDir));
59
- this.backupController.backup(storage, aggrDir);
59
+ this.storageProvider.provide().store(aggrDir);
60
60
  } finally {
61
61
  this.log.debug();
62
62
  this.fs.rmDir(aggrDir);
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.DataBackupController = void 0;
7
+
8
+ var _inversify = require("inversify");
9
+
10
+ var _AppLogger = require("../../log/AppLogger");
11
+
12
+ var _Path = require("../../fs/path/Path");
13
+
14
+ var _StorageBackendProvider = require("../../storage/StorageBackendProvider");
15
+
16
+ var _dec, _dec2, _dec3, _class;
17
+
18
+ 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; }
19
+
20
+ let DataBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof _StorageBackendProvider.StorageBackendProvider === "undefined" ? Object : _StorageBackendProvider.StorageBackendProvider]), _dec(_class = _dec2(_class = _dec3(_class = class DataBackupController {
21
+ constructor(log, storageBackendProvider) {
22
+ this.log = log;
23
+ this.storageBackendProvider = storageBackendProvider;
24
+
25
+ _defineProperty(this, "storage", inp => {
26
+ const storage = this.storageBackendProvider.provide();
27
+
28
+ const path = _Path.AbsPath.from(inp.path);
29
+
30
+ return {
31
+ backup: () => {
32
+ this.log.info(`Backing up from ${path} to '${storage}'`);
33
+ storage.store(path);
34
+ },
35
+ restore: () => {
36
+ this.log.info(`Restoring from '${storage}' to ${path}`);
37
+ storage.restore(path);
38
+ }
39
+ };
40
+ });
41
+ }
42
+
43
+ }) || _class) || _class) || _class);
44
+ exports.DataBackupController = DataBackupController;
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.PgBackupController = void 0;
7
+
8
+ var _Fs = require("../../fs/Fs");
9
+
10
+ var _inversify = require("inversify");
11
+
12
+ var _AppLogger = require("../../log/AppLogger");
13
+
14
+ var _Shell = require("../../tools/shell/Shell");
15
+
16
+ var _Path = require("../../fs/path/Path");
17
+
18
+ var _StorageBackendProvider = require("../../storage/StorageBackendProvider");
19
+
20
+ var _dec, _dec2, _dec3, _class, _class2, _temp;
21
+
22
+ 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; }
23
+
24
+ const parseConnectionUrl = url => {
25
+ var _url$match;
26
+
27
+ const regex = /postgres:\/\/(?<username>.*):(?<password>.*)@(?<host>.*):(?<port>\d*)$/;
28
+ const match = (_url$match = url.match(regex)) === null || _url$match === void 0 ? void 0 : _url$match.groups;
29
+ if (!match || !match.username || !match.password || !match.host || !match.port) throw new Error(`The Postgres connection URL does not match required regex: ${regex.toString()}`);
30
+ return {
31
+ username: match.username,
32
+ password: match.password,
33
+ host: match.host,
34
+ port: parseInt(match.port, 10)
35
+ };
36
+ };
37
+
38
+ let PgBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _Fs.Fs === "undefined" ? Object : _Fs.Fs, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof _StorageBackendProvider.StorageBackendProvider === "undefined" ? Object : _StorageBackendProvider.StorageBackendProvider, typeof _Shell.Shell === "undefined" ? Object : _Shell.Shell]), _dec(_class = _dec2(_class = _dec3(_class = (_temp = _class2 = class PgBackupController {
39
+ constructor( // private gpg: Gpg,
40
+ // private ssh: SshKeyManager,
41
+ fs, // private fsSyncer: FsSyncer,
42
+ log, storageBackendProvider, // @inject(AppConfig_) private cfg: Config,
43
+ sh) {
44
+ this.fs = fs;
45
+ this.log = log;
46
+ this.storageBackendProvider = storageBackendProvider;
47
+ this.sh = sh;
48
+
49
+ _defineProperty(this, "now", () => {
50
+ const d = new Date();
51
+ const fields = [d.getFullYear(), d.getMonth(), d.getDay(), d.getUTCHours(), d.getMinutes(), d.getSeconds()];
52
+ return fields.join('-');
53
+ });
54
+
55
+ _defineProperty(this, "getVersion", version => version || PgBackupController.defaultPgVersion);
56
+
57
+ _defineProperty(this, "backup", ({
58
+ pgUrl,
59
+ pgVersion
60
+ }) => {
61
+ const storage = this.storageBackendProvider.provide();
62
+ const version = this.getVersion(pgVersion); // TODO validate url
63
+
64
+ this.log.info(`Backing up Postgres database, version=${version}`);
65
+ const connParams = parseConnectionUrl(pgUrl);
66
+ const pass = connParams.password;
67
+ this.fs.inTmpDir('pg-backup', dir => {
68
+ const outputDir = _Path.AbsPath.from(dir);
69
+
70
+ this.log.info('Dumping database to a file');
71
+ const bashCmds = [`echo "*:*:*:*:${pass}" > ~/.pgpass`, `chmod 400 ~/.pgpass`, `pg_dumpall -d ${pgUrl}`]; // TODO improve sh logging to avoid showing secrets
72
+
73
+ const b = this.sh.execAndReturnBuffer(`docker run --network host ` + `postgres:${version} ` + `bash -c '${bashCmds.join(' && ')}'`);
74
+ const outFileName = PgBackupController.outFileName;
75
+ const dumpOut = outputDir.resolve(outFileName);
76
+ this.fs.writeFile(dumpOut, b);
77
+ this.log.info('Compressing');
78
+ const zipOutputName = `pg-backup-${this.now()}.zip`;
79
+ this.sh.exec(`cd ${outputDir.str()}; zip ${zipOutputName} ${outFileName}`);
80
+ this.fs.rmFile(dumpOut);
81
+ this.log.info('Uploading');
82
+ storage.store(_Path.AbsPath.from(dir));
83
+ });
84
+ });
85
+
86
+ _defineProperty(this, "restore", ({
87
+ pgUrl,
88
+ pgVersion
89
+ }) => {
90
+ const version = this.getVersion(pgVersion);
91
+ const storage = this.storageBackendProvider.provide(); // To validate
92
+
93
+ parseConnectionUrl(pgUrl);
94
+ this.log.info(`Restoring Postgres database, version=${version}`);
95
+ this.fs.inTmpDir('pg-restore', dirStr => {
96
+ const dir = _Path.AbsPath.from(dirStr);
97
+
98
+ storage.restore(dir);
99
+ const zipFile = this.fs.listFiles(dir)[0]; //
100
+
101
+ this.sh.exec(`unzip ${zipFile.str()} -d ${dir.str()}`);
102
+ this.fs.rmFile(zipFile);
103
+ const outFile = this.fs.listFiles(dir)[0];
104
+ this.sh.exec(`docker run --network host ` + `-v "${outFile.str()}":/pg/import.sql -w /pg ` + `postgres:${version} ` + `psql ${pgUrl} -v ON_ERROR_STOP=0 -f import.sql`);
105
+ });
106
+ });
107
+ }
108
+
109
+ }, _defineProperty(_class2, "defaultPgVersion", '14.2'), _defineProperty(_class2, "outFileName", 'out.sql'), _temp)) || _class) || _class) || _class);
110
+ exports.PgBackupController = PgBackupController;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.InvalidInput = void 0;
7
+
8
+ class InvalidInput extends Error {}
9
+
10
+ exports.InvalidInput = InvalidInput;
package/lib/cli/app.js CHANGED
@@ -13,68 +13,108 @@ var _Config = require("../config/Config");
13
13
 
14
14
  var _Context = require("../ctx/Context");
15
15
 
16
- var _AggregateBackupController = require("../bup/AggregateBackupController");
16
+ var _AggregateBackupController = require("../bup/aggregate/AggregateBackupController");
17
17
 
18
18
  var _ResticController = require("../storage/restic/ResticController");
19
19
 
20
- var _BackupController = require("../bup/BackupController");
20
+ var _DataBackupController = require("../bup/dir/DataBackupController");
21
21
 
22
- var _Path = require("../fs/path/Path");
22
+ var _PgBackupController = require("../bup/pg/PgBackupController");
23
+
24
+ const storageNameOpt = {
25
+ name: 'storage-name',
26
+ convertCase: true,
27
+ fromConfig: 'storage.name'
28
+ };
29
+ const singleStorageOptions = [storageNameOpt, {
30
+ name: 'storage-type',
31
+ convertCase: true,
32
+ fromConfig: 'storage.type'
33
+ }, {
34
+ name: 'storage-repo',
35
+ convertCase: true,
36
+ fromConfig: 'storage.repo'
37
+ }, {
38
+ name: 'storage-password',
39
+ convertCase: true,
40
+ fromConfig: 'storage.password'
41
+ }, {
42
+ name: 'storage-credentials',
43
+ convertCase: true,
44
+ fromConfig: 'storage.credentials'
45
+ }];
23
46
 
24
47
  const createApp = () => _nclif.CliApp.of({
25
48
  commands: {
26
- backup: (0, _nclif.cmd)({
27
- description: 'Backup a dir to the given storage',
28
- positionals: [{
29
- name: 'path',
30
- required: true
31
- }, {
32
- name: 'storageName',
33
- required: true
34
- }],
35
- run: (a, c) => c.get(_BackupController.BackupController).backup(a.storageName, _Path.AbsPath.from(a.path))
36
- }),
37
- restore: (0, _nclif.cmd)({
38
- description: 'Restore the storage to the given dir',
39
- positionals: [{
40
- name: 'storageName',
41
- required: true
42
- }, {
43
- name: 'path',
44
- required: true
45
- }],
46
- run: (a, c) => c.get(_BackupController.BackupController).restore(a.storageName, _Path.AbsPath.from(a.path))
49
+ data: (0, _nclif.cmdGroup)({
50
+ options: singleStorageOptions,
51
+ commands: {
52
+ backup: (0, _nclif.cmd)({
53
+ description: 'Backup a dir to the given storage',
54
+ positionals: [{
55
+ name: 'path',
56
+ required: true
57
+ }],
58
+ run: (cmd, c) => c.get(_DataBackupController.DataBackupController).storage(cmd).backup()
59
+ }),
60
+ restore: (0, _nclif.cmd)({
61
+ description: 'Restore the storage to the given dir',
62
+ positionals: [{
63
+ name: 'path',
64
+ required: true
65
+ }],
66
+ run: (cmd, c) => c.get(_DataBackupController.DataBackupController).storage(cmd).restore()
67
+ })
68
+ }
47
69
  }),
48
70
  aggr: (0, _nclif.cmdGroup)({
49
71
  commands: {
50
72
  backup: (0, _nclif.cmd)({
51
73
  description: 'Run backup',
74
+ options: [storageNameOpt],
52
75
  positionals: [{
53
76
  name: 'aggregateName',
54
77
  required: true
55
- }, {
56
- name: 'storageName',
57
- required: true
58
78
  }],
59
- run: (a, c) => c.get(_AggregateBackupController.AggregateBackupController).backup(a.aggregateName, a.storageName)
79
+ run: (a, c) => c.get(_AggregateBackupController.AggregateBackupController).backup(a.aggregateName)
60
80
  })
61
81
  }
62
82
  }),
63
- restic
83
+ restic,
84
+ pg
64
85
  }
65
- }).addObjectConfig(pwd => (0, _Config.readConfig)(pwd)).context(({
66
- config
67
- }) => (0, _Context.createContext)(config));
86
+ }).envConfig('NODEBUP').addObjectConfig(pwd => (0, _Config.readConfig)(pwd)).context(({
87
+ config,
88
+ inputs
89
+ }) => (0, _Context.createContext)(config, inputs));
68
90
 
69
91
  exports.createApp = createApp;
70
92
  const restic = (0, _nclif.cmdGroup)({
71
93
  commands: {
72
94
  'init-repo': (0, _nclif.cmd)({
73
- positionals: [{
74
- name: 'resticStorageName',
75
- required: true
76
- }],
77
- run: (arg, c) => c.get(_ResticController.ResticController).initRepo(arg.resticStorageName)
95
+ options: singleStorageOptions,
96
+ run: (_, c) => c.get(_ResticController.ResticController).initRepo()
97
+ })
98
+ }
99
+ });
100
+ const pg = (0, _nclif.cmdGroup)({
101
+ options: [...singleStorageOptions, {
102
+ name: 'pg-url',
103
+ convertCase: true,
104
+ fromConfig: 'pg.url',
105
+ required: true
106
+ }, {
107
+ name: 'pg-version',
108
+ convertCase: true,
109
+ fromConfig: 'pg.version',
110
+ description: `Postgres version - default is ${_PgBackupController.PgBackupController.defaultPgVersion}`
111
+ }],
112
+ commands: {
113
+ backup: (0, _nclif.cmd)({
114
+ run: (inp, c) => c.get(_PgBackupController.PgBackupController).backup(inp)
115
+ }),
116
+ restore: (0, _nclif.cmd)({
117
+ run: (inp, c) => c.get(_PgBackupController.PgBackupController).restore(inp)
78
118
  })
79
119
  }
80
120
  });
@@ -13,12 +13,11 @@ var _validateConfigAgainstSchema = require("./validateConfigAgainstSchema");
13
13
 
14
14
  var _expandAndCreatePath = require("./expandAndCreatePath");
15
15
 
16
- const expandPaths = (cfg, exp, cwd) => {
17
- cfg.storage.filter(s => s.type === 'restic' || s.type === 'rclone').map(s => s).forEach(s => {
18
- if (s.credentialsFile) s.credentialsFile = exp(s.credentialsFile);
19
- s.passwordFile = exp(s.passwordFile);
20
- if (s.repo.startsWith('local:')) s.repo = (0, _expandAndCreatePath.expandStrPath)(s.repo, cwd);
21
- });
16
+ var _Fs = require("../fs/Fs");
17
+
18
+ var _AppLogger = require("../log/AppLogger");
19
+
20
+ const expandPaths = (cfg, exp) => {
22
21
  cfg.aggregates.forEach(a => {
23
22
  a.sources.file.forEach(f => {
24
23
  f.from = exp(f.from);
@@ -31,15 +30,27 @@ const expandPaths = (cfg, exp, cwd) => {
31
30
  if (f.to) f.to = _Path.RelativePath.from(f.to);
32
31
  });
33
32
  });
33
+ }; // TODO
34
+
35
+
36
+ const readFromFile = cwd => {
37
+ // TODO get from the context, maybe move FS to CLI framework later?
38
+ const fs = new _Fs.Fs(cwd, new _AppLogger.AppLogger());
39
+ const cfgPath = cwd.resolve('bup.yaml');
40
+ const cfg = fs.exists(cfgPath) ? (0, _readYaml.readYaml)(cfgPath.str()) : {
41
+ aggregates: [],
42
+ storage: []
43
+ };
44
+ (0, _validateConfigAgainstSchema.validateConfigAgainstSchema)(cfg);
45
+ return cfg;
34
46
  };
35
47
 
36
48
  const readConfig = pwdStr => {
37
49
  const cwd = _Path.AbsPath.from(pwdStr);
38
50
 
39
- const cfgFile = (0, _readYaml.readYaml)(cwd.resolve('bup.yaml').str());
40
- (0, _validateConfigAgainstSchema.validateConfigAgainstSchema)(cfgFile);
41
- const cfg = cfgFile;
42
- cfg.pwd = cwd;
51
+ const cfg = { ...readFromFile(cwd),
52
+ pwd: cwd
53
+ };
43
54
  cfg.aggregates.forEach(t => {
44
55
  const {
45
56
  sources
@@ -54,7 +65,7 @@ const readConfig = pwdStr => {
54
65
  return p;
55
66
  };
56
67
 
57
- expandPaths(cfg, expand, cwd);
68
+ expandPaths(cfg, expand);
58
69
  return cfg;
59
70
  };
60
71
 
@@ -9,12 +9,14 @@ var _Path = require("../fs/path/Path");
9
9
 
10
10
  var _os = _interopRequireDefault(require("os"));
11
11
 
12
+ var _path = _interopRequireDefault(require("path"));
13
+
12
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
15
 
14
16
  const expandStrPath = (path, pwd) => {
15
17
  path = path.replace('<cwd>', pwd.str());
16
18
  path = path.replace('~', _os.default.homedir());
17
- return path;
19
+ return _path.default.resolve(path);
18
20
  };
19
21
 
20
22
  exports.expandStrPath = expandStrPath;
@@ -2,12 +2,4 @@
2
2
 
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
- });
6
- exports.StorageTypeConst = void 0;
7
- let StorageTypeConst;
8
- exports.StorageTypeConst = StorageTypeConst;
9
-
10
- (function (StorageTypeConst) {
11
- StorageTypeConst["Restic"] = "restic";
12
- StorageTypeConst["RClone"] = "rclone";
13
- })(StorageTypeConst || (exports.StorageTypeConst = StorageTypeConst = {}));
5
+ });
@@ -7,7 +7,7 @@ exports.validateConfigAgainstSchema = void 0;
7
7
 
8
8
  var _joi = _interopRequireDefault(require("@hapi/joi"));
9
9
 
10
- var _index = require("./index");
10
+ var _StoreConfig = require("../storage/StoreConfig");
11
11
 
12
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
13
 
@@ -23,21 +23,6 @@ const KeyTaskSchema = _joi.default.object({
23
23
  to: _joi.default.string().optional()
24
24
  });
25
25
 
26
- const createStorageSchema = props => _joi.default.object({
27
- name: _joi.default.string(),
28
- type: _joi.default.string().valid(_index.StorageTypeConst.Restic, _index.StorageTypeConst.RClone),
29
- ...props
30
- });
31
-
32
- const FileStorageSchema = createStorageSchema({
33
- path: _joi.default.string()
34
- });
35
- const ResticStorageSchema = createStorageSchema({
36
- repo: _joi.default.string(),
37
- credentialsFile: _joi.default.string().optional(),
38
- passwordFile: _joi.default.string()
39
- });
40
-
41
26
  const Sources = _joi.default.object({
42
27
  dir: _joi.default.array().items(DirTaskSchema).optional(),
43
28
  file: _joi.default.array().items(FileTaskSchema).optional(),
@@ -52,7 +37,7 @@ const Aggregate = _joi.default.object({
52
37
 
53
38
  const Schema = () => _joi.default.object({
54
39
  // TODO undescriptive error msg. Invalid config."storage[0]" does not match any of the allowed types
55
- storage: _joi.default.array().items(FileStorageSchema, ResticStorageSchema),
40
+ storage: _joi.default.array().items((0, _StoreConfig.NamedStorageSchema)()),
56
41
  aggregates: _joi.default.array().items(Aggregate)
57
42
  });
58
43
 
@@ -19,7 +19,7 @@ var _inversify = require("inversify");
19
19
 
20
20
  var _ContextSymbols = require("./ContextSymbols");
21
21
 
22
- var _AggregateBackupController = require("../bup/AggregateBackupController");
22
+ var _AggregateBackupController = require("../bup/aggregate/AggregateBackupController");
23
23
 
24
24
  var _AppLogger = require("../log/AppLogger");
25
25
 
@@ -33,15 +33,21 @@ var _B2CredentialsProvider = require("../storage/b2/B2CredentialsProvider");
33
33
 
34
34
  var _RCloneClientFactory = require("../storage/rclone/RCloneClientFactory");
35
35
 
36
- var _BackupController = require("../bup/BackupController");
36
+ var _DataBackupController = require("../bup/dir/DataBackupController");
37
37
 
38
- const createContext = cfg => {
38
+ var _StorageConfigProvider = require("../storage/StorageConfigProvider");
39
+
40
+ var _PgBackupController = require("../bup/pg/PgBackupController");
41
+
42
+ const createContext = (cfg, inp) => {
39
43
  const c = new _inversify.Container();
40
44
  c.bind(_ContextSymbols.AppConfig_).toConstantValue(cfg);
45
+ c.bind(_ContextSymbols.Inputs_).toConstantValue(inp);
41
46
  const log = new _AppLogger.AppLogger();
42
47
  c.bind(_ContextSymbols.Log_).toConstantValue(log);
43
48
  c.bind(_AppLogger.AppLogger).toConstantValue(log);
44
- const self = [_Gpg.Gpg, _Shell.Shell, _Fs.Fs, _FsSyncer.FsSyncer, _SshKeyManager.SshKeyManager, _StorageBackendProvider.StorageBackendProvider, _ResticClientFactory.ResticClientFactory, _AggregateBackupController.AggregateBackupController, _ResticController.ResticController, _B2CredentialsProvider.B2CredentialsProvider, _RCloneClientFactory.RCloneClientFactory, _BackupController.BackupController];
49
+ c.bind(_Fs.Fs).toConstantValue(new _Fs.Fs(cfg.pwd, log));
50
+ const self = [_Gpg.Gpg, _Shell.Shell, _FsSyncer.FsSyncer, _SshKeyManager.SshKeyManager, _StorageBackendProvider.StorageBackendProvider, _StorageConfigProvider.StorageConfigProvider, _ResticClientFactory.ResticClientFactory, _AggregateBackupController.AggregateBackupController, _ResticController.ResticController, _B2CredentialsProvider.B2CredentialsProvider, _RCloneClientFactory.RCloneClientFactory, _DataBackupController.DataBackupController, _PgBackupController.PgBackupController];
45
51
  self.forEach(s => c.bind(s).toSelf());
46
52
  return c;
47
53
  };
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.TaskConfig_ = exports.StorageConfig_ = exports.Log_ = exports.AppConfig_ = void 0;
6
+ exports.TaskConfig_ = exports.StorageConfig_ = exports.Log_ = exports.Inputs_ = exports.AppConfig_ = void 0;
7
7
  const Log_ = Symbol.for('Log');
8
8
  exports.Log_ = Log_;
9
9
  const TaskConfig_ = Symbol.for('config.Tasks');
@@ -11,4 +11,6 @@ exports.TaskConfig_ = TaskConfig_;
11
11
  const StorageConfig_ = Symbol.for('config.Storage');
12
12
  exports.StorageConfig_ = StorageConfig_;
13
13
  const AppConfig_ = Symbol.for('config.app');
14
- exports.AppConfig_ = AppConfig_;
14
+ exports.AppConfig_ = AppConfig_;
15
+ const Inputs_ = Symbol.for('cmd.input');
16
+ exports.Inputs_ = Inputs_;
package/lib/fs/Fs.js CHANGED
@@ -7,18 +7,27 @@ exports.Fs = void 0;
7
7
 
8
8
  var _fs = _interopRequireDefault(require("fs"));
9
9
 
10
+ var _path = _interopRequireDefault(require("path"));
11
+
12
+ var _Path = require("./path/Path");
13
+
10
14
  var _inversify = require("inversify");
11
15
 
12
16
  var _AppLogger = require("../log/AppLogger");
13
17
 
18
+ var _expandAndCreatePath = require("../config/expandAndCreatePath");
19
+
20
+ var _os = _interopRequireDefault(require("os"));
21
+
14
22
  var _dec, _dec2, _dec3, _class;
15
23
 
16
24
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
25
 
18
26
  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; }
19
27
 
20
- let Fs = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger]), _dec(_class = _dec2(_class = _dec3(_class = class Fs {
21
- constructor(log) {
28
+ let Fs = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _Path.AbsPath === "undefined" ? Object : _Path.AbsPath, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger]), _dec(_class = _dec2(_class = _dec3(_class = class Fs {
29
+ constructor(cwd, log) {
30
+ this.cwd = cwd;
22
31
  this.log = log;
23
32
 
24
33
  _defineProperty(this, "writeFile", (path, content) => {
@@ -42,6 +51,30 @@ let Fs = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:
42
51
  });
43
52
  });
44
53
 
54
+ _defineProperty(this, "rmFile", path => {
55
+ _fs.default.rmSync(path.str());
56
+ });
57
+
58
+ _defineProperty(this, "listFiles", path => {
59
+ return _fs.default.readdirSync(path.str()).map(f => path.resolve(f));
60
+ });
61
+
62
+ _defineProperty(this, "inTmpDir", (name, withDir) => {
63
+ const dir = this.mkTmpDir(name);
64
+
65
+ try {
66
+ withDir(dir);
67
+ } finally {
68
+ this.rmDir(_Path.AbsPath.from(dir));
69
+ }
70
+ });
71
+
72
+ _defineProperty(this, "mkTmpDir", name => {
73
+ const dir = _fs.default.mkdtempSync(_path.default.resolve(_os.default.tmpdir(), name));
74
+
75
+ return dir;
76
+ });
77
+
45
78
  _defineProperty(this, "ensureIsDir", p => {
46
79
  if (!this.isDir(p)) throw new Error(`${p} is not a dir`);
47
80
  });
@@ -75,6 +108,10 @@ let Fs = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:
75
108
  });
76
109
 
77
110
  _defineProperty(this, "exists", path => _fs.default.existsSync(path.str()));
111
+
112
+ _defineProperty(this, "expand", strPath => (0, _expandAndCreatePath.expandAndCreatePath)(strPath, this.cwd));
113
+
114
+ _defineProperty(this, "expandStrPath", strPath => (0, _expandAndCreatePath.expandStrPath)(strPath, this.cwd));
78
115
  }
79
116
 
80
117
  }) || _class) || _class) || _class);
@@ -23,7 +23,7 @@ describe('FsSync', () => {
23
23
 
24
24
  it('syncs dir', () => {
25
25
  const l = new _AppLogger.AppLogger();
26
- const sut = new _FsSyncer.FsSyncer(new _Shell.Shell(l), new _Fs.Fs(l), l);
26
+ const sut = new _FsSyncer.FsSyncer(new _Shell.Shell(l), new _Fs.Fs(_Path.AbsPath.from(__dirname), l), l);
27
27
  sut.syncDirs(from, to);
28
28
  expect((0, _areDirsSame.areDirsSame)(from, to)).toBe(true);
29
29
  });
@@ -24,7 +24,11 @@ class AbsPath {
24
24
  return AbsPath.from(_path.default.resolve(this.path, '..'));
25
25
  });
26
26
 
27
- _defineProperty(this, "str", () => this.path);
27
+ _defineProperty(this, "basename", () => {
28
+ return _path.default.basename(this.path);
29
+ });
30
+
31
+ _defineProperty(this, "str", () => _path.default.resolve(this.path));
28
32
 
29
33
  if (!_path.default.isAbsolute(path)) throw new Error(`Path ${path} must be absolute`);
30
34
  }
@@ -7,9 +7,7 @@ exports.StorageBackendProvider = void 0;
7
7
 
8
8
  var _inversify = require("inversify");
9
9
 
10
- var _ContextSymbols = require("../ctx/ContextSymbols");
11
-
12
- var _config = require("../config");
10
+ var _types = require("./types");
13
11
 
14
12
  var _ResticClientFactory = require("./restic/ResticClientFactory");
15
13
 
@@ -17,29 +15,28 @@ var _BackupClientStorageBackend = require("./BackupClientStorageBackend");
17
15
 
18
16
  var _RCloneClientFactory = require("./rclone/RCloneClientFactory");
19
17
 
20
- var _dec, _dec2, _dec3, _dec4, _class;
18
+ var _StorageConfigProvider = require("./StorageConfigProvider");
19
+
20
+ var _dec, _dec2, _dec3, _class;
21
21
 
22
22
  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; }
23
23
 
24
- let StorageBackendProvider = (_dec = (0, _inversify.injectable)(), _dec2 = function (target, key) {
25
- return (0, _inversify.inject)(_ContextSymbols.AppConfig_)(target, undefined, 2);
26
- }, _dec3 = Reflect.metadata("design:type", Function), _dec4 = Reflect.metadata("design:paramtypes", [typeof _ResticClientFactory.ResticClientFactory === "undefined" ? Object : _ResticClientFactory.ResticClientFactory, typeof _RCloneClientFactory.RCloneClientFactory === "undefined" ? Object : _RCloneClientFactory.RCloneClientFactory, typeof _config.Config === "undefined" ? Object : _config.Config]), _dec(_class = _dec2(_class = _dec3(_class = _dec4(_class = class StorageBackendProvider {
27
- constructor(resticFac, rcloneFac, cfg) {
24
+ let StorageBackendProvider = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _ResticClientFactory.ResticClientFactory === "undefined" ? Object : _ResticClientFactory.ResticClientFactory, typeof _RCloneClientFactory.RCloneClientFactory === "undefined" ? Object : _RCloneClientFactory.RCloneClientFactory, typeof _StorageConfigProvider.StorageConfigProvider === "undefined" ? Object : _StorageConfigProvider.StorageConfigProvider]), _dec(_class = _dec2(_class = _dec3(_class = class StorageBackendProvider {
25
+ constructor(resticFac, rcloneFac, cfgProvider) {
28
26
  this.resticFac = resticFac;
29
27
  this.rcloneFac = rcloneFac;
30
- this.cfg = cfg;
28
+ this.cfgProvider = cfgProvider;
31
29
 
32
- _defineProperty(this, "provide", name => {
33
- const s = this.cfg.storage.find(s => s.name === name);
34
- if (!s) throw new Error(`No such storage '${name}'`);
35
- let b;
30
+ _defineProperty(this, "provide", () => {
31
+ const s = this.cfgProvider.provide();
32
+ let b = null;
36
33
 
37
34
  switch (s.type) {
38
- case _config.StorageTypeConst.Restic:
35
+ case _types.StorageType.Restic:
39
36
  b = this.resticFac.create(s);
40
37
  break;
41
38
 
42
- case _config.StorageTypeConst.RClone:
39
+ case _types.StorageType.RClone:
43
40
  b = this.rcloneFac.create(s);
44
41
  break;
45
42
  }
@@ -49,5 +46,5 @@ let StorageBackendProvider = (_dec = (0, _inversify.injectable)(), _dec2 = funct
49
46
  });
50
47
  }
51
48
 
52
- }) || _class) || _class) || _class) || _class);
49
+ }) || _class) || _class) || _class);
53
50
  exports.StorageBackendProvider = StorageBackendProvider;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.StorageConfigProvider = void 0;
7
+
8
+ var _inversify = require("inversify");
9
+
10
+ var _ContextSymbols = require("../ctx/ContextSymbols");
11
+
12
+ var _config = require("../config");
13
+
14
+ var _Fs = require("../fs/Fs");
15
+
16
+ var _InvalidInput = require("../cli/InvalidInput");
17
+
18
+ var _StoreConfig = require("./StoreConfig");
19
+
20
+ var _dec, _dec2, _dec3, _dec4, _dec5, _class;
21
+
22
+ 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; }
23
+
24
+ let StorageConfigProvider = (_dec = (0, _inversify.injectable)(), _dec2 = function (target, key) {
25
+ return (0, _inversify.inject)(_ContextSymbols.AppConfig_)(target, undefined, 1);
26
+ }, _dec3 = function (target, key) {
27
+ return (0, _inversify.inject)(_ContextSymbols.Inputs_)(target, undefined, 2);
28
+ }, _dec4 = Reflect.metadata("design:type", Function), _dec5 = Reflect.metadata("design:paramtypes", [typeof _Fs.Fs === "undefined" ? Object : _Fs.Fs, typeof _config.Config === "undefined" ? Object : _config.Config, typeof StorageInputs === "undefined" ? Object : StorageInputs]), _dec(_class = _dec2(_class = _dec3(_class = _dec4(_class = _dec5(_class = class StorageConfigProvider {
29
+ constructor(fs, cfg, inputs) {
30
+ this.fs = fs;
31
+ this.cfg = cfg;
32
+ this.inputs = inputs;
33
+
34
+ _defineProperty(this, "provide", () => {
35
+ const {
36
+ storageName,
37
+ storagePassword,
38
+ storageRepo,
39
+ storageType
40
+ } = this.inputs;
41
+ let res;
42
+
43
+ if (storageName) {
44
+ if (storageType || storageRepo || storagePassword) throw new _InvalidInput.InvalidInput('Storage config provided. Storage name is therefore invalid input');
45
+ res = this.getByName(storageName);
46
+ } else {
47
+ res = this.getByCliConfig(this.inputs);
48
+ }
49
+
50
+ if (res.repo.startsWith('local:')) {
51
+ const path = res.repo.split('local:')[1];
52
+ res.repo = 'local:' + this.fs.expandStrPath(path);
53
+ }
54
+
55
+ return res;
56
+ });
57
+
58
+ _defineProperty(this, "getByCliConfig", inp => {
59
+ // // TODO unify validation usage
60
+ const r = (0, _StoreConfig.CliStorageConfigSchema)().validate(inp, {
61
+ presence: 'required',
62
+ allowUnknown: true
63
+ });
64
+ if (r.error) throw new _InvalidInput.InvalidInput(r.error.toString());
65
+ const cfg = inp;
66
+ return {
67
+ type: cfg.storageType,
68
+ repo: cfg.storageRepo,
69
+ encryptionPassword: cfg.storagePassword,
70
+ credentials: cfg.storageCredentials
71
+ };
72
+ });
73
+
74
+ _defineProperty(this, "getByName", name => {
75
+ const cfg = this.cfg.storage.find(s => s.name === name);
76
+ if (!cfg) throw new Error(`No such storage '${name}'`);
77
+ const encryptionPassword = cfg.passwordFile ? this.fs.readFile(this.fs.expand(cfg.passwordFile)).trim() : undefined;
78
+ const credentials = cfg.credentialsFile ? this.fs.readFile(this.fs.expand(cfg.credentialsFile)).trim() : undefined;
79
+ return {
80
+ type: cfg.type,
81
+ repo: cfg.repo,
82
+ credentials,
83
+ encryptionPassword
84
+ };
85
+ });
86
+ }
87
+
88
+ }) || _class) || _class) || _class) || _class) || _class);
89
+ exports.StorageConfigProvider = StorageConfigProvider;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.StorageSchema = exports.NamedStorageSchema = exports.CliStorageConfigSchema = void 0;
7
+
8
+ var _joi = _interopRequireDefault(require("@hapi/joi"));
9
+
10
+ var _types = require("./types");
11
+
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+
14
+ const props = {
15
+ type: _joi.default.string().valid(_types.StorageType.Restic, _types.StorageType.RClone),
16
+ repo: _joi.default.string(),
17
+ credentialsFile: _joi.default.string().optional(),
18
+ passwordFile: _joi.default.string().optional()
19
+ };
20
+
21
+ const StorageSchema = () => _joi.default.object(props);
22
+
23
+ exports.StorageSchema = StorageSchema;
24
+
25
+ const CliStorageConfigSchema = () => _joi.default.object({
26
+ storageType: _joi.default.string().valid(_types.StorageType.Restic, _types.StorageType.RClone),
27
+ storageRepo: _joi.default.string(),
28
+ storageCredentials: _joi.default.string().allow(null).optional(),
29
+ storagePassword: _joi.default.string().allow(null).optional()
30
+ });
31
+
32
+ exports.CliStorageConfigSchema = CliStorageConfigSchema;
33
+
34
+ const NamedStorageSchema = () => _joi.default.object({
35
+ name: _joi.default.string(),
36
+ ...props
37
+ });
38
+
39
+ exports.NamedStorageSchema = NamedStorageSchema;
@@ -36,11 +36,15 @@ let B2CredentialsProvider = (_dec = (0, _inversify.injectable)(), _dec2 = Reflec
36
36
  this.fs = fs;
37
37
 
38
38
  _defineProperty(this, "fromFile", path => {
39
- const credJson = this.fs.readJson(path);
39
+ return this.fromString(this.fs.readFile(path));
40
+ });
41
+
42
+ _defineProperty(this, "fromString", str => {
43
+ const credJson = JSON.parse(str);
40
44
  const validationErr = validateCredentials(credJson);
41
45
 
42
46
  if (validationErr) {
43
- throw new Error(`Invalid B2 credential in ${path}: ${validationErr}`);
47
+ throw new Error(`Invalid B2 credential in '${str.substring(0, 3)}...': ${validationErr}`);
44
48
  }
45
49
 
46
50
  const creds = credJson;
@@ -48,15 +48,15 @@ let RCloneClientFactory = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.
48
48
  type,
49
49
  location
50
50
  };
51
- const password = cfg.passwordFile && this.fs.readFile(cfg.passwordFile).trim();
51
+ const password = cfg.encryptionPassword;
52
52
  if (password) props.encryption = {
53
53
  password
54
54
  };
55
- const creds = cfg.credentialsFile && this.b2.fromFile(cfg.credentialsFile);
55
+ const creds = cfg.credentials;
56
56
 
57
57
  if (type === 'b2') {
58
- if (!creds) throw new Error(`Credentials are required for '${cfg.name}'`);
59
- props.creds = creds;
58
+ if (!creds) throw new Error(`Credentials are required for RClone storage repo='${cfg.repo}'`);
59
+ props.creds = this.b2.fromString(creds);
60
60
  } else {
61
61
  if (creds) throw new Error(`Credentials not supported for local rclone`);
62
62
  }
@@ -76,7 +76,7 @@ let RcloneClient = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadat
76
76
  return res;
77
77
  });
78
78
 
79
- _defineProperty(this, "obscure", str => this.shell.execAndReturnVal(`rclone obscure ${str}`));
79
+ _defineProperty(this, "obscure", str => this.shell.execAndReturnString(`rclone obscure ${str}`));
80
80
  }
81
81
 
82
82
  get actualRemoteName() {
@@ -29,20 +29,20 @@ let ResticClientFactory = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.
29
29
  this.b2 = b2;
30
30
 
31
31
  _defineProperty(this, "create", cfg => {
32
- const password = this.fs.readFile(cfg.passwordFile).trim();
32
+ if (!cfg.encryptionPassword) throw new Error(`Restic needs encryptionPassword. Repo=${cfg.repo}`);
33
33
  const props = {
34
34
  repo: {
35
- password,
35
+ password: cfg.encryptionPassword,
36
36
  url: cfg.repo
37
37
  }
38
38
  };
39
- const creds = cfg.credentialsFile && this.b2.fromFile(cfg.credentialsFile);
39
+ const creds = cfg.credentials;
40
40
 
41
41
  if (cfg.repo.startsWith('b2:')) {
42
- if (!creds) throw new Error(`Credentials must be provided for b2 repo in '${cfg.name}'`);
43
- props.backblaze = creds;
42
+ if (!creds) throw new Error(`Credentials must be provided for b2 repo in '${props.repo.url}'`);
43
+ props.backblaze = this.b2.fromString(creds);
44
44
  } else {
45
- if (creds) throw new Error('Credentials can be supported only for the B2 restic backend');
45
+ if (creds) throw new Error('Credentials can be set only for the B2 restic backend');
46
46
  }
47
47
 
48
48
  return new _ResticClient.ResticClient(props, this.sh, this.log);
@@ -15,23 +15,28 @@ var _ResticClientFactory = require("./ResticClientFactory");
15
15
 
16
16
  var _AppLogger = require("../../log/AppLogger");
17
17
 
18
+ var _StorageConfigProvider = require("../StorageConfigProvider");
19
+
20
+ var _types = require("../types");
21
+
18
22
  var _dec, _dec2, _dec3, _dec4, _class;
19
23
 
20
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; }
21
25
 
22
26
  let ResticController = (_dec = (0, _inversify.injectable)(), _dec2 = function (target, key) {
23
27
  return (0, _inversify.inject)(_ContextSymbols.AppConfig_)(target, undefined, 2);
24
- }, _dec3 = Reflect.metadata("design:type", Function), _dec4 = Reflect.metadata("design:paramtypes", [typeof _ResticClientFactory.ResticClientFactory === "undefined" ? Object : _ResticClientFactory.ResticClientFactory, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof _config.Config === "undefined" ? Object : _config.Config]), _dec(_class = _dec2(_class = _dec3(_class = _dec4(_class = class ResticController {
25
- constructor(restFact, log, cfg) {
28
+ }, _dec3 = Reflect.metadata("design:type", Function), _dec4 = Reflect.metadata("design:paramtypes", [typeof _ResticClientFactory.ResticClientFactory === "undefined" ? Object : _ResticClientFactory.ResticClientFactory, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof _config.Config === "undefined" ? Object : _config.Config, typeof _StorageConfigProvider.StorageConfigProvider === "undefined" ? Object : _StorageConfigProvider.StorageConfigProvider]), _dec(_class = _dec2(_class = _dec3(_class = _dec4(_class = class ResticController {
29
+ constructor(restFact, log, cfg, storageConfigProvider) {
26
30
  this.restFact = restFact;
27
31
  this.log = log;
28
32
  this.cfg = cfg;
33
+ this.storageConfigProvider = storageConfigProvider;
29
34
 
30
- _defineProperty(this, "initRepo", storageName => {
31
- const s = this.cfg.storage.filter(s => s.type === 'restic').find(s => s.name === storageName);
32
- if (!s) throw new Error(`No restic storage '${storageName}'`);
33
- this.log.info('Initializing repo', storageName);
34
- this.restFact.create(s).prepareRepo();
35
+ _defineProperty(this, "initRepo", () => {
36
+ const props = this.storageConfigProvider.provide();
37
+ if (props.type !== _types.StorageType.Restic) throw new Error('Storage is not Restic storage');
38
+ this.log.info('Initializing repo', props.repo);
39
+ this.restFact.create(props).prepareRepo();
35
40
  });
36
41
  }
37
42
 
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.StorageType = void 0;
7
+ let StorageType;
8
+ exports.StorageType = StorageType;
9
+
10
+ (function (StorageType) {
11
+ StorageType["Restic"] = "restic";
12
+ StorageType["RClone"] = "rclone";
13
+ })(StorageType || (exports.StorageType = StorageType = {}));
@@ -25,7 +25,7 @@ let Gpg = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design
25
25
  });
26
26
 
27
27
  _defineProperty(this, "exportKey", id => {
28
- const res = this.sh.execAndReturnVal(`gpg --batch --pinentry-mode=loopback --pinentry-mode=loopback --yes --passphrase foo123 --export-secret-key --armor ${id}`);
28
+ const res = this.sh.execAndReturnString(`gpg --batch --pinentry-mode=loopback --pinentry-mode=loopback --yes --passphrase foo123 --export-secret-key --armor ${id}`);
29
29
  if (!res) throw new Error(`Key '${id}' not in keyring`);
30
30
  return res;
31
31
  });
@@ -22,8 +22,7 @@ let Shell = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("desi
22
22
 
23
23
  _defineProperty(this, "exec", (cmd, opts = {}) => {
24
24
  this.log.debug(cmd);
25
- (0, _shellCmd.shellCmd)(cmd, { ...opts,
26
- returnStdout: false
25
+ (0, _shellCmd.shellCmd)(cmd, { ...opts
27
26
  });
28
27
  });
29
28
 
@@ -34,15 +33,22 @@ let Shell = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("desi
34
33
  }) => {
35
34
  this.log.debug(`<stdin> > ${cmd}`);
36
35
  (0, _shellCmd.shellCmd)(cmd, { ...opts,
37
- stdin,
38
- returnStdout: false
36
+ stdin
37
+ });
38
+ });
39
+
40
+ _defineProperty(this, "execAndReturnString", (cmd, ops = {}) => {
41
+ this.log.debug(cmd, '[stdout consumed]');
42
+ return (0, _shellCmd.shellCmd)(cmd, {
43
+ returnStdout: 'string',
44
+ ...ops
39
45
  });
40
46
  });
41
47
 
42
- _defineProperty(this, "execAndReturnVal", (cmd, ops = {}) => {
48
+ _defineProperty(this, "execAndReturnBuffer", (cmd, ops = {}) => {
43
49
  this.log.debug(cmd, '[stdout consumed]');
44
50
  return (0, _shellCmd.shellCmd)(cmd, {
45
- returnStdout: true,
51
+ returnStdout: 'buffer',
46
52
  ...ops
47
53
  });
48
54
  });
@@ -16,10 +16,16 @@ const shellCmd = (cmd, {
16
16
  const res = (0, _child_process.execSync)(cmd, {
17
17
  cwd,
18
18
  input: stdin,
19
- stdio: [stdin ? undefined : 'inherit', returnStdout ? undefined : 'inherit', 'inherit'],
19
+ stdio: [stdin ? undefined : 'inherit', returnStdout ? undefined : 'inherit', 'pipe' // TODO changed from 'inherit' as the message is not shown in the console - find out how to catch the stderr output
20
+ ],
20
21
  env
21
22
  });
22
- if (returnStdout) return res.toString().trim();
23
+
24
+ if (returnStdout) {
25
+ if (returnStdout === 'string') return res.toString().trim();
26
+ return res;
27
+ }
28
+
23
29
  return null;
24
30
  };
25
31
 
@@ -6,9 +6,11 @@ var _Fs = require("../../fs/Fs");
6
6
 
7
7
  var _AppLogger = require("../../log/AppLogger");
8
8
 
9
+ var _Path = require("../../fs/path/Path");
10
+
9
11
  // TODO setup ci to make tests work
10
12
  it.skip('works', () => {
11
- const sut = new _SshKeyManager.SshKeyManager(new _Fs.Fs(new _AppLogger.AppLogger()));
13
+ const sut = new _SshKeyManager.SshKeyManager(new _Fs.Fs(_Path.AbsPath.from(__dirname), new _AppLogger.AppLogger()));
12
14
  const key = sut.exportKey('id_rsa');
13
15
  console.log('key', key);
14
16
  });
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@ps-aux/nodebup",
3
- "version": "0.5.0",
3
+ "version": "0.7.1",
4
4
  "description": "",
5
5
  "module": "lib/index.js",
6
6
  "main": "lib/index.js",
7
7
  "scripts": {
8
8
  "build": "rm -rf build && babel --extensions '.ts,.js,.md' src -d lib src",
9
+ "publish:local": "npm run build && chmod +x lib/cli/bin.js && npm link",
9
10
  "pub": "npm publish --access public",
10
11
  "test": "jest",
12
+ "test:ci": "jest --group=-no-ci",
11
13
  "tc": "tsc --noEmit",
12
14
  "format": "prettier \"**/*.{js,ts,tsx}\" --write",
13
15
  "build-n-run": "npm run build && ",
@@ -41,12 +43,14 @@
41
43
  "@types/jest": "^27.4.0",
42
44
  "@types/jest-when": "^2.7.4",
43
45
  "@types/node": "^17.0.6",
46
+ "@types/pg": "^8.6.5",
44
47
  "@types/ramda": "^0.27.62",
45
48
  "@typescript-eslint/eslint-plugin": "^5.8.1",
46
49
  "@typescript-eslint/parser": "^5.8.1",
47
50
  "babel-plugin-module-resolver": "^4.1.0",
48
51
  "babel-plugin-transform-typescript-metadata": "^0.3.2",
49
52
  "dir-compare": "^4.0.0",
53
+ "docker-compose": "^0.23.17",
50
54
  "eslint": "^8.6.0",
51
55
  "eslint-config-standard": "^16.0.3",
52
56
  "eslint-plugin-import": "^2.25.3",
@@ -57,9 +61,11 @@
57
61
  "husky": "^7.0.4",
58
62
  "jest": "^27.4.5",
59
63
  "jest-extended": "^1.2.0",
64
+ "jest-runner-groups": "^2.2.0",
60
65
  "jest-when": "^3.5.0",
61
66
  "lint-staged": "^12.1.4",
62
67
  "npm-check-updates": "^12.0.5",
68
+ "pg": "^8.7.3",
63
69
  "prettier": "^2.5.1",
64
70
  "ts-jest": "^27.1.2",
65
71
  "typescript": "^4.5.4"
@@ -72,7 +78,7 @@
72
78
  },
73
79
  "dependencies": {
74
80
  "@hapi/joi": "^17.1.1",
75
- "@ps-aux/nclif": "^0.0.6-alpha.3",
81
+ "@ps-aux/nclif": "^0.0.7-alpha.1",
76
82
  "@types/hapi__joi": "^17.1.8",
77
83
  "axios": "^0.24.0",
78
84
  "handlebars": "^4.7.7",
@@ -1,56 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.BackupController = void 0;
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
- var _inversify = require("inversify");
17
-
18
- var _ContextSymbols = require("../ctx/ContextSymbols");
19
-
20
- var _AppLogger = require("../log/AppLogger");
21
-
22
- var _StorageBackendProvider = require("../storage/StorageBackendProvider");
23
-
24
- var _config = require("../config");
25
-
26
- var _dec, _dec2, _dec3, _dec4, _class;
27
-
28
- 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; }
29
-
30
- let BackupController = (_dec = (0, _inversify.injectable)(), _dec2 = function (target, key) {
31
- return (0, _inversify.inject)(_ContextSymbols.AppConfig_)(target, undefined, 6);
32
- }, _dec3 = Reflect.metadata("design:type", Function), _dec4 = Reflect.metadata("design:paramtypes", [typeof _Gpg.Gpg === "undefined" ? Object : _Gpg.Gpg, typeof _SshKeyManager.SshKeyManager === "undefined" ? Object : _SshKeyManager.SshKeyManager, typeof _Fs.Fs === "undefined" ? Object : _Fs.Fs, typeof _FsSyncer.FsSyncer === "undefined" ? Object : _FsSyncer.FsSyncer, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof _StorageBackendProvider.StorageBackendProvider === "undefined" ? Object : _StorageBackendProvider.StorageBackendProvider, typeof _config.Config === "undefined" ? Object : _config.Config]), _dec(_class = _dec2(_class = _dec3(_class = _dec4(_class = class BackupController {
33
- constructor(gpg, ssh, fs, fsSyncer, log, storageBackendProvider, cfg) {
34
- this.gpg = gpg;
35
- this.ssh = ssh;
36
- this.fs = fs;
37
- this.fsSyncer = fsSyncer;
38
- this.log = log;
39
- this.storageBackendProvider = storageBackendProvider;
40
- this.cfg = cfg;
41
-
42
- _defineProperty(this, "backup", (storageName, path) => {
43
- this.log.info(`Backing up from ${path} to '${storageName}'`);
44
- this.storage(storageName).store(path);
45
- });
46
-
47
- _defineProperty(this, "restore", (storageName, path) => {
48
- this.log.info(`Restoring from '${storageName}' to ${path}`);
49
- this.storage(storageName).restore(path);
50
- });
51
-
52
- _defineProperty(this, "storage", name => this.storageBackendProvider.provide(name));
53
- }
54
-
55
- }) || _class) || _class) || _class) || _class);
56
- exports.BackupController = BackupController;
@@ -1,5 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });