-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcli.ts
More file actions
196 lines (183 loc) · 5.11 KB
/
cli.ts
File metadata and controls
196 lines (183 loc) · 5.11 KB
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
import { Command } from "https://deno.land/x/cliffy@v0.20.1/command/mod.ts";
import { walkSync } from "https://deno.land/std/fs/walk.ts";
const VERSION = "0.1.0";
const ARCHIVE_URL = "https://github.com/ReMod-Games/SkyChamps/archive/refs/";
const RELEASES_URL = "https://github.com/ReMod-Games/SkyChamps/releases/latest";
const setupCommand = new Command()
.name("Setup")
.description("Setup the full repo for the game server")
.version(VERSION)
.option("-D, --database [path:string]", "Set database path", {
required: false,
requiredValue: true,
default: "./database.db",
})
.option("-C, --cards [path:string]", "Set card json file path", {
required: false,
requiredValue: true,
default: "./cards.json",
})
.option("--http-port [port:number]", "http port to use", {
required: false,
requiredValue: true,
default: 8000,
})
.option("--ws-port [port:number]", "Websocket port to use", {
required: false,
requiredValue: true,
default: 8001,
})
.option("--cache, [enabled:boolean]", "Enable caching of frontend code", {
required: false,
default: true,
})
.option("-L, --log [path:string]", "Logging to file", {
required: false,
requiredValue: true,
default: "./logs",
})
.action(setup);
const runCommand = new Command()
.name("Run")
.description("Run the game server")
.version(VERSION)
.option("-D, --debug", "Enable debug mode")
.action(run);
const updateCommand = new Command()
.name("Update")
.description("update the repo to the latest version!")
.version(VERSION)
.option(
"--git",
"Download the latest git tag",
)
.option(
"-V, --version [version:string]",
"Download a specific version (Mutually exclusive with --git)",
{
required: false,
requiredValue: true,
default: "latest",
},
)
.action(update);
await new Command()
.name("SkyChamps CLI")
.version(VERSION)
.description("CLI for SkyChamps game server")
.command("setup", setupCommand)
.command("run", runCommand)
.command("update", updateCommand)
.parse(Deno.args);
async function update(options: Record<string, string>) {
let tag = options.version;
if (options.version !== "latest" && options.git) {
console.error("--version and --git are mutually exclusive!");
Deno.exit(1);
}
if (options.git) {
tag = "/heads/main";
}
if (options.version === "latest" && !options.git) {
console.log("Retrieving latest release");
tag = await getLatestTag();
}
const tempFile = await downloadLatestArchive(
tag === "/heads/main" ? tag : "tags/" + tag,
);
const tempDir = Deno.makeTempDirSync();
await unzip(tempFile, tempDir);
const slash = Deno.build.os === "windows" ? "\\" : "/";
await move(
`${tempDir}${slash}SkyChamps-${tag === "/heads/main" ? "main" : tag}`,
);
}
async function run(options: Record<string, unknown>) {
const debug = options.debug ? "DEBUG" : "";
const args =
`deno run --no-check --unstable --allow-read --allow-write --allow-net mod.ts ${debug}`
.split(" ");
const p = Deno.run({
stdout: "inherit",
stderr: "inherit",
stdin: "inherit",
cmd: args,
});
await p.status();
}
async function setup(options: Record<string, unknown>) {
try {
Deno.openSync("./mod.ts", { create: false, createNew: false });
} catch {
console.log("First time setup detected!");
await update({ version: "latest" });
}
console.log("Generating config file");
const config = {
server: {
http: {
port: options.httpPort,
caching: options.cache,
otf: options.otfCompiling,
},
websocket: {
port: options.wsPort,
},
},
database: {
path: options.database,
},
cards: {
path: options.cards,
},
logging: {
dir: options.log,
},
};
Deno.writeTextFileSync(
"./config.json",
JSON.stringify(config, undefined, 2),
);
}
async function downloadLatestArchive(tag: string): Promise<string> {
console.log("Downloading release: " + tag);
const s = await fetch(
`${ARCHIVE_URL}${tag[0] === "/" ? tag.replace("/", "") : tag}.zip`,
);
const buff = await s.arrayBuffer();
const tempFile = await Deno.makeTempFile() + ".zip";
console.log({ tempFile });
await Deno.writeFile(tempFile, new Uint8Array(buff));
return tempFile;
}
async function move(tempDir: string) {
console.log("Writing to disk");
const cwd = Deno.cwd();
for await (const entry of walkSync(tempDir)) {
const nPath = entry.path.replace(tempDir, cwd);
if (entry.isDirectory) Deno.mkdirSync(nPath, { recursive: true });
if (entry.isFile) Deno.copyFileSync(entry.path, nPath);
}
}
async function unzip(file: string, tempDir: string) {
console.log("Unzipping archive");
const p = Deno.run({
cmd: Deno.build.os === "windows"
? [
"PowerShell",
"Expand-Archive",
"-Path",
file,
"-DestinationPath",
tempDir,
]
: ["unzip", "-o", file, "-d", tempDir],
stdout: "null",
stderr: "null",
});
await p.status();
}
async function getLatestTag() {
const f = await fetch(RELEASES_URL);
return f.url.split("/").pop()!;
}