@ps-aux/nodebup 0.6.0 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +1 -0
- package/lib/bup/{AggregateBackupController.js → aggregate/AggregateBackupController.js} +9 -9
- package/lib/bup/dir/DataBackupController.js +44 -0
- package/lib/bup/pg/PgBackupController.js +114 -0
- package/lib/cli/app.js +49 -24
- package/lib/config/Config.js +20 -4
- package/lib/ctx/Context.js +7 -3
- package/lib/fs/Fs.js +28 -0
- package/lib/fs/path/Path.js +5 -1
- package/lib/storage/StoreConfig.js +2 -2
- package/lib/storage/rclone/RcloneClient.js +1 -1
- package/lib/storage/restic/ResticClientFactory.js +1 -1
- package/lib/tools/compression/Zipper.js +39 -0
- package/lib/tools/compression/Zipper.test.js +24 -0
- package/lib/tools/gpg/Gpg.js +1 -1
- package/lib/tools/shell/Shell.js +12 -6
- package/lib/tools/shell/shellCmd.js +8 -2
- package/package.json +8 -1
- package/lib/bup/BackupController.js +0 -63
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("
|
8
|
+
var _FsSyncer = require("../../fs/fssync/FsSyncer");
|
9
9
|
|
10
|
-
var _Gpg = require("
|
10
|
+
var _Gpg = require("../../tools/gpg/Gpg");
|
11
11
|
|
12
|
-
var _Fs = require("
|
12
|
+
var _Fs = require("../../fs/Fs");
|
13
13
|
|
14
|
-
var _SshKeyManager = require("
|
14
|
+
var _SshKeyManager = require("../../tools/ssh/SshKeyManager");
|
15
15
|
|
16
16
|
var _inversify = require("inversify");
|
17
17
|
|
18
|
-
var _ContextSymbols = require("
|
18
|
+
var _ContextSymbols = require("../../ctx/ContextSymbols");
|
19
19
|
|
20
|
-
var _AppLogger = require("
|
20
|
+
var _AppLogger = require("../../log/AppLogger");
|
21
21
|
|
22
|
-
var _Path = require("
|
22
|
+
var _Path = require("../../fs/path/Path");
|
23
23
|
|
24
|
-
var _config = require("
|
24
|
+
var _config = require("../../config");
|
25
25
|
|
26
|
-
var _StorageBackendProvider = require("
|
26
|
+
var _StorageBackendProvider = require("../../storage/StorageBackendProvider");
|
27
27
|
|
28
28
|
var _dec, _dec2, _dec3, _dec4, _class;
|
29
29
|
|
@@ -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,114 @@
|
|
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 _Zipper = require("../../tools/compression/Zipper");
|
21
|
+
|
22
|
+
var _dec, _dec2, _dec3, _class, _class2, _temp;
|
23
|
+
|
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; }
|
25
|
+
|
26
|
+
const parseConnectionUrl = url => {
|
27
|
+
var _url$match;
|
28
|
+
|
29
|
+
const regex = /postgres:\/\/(?<username>.*):(?<password>.*)@(?<host>.*):(?<port>\d*)$/;
|
30
|
+
const match = (_url$match = url.match(regex)) === null || _url$match === void 0 ? void 0 : _url$match.groups;
|
31
|
+
if (!match || !match.username || !match.password || !match.host || !match.port) throw new Error(`The Postgres connection URL does not match required regex: ${regex.toString()}`);
|
32
|
+
return {
|
33
|
+
username: match.username,
|
34
|
+
password: match.password,
|
35
|
+
host: match.host,
|
36
|
+
port: parseInt(match.port, 10)
|
37
|
+
};
|
38
|
+
};
|
39
|
+
|
40
|
+
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, typeof _Zipper.Zipper === "undefined" ? Object : _Zipper.Zipper]), _dec(_class = _dec2(_class = _dec3(_class = (_temp = _class2 = class PgBackupController {
|
41
|
+
constructor( // private gpg: Gpg,
|
42
|
+
// private ssh: SshKeyManager,
|
43
|
+
fs, // private fsSyncer: FsSyncer,
|
44
|
+
log, storageBackendProvider, // @inject(AppConfig_) private cfg: Config,
|
45
|
+
sh, zip) {
|
46
|
+
this.fs = fs;
|
47
|
+
this.log = log;
|
48
|
+
this.storageBackendProvider = storageBackendProvider;
|
49
|
+
this.sh = sh;
|
50
|
+
this.zip = zip;
|
51
|
+
|
52
|
+
_defineProperty(this, "now", () => {
|
53
|
+
const d = new Date();
|
54
|
+
const fields = [d.getFullYear(), d.getMonth(), d.getDay(), d.getUTCHours(), d.getMinutes(), d.getSeconds()];
|
55
|
+
return fields.join('-');
|
56
|
+
});
|
57
|
+
|
58
|
+
_defineProperty(this, "getVersion", version => version || PgBackupController.defaultPgVersion);
|
59
|
+
|
60
|
+
_defineProperty(this, "outFileName", 'backup.sql');
|
61
|
+
|
62
|
+
_defineProperty(this, "backup", ({
|
63
|
+
pgUrl,
|
64
|
+
pgVersion
|
65
|
+
}) => {
|
66
|
+
const storage = this.storageBackendProvider.provide();
|
67
|
+
const version = this.getVersion(pgVersion); // TODO validate url
|
68
|
+
|
69
|
+
this.log.info(`Backing up Postgres database, version=${version}`);
|
70
|
+
const connParams = parseConnectionUrl(pgUrl);
|
71
|
+
const pass = connParams.password;
|
72
|
+
this.fs.inTmpDir('pg-backup', dir => {
|
73
|
+
const outputDir = _Path.AbsPath.from(dir);
|
74
|
+
|
75
|
+
this.log.info('Dumping database to a file');
|
76
|
+
const bashCmds = [`echo "*:*:*:*:${pass}" > ~/.pgpass`, `chmod 400 ~/.pgpass`, `pg_dumpall -d ${pgUrl}`]; // TODO improve sh logging to avoid showing secrets
|
77
|
+
|
78
|
+
const b = this.sh.execAndReturnBuffer(`docker run --network host ` + `postgres:${version} ` + `bash -c '${bashCmds.join(' && ')}'`);
|
79
|
+
const dumpOut = outputDir.resolve(this.outFileName);
|
80
|
+
this.fs.writeFile(dumpOut, b);
|
81
|
+
this.log.info('Compressing');
|
82
|
+
const zipOutputName = `pg-backup-${this.now()}.zip`;
|
83
|
+
this.zip.zipDir(outputDir, outputDir.resolve(zipOutputName));
|
84
|
+
this.fs.rmFile(dumpOut);
|
85
|
+
this.log.info('Uploading');
|
86
|
+
storage.store(_Path.AbsPath.from(dir));
|
87
|
+
});
|
88
|
+
});
|
89
|
+
|
90
|
+
_defineProperty(this, "restore", ({
|
91
|
+
pgUrl,
|
92
|
+
pgVersion
|
93
|
+
}) => {
|
94
|
+
const version = this.getVersion(pgVersion);
|
95
|
+
const storage = this.storageBackendProvider.provide(); // To validate
|
96
|
+
|
97
|
+
parseConnectionUrl(pgUrl);
|
98
|
+
this.log.info(`Restoring Postgres database, version=${version}`);
|
99
|
+
this.fs.inTmpDir('pg-restore', dirStr => {
|
100
|
+
const dir = _Path.AbsPath.from(dirStr);
|
101
|
+
|
102
|
+
storage.restore(dir); // TODO check if the dir contains the with the expected name
|
103
|
+
|
104
|
+
const zipFile = this.fs.listFiles(dir)[0];
|
105
|
+
this.zip.unzipDir(zipFile, dir);
|
106
|
+
this.fs.rmFile(zipFile);
|
107
|
+
const outFile = this.fs.listFiles(dir)[0];
|
108
|
+
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`);
|
109
|
+
});
|
110
|
+
});
|
111
|
+
}
|
112
|
+
|
113
|
+
}, _defineProperty(_class2, "defaultPgVersion", '14.2'), _temp)) || _class) || _class) || _class);
|
114
|
+
exports.PgBackupController = PgBackupController;
|
package/lib/cli/app.js
CHANGED
@@ -13,38 +13,41 @@ 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
|
20
|
+
var _DataBackupController = require("../bup/dir/DataBackupController");
|
21
|
+
|
22
|
+
var _PgBackupController = require("../bup/pg/PgBackupController");
|
21
23
|
|
22
24
|
const storageNameOpt = {
|
23
25
|
name: 'storage-name',
|
24
26
|
convertCase: true,
|
25
27
|
fromConfig: 'storage.name'
|
26
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
|
+
}];
|
27
46
|
|
28
47
|
const createApp = () => _nclif.CliApp.of({
|
29
48
|
commands: {
|
30
49
|
data: (0, _nclif.cmdGroup)({
|
31
|
-
options:
|
32
|
-
name: 'storage-type',
|
33
|
-
convertCase: true,
|
34
|
-
fromConfig: 'storage.type'
|
35
|
-
}, {
|
36
|
-
name: 'storage-repo',
|
37
|
-
convertCase: true,
|
38
|
-
fromConfig: 'storage.repo'
|
39
|
-
}, {
|
40
|
-
name: 'storage-password',
|
41
|
-
convertCase: true,
|
42
|
-
fromConfig: 'storage.password'
|
43
|
-
}, {
|
44
|
-
name: 'storage-credentials',
|
45
|
-
convertCase: true,
|
46
|
-
fromConfig: 'storage.credentials'
|
47
|
-
}],
|
50
|
+
options: singleStorageOptions,
|
48
51
|
commands: {
|
49
52
|
backup: (0, _nclif.cmd)({
|
50
53
|
description: 'Backup a dir to the given storage',
|
@@ -52,7 +55,7 @@ const createApp = () => _nclif.CliApp.of({
|
|
52
55
|
name: 'path',
|
53
56
|
required: true
|
54
57
|
}],
|
55
|
-
run: (cmd, c) => c.get(
|
58
|
+
run: (cmd, c) => c.get(_DataBackupController.DataBackupController).storage(cmd).backup()
|
56
59
|
}),
|
57
60
|
restore: (0, _nclif.cmd)({
|
58
61
|
description: 'Restore the storage to the given dir',
|
@@ -60,7 +63,7 @@ const createApp = () => _nclif.CliApp.of({
|
|
60
63
|
name: 'path',
|
61
64
|
required: true
|
62
65
|
}],
|
63
|
-
run: (cmd, c) => c.get(
|
66
|
+
run: (cmd, c) => c.get(_DataBackupController.DataBackupController).storage(cmd).restore()
|
64
67
|
})
|
65
68
|
}
|
66
69
|
}),
|
@@ -77,7 +80,8 @@ const createApp = () => _nclif.CliApp.of({
|
|
77
80
|
})
|
78
81
|
}
|
79
82
|
}),
|
80
|
-
restic
|
83
|
+
restic,
|
84
|
+
pg
|
81
85
|
}
|
82
86
|
}).envConfig('NODEBUP').addObjectConfig(pwd => (0, _Config.readConfig)(pwd)).context(({
|
83
87
|
config,
|
@@ -88,8 +92,29 @@ exports.createApp = createApp;
|
|
88
92
|
const restic = (0, _nclif.cmdGroup)({
|
89
93
|
commands: {
|
90
94
|
'init-repo': (0, _nclif.cmd)({
|
91
|
-
options:
|
92
|
-
run: (
|
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)
|
93
118
|
})
|
94
119
|
}
|
95
120
|
});
|
package/lib/config/Config.js
CHANGED
@@ -13,6 +13,10 @@ var _validateConfigAgainstSchema = require("./validateConfigAgainstSchema");
|
|
13
13
|
|
14
14
|
var _expandAndCreatePath = require("./expandAndCreatePath");
|
15
15
|
|
16
|
+
var _Fs = require("../fs/Fs");
|
17
|
+
|
18
|
+
var _AppLogger = require("../log/AppLogger");
|
19
|
+
|
16
20
|
const expandPaths = (cfg, exp) => {
|
17
21
|
cfg.aggregates.forEach(a => {
|
18
22
|
a.sources.file.forEach(f => {
|
@@ -26,15 +30,27 @@ const expandPaths = (cfg, exp) => {
|
|
26
30
|
if (f.to) f.to = _Path.RelativePath.from(f.to);
|
27
31
|
});
|
28
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;
|
29
46
|
};
|
30
47
|
|
31
48
|
const readConfig = pwdStr => {
|
32
49
|
const cwd = _Path.AbsPath.from(pwdStr);
|
33
50
|
|
34
|
-
const
|
35
|
-
|
36
|
-
|
37
|
-
cfg.pwd = cwd;
|
51
|
+
const cfg = { ...readFromFile(cwd),
|
52
|
+
pwd: cwd
|
53
|
+
};
|
38
54
|
cfg.aggregates.forEach(t => {
|
39
55
|
const {
|
40
56
|
sources
|
package/lib/ctx/Context.js
CHANGED
@@ -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,10 +33,14 @@ var _B2CredentialsProvider = require("../storage/b2/B2CredentialsProvider");
|
|
33
33
|
|
34
34
|
var _RCloneClientFactory = require("../storage/rclone/RCloneClientFactory");
|
35
35
|
|
36
|
-
var
|
36
|
+
var _DataBackupController = require("../bup/dir/DataBackupController");
|
37
37
|
|
38
38
|
var _StorageConfigProvider = require("../storage/StorageConfigProvider");
|
39
39
|
|
40
|
+
var _PgBackupController = require("../bup/pg/PgBackupController");
|
41
|
+
|
42
|
+
var _Zipper = require("../tools/compression/Zipper");
|
43
|
+
|
40
44
|
const createContext = (cfg, inp) => {
|
41
45
|
const c = new _inversify.Container();
|
42
46
|
c.bind(_ContextSymbols.AppConfig_).toConstantValue(cfg);
|
@@ -45,7 +49,7 @@ const createContext = (cfg, inp) => {
|
|
45
49
|
c.bind(_ContextSymbols.Log_).toConstantValue(log);
|
46
50
|
c.bind(_AppLogger.AppLogger).toConstantValue(log);
|
47
51
|
c.bind(_Fs.Fs).toConstantValue(new _Fs.Fs(cfg.pwd, log));
|
48
|
-
const self = [_Gpg.Gpg, _Shell.Shell, _FsSyncer.FsSyncer, _SshKeyManager.SshKeyManager, _StorageBackendProvider.StorageBackendProvider, _StorageConfigProvider.StorageConfigProvider, _ResticClientFactory.ResticClientFactory, _AggregateBackupController.AggregateBackupController, _ResticController.ResticController, _B2CredentialsProvider.B2CredentialsProvider, _RCloneClientFactory.RCloneClientFactory,
|
52
|
+
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, _Zipper.Zipper];
|
49
53
|
self.forEach(s => c.bind(s).toSelf());
|
50
54
|
return c;
|
51
55
|
};
|
package/lib/fs/Fs.js
CHANGED
@@ -7,6 +7,8 @@ exports.Fs = void 0;
|
|
7
7
|
|
8
8
|
var _fs = _interopRequireDefault(require("fs"));
|
9
9
|
|
10
|
+
var _path = _interopRequireDefault(require("path"));
|
11
|
+
|
10
12
|
var _Path = require("./path/Path");
|
11
13
|
|
12
14
|
var _inversify = require("inversify");
|
@@ -15,6 +17,8 @@ var _AppLogger = require("../log/AppLogger");
|
|
15
17
|
|
16
18
|
var _expandAndCreatePath = require("../config/expandAndCreatePath");
|
17
19
|
|
20
|
+
var _os = _interopRequireDefault(require("os"));
|
21
|
+
|
18
22
|
var _dec, _dec2, _dec3, _class;
|
19
23
|
|
20
24
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
@@ -47,6 +51,30 @@ let Fs = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:
|
|
47
51
|
});
|
48
52
|
});
|
49
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
|
+
|
50
78
|
_defineProperty(this, "ensureIsDir", p => {
|
51
79
|
if (!this.isDir(p)) throw new Error(`${p} is not a dir`);
|
52
80
|
});
|
package/lib/fs/path/Path.js
CHANGED
@@ -24,7 +24,11 @@ class AbsPath {
|
|
24
24
|
return AbsPath.from(_path.default.resolve(this.path, '..'));
|
25
25
|
});
|
26
26
|
|
27
|
-
_defineProperty(this, "
|
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
|
}
|
@@ -25,8 +25,8 @@ exports.StorageSchema = StorageSchema;
|
|
25
25
|
const CliStorageConfigSchema = () => _joi.default.object({
|
26
26
|
storageType: _joi.default.string().valid(_types.StorageType.Restic, _types.StorageType.RClone),
|
27
27
|
storageRepo: _joi.default.string(),
|
28
|
-
storageCredentials: _joi.default.string().optional(),
|
29
|
-
storagePassword: _joi.default.string().optional()
|
28
|
+
storageCredentials: _joi.default.string().allow(null).optional(),
|
29
|
+
storagePassword: _joi.default.string().allow(null).optional()
|
30
30
|
});
|
31
31
|
|
32
32
|
exports.CliStorageConfigSchema = CliStorageConfigSchema;
|
@@ -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.
|
79
|
+
_defineProperty(this, "obscure", str => this.shell.execAndReturnString(`rclone obscure ${str}`));
|
80
80
|
}
|
81
81
|
|
82
82
|
get actualRemoteName() {
|
@@ -42,7 +42,7 @@ let ResticClientFactory = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.
|
|
42
42
|
if (!creds) throw new Error(`Credentials must be provided for b2 repo in '${props.repo.url}'`);
|
43
43
|
props.backblaze = this.b2.fromString(creds);
|
44
44
|
} else {
|
45
|
-
if (creds) throw new Error('Credentials can be
|
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);
|
@@ -0,0 +1,39 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.Zipper = void 0;
|
7
|
+
|
8
|
+
var _admZip = _interopRequireDefault(require("adm-zip"));
|
9
|
+
|
10
|
+
var _inversify = require("inversify");
|
11
|
+
|
12
|
+
var _AppLogger = require("../../log/AppLogger");
|
13
|
+
|
14
|
+
var _dec, _dec2, _dec3, _class;
|
15
|
+
|
16
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
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 Zipper = (_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 Zipper {
|
21
|
+
constructor(log) {
|
22
|
+
this.log = log;
|
23
|
+
|
24
|
+
_defineProperty(this, "zipDir", (dir, to) => {
|
25
|
+
this.log.debug(`Zipping ${dir} to ${to}`);
|
26
|
+
const z = new _admZip.default();
|
27
|
+
z.addLocalFolder(dir.str());
|
28
|
+
z.writeZip(to.str());
|
29
|
+
});
|
30
|
+
|
31
|
+
_defineProperty(this, "unzipDir", (zipFile, toDir) => {
|
32
|
+
this.log.debug(`Unzipping ${zipFile} to ${toDir}`);
|
33
|
+
const z = new _admZip.default(zipFile.str());
|
34
|
+
z.extractAllTo(toDir.str());
|
35
|
+
});
|
36
|
+
}
|
37
|
+
|
38
|
+
}) || _class) || _class) || _class);
|
39
|
+
exports.Zipper = Zipper;
|
@@ -0,0 +1,24 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
var _Zipper = require("./Zipper");
|
4
|
+
|
5
|
+
var _Path = require("../../fs/path/Path");
|
6
|
+
|
7
|
+
var _testHelper = require("../../../test/testHelper");
|
8
|
+
|
9
|
+
var _AppLogger = require("../../log/AppLogger");
|
10
|
+
|
11
|
+
it('zip', () => {
|
12
|
+
const z = new _Zipper.Zipper(new _AppLogger.AppLogger());
|
13
|
+
|
14
|
+
const out = _Path.AbsPath.from(__dirname).resolve('../../test-data/out.zip');
|
15
|
+
|
16
|
+
const dir = _Path.AbsPath.from(__dirname).resolve('../../../test/foo');
|
17
|
+
|
18
|
+
z.zipDir(dir, out);
|
19
|
+
|
20
|
+
const extDir = _Path.AbsPath.from(__dirname).resolve('../../test-data/foo-out');
|
21
|
+
|
22
|
+
z.unzipDir(out, extDir);
|
23
|
+
(0, _testHelper.expectDirsToBeTheSame)(dir.str(), extDir.str());
|
24
|
+
});
|
package/lib/tools/gpg/Gpg.js
CHANGED
@@ -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.
|
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
|
});
|
package/lib/tools/shell/Shell.js
CHANGED
@@ -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
|
-
|
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, "
|
48
|
+
_defineProperty(this, "execAndReturnBuffer", (cmd, ops = {}) => {
|
43
49
|
this.log.debug(cmd, '[stdout consumed]');
|
44
50
|
return (0, _shellCmd.shellCmd)(cmd, {
|
45
|
-
returnStdout:
|
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
|
-
|
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
|
|
package/package.json
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
{
|
2
2
|
"name": "@ps-aux/nodebup",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.7.2",
|
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"
|
@@ -74,6 +80,7 @@
|
|
74
80
|
"@hapi/joi": "^17.1.1",
|
75
81
|
"@ps-aux/nclif": "^0.0.7-alpha.1",
|
76
82
|
"@types/hapi__joi": "^17.1.8",
|
83
|
+
"adm-zip": "^0.5.9",
|
77
84
|
"axios": "^0.24.0",
|
78
85
|
"handlebars": "^4.7.7",
|
79
86
|
"ini": "^2.0.0",
|
@@ -1,63 +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 _Path = require("../fs/path/Path");
|
23
|
-
|
24
|
-
var _StorageBackendProvider = require("../storage/StorageBackendProvider");
|
25
|
-
|
26
|
-
var _config = require("../config");
|
27
|
-
|
28
|
-
var _dec, _dec2, _dec3, _dec4, _class;
|
29
|
-
|
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; }
|
31
|
-
|
32
|
-
let BackupController = (_dec = (0, _inversify.injectable)(), _dec2 = function (target, key) {
|
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 _StorageBackendProvider.StorageBackendProvider === "undefined" ? Object : _StorageBackendProvider.StorageBackendProvider, typeof _config.Config === "undefined" ? Object : _config.Config]), _dec(_class = _dec2(_class = _dec3(_class = _dec4(_class = class BackupController {
|
35
|
-
constructor(gpg, ssh, fs, fsSyncer, log, storageBackendProvider, cfg) {
|
36
|
-
this.gpg = gpg;
|
37
|
-
this.ssh = ssh;
|
38
|
-
this.fs = fs;
|
39
|
-
this.fsSyncer = fsSyncer;
|
40
|
-
this.log = log;
|
41
|
-
this.storageBackendProvider = storageBackendProvider;
|
42
|
-
this.cfg = cfg;
|
43
|
-
|
44
|
-
_defineProperty(this, "storage", inp => {
|
45
|
-
const storage = this.storageBackendProvider.provide();
|
46
|
-
|
47
|
-
const path = _Path.AbsPath.from(inp.path);
|
48
|
-
|
49
|
-
return {
|
50
|
-
backup: () => {
|
51
|
-
this.log.info(`Backing up from ${path} to '${storage}'`);
|
52
|
-
storage.store(path);
|
53
|
-
},
|
54
|
-
restore: () => {
|
55
|
-
this.log.info(`Restoring from '${storage}' to ${path}`);
|
56
|
-
storage.restore(path);
|
57
|
-
}
|
58
|
-
};
|
59
|
-
});
|
60
|
-
}
|
61
|
-
|
62
|
-
}) || _class) || _class) || _class) || _class);
|
63
|
-
exports.BackupController = BackupController;
|