@pipelab/plugin-filesystem 1.0.0-beta.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/CHANGELOG.md +12 -0
- package/LICENSE +110 -0
- package/README.md +3 -0
- package/dist/index.cjs +28051 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +28053 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +48 -0
- package/src/copy.spec.ts +100 -0
- package/src/copy.ts +154 -0
- package/src/index.ts +58 -0
- package/src/is-file.ts +36 -0
- package/src/list-files.ts +70 -0
- package/src/open.ts +67 -0
- package/src/remove.ts +58 -0
- package/src/run.ts +138 -0
- package/src/temporary-folder.ts +50 -0
- package/src/unzip.spec.ts +33 -0
- package/src/unzip.ts +58 -0
- package/src/zip-v2.ts +120 -0
- package/src/zip.ts +133 -0
- package/tests/e2e/filesystem.spec.ts +103 -0
- package/tests/e2e/vitest.config.mts +20 -0
- package/tsconfig.json +8 -0
- package/tsdown.config.ts +15 -0
package/src/run.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAction,
|
|
3
|
+
createActionRunner,
|
|
4
|
+
createPathParam,
|
|
5
|
+
createStringParam,
|
|
6
|
+
runWithLiveLogs,
|
|
7
|
+
} from "@pipelab/plugin-core";
|
|
8
|
+
|
|
9
|
+
export const ID = "fs:run";
|
|
10
|
+
|
|
11
|
+
export const run = createAction({
|
|
12
|
+
id: ID,
|
|
13
|
+
name: "Invoke file",
|
|
14
|
+
displayString:
|
|
15
|
+
"`Invoke ${fmt.param(params.command, 'primary')} ${(params.parameters ?? []).map(x => fmt.param(x)).join(' ')}`",
|
|
16
|
+
// displayString: displayString,
|
|
17
|
+
params: {
|
|
18
|
+
command: createStringParam("", {
|
|
19
|
+
required: true,
|
|
20
|
+
description: "The command to run",
|
|
21
|
+
label: "Command",
|
|
22
|
+
}),
|
|
23
|
+
parameters: {
|
|
24
|
+
required: true,
|
|
25
|
+
description: "The command's parameters",
|
|
26
|
+
label: "Arguments",
|
|
27
|
+
value: [],
|
|
28
|
+
control: {
|
|
29
|
+
type: "array",
|
|
30
|
+
options: {
|
|
31
|
+
kind: "text",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
workingDirectory: createPathParam("", {
|
|
36
|
+
required: false,
|
|
37
|
+
description: "The directory to run the command in. Default to current task directory",
|
|
38
|
+
label: "Working directory",
|
|
39
|
+
control: {
|
|
40
|
+
type: "path",
|
|
41
|
+
options: {
|
|
42
|
+
properties: ["createDirectory", "openDirectory"],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
stopOnError: {
|
|
47
|
+
required: false,
|
|
48
|
+
description: "Stop the task if the command fails",
|
|
49
|
+
label: "Stop on error",
|
|
50
|
+
value: false,
|
|
51
|
+
control: {
|
|
52
|
+
type: "boolean",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
outputs: {
|
|
58
|
+
stdout: {
|
|
59
|
+
label: "Standard output",
|
|
60
|
+
description: "Standard output of the command",
|
|
61
|
+
value: "",
|
|
62
|
+
},
|
|
63
|
+
stderr: {
|
|
64
|
+
label: "Error output",
|
|
65
|
+
value: "",
|
|
66
|
+
},
|
|
67
|
+
exitCode: {
|
|
68
|
+
label: "Exit code",
|
|
69
|
+
value: 0,
|
|
70
|
+
},
|
|
71
|
+
duration: {
|
|
72
|
+
label: "Duration",
|
|
73
|
+
value: 0,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
description: "Invoke an arbitrary executable",
|
|
77
|
+
icon: "",
|
|
78
|
+
meta: {},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
export const runRunner = createActionRunner<typeof run>(
|
|
82
|
+
async ({ log, inputs, setOutput, abortSignal }) => {
|
|
83
|
+
const str = `${inputs.command} ${inputs.parameters.join(" ")}`;
|
|
84
|
+
|
|
85
|
+
log(`Running ${str}`);
|
|
86
|
+
|
|
87
|
+
let stdout: string = "";
|
|
88
|
+
let stderr: string = "";
|
|
89
|
+
let exitCode: number = 0;
|
|
90
|
+
const durationMs: number = 0;
|
|
91
|
+
|
|
92
|
+
const wd = inputs.workingDirectory ?? process.cwd();
|
|
93
|
+
log(`Working directory: ${wd}`);
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
await runWithLiveLogs(
|
|
97
|
+
inputs.command,
|
|
98
|
+
inputs.parameters,
|
|
99
|
+
{
|
|
100
|
+
cwd: wd,
|
|
101
|
+
cancelSignal: abortSignal,
|
|
102
|
+
},
|
|
103
|
+
log,
|
|
104
|
+
{
|
|
105
|
+
onStdout: (data) => {
|
|
106
|
+
stdout += data.toString();
|
|
107
|
+
log(data.toString());
|
|
108
|
+
},
|
|
109
|
+
onStderr: (data) => {
|
|
110
|
+
stderr += data.toString();
|
|
111
|
+
log(data.toString());
|
|
112
|
+
},
|
|
113
|
+
onExit(code) {
|
|
114
|
+
exitCode = code;
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
setOutput("exitCode", exitCode === undefined ? -1 : exitCode);
|
|
120
|
+
setOutput("stdout", stdout);
|
|
121
|
+
setOutput("stderr", stderr);
|
|
122
|
+
setOutput("duration", durationMs);
|
|
123
|
+
if ((exitCode > 0 || exitCode === undefined) && inputs.stopOnError === true) {
|
|
124
|
+
throw new Error(`Command failed with exit code ${exitCode}`);
|
|
125
|
+
}
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.log("error", error);
|
|
128
|
+
if (inputs.stopOnError === true) {
|
|
129
|
+
throw error;
|
|
130
|
+
} else if (error /* instanceof ExecaError */) {
|
|
131
|
+
setOutput("exitCode", error.exitCode === undefined ? -1 : error.exitCode);
|
|
132
|
+
setOutput("stdout", error.stdout ?? "");
|
|
133
|
+
setOutput("stderr", error.stderr ?? "");
|
|
134
|
+
setOutput("duration", error.durationMs ?? 0);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// import { ComputeOutput, Context, CynNode, IODef, createDefinition, path, schema } from '@pipelab/plugin-core';
|
|
2
|
+
// import { nanoid } from 'nanoid'
|
|
3
|
+
|
|
4
|
+
// export const ID = 'temporary-folder'
|
|
5
|
+
|
|
6
|
+
// export type Data = {
|
|
7
|
+
// }
|
|
8
|
+
|
|
9
|
+
// export const definition = createDefinition({
|
|
10
|
+
// inputs: {
|
|
11
|
+
|
|
12
|
+
// },
|
|
13
|
+
// outputs: {
|
|
14
|
+
// value: {
|
|
15
|
+
// type: 'data',
|
|
16
|
+
// schema: schema.string()
|
|
17
|
+
// }
|
|
18
|
+
// }
|
|
19
|
+
// } satisfies IODef)
|
|
20
|
+
|
|
21
|
+
// export class TemporaryFolderNode extends CynNode<Data, typeof ID, typeof definition> {
|
|
22
|
+
// width = 180;
|
|
23
|
+
// height = 250;
|
|
24
|
+
|
|
25
|
+
// path: string | undefined
|
|
26
|
+
|
|
27
|
+
// constructor(context: Context) {
|
|
28
|
+
// super(ID, "Temporary folder", context);
|
|
29
|
+
|
|
30
|
+
// const value = new ClassicPreset.Output(path(), "Valeur")
|
|
31
|
+
// this.addOutput('value', value);
|
|
32
|
+
// }
|
|
33
|
+
// run() { }
|
|
34
|
+
// compute(): ComputeOutput<typeof definition> {
|
|
35
|
+
// if (!this.path) {
|
|
36
|
+
// this.path = nanoid()
|
|
37
|
+
// }
|
|
38
|
+
// return {
|
|
39
|
+
// value: this.path
|
|
40
|
+
// };
|
|
41
|
+
// }
|
|
42
|
+
|
|
43
|
+
// load(data: Data) {
|
|
44
|
+
// }
|
|
45
|
+
|
|
46
|
+
// save() {
|
|
47
|
+
// return {
|
|
48
|
+
// }
|
|
49
|
+
// }
|
|
50
|
+
// }
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { expect, test } from "vitest";
|
|
2
|
+
import { unzipRunner } from "./unzip.js";
|
|
3
|
+
import { browserWindow } from "@pipelab/shared";
|
|
4
|
+
|
|
5
|
+
test("adds 1 + 2 to equal 3", async () => {
|
|
6
|
+
const outputs: Record<string, unknown> = {};
|
|
7
|
+
// await unzipRunner({
|
|
8
|
+
// inputs: {
|
|
9
|
+
// file: ''
|
|
10
|
+
// },
|
|
11
|
+
// log: (...args) => {
|
|
12
|
+
// console.log(...args)
|
|
13
|
+
// },
|
|
14
|
+
// setOutput: (key, value) => {
|
|
15
|
+
// outputs[key] = value
|
|
16
|
+
// },
|
|
17
|
+
// meta: {
|
|
18
|
+
// definition: ''
|
|
19
|
+
// },
|
|
20
|
+
// setMeta: () => {
|
|
21
|
+
// console.log('set meta defined here')
|
|
22
|
+
// },
|
|
23
|
+
// cwd: '',
|
|
24
|
+
// paths: {
|
|
25
|
+
// assets: '',
|
|
26
|
+
// unpack: ''
|
|
27
|
+
// },
|
|
28
|
+
// api: undefined,
|
|
29
|
+
// browserWindow,
|
|
30
|
+
// })
|
|
31
|
+
console.log("outputs", outputs);
|
|
32
|
+
expect(true).toBe(true);
|
|
33
|
+
}, 120_000);
|
package/src/unzip.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import StreamZip from "node-stream-zip";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { createAction, createActionRunner, createPathParam } from "@pipelab/plugin-core";
|
|
4
|
+
|
|
5
|
+
export const ID = "unzip-file-node";
|
|
6
|
+
|
|
7
|
+
export const unzip = createAction({
|
|
8
|
+
id: ID,
|
|
9
|
+
name: "Unzip file",
|
|
10
|
+
displayString: '`Unzip ${fmt.param(params.file, "primary", "No file specified")}`',
|
|
11
|
+
params: {
|
|
12
|
+
file: createPathParam("", {
|
|
13
|
+
required: true,
|
|
14
|
+
control: {
|
|
15
|
+
type: "path",
|
|
16
|
+
options: {
|
|
17
|
+
properties: ["openFile"],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
label: "File",
|
|
21
|
+
}),
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
outputs: {
|
|
25
|
+
output: {
|
|
26
|
+
value: "",
|
|
27
|
+
label: "Output",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
description: "Unzip a file to a specified folder",
|
|
31
|
+
icon: "",
|
|
32
|
+
meta: {},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export const unzipRunner = createActionRunner<typeof unzip>(
|
|
36
|
+
async ({ log, inputs, setOutput, cwd }) => {
|
|
37
|
+
console.log("inputs", inputs);
|
|
38
|
+
|
|
39
|
+
console.log("inputs.file", inputs.file);
|
|
40
|
+
const file = inputs.file;
|
|
41
|
+
console.log("file", file);
|
|
42
|
+
const output = join(cwd);
|
|
43
|
+
|
|
44
|
+
console.log("file", file);
|
|
45
|
+
console.log("output", output);
|
|
46
|
+
|
|
47
|
+
log("Unzip file", inputs.file, "to", output);
|
|
48
|
+
|
|
49
|
+
const zip = new StreamZip.async({ file });
|
|
50
|
+
|
|
51
|
+
const bytes = await zip.extract(null, output);
|
|
52
|
+
await zip.close();
|
|
53
|
+
|
|
54
|
+
console.log("bytes", bytes);
|
|
55
|
+
|
|
56
|
+
setOutput("output", output);
|
|
57
|
+
},
|
|
58
|
+
);
|
package/src/zip-v2.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { createWriteStream } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import archiver from "archiver";
|
|
4
|
+
import { createAction, createActionRunner, createPathParam } from "@pipelab/plugin-core";
|
|
5
|
+
|
|
6
|
+
export const ID = "zip-v2-node";
|
|
7
|
+
|
|
8
|
+
export type MaybeArray<T> = T | T[];
|
|
9
|
+
|
|
10
|
+
export const getValue = <T>(array: MaybeArray<T>): T => {
|
|
11
|
+
if (Array.isArray(array)) {
|
|
12
|
+
return array[0];
|
|
13
|
+
} else {
|
|
14
|
+
return array;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const zipV2 = createAction({
|
|
19
|
+
id: ID,
|
|
20
|
+
name: "Zip",
|
|
21
|
+
displayString: '`Zip ${fmt.param(params.folder, "primary", "No folder specified")}`',
|
|
22
|
+
params: {
|
|
23
|
+
folder: createPathParam("", {
|
|
24
|
+
required: true,
|
|
25
|
+
control: {
|
|
26
|
+
type: "path",
|
|
27
|
+
options: {
|
|
28
|
+
properties: ["openDirectory"],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
label: "Folder",
|
|
32
|
+
}),
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
outputs: {
|
|
36
|
+
path: {
|
|
37
|
+
value: "",
|
|
38
|
+
label: "Path",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
description: "Zip a folder into a .zip file",
|
|
42
|
+
icon: "",
|
|
43
|
+
meta: {},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export const zipV2Runner = createActionRunner<typeof zipV2>(
|
|
47
|
+
async ({ log, inputs, setOutput, abortSignal, paths }) => {
|
|
48
|
+
abortSignal.addEventListener("abort", () => {
|
|
49
|
+
throw new Error("Aborted");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const outputDir = paths.cache;
|
|
53
|
+
const outputFile = join(outputDir, "output.zip");
|
|
54
|
+
|
|
55
|
+
console.log("outputFile", outputFile);
|
|
56
|
+
|
|
57
|
+
const output = createWriteStream(outputFile);
|
|
58
|
+
|
|
59
|
+
const archive = archiver("zip", {
|
|
60
|
+
zlib: { level: 9 }, // Sets the compression level.
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
output.on("close", function () {
|
|
65
|
+
console.log(archive.pointer() + " total bytes");
|
|
66
|
+
console.log("archiver has been finalized and the output file descriptor has closed.");
|
|
67
|
+
|
|
68
|
+
setOutput("path", outputFile);
|
|
69
|
+
resolve();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
output.on("end", function () {
|
|
73
|
+
console.log("Data has been drained");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
archive.on("warning", function (err) {
|
|
77
|
+
if (err.code === "ENOENT") {
|
|
78
|
+
console.log("Archiver warning: ENOENT");
|
|
79
|
+
} else {
|
|
80
|
+
reject(err);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
archive.on("error", function (err) {
|
|
85
|
+
reject(err);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// archive.on('data', function (data) {
|
|
89
|
+
// log('data', data)
|
|
90
|
+
// })
|
|
91
|
+
// archive.on('progress', function (data) {
|
|
92
|
+
// /* {
|
|
93
|
+
// entries:
|
|
94
|
+
// {
|
|
95
|
+
// total: 5012,
|
|
96
|
+
// processed: 5012
|
|
97
|
+
// },
|
|
98
|
+
// fs:
|
|
99
|
+
// {
|
|
100
|
+
// totalBytes: 318794388,
|
|
101
|
+
// processedBytes: 318794388
|
|
102
|
+
// }
|
|
103
|
+
// } */
|
|
104
|
+
// // log('progress', data.entries.processed + '/' + data.entries.total)
|
|
105
|
+
// })
|
|
106
|
+
archive.on("entry", function (data) {
|
|
107
|
+
log("Adding", data.name);
|
|
108
|
+
});
|
|
109
|
+
archive.on("finish", function () {
|
|
110
|
+
log("finish");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
archive.pipe(output);
|
|
114
|
+
|
|
115
|
+
archive.directory(inputs.folder, false);
|
|
116
|
+
|
|
117
|
+
archive.finalize();
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
);
|
package/src/zip.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { createWriteStream } from "node:fs";
|
|
2
|
+
import archiver from "archiver";
|
|
3
|
+
import { createAction, createActionRunner, createPathParam } from "@pipelab/plugin-core";
|
|
4
|
+
|
|
5
|
+
export const ID = "zip-node";
|
|
6
|
+
|
|
7
|
+
export type MaybeArray<T> = T | T[];
|
|
8
|
+
|
|
9
|
+
export const getValue = <T>(array: MaybeArray<T>): T => {
|
|
10
|
+
if (Array.isArray(array)) {
|
|
11
|
+
return array[0];
|
|
12
|
+
} else {
|
|
13
|
+
return array;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const zip = createAction({
|
|
18
|
+
id: ID,
|
|
19
|
+
name: "Zip",
|
|
20
|
+
updateAvailable: true,
|
|
21
|
+
displayString:
|
|
22
|
+
'`Zip ${fmt.param(params.folder, "primary", "No folder specified")} to ${fmt.param(params.output, "secondary", "No output specified")}`',
|
|
23
|
+
params: {
|
|
24
|
+
folder: createPathParam("", {
|
|
25
|
+
required: true,
|
|
26
|
+
control: {
|
|
27
|
+
type: "path",
|
|
28
|
+
options: {
|
|
29
|
+
properties: ["openDirectory"],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
label: "Folder",
|
|
33
|
+
}),
|
|
34
|
+
output: createPathParam("", {
|
|
35
|
+
required: true,
|
|
36
|
+
control: {
|
|
37
|
+
type: "path",
|
|
38
|
+
options: {
|
|
39
|
+
properties: ["openFile", "promptToCreate"],
|
|
40
|
+
// must be zip file
|
|
41
|
+
filters: [
|
|
42
|
+
{
|
|
43
|
+
extensions: ["zip"],
|
|
44
|
+
name: "Zip file",
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
label: "Folder",
|
|
50
|
+
}),
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
outputs: {
|
|
54
|
+
path: {
|
|
55
|
+
value: "",
|
|
56
|
+
label: "Path",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
description: "Zip a folder into a .zip file",
|
|
60
|
+
icon: "",
|
|
61
|
+
meta: {},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export const zipRunner = createActionRunner<typeof zip>(
|
|
65
|
+
async ({ log, inputs, setOutput, abortSignal }) => {
|
|
66
|
+
abortSignal.addEventListener("abort", () => {
|
|
67
|
+
throw new Error("Aborted");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const output = createWriteStream(inputs.output);
|
|
71
|
+
|
|
72
|
+
const archive = archiver("zip", {
|
|
73
|
+
zlib: { level: 9 }, // Sets the compression level.
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
output.on("close", function () {
|
|
78
|
+
console.log(archive.pointer() + " total bytes");
|
|
79
|
+
console.log("archiver has been finalized and the output file descriptor has closed.");
|
|
80
|
+
|
|
81
|
+
setOutput("path", inputs.output);
|
|
82
|
+
resolve();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
output.on("end", function () {
|
|
86
|
+
console.log("Data has been drained");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
archive.on("warning", function (err) {
|
|
90
|
+
if (err.code === "ENOENT") {
|
|
91
|
+
console.log("Archiver warning: ENOENT");
|
|
92
|
+
} else {
|
|
93
|
+
reject(err);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
archive.on("error", function (err) {
|
|
98
|
+
reject(err);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// archive.on('data', function (data) {
|
|
102
|
+
// log('data', data)
|
|
103
|
+
// })
|
|
104
|
+
// archive.on('progress', function (data) {
|
|
105
|
+
// /* {
|
|
106
|
+
// entries:
|
|
107
|
+
// {
|
|
108
|
+
// total: 5012,
|
|
109
|
+
// processed: 5012
|
|
110
|
+
// },
|
|
111
|
+
// fs:
|
|
112
|
+
// {
|
|
113
|
+
// totalBytes: 318794388,
|
|
114
|
+
// processedBytes: 318794388
|
|
115
|
+
// }
|
|
116
|
+
// } */
|
|
117
|
+
// // log('progress', data.entries.processed + '/' + data.entries.total)
|
|
118
|
+
// })
|
|
119
|
+
archive.on("entry", function (data) {
|
|
120
|
+
log("Adding", data.name);
|
|
121
|
+
});
|
|
122
|
+
archive.on("finish", function () {
|
|
123
|
+
log("finish");
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
archive.pipe(output);
|
|
127
|
+
|
|
128
|
+
archive.directory(inputs.folder, false);
|
|
129
|
+
|
|
130
|
+
archive.finalize();
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
);
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { expect, test, describe, beforeAll, afterAll, afterEach } from "vitest";
|
|
2
|
+
import { mkdir, writeFile, readFile, access } from "node:fs/promises";
|
|
3
|
+
import { join, dirname } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { createSandbox, runAction } from "@pipelab/test-utils";
|
|
6
|
+
import { copyRunner } from "../../src/copy";
|
|
7
|
+
import { removeRunner } from "../../src/remove";
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
|
|
12
|
+
describe("End-to-End: Filesystem Plugin", () => {
|
|
13
|
+
let sandbox: Awaited<ReturnType<typeof createSandbox>>;
|
|
14
|
+
|
|
15
|
+
afterEach(async () => {
|
|
16
|
+
if (sandbox) {
|
|
17
|
+
await sandbox.remove();
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("should copy a file using 'copy' action", { timeout: 60000 }, async () => {
|
|
22
|
+
sandbox = await createSandbox("fs-copy-e2e");
|
|
23
|
+
const testPath = sandbox.path;
|
|
24
|
+
const sourcePath = join(testPath, "source");
|
|
25
|
+
const destPath = join(testPath, "destination");
|
|
26
|
+
await mkdir(sourcePath, { recursive: true });
|
|
27
|
+
await mkdir(destPath, { recursive: true });
|
|
28
|
+
|
|
29
|
+
const sourceFile = join(sourcePath, "file.txt");
|
|
30
|
+
const destFile = join(destPath, "file.txt");
|
|
31
|
+
await writeFile(sourceFile, "Hello World");
|
|
32
|
+
|
|
33
|
+
await runAction(copyRunner, {
|
|
34
|
+
inputs: {
|
|
35
|
+
from: sourceFile,
|
|
36
|
+
to: destFile,
|
|
37
|
+
recursive: false,
|
|
38
|
+
overwrite: false,
|
|
39
|
+
cleanup: false,
|
|
40
|
+
},
|
|
41
|
+
sandboxPath: testPath,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
await expect(access(destFile)).resolves.not.toThrow();
|
|
45
|
+
const content = await readFile(destFile, "utf-8");
|
|
46
|
+
expect(content).toBe("Hello World");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("should move a file using 'copy' then 'remove' actions", { timeout: 60000 }, async () => {
|
|
50
|
+
sandbox = await createSandbox("fs-move-e2e");
|
|
51
|
+
const testPath = sandbox.path;
|
|
52
|
+
const sourcePath = join(testPath, "source");
|
|
53
|
+
const destPath = join(testPath, "destination");
|
|
54
|
+
await mkdir(sourcePath, { recursive: true });
|
|
55
|
+
await mkdir(destPath, { recursive: true });
|
|
56
|
+
|
|
57
|
+
const sourceFile = join(sourcePath, "file.txt");
|
|
58
|
+
const destFile = join(destPath, "file.txt");
|
|
59
|
+
await writeFile(sourceFile, "File to move");
|
|
60
|
+
|
|
61
|
+
// Copy
|
|
62
|
+
await runAction(copyRunner, {
|
|
63
|
+
inputs: {
|
|
64
|
+
from: sourceFile,
|
|
65
|
+
to: destFile,
|
|
66
|
+
recursive: false,
|
|
67
|
+
overwrite: false,
|
|
68
|
+
cleanup: false,
|
|
69
|
+
},
|
|
70
|
+
sandboxPath: testPath,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Remove
|
|
74
|
+
await runAction(removeRunner, {
|
|
75
|
+
inputs: {
|
|
76
|
+
from: sourceFile,
|
|
77
|
+
recursive: true,
|
|
78
|
+
},
|
|
79
|
+
sandboxPath: testPath,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
await expect(access(destFile)).resolves.not.toThrow();
|
|
83
|
+
await expect(access(sourceFile)).rejects.toThrow();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("should delete a file using 'remove' action", { timeout: 60000 }, async () => {
|
|
87
|
+
sandbox = await createSandbox("fs-remove-e2e");
|
|
88
|
+
const testPath = sandbox.path;
|
|
89
|
+
await mkdir(testPath, { recursive: true });
|
|
90
|
+
const fileToDelete = join(testPath, "file_to_delete.txt");
|
|
91
|
+
await writeFile(fileToDelete, "Delete me");
|
|
92
|
+
|
|
93
|
+
await runAction(removeRunner, {
|
|
94
|
+
inputs: {
|
|
95
|
+
from: fileToDelete,
|
|
96
|
+
recursive: true,
|
|
97
|
+
},
|
|
98
|
+
sandboxPath: testPath,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
await expect(access(fileToDelete)).rejects.toThrow();
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineConfig } from "vitest/config";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
fileParallelism: false,
|
|
6
|
+
testTimeout: 60000,
|
|
7
|
+
hookTimeout: 60000,
|
|
8
|
+
maxWorkers: 1,
|
|
9
|
+
minWorkers: 1,
|
|
10
|
+
poolOptions: {
|
|
11
|
+
forks: {
|
|
12
|
+
singleFork: true,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
include: ["**/*.spec.ts"],
|
|
16
|
+
root: "tests/e2e",
|
|
17
|
+
environment: "node",
|
|
18
|
+
env: { NODE_ENV: "development", PIPELAB_DISABLE_HISTORY: "true" },
|
|
19
|
+
},
|
|
20
|
+
});
|
package/tsconfig.json
ADDED
package/tsdown.config.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineConfig } from "tsdown";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
entry: ["src/index.ts"],
|
|
5
|
+
format: ["esm", "cjs"],
|
|
6
|
+
dts: true,
|
|
7
|
+
clean: true,
|
|
8
|
+
loader: {
|
|
9
|
+
".webp": "dataurl",
|
|
10
|
+
".png": "dataurl",
|
|
11
|
+
".jpg": "dataurl",
|
|
12
|
+
".jpeg": "dataurl",
|
|
13
|
+
".svg": "dataurl",
|
|
14
|
+
},
|
|
15
|
+
});
|