@datatruck/cli 0.26.1 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Action/RestoreAction.d.ts +1 -1
- package/Action/RestoreAction.js +1 -1
- package/Command/RestoreCommand.d.ts +1 -1
- package/Command/RestoreCommand.js +2 -2
- package/Command/StartServerCommand.d.ts +6 -0
- package/Command/StartServerCommand.js +24 -0
- package/Config/Config.d.ts +2 -0
- package/Config/Config.js +26 -0
- package/Factory/CommandFactory.d.ts +4 -1
- package/Factory/CommandFactory.js +6 -0
- package/Repository/DatatruckRepository.d.ts +8 -8
- package/Repository/DatatruckRepository.js +97 -132
- package/Task/MysqlDumpTask.js +1 -1
- package/Task/SqlDumpTaskAbstract.js +1 -1
- package/cli.js +1 -0
- package/config.schema.json +38 -2
- package/package.json +1 -1
- package/utils/cli.js +3 -1
- package/utils/datatruck/client.d.ts +22 -0
- package/utils/datatruck/client.js +96 -0
- package/utils/datatruck/config.d.ts +6 -6
- package/utils/datatruck/server.d.ts +21 -0
- package/utils/datatruck/server.js +96 -0
- package/utils/fs.d.ts +13 -6
- package/utils/fs.js +34 -19
- package/utils/http.d.ts +21 -0
- package/utils/http.js +154 -0
- package/utils/virtual-fs.d.ts +33 -0
- package/utils/virtual-fs.js +59 -0
package/package.json
CHANGED
package/utils/cli.js
CHANGED
|
@@ -96,7 +96,9 @@ exports.errorColumn = errorColumn;
|
|
|
96
96
|
function parseOptions(object, options) {
|
|
97
97
|
const result = {};
|
|
98
98
|
for (const key in options) {
|
|
99
|
-
const
|
|
99
|
+
const isNegative = options[key].option.startsWith("--no");
|
|
100
|
+
const defaultsValue = isNegative ? true : options[key].defaults;
|
|
101
|
+
const value = object?.[key] ?? defaultsValue;
|
|
100
102
|
const parser = options[key].parser;
|
|
101
103
|
if (typeof value !== "undefined") {
|
|
102
104
|
result[key] = parser ? parser(value) : value;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AbstractFs, FsOptions } from "../virtual-fs";
|
|
2
|
+
export declare class RemoteFs extends AbstractFs {
|
|
3
|
+
readonly options: FsOptions;
|
|
4
|
+
protected url: string;
|
|
5
|
+
protected headers: Record<string, string>;
|
|
6
|
+
constructor(options: FsOptions);
|
|
7
|
+
isLocal(): boolean;
|
|
8
|
+
protected fetchJson(name: string, params: any[]): Promise<any>;
|
|
9
|
+
protected post(name: string, params: any[], data: string): Promise<void>;
|
|
10
|
+
existsDir(path: string): Promise<any>;
|
|
11
|
+
mkdir(path: string): Promise<any>;
|
|
12
|
+
readFile(path: string): Promise<any>;
|
|
13
|
+
readdir(path: string): Promise<any>;
|
|
14
|
+
readFileIfExists(path: string): Promise<string | undefined>;
|
|
15
|
+
ensureEmptyDir(path: string): Promise<void>;
|
|
16
|
+
writeFile(path: string, contents: string): Promise<void>;
|
|
17
|
+
rmAll(path: string): Promise<void>;
|
|
18
|
+
upload(source: string, target: string): Promise<void>;
|
|
19
|
+
download(source: string, target: string, timeout?: number): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export declare function isRemoteBackend(backend: string): boolean;
|
|
22
|
+
export declare function createFs(backend: string): AbstractFs;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createFs = exports.isRemoteBackend = exports.RemoteFs = void 0;
|
|
4
|
+
const http_1 = require("../http");
|
|
5
|
+
const virtual_fs_1 = require("../virtual-fs");
|
|
6
|
+
const server_1 = require("./server");
|
|
7
|
+
class RemoteFs extends virtual_fs_1.AbstractFs {
|
|
8
|
+
options;
|
|
9
|
+
url;
|
|
10
|
+
headers;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
super(options);
|
|
13
|
+
this.options = options;
|
|
14
|
+
const url = new URL(options.backend);
|
|
15
|
+
this.headers = {
|
|
16
|
+
[server_1.headerKey.user]: url.username,
|
|
17
|
+
[server_1.headerKey.password]: url.password,
|
|
18
|
+
};
|
|
19
|
+
url.username = "";
|
|
20
|
+
url.password = "";
|
|
21
|
+
this.url = url.href;
|
|
22
|
+
if (this.url.endsWith("/"))
|
|
23
|
+
this.url = this.url.slice(0, -1);
|
|
24
|
+
}
|
|
25
|
+
isLocal() {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
async fetchJson(name, params) {
|
|
29
|
+
return await (0, http_1.fetchJson)(`${this.url}/${name}`, {
|
|
30
|
+
headers: this.headers,
|
|
31
|
+
query: {
|
|
32
|
+
params: JSON.stringify(params),
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async post(name, params, data) {
|
|
37
|
+
return await (0, http_1.post)(`${this.url}/${name}`, data, {
|
|
38
|
+
headers: this.headers,
|
|
39
|
+
query: {
|
|
40
|
+
params: JSON.stringify(params),
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async existsDir(path) {
|
|
45
|
+
return await this.fetchJson("existsDir", [path]);
|
|
46
|
+
}
|
|
47
|
+
async mkdir(path) {
|
|
48
|
+
return await this.fetchJson("mkdir", [path]);
|
|
49
|
+
}
|
|
50
|
+
async readFile(path) {
|
|
51
|
+
return await this.fetchJson("readFile", [path]);
|
|
52
|
+
}
|
|
53
|
+
async readdir(path) {
|
|
54
|
+
return await this.fetchJson("readdir", [path]);
|
|
55
|
+
}
|
|
56
|
+
async readFileIfExists(path) {
|
|
57
|
+
return await this.fetchJson("readFileIfExists", [path]);
|
|
58
|
+
}
|
|
59
|
+
async ensureEmptyDir(path) {
|
|
60
|
+
return await this.fetchJson("readdir", [path]);
|
|
61
|
+
}
|
|
62
|
+
async writeFile(path, contents) {
|
|
63
|
+
await this.post("writeFile", [path], contents);
|
|
64
|
+
}
|
|
65
|
+
async rmAll(path) {
|
|
66
|
+
await this.fetchJson("rmAll", [path]);
|
|
67
|
+
}
|
|
68
|
+
async upload(source, target) {
|
|
69
|
+
await (0, http_1.uploadFile)(`${this.url}/upload`, source, {
|
|
70
|
+
headers: this.headers,
|
|
71
|
+
query: {
|
|
72
|
+
params: JSON.stringify([target]),
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async download(source, target, timeout = 100000) {
|
|
77
|
+
await (0, http_1.downloadFile)(`${this.url}/download`, target, {
|
|
78
|
+
timeout,
|
|
79
|
+
headers: this.headers,
|
|
80
|
+
query: {
|
|
81
|
+
params: JSON.stringify([source]),
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
exports.RemoteFs = RemoteFs;
|
|
87
|
+
function isRemoteBackend(backend) {
|
|
88
|
+
return backend.startsWith("http:") || backend.startsWith("https:");
|
|
89
|
+
}
|
|
90
|
+
exports.isRemoteBackend = isRemoteBackend;
|
|
91
|
+
function createFs(backend) {
|
|
92
|
+
return isRemoteBackend(backend)
|
|
93
|
+
? new RemoteFs({ backend })
|
|
94
|
+
: new virtual_fs_1.LocalFs({ backend });
|
|
95
|
+
}
|
|
96
|
+
exports.createFs = createFs;
|
|
@@ -31,18 +31,18 @@ export declare const pkgPathParams: {
|
|
|
31
31
|
[name in "temp" | Exclude<keyof ResolvePackagePathParamsType, "path">]: string;
|
|
32
32
|
};
|
|
33
33
|
export declare const pkgIncludeParams: {
|
|
34
|
+
action: string;
|
|
34
35
|
packageName: string;
|
|
35
36
|
temp: string;
|
|
36
37
|
snapshotId: string;
|
|
37
38
|
snapshotDate: string;
|
|
38
|
-
action: string;
|
|
39
39
|
};
|
|
40
40
|
export declare const pkgExcludeParams: {
|
|
41
|
+
action: string;
|
|
41
42
|
packageName: string;
|
|
42
43
|
temp: string;
|
|
43
44
|
snapshotId: string;
|
|
44
45
|
snapshotDate: string;
|
|
45
|
-
action: string;
|
|
46
46
|
};
|
|
47
47
|
export declare const pkgRestorePathParams: {
|
|
48
48
|
[name in "temp" | keyof ResolvePackagePathParamsType]: string;
|
|
@@ -52,33 +52,33 @@ export declare const dbNameParams: {
|
|
|
52
52
|
};
|
|
53
53
|
export declare const params: {
|
|
54
54
|
pkgPath: {
|
|
55
|
+
action: string;
|
|
55
56
|
packageName: string;
|
|
56
57
|
temp: string;
|
|
57
58
|
snapshotId: string;
|
|
58
59
|
snapshotDate: string;
|
|
59
|
-
action: string;
|
|
60
60
|
};
|
|
61
61
|
pkgRestorePath: {
|
|
62
62
|
path: string;
|
|
63
|
+
action: string;
|
|
63
64
|
packageName: string;
|
|
64
65
|
temp: string;
|
|
65
66
|
snapshotId: string;
|
|
66
67
|
snapshotDate: string;
|
|
67
|
-
action: string;
|
|
68
68
|
};
|
|
69
69
|
pkgInclude: {
|
|
70
|
+
action: string;
|
|
70
71
|
packageName: string;
|
|
71
72
|
temp: string;
|
|
72
73
|
snapshotId: string;
|
|
73
74
|
snapshotDate: string;
|
|
74
|
-
action: string;
|
|
75
75
|
};
|
|
76
76
|
pkgExclude: {
|
|
77
|
+
action: string;
|
|
77
78
|
packageName: string;
|
|
78
79
|
temp: string;
|
|
79
80
|
snapshotId: string;
|
|
80
81
|
snapshotDate: string;
|
|
81
|
-
action: string;
|
|
82
82
|
};
|
|
83
83
|
dbName: {
|
|
84
84
|
snapshotId: string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { IncomingMessage } from "http";
|
|
3
|
+
type User = {
|
|
4
|
+
name: string;
|
|
5
|
+
password: string;
|
|
6
|
+
};
|
|
7
|
+
export type DatatruckServerOptions = {
|
|
8
|
+
path?: string;
|
|
9
|
+
log?: boolean;
|
|
10
|
+
listen?: {
|
|
11
|
+
port?: number;
|
|
12
|
+
address?: string;
|
|
13
|
+
};
|
|
14
|
+
users?: User[];
|
|
15
|
+
};
|
|
16
|
+
export declare const headerKey: {
|
|
17
|
+
user: string;
|
|
18
|
+
password: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function createDatatruckServer(options: DatatruckServerOptions): import("node:http").Server<typeof IncomingMessage, typeof import("node:http").ServerResponse>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDatatruckServer = exports.headerKey = void 0;
|
|
4
|
+
const http_1 = require("../http");
|
|
5
|
+
const virtual_fs_1 = require("../virtual-fs");
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const http_2 = require("http");
|
|
8
|
+
function parseUrl(inUrl) {
|
|
9
|
+
const url = new URL(`http://127.0.0.1${inUrl}`);
|
|
10
|
+
const inParams = url.searchParams.get("params");
|
|
11
|
+
const action = url.pathname.slice(1);
|
|
12
|
+
if (typeof inParams === "string") {
|
|
13
|
+
const params = JSON.parse(inParams);
|
|
14
|
+
if (!Array.isArray(params))
|
|
15
|
+
throw new Error(`Invalid params`);
|
|
16
|
+
return { action, params };
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
return { action, params: [] };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.headerKey = {
|
|
23
|
+
user: "x-dtt-user",
|
|
24
|
+
password: "x-dtt-password",
|
|
25
|
+
};
|
|
26
|
+
function validateRequest(req, users) {
|
|
27
|
+
const name = req.headers[exports.headerKey.user];
|
|
28
|
+
const password = req.headers[exports.headerKey.password];
|
|
29
|
+
return users.some((user) => user.name.length &&
|
|
30
|
+
user.password.length &&
|
|
31
|
+
user.name === name &&
|
|
32
|
+
user.password === password);
|
|
33
|
+
}
|
|
34
|
+
function createDatatruckServer(options) {
|
|
35
|
+
const log = options.log ?? true;
|
|
36
|
+
return (0, http_2.createServer)(async (req, res) => {
|
|
37
|
+
try {
|
|
38
|
+
if (req.url === "/" || req.url === "/favicon.ico") {
|
|
39
|
+
return res.end();
|
|
40
|
+
}
|
|
41
|
+
else if (!validateRequest(req, options.users || [])) {
|
|
42
|
+
res.statusCode = 401;
|
|
43
|
+
return res.end();
|
|
44
|
+
}
|
|
45
|
+
if (log)
|
|
46
|
+
console.info(`> ${req.url}`);
|
|
47
|
+
const fs = new virtual_fs_1.LocalFs({
|
|
48
|
+
backend: options.path ?? ".",
|
|
49
|
+
});
|
|
50
|
+
const { action, params } = parseUrl(req.url);
|
|
51
|
+
if (action === "upload") {
|
|
52
|
+
const [target] = params;
|
|
53
|
+
const file = (0, fs_1.createWriteStream)(fs.resolvePath(target));
|
|
54
|
+
req.pipe(file);
|
|
55
|
+
await new Promise((resolve, reject) => {
|
|
56
|
+
req.on("error", reject);
|
|
57
|
+
file.on("error", reject);
|
|
58
|
+
file.on("close", resolve);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else if (action === "download") {
|
|
62
|
+
const [target] = params;
|
|
63
|
+
const file = (0, fs_1.createReadStream)(fs.resolvePath(target));
|
|
64
|
+
file.pipe(res);
|
|
65
|
+
await new Promise((resolve, reject) => {
|
|
66
|
+
req.on("error", reject);
|
|
67
|
+
file.on("error", reject);
|
|
68
|
+
res.on("error", reject);
|
|
69
|
+
res.on("close", resolve);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
else if (action === "writeFile") {
|
|
73
|
+
const data = await (0, http_1.readRequestData)(req);
|
|
74
|
+
const [target] = params;
|
|
75
|
+
await fs.writeFile(target, data);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
const object = fs[action]?.bind(fs);
|
|
79
|
+
if (!object)
|
|
80
|
+
throw new Error(`Invalid action: ${action}`);
|
|
81
|
+
const json = await object(...params);
|
|
82
|
+
if (json !== undefined)
|
|
83
|
+
res.write(JSON.stringify(json));
|
|
84
|
+
}
|
|
85
|
+
res.end();
|
|
86
|
+
if (log)
|
|
87
|
+
console.info(`<${action}`);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (log)
|
|
91
|
+
console.error(`<${req.url}`, error);
|
|
92
|
+
res.statusCode = 500;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
exports.createDatatruckServer = createDatatruckServer;
|
package/utils/fs.d.ts
CHANGED
|
@@ -87,18 +87,24 @@ export declare function cpy(options: {
|
|
|
87
87
|
files: number;
|
|
88
88
|
dirs: number;
|
|
89
89
|
}>;
|
|
90
|
+
type ProgressObject = {
|
|
91
|
+
disposed: boolean;
|
|
92
|
+
total: number;
|
|
93
|
+
current: number;
|
|
94
|
+
update: (description: string, path?: string, increment?: boolean) => Promise<void>;
|
|
95
|
+
};
|
|
96
|
+
export declare function createProgress(options: {
|
|
97
|
+
onProgress: (data: Progress) => Promise<void>;
|
|
98
|
+
}): ProgressObject;
|
|
90
99
|
export declare function createFileScanner(options: {
|
|
91
100
|
glob: Options & {
|
|
92
101
|
include: string[];
|
|
93
102
|
};
|
|
94
103
|
onProgress: (data: Progress) => Promise<void>;
|
|
95
|
-
}): Promise<{
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
current: number;
|
|
99
|
-
progress: (description: string, path?: string, increment?: boolean) => Promise<void>;
|
|
104
|
+
}): Promise<ProgressObject & {
|
|
105
|
+
progress: ProgressObject["update"];
|
|
106
|
+
start: (cb?: (entry: Required<Entry>) => any) => Promise<void>;
|
|
100
107
|
end: () => Promise<void>;
|
|
101
|
-
start: (cb?: ((entry: Required<Entry>) => any) | undefined) => Promise<void>;
|
|
102
108
|
}>;
|
|
103
109
|
type StreamItem = {
|
|
104
110
|
key: string;
|
|
@@ -121,4 +127,5 @@ export declare function createWriteStreamPool(options: {
|
|
|
121
127
|
export declare function countFileLines(path: string): Promise<number>;
|
|
122
128
|
export declare function fetchData<T>(input: T, onPath?: (input: Exclude<T, string>) => string | undefined): Promise<string | null>;
|
|
123
129
|
export declare function safeRename(oldPath: string, newPath: string): Promise<void>;
|
|
130
|
+
export declare function tryRm(path: string): Promise<void>;
|
|
124
131
|
export {};
|
package/utils/fs.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.safeRename = exports.fetchData = exports.countFileLines = exports.createWriteStreamPool = exports.createFileScanner = exports.cpy = exports.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.waitForClose = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.readPartialFile = exports.mkTmpDir = exports.fastFolderSizeAsync = exports.tmpDir = exports.rmTmpDir = exports.isTmpDir = exports.sessionTmpDir = exports.parentTmpDir = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.writeJSONFile = exports.existsFile = exports.existsDir = exports.safeStat = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isLocalDir = exports.isEmptyDir = exports.isWSLSystem = void 0;
|
|
6
|
+
exports.tryRm = exports.safeRename = exports.fetchData = exports.countFileLines = exports.createWriteStreamPool = exports.createFileScanner = exports.createProgress = exports.cpy = exports.isNotFoundError = exports.updateFileStats = exports.copyFileWithStreams = exports.waitForClose = exports.writeGitIgnoreList = exports.fastglobToGitIgnore = exports.forEachFile = exports.readDir = exports.readPartialFile = exports.mkTmpDir = exports.fastFolderSizeAsync = exports.tmpDir = exports.rmTmpDir = exports.isTmpDir = exports.sessionTmpDir = exports.parentTmpDir = exports.findFile = exports.parsePackageFile = exports.parseFile = exports.parseFileExtensions = exports.writeJSONFile = exports.existsFile = exports.existsDir = exports.safeStat = exports.ensureEmptyDir = exports.mkdirIfNotExists = exports.isLocalDir = exports.isEmptyDir = exports.isWSLSystem = void 0;
|
|
7
7
|
const globalData_1 = __importDefault(require("../globalData"));
|
|
8
8
|
const math_1 = require("./math");
|
|
9
9
|
const path_1 = require("./path");
|
|
@@ -404,57 +404,65 @@ async function cpy(options) {
|
|
|
404
404
|
return stats;
|
|
405
405
|
}
|
|
406
406
|
exports.cpy = cpy;
|
|
407
|
-
|
|
408
|
-
const
|
|
407
|
+
function createProgress(options) {
|
|
408
|
+
const progress = {
|
|
409
409
|
disposed: false,
|
|
410
410
|
total: 0,
|
|
411
411
|
current: 0,
|
|
412
|
-
|
|
413
|
-
if (
|
|
412
|
+
update: async (description, path, increment = true) => {
|
|
413
|
+
if (progress.disposed)
|
|
414
414
|
return;
|
|
415
415
|
if (path && increment)
|
|
416
|
-
|
|
416
|
+
progress.current++;
|
|
417
417
|
await options.onProgress({
|
|
418
418
|
relative: {
|
|
419
419
|
description,
|
|
420
420
|
payload: path,
|
|
421
421
|
},
|
|
422
422
|
absolute: {
|
|
423
|
-
total:
|
|
424
|
-
current:
|
|
425
|
-
percent: (0, math_1.progressPercent)(
|
|
423
|
+
total: progress.total,
|
|
424
|
+
current: progress.current,
|
|
425
|
+
percent: (0, math_1.progressPercent)(progress.total, progress.current),
|
|
426
426
|
},
|
|
427
427
|
});
|
|
428
428
|
},
|
|
429
|
+
};
|
|
430
|
+
return progress;
|
|
431
|
+
}
|
|
432
|
+
exports.createProgress = createProgress;
|
|
433
|
+
async function createFileScanner(options) {
|
|
434
|
+
const progress = createProgress(options);
|
|
435
|
+
Object.assign(progress, {
|
|
436
|
+
progress: progress.update,
|
|
429
437
|
end: async () => {
|
|
430
|
-
if (!
|
|
431
|
-
await
|
|
432
|
-
|
|
438
|
+
if (!progress.disposed)
|
|
439
|
+
await progress.update("Finished");
|
|
440
|
+
progress.disposed = true;
|
|
433
441
|
},
|
|
434
442
|
start: async (cb) => {
|
|
435
443
|
let lastTime = performance.now();
|
|
436
|
-
await
|
|
444
|
+
await progress.update("Scanning files");
|
|
437
445
|
for await (const entry of pathIterator(stream)) {
|
|
438
446
|
if (cb) {
|
|
439
447
|
if (await cb(entry))
|
|
440
|
-
|
|
448
|
+
progress.total++;
|
|
441
449
|
}
|
|
442
450
|
else {
|
|
443
|
-
|
|
451
|
+
progress.total++;
|
|
444
452
|
}
|
|
445
453
|
if (lastTime - performance.now() > 500)
|
|
446
|
-
await
|
|
454
|
+
await progress.update("Scanning files");
|
|
447
455
|
}
|
|
448
|
-
await
|
|
456
|
+
await progress.update("Scanned files");
|
|
449
457
|
},
|
|
450
|
-
};
|
|
458
|
+
});
|
|
451
459
|
const stream = fast_glob_1.default.stream(options.glob.include, {
|
|
452
460
|
dot: true,
|
|
453
461
|
markDirectories: true,
|
|
454
462
|
stats: true,
|
|
455
463
|
...options.glob,
|
|
456
464
|
});
|
|
457
|
-
return
|
|
465
|
+
return progress;
|
|
458
466
|
}
|
|
459
467
|
exports.createFileScanner = createFileScanner;
|
|
460
468
|
function createWriteStreamPool(options) {
|
|
@@ -560,3 +568,10 @@ async function safeRename(oldPath, newPath) {
|
|
|
560
568
|
}
|
|
561
569
|
}
|
|
562
570
|
exports.safeRename = safeRename;
|
|
571
|
+
async function tryRm(path) {
|
|
572
|
+
try {
|
|
573
|
+
await (0, promises_1.rm)(path);
|
|
574
|
+
}
|
|
575
|
+
catch (_) { }
|
|
576
|
+
}
|
|
577
|
+
exports.tryRm = tryRm;
|
package/utils/http.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { IncomingMessage, Server } from "http";
|
|
3
|
+
export declare function closeServer(server: Server): Promise<void>;
|
|
4
|
+
export declare function readRequestData(req: IncomingMessage): Promise<string | undefined>;
|
|
5
|
+
export declare function fetchJson<T = any>(url: string, options?: {
|
|
6
|
+
headers?: Record<string, string>;
|
|
7
|
+
query?: Record<string, string>;
|
|
8
|
+
}): Promise<T>;
|
|
9
|
+
export declare function post(url: string, data: string, options?: {
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
query?: Record<string, string>;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
export declare function downloadFile(url: string, output: string, options?: {
|
|
14
|
+
headers?: Record<string, string>;
|
|
15
|
+
query?: Record<string, string>;
|
|
16
|
+
timeout?: number;
|
|
17
|
+
}): Promise<void>;
|
|
18
|
+
export declare function uploadFile(url: string, path: string, options?: {
|
|
19
|
+
headers?: Record<string, string>;
|
|
20
|
+
query?: Record<string, string>;
|
|
21
|
+
}): Promise<void>;
|
package/utils/http.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.uploadFile = exports.downloadFile = exports.post = exports.fetchJson = exports.readRequestData = exports.closeServer = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const promises_1 = require("fs/promises");
|
|
6
|
+
const http_1 = require("http");
|
|
7
|
+
const https_1 = require("https");
|
|
8
|
+
const request = (url, options, callback) => {
|
|
9
|
+
return url.startsWith("https://")
|
|
10
|
+
? (0, https_1.request)(url, options, callback)
|
|
11
|
+
: (0, http_1.request)(url, options, callback);
|
|
12
|
+
};
|
|
13
|
+
function href(inUrl, query) {
|
|
14
|
+
const url = new URL(inUrl);
|
|
15
|
+
for (const key in query || {})
|
|
16
|
+
url.searchParams.set(key, query[key]);
|
|
17
|
+
return url.href;
|
|
18
|
+
}
|
|
19
|
+
async function closeServer(server) {
|
|
20
|
+
await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())));
|
|
21
|
+
}
|
|
22
|
+
exports.closeServer = closeServer;
|
|
23
|
+
function readRequestData(req) {
|
|
24
|
+
let data;
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
req
|
|
27
|
+
.on("error", reject)
|
|
28
|
+
.on("data", (chunk) => {
|
|
29
|
+
if (data === undefined)
|
|
30
|
+
data = "";
|
|
31
|
+
data += chunk;
|
|
32
|
+
})
|
|
33
|
+
.on("close", async () => {
|
|
34
|
+
resolve(data);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
exports.readRequestData = readRequestData;
|
|
39
|
+
async function fetchJson(url, options = {}) {
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
let data;
|
|
42
|
+
request(href(url, options.query), {
|
|
43
|
+
method: "GET",
|
|
44
|
+
headers: options.headers,
|
|
45
|
+
}, (res) => {
|
|
46
|
+
if (res.statusCode !== 200)
|
|
47
|
+
return reject(new Error(`GET failed: ${res.statusCode} ${res.statusMessage}`));
|
|
48
|
+
res
|
|
49
|
+
.on("data", (chunk) => {
|
|
50
|
+
if (data === undefined)
|
|
51
|
+
data = "";
|
|
52
|
+
data += chunk;
|
|
53
|
+
})
|
|
54
|
+
.on("error", reject)
|
|
55
|
+
.on("close", () => {
|
|
56
|
+
if (data === undefined) {
|
|
57
|
+
resolve(undefined);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
try {
|
|
61
|
+
resolve(JSON.parse(data));
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
reject(error);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
})
|
|
69
|
+
.on("error", reject)
|
|
70
|
+
.end();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
exports.fetchJson = fetchJson;
|
|
74
|
+
async function post(url, data, options = {}) {
|
|
75
|
+
await new Promise((resolve, reject) => {
|
|
76
|
+
const req = request(href(url, options.query), { method: "POST", headers: options.headers }, (res) => {
|
|
77
|
+
res.on("error", reject);
|
|
78
|
+
if (res.statusCode !== 200) {
|
|
79
|
+
reject(new Error(`Post failed: ${res.statusCode} ${res.statusMessage}`));
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
resolve();
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
req.on("error", reject);
|
|
86
|
+
req.write(data);
|
|
87
|
+
req.end();
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
exports.post = post;
|
|
91
|
+
async function downloadFile(url, output, options = {}) {
|
|
92
|
+
const timeout = options.timeout ?? 3600 * 100;
|
|
93
|
+
const file = (0, fs_1.createWriteStream)(output);
|
|
94
|
+
await new Promise((resolve, reject) => {
|
|
95
|
+
const req = request(href(url, options.query), {
|
|
96
|
+
headers: options.headers,
|
|
97
|
+
}, (res) => {
|
|
98
|
+
if (res.statusCode === 200) {
|
|
99
|
+
res
|
|
100
|
+
.on("error", async (error) => {
|
|
101
|
+
file.destroy();
|
|
102
|
+
try {
|
|
103
|
+
await (0, promises_1.unlink)(output);
|
|
104
|
+
}
|
|
105
|
+
catch (_) { }
|
|
106
|
+
reject(error);
|
|
107
|
+
})
|
|
108
|
+
.pipe(file);
|
|
109
|
+
file.on("finish", () => {
|
|
110
|
+
file.close((error) => {
|
|
111
|
+
error ? reject(error) : resolve();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
reject(new Error(`Download failed: ${res.statusCode} ${res.statusMessage}`));
|
|
117
|
+
}
|
|
118
|
+
}).on("error", async (error) => {
|
|
119
|
+
try {
|
|
120
|
+
await (0, promises_1.unlink)(output);
|
|
121
|
+
}
|
|
122
|
+
catch (_) { }
|
|
123
|
+
reject(error);
|
|
124
|
+
});
|
|
125
|
+
req.setTimeout(timeout, () => {
|
|
126
|
+
req.destroy();
|
|
127
|
+
reject(new Error(`Request timeout after ${timeout / 1000}s`));
|
|
128
|
+
});
|
|
129
|
+
req.end();
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
exports.downloadFile = downloadFile;
|
|
133
|
+
async function uploadFile(url, path, options = {}) {
|
|
134
|
+
const { size } = await (0, promises_1.stat)(path);
|
|
135
|
+
const readStream = (0, fs_1.createReadStream)(path);
|
|
136
|
+
await new Promise((resolve, reject) => {
|
|
137
|
+
const req = request(href(url, options.query), {
|
|
138
|
+
method: "POST",
|
|
139
|
+
headers: {
|
|
140
|
+
...options.headers,
|
|
141
|
+
"Content-length": size,
|
|
142
|
+
},
|
|
143
|
+
}, (res) => {
|
|
144
|
+
if (res.statusCode !== 200) {
|
|
145
|
+
reject(new Error(`Upload failed: ${res.statusCode} ${res.statusMessage}`));
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
resolve();
|
|
149
|
+
}
|
|
150
|
+
}).on("error", reject);
|
|
151
|
+
readStream.on("error", reject).pipe(req);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
exports.uploadFile = uploadFile;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export declare function resolvePath(path: string): string;
|
|
2
|
+
export type FsOptions = {
|
|
3
|
+
backend: string;
|
|
4
|
+
};
|
|
5
|
+
export declare abstract class AbstractFs {
|
|
6
|
+
readonly options: FsOptions;
|
|
7
|
+
constructor(options: FsOptions);
|
|
8
|
+
resolvePath(path: string): string;
|
|
9
|
+
abstract isLocal(): boolean;
|
|
10
|
+
abstract existsDir(path: string): Promise<boolean>;
|
|
11
|
+
abstract mkdir(path: string): Promise<void>;
|
|
12
|
+
abstract readFile(path: string): Promise<string>;
|
|
13
|
+
abstract rmAll(path: string): Promise<void>;
|
|
14
|
+
abstract readFileIfExists(path: string): Promise<string | undefined>;
|
|
15
|
+
abstract readdir(path: string): Promise<string[]>;
|
|
16
|
+
abstract ensureEmptyDir(path: string): Promise<void>;
|
|
17
|
+
abstract writeFile(path: string, contents: string): Promise<void>;
|
|
18
|
+
abstract upload(url: string, path: string): Promise<void>;
|
|
19
|
+
abstract download(url: string, path: string): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export declare class LocalFs extends AbstractFs {
|
|
22
|
+
isLocal(): boolean;
|
|
23
|
+
existsDir(path: string): Promise<boolean>;
|
|
24
|
+
mkdir(path: string): Promise<void>;
|
|
25
|
+
ensureEmptyDir(path: string): Promise<void>;
|
|
26
|
+
readFile(path: string): Promise<string>;
|
|
27
|
+
readFileIfExists(inPath: string): Promise<string | undefined>;
|
|
28
|
+
readdir(path: string): Promise<string[]>;
|
|
29
|
+
writeFile(path: string, contents: string): Promise<void>;
|
|
30
|
+
rmAll(path: string): Promise<void>;
|
|
31
|
+
upload(source: string, target: string): Promise<void>;
|
|
32
|
+
download(source: string, target: string): Promise<void>;
|
|
33
|
+
}
|