@datatruck/cli 0.0.1

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.
Files changed (154) hide show
  1. package/lib/Action/BackupAction.d.ts +32 -0
  2. package/lib/Action/BackupAction.js +201 -0
  3. package/lib/Action/BackupSessionsAction.d.ts +13 -0
  4. package/lib/Action/BackupSessionsAction.js +16 -0
  5. package/lib/Action/CleanCacheAction.d.ts +9 -0
  6. package/lib/Action/CleanCacheAction.js +18 -0
  7. package/lib/Action/ConfigAction.d.ts +14 -0
  8. package/lib/Action/ConfigAction.js +64 -0
  9. package/lib/Action/InitAction.d.ts +18 -0
  10. package/lib/Action/InitAction.js +39 -0
  11. package/lib/Action/PruneAction.d.ts +37 -0
  12. package/lib/Action/PruneAction.js +80 -0
  13. package/lib/Action/RestoreAction.d.ts +36 -0
  14. package/lib/Action/RestoreAction.js +246 -0
  15. package/lib/Action/RestoreSessionsAction.d.ts +13 -0
  16. package/lib/Action/RestoreSessionsAction.js +16 -0
  17. package/lib/Action/SnapshotsAction.d.ts +30 -0
  18. package/lib/Action/SnapshotsAction.js +35 -0
  19. package/lib/Command/BackupCommand.d.ts +15 -0
  20. package/lib/Command/BackupCommand.js +83 -0
  21. package/lib/Command/BackupSessionsCommand.d.ts +12 -0
  22. package/lib/Command/BackupSessionsCommand.js +88 -0
  23. package/lib/Command/CleanCacheCommand.d.ts +6 -0
  24. package/lib/Command/CleanCacheCommand.js +20 -0
  25. package/lib/Command/CommandAbstract.d.ts +19 -0
  26. package/lib/Command/CommandAbstract.js +14 -0
  27. package/lib/Command/ConfigCommand.d.ts +17 -0
  28. package/lib/Command/ConfigCommand.js +61 -0
  29. package/lib/Command/InitCommand.d.ts +13 -0
  30. package/lib/Command/InitCommand.js +67 -0
  31. package/lib/Command/PruneCommand.d.ts +27 -0
  32. package/lib/Command/PruneCommand.js +160 -0
  33. package/lib/Command/RestoreCommand.d.ts +14 -0
  34. package/lib/Command/RestoreCommand.js +71 -0
  35. package/lib/Command/RestoreSessionsCommand.d.ts +12 -0
  36. package/lib/Command/RestoreSessionsCommand.js +87 -0
  37. package/lib/Command/SnapshotsCommand.d.ts +25 -0
  38. package/lib/Command/SnapshotsCommand.js +128 -0
  39. package/lib/Config/Config.d.ts +8 -0
  40. package/lib/Config/Config.js +19 -0
  41. package/lib/Config/PackageConfig.d.ts +27 -0
  42. package/lib/Config/PackageConfig.js +69 -0
  43. package/lib/Config/PackageRepositoryConfig.d.ts +17 -0
  44. package/lib/Config/PackageRepositoryConfig.js +37 -0
  45. package/lib/Config/PrunePolicyConfig.d.ts +4 -0
  46. package/lib/Config/PrunePolicyConfig.js +28 -0
  47. package/lib/Config/RepositoryConfig.d.ts +18 -0
  48. package/lib/Config/RepositoryConfig.js +37 -0
  49. package/lib/Config/TaskConfig.d.ts +23 -0
  50. package/lib/Config/TaskConfig.js +39 -0
  51. package/lib/Decorator/EntityDecorator.d.ts +11 -0
  52. package/lib/Decorator/EntityDecorator.js +17 -0
  53. package/lib/Entity/BackupSessionEntity.d.ts +6 -0
  54. package/lib/Entity/BackupSessionEntity.js +22 -0
  55. package/lib/Entity/BackupSessionRepositoryEntity.d.ts +6 -0
  56. package/lib/Entity/BackupSessionRepositoryEntity.js +22 -0
  57. package/lib/Entity/BackupSessionTaskEntity.d.ts +5 -0
  58. package/lib/Entity/BackupSessionTaskEntity.js +22 -0
  59. package/lib/Entity/CrudEntityAbstract.d.ts +5 -0
  60. package/lib/Entity/CrudEntityAbstract.js +6 -0
  61. package/lib/Entity/RestoreSessionEntity.d.ts +5 -0
  62. package/lib/Entity/RestoreSessionEntity.js +22 -0
  63. package/lib/Entity/RestoreSessionRepositoryEntity.d.ts +6 -0
  64. package/lib/Entity/RestoreSessionRepositoryEntity.js +22 -0
  65. package/lib/Entity/RestoreSessionTaskEntity.d.ts +5 -0
  66. package/lib/Entity/RestoreSessionTaskEntity.js +22 -0
  67. package/lib/Entity/StateEntityAbstract.d.ts +12 -0
  68. package/lib/Entity/StateEntityAbstract.js +7 -0
  69. package/lib/Error/AppError.d.ts +2 -0
  70. package/lib/Error/AppError.js +6 -0
  71. package/lib/Factory/CommandFactory.d.ts +42 -0
  72. package/lib/Factory/CommandFactory.js +79 -0
  73. package/lib/Factory/EntityFactory.d.ts +6 -0
  74. package/lib/Factory/EntityFactory.js +40 -0
  75. package/lib/Factory/RepositoryFactory.d.ts +3 -0
  76. package/lib/Factory/RepositoryFactory.js +23 -0
  77. package/lib/Factory/TaskFactory.d.ts +3 -0
  78. package/lib/Factory/TaskFactory.js +30 -0
  79. package/lib/JsonSchema/DefinitionEnum.d.ts +25 -0
  80. package/lib/JsonSchema/DefinitionEnum.js +32 -0
  81. package/lib/JsonSchema/JsonSchema.d.ts +4 -0
  82. package/lib/JsonSchema/JsonSchema.js +50 -0
  83. package/lib/Repository/GitRepository.d.ts +29 -0
  84. package/lib/Repository/GitRepository.js +237 -0
  85. package/lib/Repository/LocalRepository.d.ts +51 -0
  86. package/lib/Repository/LocalRepository.js +358 -0
  87. package/lib/Repository/RepositoryAbstract.d.ts +77 -0
  88. package/lib/Repository/RepositoryAbstract.js +19 -0
  89. package/lib/Repository/ResticRepository.d.ts +36 -0
  90. package/lib/Repository/ResticRepository.js +230 -0
  91. package/lib/SessionDriver/ConsoleSessionDriver.d.ts +37 -0
  92. package/lib/SessionDriver/ConsoleSessionDriver.js +178 -0
  93. package/lib/SessionDriver/SessionDriverAbstract.d.ts +78 -0
  94. package/lib/SessionDriver/SessionDriverAbstract.js +27 -0
  95. package/lib/SessionDriver/SqliteSessionDriver.d.ts +20 -0
  96. package/lib/SessionDriver/SqliteSessionDriver.js +169 -0
  97. package/lib/SessionManager/BackupSessionManager.d.ts +44 -0
  98. package/lib/SessionManager/BackupSessionManager.js +206 -0
  99. package/lib/SessionManager/RestoreSessionManager.d.ts +44 -0
  100. package/lib/SessionManager/RestoreSessionManager.js +206 -0
  101. package/lib/Task/GitTask.d.ts +35 -0
  102. package/lib/Task/GitTask.js +248 -0
  103. package/lib/Task/MariadbTask.d.ts +25 -0
  104. package/lib/Task/MariadbTask.js +139 -0
  105. package/lib/Task/MssqlTask.d.ts +22 -0
  106. package/lib/Task/MssqlTask.js +109 -0
  107. package/lib/Task/MysqlDumpTask.d.ts +14 -0
  108. package/lib/Task/MysqlDumpTask.js +129 -0
  109. package/lib/Task/PostgresqlDumpTask.d.ts +14 -0
  110. package/lib/Task/PostgresqlDumpTask.js +101 -0
  111. package/lib/Task/SqlDumpTaskAbstract.d.ts +36 -0
  112. package/lib/Task/SqlDumpTaskAbstract.js +146 -0
  113. package/lib/Task/TaskAbstract.d.ts +37 -0
  114. package/lib/Task/TaskAbstract.js +17 -0
  115. package/lib/bin.d.ts +2 -0
  116. package/lib/bin.js +5 -0
  117. package/lib/cli.d.ts +4 -0
  118. package/lib/cli.js +110 -0
  119. package/lib/index.d.ts +0 -0
  120. package/lib/index.js +1 -0
  121. package/lib/util/DataFormat.d.ts +24 -0
  122. package/lib/util/DataFormat.js +50 -0
  123. package/lib/util/GitUtil.d.ts +38 -0
  124. package/lib/util/GitUtil.js +105 -0
  125. package/lib/util/ObjectVault.d.ts +13 -0
  126. package/lib/util/ObjectVault.js +31 -0
  127. package/lib/util/ResticUtil.d.ts +92 -0
  128. package/lib/util/ResticUtil.js +144 -0
  129. package/lib/util/cli-util.d.ts +27 -0
  130. package/lib/util/cli-util.js +118 -0
  131. package/lib/util/datatruck/config-util.d.ts +55 -0
  132. package/lib/util/datatruck/config-util.js +93 -0
  133. package/lib/util/datatruck/paths-util.d.ts +5 -0
  134. package/lib/util/datatruck/paths-util.js +22 -0
  135. package/lib/util/datatruck/snapshot-util.d.ts +4 -0
  136. package/lib/util/datatruck/snapshot-util.js +31 -0
  137. package/lib/util/date-util.d.ts +12 -0
  138. package/lib/util/date-util.js +74 -0
  139. package/lib/util/entity-util.d.ts +4 -0
  140. package/lib/util/entity-util.js +10 -0
  141. package/lib/util/fs-util.d.ts +43 -0
  142. package/lib/util/fs-util.js +278 -0
  143. package/lib/util/math-util.d.ts +1 -0
  144. package/lib/util/math-util.js +7 -0
  145. package/lib/util/object-util.d.ts +7 -0
  146. package/lib/util/object-util.js +58 -0
  147. package/lib/util/process-util.d.ts +50 -0
  148. package/lib/util/process-util.js +181 -0
  149. package/lib/util/string-util.d.ts +17 -0
  150. package/lib/util/string-util.js +77 -0
  151. package/lib/util/zip-util.d.ts +52 -0
  152. package/lib/util/zip-util.js +135 -0
  153. package/migrations/001-initial.sql +122 -0
  154. package/package.json +62 -0
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MysqlDumpTask = exports.mysqlDumpTaskDefinition = exports.mysqlDumpTaskName = void 0;
4
+ const AppError_1 = require("../Error/AppError");
5
+ const DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
6
+ const fs_util_1 = require("../util/fs-util");
7
+ const process_util_1 = require("../util/process-util");
8
+ const SqlDumpTaskAbstract_1 = require("./SqlDumpTaskAbstract");
9
+ const fs_1 = require("fs");
10
+ const fs_2 = require("fs");
11
+ exports.mysqlDumpTaskName = "mysql-dump";
12
+ exports.mysqlDumpTaskDefinition = {
13
+ allOf: [(0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.sqlDumpTask)],
14
+ };
15
+ class MysqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
16
+ async buildConnectionArgs(database = true) {
17
+ const password = await this.fetchPassword();
18
+ return [
19
+ `--host=${this.config.hostname}`,
20
+ `--user=${this.config.username}`,
21
+ `--password=${password ?? ""}`,
22
+ ...(database && this.config.database ? [this.config.database] : []),
23
+ ];
24
+ }
25
+ async onDatabaseIsEmpty(name) {
26
+ const [total] = await this.fetchValues(`
27
+ SELECT
28
+ COUNT(*) AS total
29
+ FROM
30
+ information_schema.tables
31
+ WHERE
32
+ table_schema = '${name}'
33
+ `);
34
+ return Number(total) ? false : true;
35
+ }
36
+ async onCreateDatabase(database) {
37
+ const query = `
38
+ CREATE DATABASE IF NOT EXISTS \`${database.name}\`
39
+ CHARACTER SET ${database.charset ?? "utf8"}
40
+ COLLATE ${database.charset ?? "utf8_general_ci"}
41
+ `;
42
+ await this.onExecQuery(query);
43
+ }
44
+ async onExecQuery(query) {
45
+ return await (0, process_util_1.exec)("mysql", [
46
+ ...(await this.buildConnectionArgs()),
47
+ "-e",
48
+ query.replace(/\s{1,}/g, " "),
49
+ "-N",
50
+ ], undefined, {
51
+ log: this.verbose,
52
+ stderr: {
53
+ toExitCode: true,
54
+ },
55
+ stdout: {
56
+ save: true,
57
+ },
58
+ });
59
+ }
60
+ async onFetchTableNames() {
61
+ return await this.fetchValues(`
62
+ SELECT
63
+ table_name
64
+ FROM
65
+ information_schema.tables
66
+ WHERE
67
+ table_schema = '${this.config.database}'
68
+ `);
69
+ }
70
+ async onExport(tableNames, output) {
71
+ const stream = (0, fs_1.createWriteStream)(output);
72
+ await Promise.all([
73
+ new Promise((resolve, reject) => {
74
+ stream.on("close", resolve);
75
+ stream.on("error", reject);
76
+ }),
77
+ await (0, process_util_1.exec)("mysqldump", [
78
+ ...(await this.buildConnectionArgs()),
79
+ "--lock-tables=false",
80
+ ...tableNames,
81
+ ], null, {
82
+ pipe: { stream: stream },
83
+ log: {
84
+ exec: this.verbose,
85
+ stderr: this.verbose,
86
+ allToStderr: true,
87
+ },
88
+ stderr: {
89
+ toExitCode: true,
90
+ },
91
+ }),
92
+ ]);
93
+ const headerContents = await (0, fs_util_1.readPartialFile)(output, [0, 100]);
94
+ const footerContents = await (0, fs_util_1.readPartialFile)(output, [-100]);
95
+ const successHeader = headerContents.split(/\r?\n/).some((line) => {
96
+ const firstLine = line.trim().toLowerCase();
97
+ return (firstLine.startsWith("-- mysql dump") ||
98
+ firstLine.startsWith("-- mariadb dump"));
99
+ });
100
+ if (!successHeader)
101
+ throw new AppError_1.AppError("No start line found");
102
+ const successFooter = footerContents
103
+ .split(/\r?\n/)
104
+ .some((line) => line.trim().toLowerCase().startsWith("-- dump completed"));
105
+ if (!successFooter)
106
+ throw new AppError_1.AppError("No end line found (incomplete backup)");
107
+ }
108
+ async onImport(path, database) {
109
+ await (0, process_util_1.exec)("mysql", [...(await this.buildConnectionArgs(false)), database], null, {
110
+ pipe: {
111
+ stream: (0, fs_2.createReadStream)(path),
112
+ onReadProgress: (data) => {
113
+ if (this.verbose)
114
+ (0, process_util_1.logExecStdout)({
115
+ data: JSON.stringify(data),
116
+ colorize: true,
117
+ stderr: true,
118
+ lineSalt: true,
119
+ });
120
+ },
121
+ },
122
+ log: this.verbose,
123
+ stderr: {
124
+ toExitCode: true,
125
+ },
126
+ });
127
+ }
128
+ }
129
+ exports.MysqlDumpTask = MysqlDumpTask;
@@ -0,0 +1,14 @@
1
+ import { SqlDumpTaskAbstract, SqlDumpTaskConfigType, TargetDatabaseType } from "./SqlDumpTaskAbstract";
2
+ import { JSONSchema7 } from "json-schema";
3
+ export declare const postgresqlDumpTaskName = "postgresql-dump";
4
+ export declare type PostgresqlDumpTaskConfigType = {} & SqlDumpTaskConfigType;
5
+ export declare const postgresqlDumpTaskDefinition: JSONSchema7;
6
+ export declare class PostgresqlDumpTask extends SqlDumpTaskAbstract<PostgresqlDumpTaskConfigType> {
7
+ buildConnectionArgs(database?: string): Promise<string[]>;
8
+ onDatabaseIsEmpty(name: string): Promise<boolean>;
9
+ onCreateDatabase(database: TargetDatabaseType): Promise<void>;
10
+ onExecQuery(query: string): Promise<import("../util/process-util").ExecResultType>;
11
+ onFetchTableNames(): Promise<string[]>;
12
+ onExport(tableNames: string[], output: string): Promise<void>;
13
+ onImport(path: string, database: string): Promise<void>;
14
+ }
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PostgresqlDumpTask = exports.postgresqlDumpTaskDefinition = exports.postgresqlDumpTaskName = void 0;
4
+ const DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
5
+ const process_util_1 = require("../util/process-util");
6
+ const SqlDumpTaskAbstract_1 = require("./SqlDumpTaskAbstract");
7
+ const fs_1 = require("fs");
8
+ const path_1 = require("path");
9
+ exports.postgresqlDumpTaskName = "postgresql-dump";
10
+ exports.postgresqlDumpTaskDefinition = {
11
+ allOf: [(0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.sqlDumpTask)],
12
+ };
13
+ class PostgresqlDumpTask extends SqlDumpTaskAbstract_1.SqlDumpTaskAbstract {
14
+ async buildConnectionArgs(database) {
15
+ const password = await this.fetchPassword();
16
+ const config = this.config;
17
+ return [
18
+ "--no-password",
19
+ `--dbname=postgresql://${config.username}:${password ?? ""}@${config.hostname}:${config.port ?? 5432}/${database ?? config.database ?? ""}`,
20
+ ];
21
+ }
22
+ async onDatabaseIsEmpty(name) {
23
+ const [total] = await this.fetchValues(`
24
+ SELECT
25
+ COUNT(*) AS total
26
+ FROM
27
+ information_schema.tables
28
+ WHERE
29
+ table_catalog = '${name}' AND
30
+ table_schema NOT IN ('pg_catalog', 'information_schema')
31
+ `);
32
+ return Number(total) ? false : true;
33
+ }
34
+ async onCreateDatabase(database) {
35
+ let query = `CREATE DATABASE ${database.name}`;
36
+ if (database.charset || database.collate) {
37
+ query += ` WITH`;
38
+ if (database.charset) {
39
+ query += ` ENCONDING '${database.charset}'`;
40
+ }
41
+ if (database.collate) {
42
+ query += ` LC_COLLATE '${database.collate}'`;
43
+ }
44
+ }
45
+ await this.onExecQuery(query);
46
+ }
47
+ async onExecQuery(query) {
48
+ return await (0, process_util_1.exec)("psql", [
49
+ ...(await this.buildConnectionArgs()),
50
+ "-t",
51
+ "-c",
52
+ query.replace(/\s{1,}/g, " "),
53
+ ], undefined, {
54
+ log: this.verbose,
55
+ stderr: {
56
+ toExitCode: true,
57
+ },
58
+ stdout: {
59
+ save: true,
60
+ },
61
+ });
62
+ }
63
+ async onFetchTableNames() {
64
+ return await this.fetchValues(`
65
+ SELECT
66
+ CONCAT(table_schema, '.', table_name)
67
+ FROM
68
+ information_schema.tables
69
+ WHERE
70
+ table_catalog = '${this.config.database}' AND
71
+ table_schema NOT IN ('pg_catalog', 'information_schema')
72
+ `);
73
+ }
74
+ async onExport(tableNames, output) {
75
+ const stream = (0, fs_1.createWriteStream)(output);
76
+ await Promise.all([
77
+ new Promise((resolve, reject) => {
78
+ stream.on("close", resolve);
79
+ stream.on("error", reject);
80
+ }),
81
+ (0, process_util_1.exec)("pg_dump", [
82
+ ...(await this.buildConnectionArgs()),
83
+ "--clean",
84
+ "--if-exists",
85
+ ...(tableNames?.flatMap((v) => ["-t", v]) ?? []),
86
+ ], null, {
87
+ pipe: { stream: stream },
88
+ stderr: {
89
+ toExitCode: true,
90
+ },
91
+ log: this.verbose,
92
+ }),
93
+ ]);
94
+ }
95
+ async onImport(path, database) {
96
+ await (0, process_util_1.exec)("psql", [...(await this.buildConnectionArgs(database)), "-f", (0, path_1.normalize)(path)], undefined, {
97
+ log: this.verbose,
98
+ });
99
+ }
100
+ }
101
+ exports.PostgresqlDumpTask = PostgresqlDumpTask;
@@ -0,0 +1,36 @@
1
+ import { exec } from "../util/process-util";
2
+ import { BackupDataType, RestoreDataType, TaskAbstract } from "./TaskAbstract";
3
+ import { JSONSchema7 } from "json-schema";
4
+ export declare type TargetDatabaseType = {
5
+ name: string;
6
+ charset?: string;
7
+ collate?: string;
8
+ };
9
+ export declare type SqlDumpTaskConfigType = {
10
+ password: string | {
11
+ path: string;
12
+ };
13
+ hostname: string;
14
+ port?: number;
15
+ database: string;
16
+ username: string;
17
+ targetDatabase?: TargetDatabaseType;
18
+ includeTables?: string[];
19
+ excludeTables?: string[];
20
+ oneFileByTable?: boolean;
21
+ };
22
+ export declare const sqlDumpTaskDefinition: JSONSchema7;
23
+ export declare abstract class SqlDumpTaskAbstract<TConfig extends SqlDumpTaskConfigType> extends TaskAbstract<TConfig> {
24
+ protected verbose?: boolean;
25
+ fetchPassword(): Promise<string | null>;
26
+ fetchValues(query: string): Promise<string[]>;
27
+ abstract onCreateDatabase(database: TargetDatabaseType): Promise<void>;
28
+ abstract onDatabaseIsEmpty(databaseName: string): Promise<boolean>;
29
+ abstract onFetchTableNames(): Promise<string[]>;
30
+ abstract onExecQuery(query: string): ReturnType<typeof exec>;
31
+ abstract onExport(tableNames: string[], output: string): Promise<void>;
32
+ abstract onImport(path: string, database: string): Promise<void>;
33
+ fetchTableNames(): Promise<string[]>;
34
+ onBackup(data: BackupDataType): Promise<void>;
35
+ onRestore(data: RestoreDataType): Promise<void>;
36
+ }
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SqlDumpTaskAbstract = exports.sqlDumpTaskDefinition = void 0;
4
+ const AppError_1 = require("../Error/AppError");
5
+ const DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
6
+ const cli_util_1 = require("../util/cli-util");
7
+ const config_util_1 = require("../util/datatruck/config-util");
8
+ const fs_util_1 = require("../util/fs-util");
9
+ const math_util_1 = require("../util/math-util");
10
+ const TaskAbstract_1 = require("./TaskAbstract");
11
+ const assert_1 = require("assert");
12
+ const promises_1 = require("fs/promises");
13
+ const micromatch_1 = require("micromatch");
14
+ const path_1 = require("path");
15
+ exports.sqlDumpTaskDefinition = {
16
+ type: "object",
17
+ required: ["password", "hostname", "username", "database"],
18
+ properties: {
19
+ password: {
20
+ anyOf: [
21
+ {
22
+ type: "string",
23
+ },
24
+ {
25
+ type: "object",
26
+ additionalProperties: false,
27
+ required: ["path"],
28
+ properties: {
29
+ path: { type: "string" },
30
+ },
31
+ },
32
+ ],
33
+ },
34
+ hostname: { type: "string" },
35
+ port: { type: "integer" },
36
+ username: { type: "string" },
37
+ database: { type: "string" },
38
+ targetDatabase: {
39
+ type: "object",
40
+ required: ["name"],
41
+ properties: {
42
+ name: { type: "string" },
43
+ charset: { type: "string" },
44
+ collate: { type: "string" },
45
+ },
46
+ },
47
+ includeTables: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
48
+ excludeTables: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
49
+ oneFileByTable: { type: "boolean" },
50
+ },
51
+ };
52
+ class SqlDumpTaskAbstract extends TaskAbstract_1.TaskAbstract {
53
+ async fetchPassword() {
54
+ if (typeof this.config.password === "string")
55
+ return this.config.password;
56
+ if (this.config.password)
57
+ return (await (0, promises_1.readFile)(this.config.password.path)).toString();
58
+ return null;
59
+ }
60
+ async fetchValues(query) {
61
+ const result = await this.onExecQuery(query);
62
+ return result.stdout.split(/\r?\n/).reduce((result, value) => {
63
+ value = value.trim();
64
+ if (value.length)
65
+ result.push(value);
66
+ return result;
67
+ }, []);
68
+ }
69
+ async fetchTableNames() {
70
+ const tableNames = await this.onFetchTableNames();
71
+ const config = this.config;
72
+ return tableNames.filter((tableName) => {
73
+ if (config.includeTables && !(0, micromatch_1.isMatch)(tableName, config.includeTables))
74
+ return false;
75
+ if (config.excludeTables && (0, micromatch_1.isMatch)(tableName, config.excludeTables))
76
+ return false;
77
+ return true;
78
+ });
79
+ }
80
+ async onBackup(data) {
81
+ this.verbose = data.options.verbose;
82
+ const outputPath = data.package.path;
83
+ const tableNames = await this.fetchTableNames();
84
+ (0, assert_1.ok)(typeof outputPath === "string");
85
+ if (!(await (0, fs_util_1.checkDir)(outputPath)))
86
+ await (0, promises_1.mkdir)(outputPath, { recursive: true });
87
+ if (!this.config.oneFileByTable) {
88
+ const outPath = (0, path_1.join)(outputPath, this.config.database) + ".database.sql";
89
+ await this.onExport(tableNames, outPath);
90
+ }
91
+ else {
92
+ let current = 0;
93
+ for (const tableName of tableNames) {
94
+ data.onProgress({
95
+ total: tableNames.length,
96
+ current: current,
97
+ percent: (0, math_util_1.progressPercent)(tableNames.length, current),
98
+ step: tableName,
99
+ });
100
+ current++;
101
+ const outPath = (0, path_1.join)(outputPath, tableName) + ".table.sql";
102
+ await this.onExport([tableName], outPath);
103
+ }
104
+ }
105
+ }
106
+ async onRestore(data) {
107
+ const restorePath = data.package.restorePath;
108
+ this.verbose = data.options.verbose;
109
+ (0, assert_1.ok)(typeof restorePath === "string");
110
+ const database = {
111
+ name: (0, config_util_1.resolveDatabaseName)(this.config.database, {
112
+ packageName: data.package.name,
113
+ snapshotId: data.options.snapshotId,
114
+ action: "restore",
115
+ database: undefined,
116
+ }),
117
+ };
118
+ if (this.config.targetDatabase) {
119
+ database.name = (0, config_util_1.resolveDatabaseName)(this.config.targetDatabase.name, {
120
+ packageName: data.package.name,
121
+ snapshotId: data.options.snapshotId,
122
+ action: "restore",
123
+ database: database.name,
124
+ });
125
+ }
126
+ if (!(await this.onDatabaseIsEmpty(database.name)))
127
+ throw new AppError_1.AppError(`Target database is not empty: ${database.name}`);
128
+ await this.onCreateDatabase(database);
129
+ if (this.verbose)
130
+ (0, cli_util_1.logExec)("readdir", [restorePath]);
131
+ const files = (await (0, promises_1.readdir)(restorePath)).filter((name) => /\.sql$/i.test(name));
132
+ let current = 0;
133
+ for (const file of files) {
134
+ const path = (0, path_1.join)(restorePath, file);
135
+ data.onProgress({
136
+ total: files.length,
137
+ current: current,
138
+ percent: (0, math_util_1.progressPercent)(files.length, current),
139
+ step: file,
140
+ });
141
+ current++;
142
+ await this.onImport(path, database.name);
143
+ }
144
+ }
145
+ }
146
+ exports.SqlDumpTaskAbstract = SqlDumpTaskAbstract;
@@ -0,0 +1,37 @@
1
+ import { BackupActionOptionsType } from "../Action/BackupAction";
2
+ import { RestoreActionOptionsType } from "../Action/RestoreAction";
3
+ import { PackageConfigType } from "../Config/PackageConfig";
4
+ import { SnapshotType } from "../Repository/RepositoryAbstract";
5
+ export declare type ProgressDataType = {
6
+ total: number;
7
+ current: number;
8
+ percent: number;
9
+ step: string;
10
+ stepPercent?: number;
11
+ };
12
+ export declare type BackupDataType = {
13
+ onProgress: (data: ProgressDataType) => Promise<void>;
14
+ options: BackupActionOptionsType;
15
+ package: PackageConfigType;
16
+ targetPath: string | undefined;
17
+ snapshot: SnapshotType;
18
+ };
19
+ export declare type RestoreDataType = {
20
+ onProgress: (data: ProgressDataType) => Promise<void>;
21
+ options: RestoreActionOptionsType;
22
+ package: PackageConfigType;
23
+ targetPath: string | undefined;
24
+ snapshot: SnapshotType;
25
+ };
26
+ export declare abstract class TaskAbstract<TConfig = any> {
27
+ readonly config: TConfig;
28
+ constructor(config: TConfig);
29
+ onBeforeBackup(data: Omit<BackupDataType, "onProgress" | "targetPath">): Promise<{
30
+ targetPath?: string;
31
+ } | undefined>;
32
+ onBackup(data: BackupDataType): Promise<void>;
33
+ onBeforeRestore(data: Omit<RestoreDataType, "onProgress" | "targetPath">): Promise<{
34
+ targetPath?: string;
35
+ } | undefined>;
36
+ onRestore(data: RestoreDataType): Promise<void>;
37
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TaskAbstract = void 0;
4
+ class TaskAbstract {
5
+ constructor(config) {
6
+ this.config = config;
7
+ }
8
+ async onBeforeBackup(data) {
9
+ return undefined;
10
+ }
11
+ async onBackup(data) { }
12
+ async onBeforeRestore(data) {
13
+ return undefined;
14
+ }
15
+ async onRestore(data) { }
16
+ }
17
+ exports.TaskAbstract = TaskAbstract;
package/lib/bin.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/lib/bin.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const cli_1 = require("./cli");
5
+ (0, cli_1.parseArgs)(process.argv);
package/lib/cli.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { OptionsMapType } from "./Factory/CommandFactory";
2
+ export declare function buildArgs<TCommand extends keyof OptionsMapType>(input: TCommand, options: OptionsMapType[TCommand]): any[];
3
+ export declare function parseArgs(args: string[]): void;
4
+ export declare function exec<TCommand extends keyof OptionsMapType>(input: TCommand, options: OptionsMapType[TCommand]): Promise<void>;
package/lib/cli.js ADDED
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exec = exports.parseArgs = exports.buildArgs = void 0;
4
+ const AppError_1 = require("./Error/AppError");
5
+ const CommandFactory_1 = require("./Factory/CommandFactory");
6
+ const cli_util_1 = require("./util/cli-util");
7
+ const fs_util_1 = require("./util/fs-util");
8
+ const process_util_1 = require("./util/process-util");
9
+ const string_util_1 = require("./util/string-util");
10
+ const chalk_1 = require("chalk");
11
+ const commander_1 = require("commander");
12
+ const fs_1 = require("fs");
13
+ const path_1 = require("path");
14
+ function getGlobalOptions() {
15
+ return program.opts();
16
+ }
17
+ function makeCommand(command) {
18
+ const programCommand = program.command(command);
19
+ const instance = (0, CommandFactory_1.CommandFactory)(command, getGlobalOptions(), null);
20
+ const options = instance.onOptions();
21
+ for (const key in options) {
22
+ const option = options[key];
23
+ const description = `${option.description}${option.defaults ? ` (defaults: ${option.defaults})` : ""}`;
24
+ if (option.required) {
25
+ programCommand.requiredOption(option.option, description);
26
+ }
27
+ else {
28
+ programCommand.option(option.option, description);
29
+ }
30
+ }
31
+ return programCommand.action(makeCommandAction(command));
32
+ }
33
+ function makeCommandAction(command) {
34
+ return async function (options) {
35
+ let exitCode = 1;
36
+ const globalOptions = getGlobalOptions();
37
+ try {
38
+ exitCode = await (0, CommandFactory_1.CommandFactory)(command, getGlobalOptions(), options).onExec();
39
+ }
40
+ catch (e) {
41
+ const error = e;
42
+ if (globalOptions.verbose) {
43
+ console.error((0, chalk_1.red)(error.stack));
44
+ }
45
+ else {
46
+ if (error instanceof AppError_1.AppError) {
47
+ console.error((0, chalk_1.red)(error.message));
48
+ }
49
+ else {
50
+ console.error((0, chalk_1.red)(error.stack));
51
+ }
52
+ }
53
+ }
54
+ process.exit(exitCode);
55
+ };
56
+ }
57
+ const program = new commander_1.Command();
58
+ const { name, version, description } = (0, fs_util_1.parsePackageFile)();
59
+ const [, subname] = name.split("/");
60
+ const cwd = process.cwd();
61
+ program.name(subname);
62
+ program.version(version);
63
+ program.description(description);
64
+ program.option("-v,--verbose", "Verbose", (_, previous) => previous + 1, 0);
65
+ program.option("-c,--config <path>", "Config path", process.env["DATATRUCK_CONFIG"] ?? (cwd.endsWith(path_1.sep) ? cwd : `${cwd}${path_1.sep}`));
66
+ program.option("-o,--output-format <format>", "Output format (json, pjson, yaml, table)", "table");
67
+ makeCommand(CommandFactory_1.CommandEnum.config).alias("c");
68
+ makeCommand(CommandFactory_1.CommandEnum.init).alias("i");
69
+ makeCommand(CommandFactory_1.CommandEnum.snapshots).alias("s");
70
+ makeCommand(CommandFactory_1.CommandEnum.prune).alias("p");
71
+ makeCommand(CommandFactory_1.CommandEnum.backup).alias("b");
72
+ makeCommand(CommandFactory_1.CommandEnum.backupSessions).alias("bs");
73
+ makeCommand(CommandFactory_1.CommandEnum.restore).alias("r");
74
+ makeCommand(CommandFactory_1.CommandEnum.restoreSessions).alias("rs");
75
+ makeCommand(CommandFactory_1.CommandEnum.cleanCache).alias("cc");
76
+ function buildArgs(input, options) {
77
+ const optionsArray = Object.keys(options).flatMap((name) => [
78
+ `--${(0, string_util_1.snakeCase)(name, "-")}`,
79
+ options[name],
80
+ ]);
81
+ return [input, ...optionsArray];
82
+ }
83
+ exports.buildArgs = buildArgs;
84
+ function parseArgs(args) {
85
+ program.parse(args);
86
+ const verbose = getGlobalOptions().verbose;
87
+ (0, process_util_1.onExit)((eventName) => {
88
+ if (eventName !== "exit") {
89
+ process.stdout.write(cli_util_1.showCursorCommand);
90
+ console.log("\nClosing...");
91
+ }
92
+ if (!verbose)
93
+ try {
94
+ (0, fs_1.rmSync)((0, fs_util_1.sessionTmpDir)(), {
95
+ force: true,
96
+ recursive: true,
97
+ maxRetries: 5,
98
+ });
99
+ }
100
+ catch (error) { }
101
+ if (eventName !== "exit")
102
+ process.exit(1);
103
+ });
104
+ }
105
+ exports.parseArgs = parseArgs;
106
+ async function exec(input, options) {
107
+ const argv = buildArgs(input, options);
108
+ return parseArgs(argv);
109
+ }
110
+ exports.exec = exec;
package/lib/index.d.ts ADDED
File without changes
package/lib/index.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,24 @@
1
+ export declare type FormatType = "json" | "pjson" | "table" | "yaml";
2
+ export declare class DataFormat<TItem extends Record<string, unknown>> {
3
+ readonly options: {
4
+ items: TItem[];
5
+ json?: (item: TItem) => any;
6
+ table: {
7
+ labels: string[];
8
+ handler: (item: TItem) => (string | number | null | undefined)[];
9
+ };
10
+ };
11
+ constructor(options: {
12
+ items: TItem[];
13
+ json?: (item: TItem) => any;
14
+ table: {
15
+ labels: string[];
16
+ handler: (item: TItem) => (string | number | null | undefined)[];
17
+ };
18
+ });
19
+ protected formatToJson(): string;
20
+ protected formatToPrettyJson(): string;
21
+ protected formatToYaml(): any;
22
+ protected formatToTable(): string;
23
+ format(format: FormatType): any;
24
+ }