-
Notifications
You must be signed in to change notification settings - Fork 24
/
export_scripts.ts
100 lines (95 loc) · 2.92 KB
/
export_scripts.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { ConfigData } from "./load_config.ts";
import { validateConfigData } from "./validate_config_data.ts";
import { validateScript } from "./validate_script.ts";
import { isWindows, OneOrMore, makeFileExecutable } from "./util.ts";
import { normalizeScript } from "./normalize_script.ts";
import { CompoundCommandItem } from "./command.ts";
import { log } from "./logger.ts";
import { isParallel } from "./command.ts";
import { buildCommandString } from "./build_command_string.ts";
import { escape } from "./util.ts";
import {
path,
existsSync,
readFileStrSync,
writeFileStr,
moveSync,
ensureDirSync,
} from "../deps.ts";
const VR_MARK = "Generated by velociraptor";
export async function exportScripts(
configData: ConfigData | null,
scripts: string[],
outDir: string = "bin",
) {
validateConfigData(configData);
const { cwd, config } = configData as ConfigData;
const outDirPath = path.isAbsolute(outDir) ? outDir : path.join(cwd, outDir);
ensureDirSync(outDirPath);
if (!scripts || scripts.length < 1) {
scripts = Object.keys(config.scripts);
}
await Promise.all(
scripts.map(async (script) => {
validateScript(script, config);
const scriptDef = config.scripts[script];
const { scripts, ...rootConfig } = config;
const commands = normalizeScript(scriptDef, rootConfig);
const content = generateExecutableFile(commands);
if (content) {
const filePath = path.join(outDirPath, script);
if (
existsSync(filePath) &&
!readFileStrSync(filePath).includes(VR_MARK)
) {
moveSync(filePath, `${filePath}.bkp`);
}
await writeFileStr(filePath, content);
makeFileExecutable(filePath);
}
}),
);
}
function generateExecutableFile(commands: CompoundCommandItem[]) {
if (isWindows) {
log.warning("Scripts exporting only supports sh.");
}
return `#!/bin/sh
# ${VR_MARK}
${exportCommands(commands)}
`;
}
function exportCommands(commands: CompoundCommandItem[]): string {
const _exportCommands = (
commands: OneOrMore<CompoundCommandItem>,
doGroup: boolean = false,
): string => {
if (!commands) return "";
if (Array.isArray(commands)) {
let res = commands.map((c) => _exportCommands(c, commands.length > 1))
.join(" && ");
if (doGroup) res = `( ${res} )`;
return res;
} else {
if (isParallel(commands)) {
return `( ${
commands.pll.map((c) => _exportCommands(c, true)).join(" & ")
}; wait )`;
}
const cmd = commands;
let res = "";
if (cmd.env) {
const envVars = Object.entries(cmd.env);
if (envVars.length > 0) {
res += envVars
.map(([key, val]) => `${key}="${escape(val, '"')}"`)
.join(" ") + " ";
}
}
res += buildCommandString(cmd) + ' "$@"';
if (doGroup) res = `( ${res} )`;
return res;
}
};
return _exportCommands(commands);
}