forked from nawbc/command-not-found
-
Notifications
You must be signed in to change notification settings - Fork 0
/
generate-db.js
executable file
·125 lines (118 loc) · 4.36 KB
/
generate-db.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
#!/usr/bin/env node
const fs = require("node:fs");
const http2 = require("node:http2");
const path = require("node:path");
const zlib = require("node:zlib");
const repositoryURL = "https://packages-cf.termux.dev/apt";
// TODO(@thunder-coding): Do not hardcode list of known architectures.
const archs = ["aarch64", "arm", "i686", "x86_64"];
const scriptdir = process.env["TERMUX_SCRIPTDIR"];
const defaultPrefixRegExp = /^data\/data\/com\.termux\/files\/usr/g;
const prefix = process.env["TERMUX_PREFIX"];
if (scriptdir === undefined) {
throw new Error("TERMUX_SCRIPTDIR environment variable is not defined");
}
if (prefix === undefined) {
throw new Error("TERMUX_PREFIX environment variable is not defined");
}
const binPrefix = prefix.substring(1) + "/bin/";
const repoBuffer = fs.readFileSync(path.join(scriptdir, "repo.json"));
const repoJSON = JSON.parse(repoBuffer);
const http2session = http2.connect(repositoryURL);
const connectedPromise = new Promise((resolve, reject) => {
http2session.on("error", (err) => {
http2session.destroy();
reject(err);
});
http2session.on("connect", () => {
resolve();
});
});
const fetchFile = (url) => new Promise((resolve, reject) => {
if (http2session.destroyed) {
reject(new Error(`http2session has been destroyed`));
return;
}
connectedPromise.then(() => {
url = new URL(url);
let req = http2session.request({
[http2.constants.HTTP2_HEADER_METHOD]: http2.constants.HTTP2_METHOD_GET,
[http2.constants.HTTP2_HEADER_PATH]: `${url.pathname}${url.search}`,
}).end();
req.on("error", (err) => {
req.destroy();
reject(err);
});
req.on("response", (headers, flags) => {
const respStatusCode = headers[http2.constants.HTTP2_HEADER_STATUS];
if (respStatusCode != 200) {
req.destroy();
reject(new Error(`${url} returned ${respStatusCode}`));
}
});
let rawData = [];
req.on("data", (chunk) => {
rawData.push(chunk);
});
req.on("end", () => {
req.destroy();
resolve(Buffer.concat(rawData));
});
}).catch((e) => {
reject(e);
});
});
const promises = [];
Object.keys(repoJSON).forEach((repo_path) => {
const repo = repoJSON[repo_path];
archs.forEach((arch) => {
let reqUrl = `${repositoryURL}/${repo.name}/dists/${repo.distribution}/Contents-${arch}.gz`;
promises.push(fetchFile(reqUrl).then((rawBuffer) => {
let binMap = {};
let ungzipped = zlib.gunzipSync(rawBuffer).toString();
let lines = ungzipped
.split("\n")
.map(s => s.replace(defaultPrefixRegExp, prefix.substring(1)));
let linesContainingPathToBinaries = lines
.filter((line) => {
return line.startsWith(binPrefix);
});
linesContainingPathToBinaries.forEach((line) => {
const [pathToBinary, packageNames] = line.split(" ");
const binary = pathToBinary.substring(
pathToBinary.lastIndexOf("/") + 1
);
const packages = packageNames.split(",");
packages.forEach((packageName) => {
if (binMap[packageName] === undefined) {
binMap[packageName] = [];
}
binMap[packageName].push(binary);
});
});
const unjoinedContent = [];
Object.keys(binMap)
.sort()
.forEach((packageName) => {
unjoinedContent.push(`"${packageName}",\n`);
binMap[packageName].sort().forEach((packageName) => {
unjoinedContent.push(`" ${packageName}",\n`);
});
});
const content = unjoinedContent.join("");
const headerFile = `commands-${arch}-${repo.name}.h`;
if (fs.existsSync(headerFile)) {
fs.rmSync(headerFile);
}
if (content.replace(/\n/g, "") === "") throw new Error(`content is empty`);
const encoding = "utf-8";
fs.writeFileSync(headerFile, content, { encoding: encoding });
if (fs.readFileSync(headerFile, { encoding: encoding }) !== content) throw new Error(`error writting to ${headerFile}`);
console.log(`${path.basename(__filename)}: downloaded from ${reqUrl} and then written to ${headerFile}`);
}).catch((e) => {
console.error(`${path.basename(__filename)}: error during/after downloading from ${reqUrl}`, e);
throw e;
}));
});
});
Promise.allSettled(promises).then((results) => process.exit(results.find((result) => result.status !== "fulfilled") == null ? 0 : -1));