1interface GHRelease {
2 tag_name: string;
3}
4
5const decode = (buffer: Uint8Array) => new TextDecoder("utf-8").decode(buffer);
6const decodeTrim = (b: Uint8Array) => decode(b).trimEnd();
7export const run = async (command: string, args: string[]) => {
8 const cmd = Deno.run({
9 cmd: [command, ...args],
10 stdout: "piped",
11 stderr: "piped",
12 });
13 if (!(await cmd.status()).success) {
14 const error = await cmd.stderrOutput().then(decodeTrim);
15 // Known error we can ignore
16 if (error.includes("'allow-unsafe-native-code-during-evaluation'")) {
17 // Extract the target sha256 out of the error
18 const target = " got: sha256:";
19 const match = error
20 .split("\n")
21 .find((l) => l.includes(target))
22 ?.split(target)[1];
23 if (typeof match !== "undefined") {
24 return match;
25 }
26 }
27 throw new Error(error);
28 }
29 return cmd.output().then(decodeTrim);
30};
31
32// Exports
33export const versionRegExp = /\d+\.\d+\.\d+/;
34export const sha256RegExp = /[a-z0-9]{52}|sha256-.{44}/;
35
36export const getExistingVersion = async (filePath: string) =>
37 read(filePath).then(
38 (s) => s.match(genValueRegExp("version", versionRegExp))?.shift() || "",
39 );
40
41export const getLatestVersion = (owner: string, repo: string) =>
42 fetch(`https://api.github.com/repos/${owner}/${repo}/releases`)
43 .then((res) => res.json())
44 .then((res: GHRelease[]) => res[0].tag_name);
45
46// The (?<=) and (?=) allow replace to only change inside
47// Match the regex passed in or empty
48export const genValueRegExp = (key: string, regex: RegExp) =>
49 new RegExp(`(?<=${key} = ")(${regex.source}|)(?=")`);
50
51export const logger = (name: string) =>
52 (...a: any) => console.log(`[${name}]`, ...a);
53
54export const read = Deno.readTextFile;
55export const write = Deno.writeTextFile;