Skip to content

Commit 9b334f6

Browse files
committed
Replace CMD: to cmd
1 parent 079c012 commit 9b334f6

File tree

9 files changed

+168
-90
lines changed

9 files changed

+168
-90
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,16 +202,16 @@ $ dim install https://example.com -n "example" -p xlsx-to-csv
202202

203203
Postprocess custom command
204204

205-
You can specify a custom command after **"CMD:"**.
205+
You can specify a custom command after **"cmd"**.
206206

207207
```
208-
$ dim install https://example.com -n "example" -p "CMD:******"
208+
$ dim install https://example.com -n "example" -p "cmd ******"
209209
```
210210

211211
The file path will be passed as an argument at the end of the specified command.
212212

213213
```
214-
$ dim install https://example.com -n "example" -p "CMD:python ./tests/test_custom_command.py"
214+
$ dim install https://example.com -n "example" -p "cmd python ./tests/test_custom_command.py"
215215
```
216216

217217
Command to be executed during postprocessing.
@@ -223,6 +223,7 @@ $ python ./tests/test_custom_command.py ./data_files/***/***.xx
223223
#### Forced execution
224224

225225
Forced install. Overwrite already exist data file.
226+
226227
```
227228
$ dim install https://example.com -n "example" -F
228229
```

libs/actions.ts

Lines changed: 6 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,8 @@ import {
2525
DimLockJSON,
2626
LockContent,
2727
} from "./types.ts";
28-
import { Encoder } from "./postprocess/encoder.ts";
29-
import { Unzipper } from "./postprocess/unzipper.ts";
30-
import { XLSXConverter } from "./postprocess/xlsx_converter.ts";
31-
import { Command } from "./postprocess/command.ts";
3228
import { CkanApiClient } from "./ckan_api_client.ts";
29+
import { PostprocessDispatcher } from "./postprocess/postprocess_dispatcher.ts";
3330

