-
Notifications
You must be signed in to change notification settings - Fork 19
/
build.js
151 lines (133 loc) · 4.69 KB
/
build.js
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
"use strict";
const events = require("events");
const fs = require("fs-extra");
const JSZip = require("jszip");
const klaw = require("klaw");
const path = require("path");
const yargs = require("yargs");
const child_process = require("child_process");
const util = require("util");
async function exec(file, args) {
let child = child_process.spawn(file, args, { shell: false, stdio: 'inherit' });
await events.once(child, "exit");
if (child.exitCode !== 0) {
throw new Error(`Process exited with code ${child.exitCode}`);
}
}
async function main() {
const args = yargs
.scriptName("build")
.options({
'render': { describe: "Render assets", type: 'boolean', default: false },
'post': { describe: "Post process assets", type: 'boolean', default: false },
'clean': { describe: "Remove previous builds", type: 'boolean', default: false },
'build': { describe: "Build mod(s)", type: 'boolean', default: true },
'pack': { describe: "Pack into zip file", type: 'boolean', default: true },
'source-dir': { describe: "Path to mod source directory", nargs: 1, type: 'string', default: "src" },
'output-dir': { describe: "Path to output built mod(s)", nargs: 1, type: 'string', default: "dist" },
'blender-path': { describe: "Path to blender", type: 'string', default: 'blender' },
})
.argv
;
// Warn on modified files being present in the src/ directory.
let status = await util.promisify(child_process.exec)("git status --porcelain");
for (let line of status.stdout.split("\n")) {
if (line.slice(3, 6).startsWith("src")) {
console.warn(`Warning: ${line.slice(3)} is unclean`);
}
}
if (args.render) {
await exec(
args.blenderPath,
[
"--background",
"--python-exit-code", "1",
path.join("assets", "model.blend"),
"--python", path.join("assets", "render.py")
]
);
}
if (args.post) {
await exec(
process.platform === 'win32' ? "py" : "python",
["post.py"],
);
}
let info = JSON.parse(await fs.readFile(path.join(args.sourceDir, "info.json")));
if (args.clean) {
let splitter = /^(.*)_(\d+\.\d+\.\d+)(\.zip)?$/
for (let entry of await fs.readdir(args.outputDir)) {
let match = splitter.exec(entry);
if (match) {
let [, name, version] = match;
if (name === info.name) {
let modPath = path.join(args.outputDir, entry);
console.log(`Removing ${modPath}`);
await fs.remove(modPath);
}
}
}
}
if (info.variants) {
for (let [variant, variantOverrides] of Object.entries(info.variants)) {
let variantInfo = {
...info,
...variantOverrides,
}
delete variantInfo.variants;
await buildMod(args, variantInfo);
}
} else {
await buildMod(args, info);
}
}
async function buildMod(args, info) {
if (args.build) {
await fs.ensureDir(args.outputDir);
let modName = `${info.name}_${info.version}`;
if (args.pack) {
let zip = new JSZip();
let walker = klaw(args.sourceDir)
.on('data', item => {
if (item.stats.isFile()) {
// On Windows the path created uses backslashes as the directory sepparator
// but the zip file needs to use forward slashes. We can't use the posix
// version of relative here as it doesn't work with Windows style paths.
let basePath = path.relative(args.sourceDir, item.path).replace(/\\/g, "/");
zip.file(path.posix.join(modName, basePath), fs.createReadStream(item.path));
}
});
await events.once(walker, 'end');
for (let [fileName, pathParts] of Object.entries(info.additional_files || {})) {
let filePath = path.join(args.sourceDir, ...pathParts);
if (!await fs.pathExists(filePath)) {
throw new Error(`Additional file ${filePath} does not exist`);
}
zip.file(path.posix.join(modName, fileName), fs.createReadStream(filePath));
}
delete info.additional_files;
zip.file(path.posix.join(modName, "info.json"), JSON.stringify(info, null, 4));
let modPath = path.join(args.outputDir, `${modName}.zip`);
console.log(`Writing ${modPath}`);
let writeStream = zip.generateNodeStream().pipe(fs.createWriteStream(modPath));
await events.once(writeStream, 'finish');
} else {
let modDir = path.join(args.outputDir, modName);
if (await fs.exists(modDir)) {
console.log(`Removing existing build ${modDir}`);
await fs.remove(modDir);
}
console.log(`Building ${modDir}`);
await fs.copy(args.sourceDir, modDir);
for (let [fileName, pathParts] of Object.entries(info.additional_files) || []) {
let filePath = path.join(...pathParts);
await fs.copy(filePath, path.join(modDir, fileName));
}
delete info.additional_files;
await fs.writeFile(path.join(modDir, "info.json"), JSON.stringify(info, null, 4));
}
}
}
if (module === require.main) {
main().catch(err => { console.log(err) });
}