@ps-aux/nodebup 0.1.0 → 0.2.2
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.
- package/README.md +0 -0
- package/lib/bup/AggregateBackupController.js +84 -0
- package/lib/cli/app.js +55 -0
- package/lib/cli/bin.js +2 -8
- package/lib/config/Config.js +58 -0
- package/lib/config/expandAndCreatePath.js +24 -0
- package/lib/config/validateConfigAgainstSchema.js +65 -0
- package/lib/config/validateConfigAgainstSchema.spec.js +29 -0
- package/lib/ctx/Context.js +23 -16
- package/lib/ctx/ContextSymbols.js +14 -0
- package/lib/fs/Fs.js +81 -0
- package/lib/fs/areDirsSame.js +20 -0
- package/lib/fs/areDirsSame.test.js +20 -0
- package/lib/fs/fssync/FsSync.spec.js +37 -0
- package/lib/fs/fssync/FsSyncer.js +54 -0
- package/lib/fs/path/Path.js +59 -0
- package/lib/fs/readYaml.js +20 -0
- package/lib/globald.d.js +3 -0
- package/lib/log/AppLogger.js +28 -0
- package/lib/log/MinimalLogger.js +10 -4
- package/lib/storage/StorageBackendProvider.js +53 -0
- package/lib/storage/local-file/LocalFileStorageBackend.js +22 -0
- package/lib/storage/restic/ResticClient.js +86 -0
- package/lib/storage/restic/ResticClient.spec.js +96 -0
- package/lib/storage/restic/ResticClientFactory.js +77 -0
- package/lib/storage/restic/ResticController.js +39 -0
- package/lib/storage/restic/ResticStorageBackend.js +23 -0
- package/lib/storage/types.d.js +5 -0
- package/lib/tools/gpg/Gpg.js +28 -0
- package/lib/tools/gpg/Gpg.spec.js +14 -0
- package/lib/tools/shell/Shell.js +52 -0
- package/lib/{shell → tools/shell}/shellCmd.js +4 -2
- package/lib/tools/ssh/SshKeyManager.js +36 -0
- package/lib/tools/ssh/SshKeyManager.spec.js +14 -0
- package/lib/types.js +5 -0
- package/package.json +53 -48
- package/lib/cli/entrypoint.js +0 -27
- package/lib/foo/foo.command.js +0 -16
- package/lib/shell/LocalShellCmdExecutor.js +0 -46
- package/lib/types.d.js +0 -1
package/README.md
ADDED
File without changes
|
@@ -0,0 +1,84 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.AggregateBackupController = void 0;
|
7
|
+
|
8
|
+
var _FsSyncer = require("../fs/fssync/FsSyncer");
|
9
|
+
|
10
|
+
var _Config = require("../config/Config");
|
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
|
+
var _inversify = require("inversify");
|
19
|
+
|
20
|
+
var _ContextSymbols = require("../ctx/ContextSymbols");
|
21
|
+
|
22
|
+
var _AppLogger = require("../log/AppLogger");
|
23
|
+
|
24
|
+
var _StorageBackendProvider = require("../storage/StorageBackendProvider");
|
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 AggregateBackupController = (_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 AggregateBackupController {
|
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", async (aggregate, storage) => {
|
43
|
+
const aggrDir = this.cfg.pwd.resolve('.aggr');
|
44
|
+
this.fs.ensureDir(aggrDir);
|
45
|
+
const aggr = this.cfg.aggregates.find(a => a.name === aggregate);
|
46
|
+
|
47
|
+
for (const f of aggr.sources.file) {
|
48
|
+
await this.runFileTask(f, aggrDir);
|
49
|
+
}
|
50
|
+
|
51
|
+
this.storageBackendProvider.provide(storage).store(aggrDir);
|
52
|
+
this.fs.rmDir(aggrDir);
|
53
|
+
});
|
54
|
+
|
55
|
+
_defineProperty(this, "runGpgKeyTask", t => {
|
56
|
+
this.log.info('Running GPG key task', t);
|
57
|
+
const key = this.gpg.exportKey(t.id);
|
58
|
+
const to = this.storagePath(t.to || `keys/gpg/${t.id}.asc`);
|
59
|
+
this.fs.writeFile(to, key);
|
60
|
+
});
|
61
|
+
|
62
|
+
_defineProperty(this, "runSshKeyTask", t => {
|
63
|
+
this.log.info('Running SSH key task', t);
|
64
|
+
const key = this.ssh.exportKey(t.id);
|
65
|
+
const to = this.storagePath(t.to || `keys/ssh/${t.id}`);
|
66
|
+
this.fs.writeFile(to, key);
|
67
|
+
});
|
68
|
+
|
69
|
+
_defineProperty(this, "runFileTask", (f, dir) => {
|
70
|
+
this.log.info('Running file task', f);
|
71
|
+
const {
|
72
|
+
from,
|
73
|
+
to
|
74
|
+
} = f;
|
75
|
+
this.fsSyncer.sync(from, dir.resolve(to));
|
76
|
+
});
|
77
|
+
|
78
|
+
_defineProperty(this, "storagePath", path => {
|
79
|
+
throw new Error('Unspported');
|
80
|
+
});
|
81
|
+
}
|
82
|
+
|
83
|
+
}) || _class) || _class) || _class) || _class);
|
84
|
+
exports.AggregateBackupController = AggregateBackupController;
|
package/lib/cli/app.js
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.createApp = void 0;
|
7
|
+
|
8
|
+
require("reflect-metadata");
|
9
|
+
|
10
|
+
var _nclif = require("@ps-aux/nclif");
|
11
|
+
|
12
|
+
var _Config = require("../config/Config");
|
13
|
+
|
14
|
+
var _Context = require("../ctx/Context");
|
15
|
+
|
16
|
+
var _AggregateBackupController = require("../bup/AggregateBackupController");
|
17
|
+
|
18
|
+
var _ResticController = require("../storage/restic/ResticController");
|
19
|
+
|
20
|
+
const createApp = () => _nclif.CliApp.of({
|
21
|
+
commands: {
|
22
|
+
restic: (0, _nclif.cmdGroup)({
|
23
|
+
commands: {
|
24
|
+
'init-repo': (0, _nclif.cmd)({
|
25
|
+
positionals: [{
|
26
|
+
name: 'resticStorageName',
|
27
|
+
required: true
|
28
|
+
}],
|
29
|
+
run: (arg, c) => c.get(_ResticController.ResticController).initRepo(arg.resticStorageName)
|
30
|
+
})
|
31
|
+
}
|
32
|
+
}),
|
33
|
+
aggr: (0, _nclif.cmdGroup)({
|
34
|
+
commands: {
|
35
|
+
backup: (0, _nclif.cmd)({
|
36
|
+
description: 'Run backup',
|
37
|
+
positionals: [{
|
38
|
+
name: 'aggregateName',
|
39
|
+
type: 'string',
|
40
|
+
required: true
|
41
|
+
}, {
|
42
|
+
name: 'storageName',
|
43
|
+
type: 'string',
|
44
|
+
required: true
|
45
|
+
}],
|
46
|
+
run: (a, c) => c.get(_AggregateBackupController.AggregateBackupController).backup(a.aggregateName, a.storageName)
|
47
|
+
})
|
48
|
+
}
|
49
|
+
})
|
50
|
+
}
|
51
|
+
}).addObjectConfig(pwd => (0, _Config.readConfig)(pwd)).context(({
|
52
|
+
config
|
53
|
+
}) => (0, _Context.createContext)(config));
|
54
|
+
|
55
|
+
exports.createApp = createApp;
|
package/lib/cli/bin.js
CHANGED
@@ -1,12 +1,6 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
2
|
"use strict";
|
3
3
|
|
4
|
-
var
|
4
|
+
var _app = require("./app");
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
9
|
-
|
10
|
-
const rootDir = process.cwd();
|
11
|
-
const ctx = (0, _Context.createContext)(rootDir);
|
12
|
-
(0, _entrypoint.default)(ctx);
|
6
|
+
(0, _app.createApp)().run();
|
@@ -0,0 +1,58 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.readConfig = void 0;
|
7
|
+
|
8
|
+
var _Path = require("../fs/path/Path");
|
9
|
+
|
10
|
+
var _readYaml = require("../fs/readYaml");
|
11
|
+
|
12
|
+
var _validateConfigAgainstSchema = require("./validateConfigAgainstSchema");
|
13
|
+
|
14
|
+
var _expandAndCreatePath = require("./expandAndCreatePath");
|
15
|
+
|
16
|
+
const expandPaths = (cfg, exp, cwd) => {
|
17
|
+
cfg.storage.filter(s => s.type === 'file').map(s => s).forEach(s => {
|
18
|
+
s.path = exp(s.path);
|
19
|
+
});
|
20
|
+
cfg.storage.filter(s => s.type === 'restic').map(s => s).forEach(s => {
|
21
|
+
if (s.credentialsFile) s.credentialsFile = exp(s.credentialsFile);
|
22
|
+
s.passwordFile = exp(s.passwordFile);
|
23
|
+
if (s.repo.startsWith('local:')) s.repo = (0, _expandAndCreatePath.expandStrPath)(s.repo, cwd);
|
24
|
+
});
|
25
|
+
cfg.aggregates.forEach(a => {
|
26
|
+
a.sources.file.forEach(f => {
|
27
|
+
f.from = exp(f.from);
|
28
|
+
f.to = _Path.RelativePath.from(f.to);
|
29
|
+
});
|
30
|
+
});
|
31
|
+
};
|
32
|
+
|
33
|
+
const readConfig = pwdStr => {
|
34
|
+
const cwd = _Path.AbsPath.from(pwdStr);
|
35
|
+
|
36
|
+
const cfgFile = (0, _readYaml.readYaml)(cwd.resolve('bup.yaml').str());
|
37
|
+
(0, _validateConfigAgainstSchema.validateConfigAgainstSchema)(cfgFile);
|
38
|
+
const cfg = cfgFile;
|
39
|
+
cfg.pwd = cwd;
|
40
|
+
cfg.aggregates.forEach(t => {
|
41
|
+
const {
|
42
|
+
sources
|
43
|
+
} = t;
|
44
|
+
sources.file = sources.file ?? [];
|
45
|
+
sources.sshKey = sources.sshKey ?? [];
|
46
|
+
sources.gpgKey = sources.gpgKey ?? [];
|
47
|
+
});
|
48
|
+
|
49
|
+
const expand = str => {
|
50
|
+
const p = (0, _expandAndCreatePath.expandAndCreatePath)(str, cwd);
|
51
|
+
return p;
|
52
|
+
};
|
53
|
+
|
54
|
+
expandPaths(cfg, expand, cwd);
|
55
|
+
return cfg;
|
56
|
+
};
|
57
|
+
|
58
|
+
exports.readConfig = readConfig;
|
@@ -0,0 +1,24 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.expandStrPath = exports.expandAndCreatePath = void 0;
|
7
|
+
|
8
|
+
var _Path = require("../fs/path/Path");
|
9
|
+
|
10
|
+
var _os = _interopRequireDefault(require("os"));
|
11
|
+
|
12
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
13
|
+
|
14
|
+
const expandStrPath = (path, pwd) => {
|
15
|
+
path = path.replace('<cwd>', pwd.str());
|
16
|
+
path = path.replace('~', _os.default.homedir());
|
17
|
+
return path;
|
18
|
+
};
|
19
|
+
|
20
|
+
exports.expandStrPath = expandStrPath;
|
21
|
+
|
22
|
+
const expandAndCreatePath = (path, pwd) => _Path.AbsPath.from(expandStrPath(path, pwd));
|
23
|
+
|
24
|
+
exports.expandAndCreatePath = expandAndCreatePath;
|
@@ -0,0 +1,65 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.validateConfigAgainstSchema = void 0;
|
7
|
+
|
8
|
+
var _joi = _interopRequireDefault(require("@hapi/joi"));
|
9
|
+
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
11
|
+
|
12
|
+
const DirTaskSchema = _joi.default.object({
|
13
|
+
from: _joi.default.string(),
|
14
|
+
to: _joi.default.string()
|
15
|
+
});
|
16
|
+
|
17
|
+
const FileTaskSchema = DirTaskSchema;
|
18
|
+
|
19
|
+
const KeyTaskSchema = _joi.default.object({
|
20
|
+
id: _joi.default.string(),
|
21
|
+
to: _joi.default.string().optional()
|
22
|
+
});
|
23
|
+
|
24
|
+
const createStorageSchema = props => _joi.default.object({
|
25
|
+
name: _joi.default.string(),
|
26
|
+
type: _joi.default.string(),
|
27
|
+
...props
|
28
|
+
});
|
29
|
+
|
30
|
+
const FileStorageSchema = createStorageSchema({
|
31
|
+
path: _joi.default.string()
|
32
|
+
});
|
33
|
+
const ResticStorageSchema = createStorageSchema({
|
34
|
+
repo: _joi.default.string(),
|
35
|
+
credentialsFile: _joi.default.string().optional(),
|
36
|
+
passwordFile: _joi.default.string()
|
37
|
+
});
|
38
|
+
|
39
|
+
const Sources = _joi.default.object({
|
40
|
+
dir: _joi.default.array().items(DirTaskSchema).optional(),
|
41
|
+
file: _joi.default.array().items(FileTaskSchema).optional(),
|
42
|
+
gpgKey: _joi.default.array().items(KeyTaskSchema).optional(),
|
43
|
+
sshKey: _joi.default.array().items(KeyTaskSchema).optional()
|
44
|
+
});
|
45
|
+
|
46
|
+
const Aggregate = _joi.default.object({
|
47
|
+
name: _joi.default.string(),
|
48
|
+
sources: Sources
|
49
|
+
});
|
50
|
+
|
51
|
+
const Schema = () => _joi.default.object({
|
52
|
+
// TODO undescriptive error msg. Invalid config."storage[0]" does not match any of the allowed types
|
53
|
+
storage: _joi.default.array().items(FileStorageSchema, ResticStorageSchema),
|
54
|
+
aggregates: _joi.default.array().items(Aggregate)
|
55
|
+
});
|
56
|
+
|
57
|
+
const validateConfigAgainstSchema = cfg => {
|
58
|
+
const r = Schema().validate(cfg, {
|
59
|
+
presence: 'required',
|
60
|
+
allowUnknown: false
|
61
|
+
});
|
62
|
+
if (r.error) throw new Error('Invalid config.' + r.error.message);
|
63
|
+
};
|
64
|
+
|
65
|
+
exports.validateConfigAgainstSchema = validateConfigAgainstSchema;
|
@@ -0,0 +1,29 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
var _validateConfigAgainstSchema = require("./validateConfigAgainstSchema");
|
4
|
+
|
5
|
+
const f1 = {
|
6
|
+
storage: [{
|
7
|
+
name: 'fs',
|
8
|
+
type: 'file',
|
9
|
+
path: '~/tmp/nodepub/test-store'
|
10
|
+
}, {
|
11
|
+
name: 'restic',
|
12
|
+
type: 'restic',
|
13
|
+
repo: 'b2:reo',
|
14
|
+
credentialsFile: '.b2-credentials.json',
|
15
|
+
passwordFile: 'pass-file'
|
16
|
+
}],
|
17
|
+
aggregates: [{
|
18
|
+
name: 'my-task',
|
19
|
+
sources: {
|
20
|
+
file: [{
|
21
|
+
from: 'foo',
|
22
|
+
to: 'foo'
|
23
|
+
}]
|
24
|
+
}
|
25
|
+
}]
|
26
|
+
};
|
27
|
+
it('validate', () => {
|
28
|
+
(0, _validateConfigAgainstSchema.validateConfigAgainstSchema)(f1);
|
29
|
+
});
|
package/lib/ctx/Context.js
CHANGED
@@ -5,32 +5,39 @@ Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
});
|
6
6
|
exports.createContext = void 0;
|
7
7
|
|
8
|
-
var
|
8
|
+
var _Shell = require("../tools/shell/Shell");
|
9
9
|
|
10
|
-
var
|
10
|
+
var _FsSyncer = require("../fs/fssync/FsSyncer");
|
11
11
|
|
12
|
-
|
12
|
+
var _Gpg = require("../tools/gpg/Gpg");
|
13
13
|
|
14
|
-
|
15
|
-
constructor(rootDir) {
|
16
|
-
_defineProperty(this, "_log", void 0);
|
14
|
+
var _Fs = require("../fs/Fs");
|
17
15
|
|
18
|
-
|
16
|
+
var _SshKeyManager = require("../tools/ssh/SshKeyManager");
|
19
17
|
|
20
|
-
|
18
|
+
var _inversify = require("inversify");
|
21
19
|
|
22
|
-
|
20
|
+
var _ContextSymbols = require("./ContextSymbols");
|
23
21
|
|
24
|
-
|
22
|
+
var _AggregateBackupController = require("../bup/AggregateBackupController");
|
25
23
|
|
26
|
-
|
27
|
-
this.sh = new _LocalShellCmdExecutor.LocalShellCmdExecutor(this._log);
|
28
|
-
}
|
24
|
+
var _AppLogger = require("../log/AppLogger");
|
29
25
|
|
30
|
-
|
26
|
+
var _StorageBackendProvider = require("../storage/StorageBackendProvider");
|
31
27
|
|
32
|
-
|
33
|
-
|
28
|
+
var _ResticClientFactory = require("../storage/restic/ResticClientFactory");
|
29
|
+
|
30
|
+
var _ResticController = require("../storage/restic/ResticController");
|
31
|
+
|
32
|
+
const createContext = cfg => {
|
33
|
+
const c = new _inversify.Container();
|
34
|
+
c.bind(_ContextSymbols.AppConfig_).toConstantValue(cfg);
|
35
|
+
const log = new _AppLogger.AppLogger();
|
36
|
+
c.bind(_ContextSymbols.Log_).toConstantValue(log);
|
37
|
+
c.bind(_AppLogger.AppLogger).toConstantValue(log);
|
38
|
+
const self = [_Gpg.Gpg, _Shell.Shell, _Fs.Fs, _FsSyncer.FsSyncer, _SshKeyManager.SshKeyManager, _StorageBackendProvider.StorageBackendProvider, _ResticClientFactory.ResticClientFactory, _AggregateBackupController.AggregateBackupController, _ResticController.ResticController];
|
39
|
+
self.forEach(s => c.bind(s).toSelf());
|
40
|
+
return c;
|
34
41
|
};
|
35
42
|
|
36
43
|
exports.createContext = createContext;
|
@@ -0,0 +1,14 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.TaskConfig_ = exports.StorageConfig_ = exports.Log_ = exports.AppConfig_ = void 0;
|
7
|
+
const Log_ = Symbol.for('Log');
|
8
|
+
exports.Log_ = Log_;
|
9
|
+
const TaskConfig_ = Symbol.for('config.Tasks');
|
10
|
+
exports.TaskConfig_ = TaskConfig_;
|
11
|
+
const StorageConfig_ = Symbol.for('config.Storage');
|
12
|
+
exports.StorageConfig_ = StorageConfig_;
|
13
|
+
const AppConfig_ = Symbol.for('config.app');
|
14
|
+
exports.AppConfig_ = AppConfig_;
|
package/lib/fs/Fs.js
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.Fs = void 0;
|
7
|
+
|
8
|
+
var _fs = _interopRequireDefault(require("fs"));
|
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 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) {
|
22
|
+
this.log = log;
|
23
|
+
|
24
|
+
_defineProperty(this, "writeFile", (path, content) => {
|
25
|
+
this.log.debug('Writing into file', path);
|
26
|
+
this.ensureParentDir(path);
|
27
|
+
|
28
|
+
_fs.default.writeFileSync(path.str(), content);
|
29
|
+
});
|
30
|
+
|
31
|
+
_defineProperty(this, "isFile", path => !this.isDir(path));
|
32
|
+
|
33
|
+
_defineProperty(this, "ensureIsFile", p => {
|
34
|
+
if (!this.isFile(p)) throw new Error(`${p} is not a file`);
|
35
|
+
});
|
36
|
+
|
37
|
+
_defineProperty(this, "isDir", path => _fs.default.lstatSync(path.str()).isDirectory());
|
38
|
+
|
39
|
+
_defineProperty(this, "rmDir", path => {
|
40
|
+
_fs.default.rmdirSync(path.str(), {
|
41
|
+
recursive: true
|
42
|
+
});
|
43
|
+
});
|
44
|
+
|
45
|
+
_defineProperty(this, "ensureIsDir", p => {
|
46
|
+
if (!this.isDir(p)) throw new Error(`${p} is not a dir`);
|
47
|
+
});
|
48
|
+
|
49
|
+
_defineProperty(this, "readFile", path => {
|
50
|
+
this.log.debug('Reading from file', path.str());
|
51
|
+
return _fs.default.readFileSync(path.str()).toString();
|
52
|
+
});
|
53
|
+
|
54
|
+
_defineProperty(this, "readJson", path => {
|
55
|
+
const file = this.readFile(path);
|
56
|
+
return JSON.parse(file);
|
57
|
+
});
|
58
|
+
|
59
|
+
_defineProperty(this, "ensureDir", path => {
|
60
|
+
if (!this.exists(path)) {
|
61
|
+
this.log.debug('Dir ', path, 'does not exist. Wil be created');
|
62
|
+
|
63
|
+
_fs.default.mkdirSync(path.str(), {
|
64
|
+
recursive: true
|
65
|
+
});
|
66
|
+
} else {
|
67
|
+
if (this.isFile(path)) throw new Error(`${path.str()} exists and is not a directory`);
|
68
|
+
}
|
69
|
+
});
|
70
|
+
|
71
|
+
_defineProperty(this, "ensureParentDir", path => {
|
72
|
+
const parent = path.parent();
|
73
|
+
if (this.exists(parent)) return;
|
74
|
+
this.ensureDir(parent);
|
75
|
+
});
|
76
|
+
|
77
|
+
_defineProperty(this, "exists", path => _fs.default.existsSync(path.str()));
|
78
|
+
}
|
79
|
+
|
80
|
+
}) || _class) || _class) || _class);
|
81
|
+
exports.Fs = Fs;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.areDirsSame = void 0;
|
7
|
+
|
8
|
+
var _dirCompare = require("dir-compare");
|
9
|
+
|
10
|
+
const opts = {
|
11
|
+
compareContent: true,
|
12
|
+
compareDate: true
|
13
|
+
};
|
14
|
+
|
15
|
+
const areDirsSame = (a, b) => {
|
16
|
+
const res = (0, _dirCompare.compareSync)(a.str(), b.str(), opts);
|
17
|
+
return res.same;
|
18
|
+
};
|
19
|
+
|
20
|
+
exports.areDirsSame = areDirsSame;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
var _areDirsSame = require("./areDirsSame");
|
4
|
+
|
5
|
+
var _test = require("../../test");
|
6
|
+
|
7
|
+
var _Path = require("./path/Path");
|
8
|
+
|
9
|
+
const thisDir = _Path.AbsPath.from(__dirname);
|
10
|
+
|
11
|
+
it('same', () => {
|
12
|
+
const res = (0, _areDirsSame.areDirsSame)(thisDir, thisDir);
|
13
|
+
expect(res).toBe(true);
|
14
|
+
});
|
15
|
+
it('not same', () => {
|
16
|
+
const otherDir = _Path.AbsPath.from((0, _test.testDir)());
|
17
|
+
|
18
|
+
const res = (0, _areDirsSame.areDirsSame)(thisDir, otherDir);
|
19
|
+
expect(res).toBe(false);
|
20
|
+
});
|
@@ -0,0 +1,37 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
var _FsSyncer = require("./FsSyncer");
|
4
|
+
|
5
|
+
var _Shell = require("../../tools/shell/Shell");
|
6
|
+
|
7
|
+
var _test = require("../../../test");
|
8
|
+
|
9
|
+
var _fs = _interopRequireDefault(require("fs"));
|
10
|
+
|
11
|
+
var _areDirsSame = require("../areDirsSame");
|
12
|
+
|
13
|
+
var _Fs = require("../Fs");
|
14
|
+
|
15
|
+
var _Path = require("../path/Path");
|
16
|
+
|
17
|
+
var _AppLogger = require("../../log/AppLogger");
|
18
|
+
|
19
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
20
|
+
|
21
|
+
describe('FsSync', () => {
|
22
|
+
const from = _Path.AbsPath.from((0, _test.testDir)('fs/fssync/src'));
|
23
|
+
|
24
|
+
const to = _Path.AbsPath.from((0, _test.testDir)('fs/fssync/dst/inner'));
|
25
|
+
|
26
|
+
it('syncs dir', () => {
|
27
|
+
const l = new _AppLogger.AppLogger();
|
28
|
+
const sut = new _FsSyncer.FsSyncer(new _Shell.Shell(l), new _Fs.Fs(l), l);
|
29
|
+
sut.syncDirs(from, to);
|
30
|
+
expect((0, _areDirsSame.areDirsSame)(from, to)).toBe(true);
|
31
|
+
});
|
32
|
+
afterAll(() => {
|
33
|
+
_fs.default.rmdirSync(to.str(), {
|
34
|
+
recursive: true
|
35
|
+
});
|
36
|
+
});
|
37
|
+
});
|
@@ -0,0 +1,54 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.FsSyncer = void 0;
|
7
|
+
|
8
|
+
var _Shell = require("../../tools/shell/Shell");
|
9
|
+
|
10
|
+
var _Fs = require("../Fs");
|
11
|
+
|
12
|
+
var _inversify = require("inversify");
|
13
|
+
|
14
|
+
var _AppLogger = require("../../log/AppLogger");
|
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
|
+
const toUnixDirString = path => {
|
21
|
+
const val = path.str();
|
22
|
+
if (val.endsWith('/')) return val;
|
23
|
+
return val + '/';
|
24
|
+
};
|
25
|
+
|
26
|
+
let FsSyncer = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _Shell.Shell === "undefined" ? Object : _Shell.Shell, typeof _Fs.Fs === "undefined" ? Object : _Fs.Fs, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger]), _dec(_class = _dec2(_class = _dec3(_class = class FsSyncer {
|
27
|
+
constructor(sh, fs, log) {
|
28
|
+
this.sh = sh;
|
29
|
+
this.fs = fs;
|
30
|
+
this.log = log;
|
31
|
+
|
32
|
+
_defineProperty(this, "sync", (from, to) => {
|
33
|
+
if (this.fs.isFile(from)) this.syncFile(from, to);else this.syncDirs(from, to);
|
34
|
+
});
|
35
|
+
|
36
|
+
_defineProperty(this, "syncDirs", (from, to) => {
|
37
|
+
this.fs.ensureIsDir(from);
|
38
|
+
this.log.info('Syncing dir', from.str(), '==>', to.str());
|
39
|
+
const fromPath = toUnixDirString(from);
|
40
|
+
const toPath = toUnixDirString(to);
|
41
|
+
this.fs.ensureParentDir(to);
|
42
|
+
this.sh.exec(`rsync -rtv --delete ${fromPath} ${toPath}`);
|
43
|
+
});
|
44
|
+
|
45
|
+
_defineProperty(this, "syncFile", (from, to) => {
|
46
|
+
this.fs.ensureIsFile(from);
|
47
|
+
this.log.info('Syncing file', from.str(), '==>', to.str());
|
48
|
+
this.fs.ensureParentDir(to);
|
49
|
+
this.sh.exec(`rsync -rtv ${from.str()} ${to.str()}`);
|
50
|
+
});
|
51
|
+
}
|
52
|
+
|
53
|
+
}) || _class) || _class) || _class);
|
54
|
+
exports.FsSyncer = FsSyncer;
|
@@ -0,0 +1,59 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.RelativePath = exports.AbsPath = void 0;
|
7
|
+
|
8
|
+
var _path = _interopRequireDefault(require("path"));
|
9
|
+
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
11
|
+
|
12
|
+
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; }
|
13
|
+
|
14
|
+
class AbsPath {
|
15
|
+
constructor(path) {
|
16
|
+
this.path = path;
|
17
|
+
|
18
|
+
_defineProperty(this, "resolve", path => {
|
19
|
+
const str = typeof path === 'string' ? path : path.str();
|
20
|
+
return AbsPath.from(_path.default.resolve(this.str(), str));
|
21
|
+
});
|
22
|
+
|
23
|
+
_defineProperty(this, "parent", () => {
|
24
|
+
return AbsPath.from(_path.default.resolve(this.path, '..'));
|
25
|
+
});
|
26
|
+
|
27
|
+
_defineProperty(this, "str", () => this.path);
|
28
|
+
|
29
|
+
if (!_path.default.isAbsolute(path)) throw new Error(`Path ${path} must be absolute`);
|
30
|
+
}
|
31
|
+
|
32
|
+
toString() {
|
33
|
+
return `AbsPath(${this.str()})`;
|
34
|
+
}
|
35
|
+
|
36
|
+
}
|
37
|
+
|
38
|
+
exports.AbsPath = AbsPath;
|
39
|
+
|
40
|
+
_defineProperty(AbsPath, "from", str => {
|
41
|
+
const p = new AbsPath(str);
|
42
|
+
return p;
|
43
|
+
});
|
44
|
+
|
45
|
+
class RelativePath {
|
46
|
+
constructor(path) {
|
47
|
+
this.path = path;
|
48
|
+
|
49
|
+
_defineProperty(this, "str", () => this.path);
|
50
|
+
|
51
|
+
if (_path.default.isAbsolute(path)) throw new Error(`Path ${path} must be relative`);
|
52
|
+
}
|
53
|
+
|
54
|
+
} // AbsPath.prototype.toString = () => 'hovno'
|
55
|
+
|
56
|
+
|
57
|
+
exports.RelativePath = RelativePath;
|
58
|
+
|
59
|
+
_defineProperty(RelativePath, "from", str => new RelativePath(str));
|