3431
const initDimFile = async () => {
3532
const dimData: DimJSON = { fileVersion: DIM_FILE_VERSION, contents: [] };
@@ -256,70 +253,15 @@ const installFromCatalog = async (
256253
return fullPath;
257254
};
258255

256+
const postprocessDispatcher = new PostprocessDispatcher();
257+
259258
const executePostprocess = async (
260259
postProcesses: string[],
261260
targetPath: string,
262261
) => {
263262
for (const postProcess of postProcesses) {
264263
const [type, ...argumentList] = postProcess.split(" ");
265-
if (type === "encode") {
266-
if (argumentList.length === 0) {
267-
console.log(
268-
Colors.red("Argument not specified."),
269-
);
270-
Deno.exit(1);
271-
} else if (argumentList.length > 1) {
272-
console.log(
273-
Colors.red("error: Too many arguments:"),
274-
Colors.red(type + " " + argumentList.join(" ")),
275-
);
276-
Deno.exit(1);
277-
}
278-
const encodingTo = argumentList[0].toUpperCase();
279-
await new Encoder().encodeFile(targetPath, encodingTo);
280-
console.log("Converted encoding to", encodingTo);
281-
} else if (type === "unzip") {
282-
if (argumentList.length > 0) {
283-
console.log(
284-
Colors.red("error: Too many arguments:"),
285-
Colors.red(type + " " + argumentList.join(" ")),
286-
);
287-
Deno.exit(1);
288-
}
289-
const targetDir = await new Unzipper().unzip(targetPath);
290-
console.log(`Unzip the file to ${targetDir}`);
291-
} else if (type === "xlsx-to-csv") {
292-
if (argumentList.length > 0) {
293-
console.log(
294-
Colors.red("error: Too many arguments:"),
295-
Colors.red(type + " " + argumentList.join(" ")),
296-
);
297-
Deno.exit(1);
298-
}
299-
await new XLSXConverter().convertToCSV(targetPath);
300-
console.log(`Convert xlsx to csv.`);
301-
} else if (postProcess.startsWith("CMD:")) {
302-
const script = postProcess.replace("CMD:", "").trim();
303-
if (script === "") {
304-
console.log(
305-
Colors.red("No command entered"),
306-
);
307-
Deno.exit(1);
308-
}
309-
try {
310-
console.log("Execute Command: ", script, targetPath);
311-
const result = await new Command().execute(script, targetPath);
312-
console.log(result);
313-
} catch (e) {
314-
console.log(
315-
Colors.red(`Failed to execute the "${script}"\n`),
316-
Colors.red(`${e}`),
317-
);
318-
// Do not `exit` because there are commands that do not correspond when obtained from external dim.json.
319-
}
320-
} else {
321-
console.log(`No support a postprocess '${postProcess}'.`);
322-
}
264+
await postprocessDispatcher.dispatch(type, argumentList, targetPath);
323265
}
324266
};
325267

@@ -716,9 +658,9 @@ export class SearchAction {
716658
message:
717659
"Enter the post-processing you want to add. Enter blank if not required.",
718660
hint:
719-
"(ex.: > unzip, xlsx-to-csv, encode utf-8 or CMD:[some cli command])",
661+
"(ex.: > unzip, xlsx-to-csv, encode utf-8 or cmd [some cli command])",
720662
validate: (text) => {
721-
return text === "" || text.startsWith("CMD:") ||
663+
return text === "" || text.startsWith("cmd ") ||
722664
availablePostProcesses.includes(text);
723665
},
724666
suggestions: availablePostProcesses,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export abstract class BasePostprocess {
2+
type: string;
3+
argumentNameList: string[];
4+
constructor(type: string, argumentNameList: string[]) {
5+
this.type = type;
6+
this.argumentNameList = argumentNameList;
7+
}
8+
abstract execute(argumentList: string[], targetPath: string): Promise<string>;
9+
abstract validate(argumentList: string[]): boolean;
10+
printUsage() {
11+
console.log(
12+
"usage: " + this.type + " " +
13+
this.argumentNameList.map((arg) => `[${arg}]`).join(" "),
14+
);
15+
}
16+
}

libs/postprocess/command.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
1-
export class Command {
2-
async execute(script: string, path: string) {
3-
const cmd = script.split(" ");
4-
cmd.push(path);
1+
import { Colors } from "../../deps.ts";
2+
import { BasePostprocess } from "./base_postprocess.ts";
3+
4+
export class Command extends BasePostprocess {
5+
async execute(argumentList: string[], targetPath: string): Promise<string> {
6+
const cmd = argumentList[0].split(" ");
7+
cmd.push(targetPath);
58
const p = Deno.run({
69
cmd: cmd,
710
stdout: "piped",
811
});
912
const o = await p.output();
1013
return new TextDecoder().decode(o);
1114
}
15+
validate(argumentList: string[]) {
16+
if (argumentList.length < 1) {
17+
console.log(
18+
Colors.red("No command entered"),
19+
);
20+
this.printUsage();
21+
return false;
22+
}
23+
return true;
24+
}
1225
}

libs/postprocess/encoder.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,34 @@
1-
import { encoding } from "./../../deps.ts";
2-
export class Encoder {
3-
async encodeFile(filePath: string, to: string, from = "AUTO") {
4-
const byteArray = Deno.readFileSync(filePath);
1+
import { Colors, encoding } from "./../../deps.ts";
2+
import { BasePostprocess } from "./base_postprocess.ts";
3+
4+
export class Encoder extends BasePostprocess {
5+
async execute(argumentList: string[], targetPath: string): Promise<string> {
6+
const byteArray = Deno.readFileSync(targetPath);
57
const encodedByteArray = encoding.default.convert(byteArray, {
6-
to,
7-
from,
8+
to: argumentList[0],
9+
from: "AUTO",
810
});
911
await Deno.writeFile(
10-
filePath,
12+
targetPath,
1113
Uint8Array.from(encodedByteArray),
1214
);
15+
return targetPath;
16+
}
17+
validate(argumentList: string[]) {
18+
if (argumentList.length === 0) {
19+
console.log(
20+
Colors.red("Argument not specified."),
21+
);
22+
this.printUsage();
23+
return false;
24+
} else if (argumentList.length > 1) {
25+
console.log(
26+
Colors.red("error: Too many arguments:"),
27+
Colors.red(this.type + " " + argumentList.join(" ")),
28+
);
29+
this.printUsage();
30+
return false;
31+
}
32+
return true;
1333
}
1434
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { Colors } from "../../deps.ts";
2+
import { Command } from "./command.ts";
3+
import { Encoder } from "./encoder.ts";
4+
import { Unzipper } from "./unzipper.ts";
5+
import { XlsxToCsvConverter } from "./xlsx_to_csv_converter.ts";
6+
7+
export class PostprocessDispatcher {
8+
private encoder;
9+
private unzipper;
10+
private xlsxToCsvConverter;
11+
private command;
12+
constructor() {
13+
this.encoder = new Encoder("encode", ["encoding-to"]);
14+
this.unzipper = new Unzipper("unzip", []);
15+
this.xlsxToCsvConverter = new XlsxToCsvConverter("xlsx-to-csv", []);
16+
this.command = new Command("cmd", ["script"]);
17+
}
18+
async dispatch(type: string, argumentList: string[], targetPath: string) {
19+
if (type === this.encoder.type) {
20+
if (this.encoder.validate(argumentList)) {
21+
const encodingTo = argumentList[0].toUpperCase();
22+
await this.encoder.execute([encodingTo], targetPath);
23+
console.log("Converted encoding to", encodingTo);
24+
} else {
25+
Deno.exit(1);
26+
}
27+
} else if (type === this.unzipper.type) {
28+
if (this.unzipper.validate(argumentList)) {
29+
const targetDir = await this.unzipper.execute([], targetPath);
30+
console.log(`Unzip the file to ${targetDir}`);
31+
} else {
32+
Deno.exit(1);
33+
}
34+
} else if (type === this.xlsxToCsvConverter.type) {
35+
if (this.xlsxToCsvConverter.validate(argumentList)) {
36+
await this.xlsxToCsvConverter.execute([], targetPath);
37+
console.log(`Convert xlsx to csv.`);
38+
} else {
39+
Deno.exit(1);
40+
}
41+
} else if (type === this.command.type) {
42+
const script = argumentList.join(" ");
43+
try {
44+
if (this.command.validate(argumentList)) {
45+
console.log("Execute Command: ", argumentList, targetPath);
46+
const result = await this.command.execute([script], targetPath);
47+
console.log(result);
48+
}
49+
} catch (e) {
50+
console.log(
51+
Colors.red(`Failed to execute the "${script}"\n`),
52+
Colors.red(`${e}`),
53+
);
54+
// Do not `exit` because there are commands that do not correspond when obtained from external dim.json.
55+
}
56+
} else {
57+
console.log(`No support a postprocess '${type}' '${argumentList}'.`);
58+
}
59+
}
60+
}

libs/postprocess/unzipper.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { decompress } from "../../deps.ts";
1+
import { Colors, decompress } from "../../deps.ts";
2+
import { BasePostprocess } from "./base_postprocess.ts";
23

3-
export class Unzipper {
4-
async unzip(targetPath: string) {
4+
export class Unzipper extends BasePostprocess {
5+
async execute(_: string[], targetPath: string): Promise<string> {
56
const splitedPath = targetPath.split("/");
67
const targetDir = splitedPath.slice(0, splitedPath.length - 1).join("/");
78
if (Deno.build.os === "darwin") {
@@ -17,4 +18,15 @@ export class Unzipper {
1718
}
1819
return targetDir;
1920
}
21+
validate(argumentList: string[]) {
22+
if (argumentList.length > 0) {
23+
console.log(
24+
Colors.red("error: Too many arguments:"),
25+
Colors.red(this.type + " " + argumentList.join(" ")),
26+
);
27+
this.printUsage();
28+
return false;
29+
}
30+
return true;
31+
}
2032
}

libs/postprocess/xlsx_converter.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Colors, readXLSX, xlsx } from "../../deps.ts";
2+
import { BasePostprocess } from "./base_postprocess.ts";
3+
4+
export class XlsxToCsvConverter extends BasePostprocess {
5+
async execute(_: string[], targetPath: string): Promise<string> {
6+
const workbook = await readXLSX(targetPath);
7+
const sheetData = workbook.Sheets[workbook.SheetNames[0]];
8+
const csv = xlsx.utils.sheet_to_csv(sheetData);
9+
Deno.writeTextFileSync(targetPath.replace(/\.xlsx$/, ".csv"), csv);
10+
return targetPath;
11+
}
12+
validate(argumentList: string[]) {
13+
if (argumentList.length > 0) {
14+
console.log(
15+
Colors.red("error: Too many arguments:"),
16+
Colors.red(this.type + " " + argumentList.join(" ")),
17+
);
18+
this.printUsage();
19+
return false;
20+
}
21+
return true;
22+
}
23+
}

0 commit comments

Comments
 (0)