/[sudobot]/branches/6.x/scripts/extensions.js
ViewVC logotype

Contents of /branches/6.x/scripts/extensions.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 577 - (show annotations)
Mon Jul 29 18:52:37 2024 UTC (8 months ago) by rakinar2
File MIME type: text/javascript
File size: 8814 byte(s)
chore: add old version archive branches (2.x to 9.x-dev)
1 #!/usr/bin/env node
2
3 /*
4 * This file is part of SudoBot.
5 *
6 * Copyright (C) 2021-2023 OSN Developers.
7 *
8 * SudoBot is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * SudoBot is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with SudoBot. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 require("module-alias/register");
23 const chalk = require("chalk");
24 const { spawnSync } = require("child_process");
25 const { existsSync, lstatSync, readdirSync, readFileSync, writeFileSync, rmSync } = require("fs");
26 const path = require("path");
27 const { chdir, cwd } = require("process");
28
29 const extensionsPath = path.resolve(__dirname, "../extensions");
30
31 function error(...args) {
32 console.error(...args);
33 process.exit(-1);
34 }
35
36 if (!existsSync(extensionsPath)) {
37 error("You're not using any extension! To get started, create an `extensions` folder in the project root.");
38 }
39
40 function getRecuriveJavaScriptFiles(dir) {
41 const files = readdirSync(dir);
42 const flat = [];
43
44 for (const fileName of files) {
45 const file = path.join(dir, fileName);
46 const isDirectory = lstatSync(file).isDirectory();
47
48 if (isDirectory) {
49 flat.push(...getRecuriveJavaScriptFiles(file));
50 continue;
51 }
52
53 if (!file.endsWith(".js")) {
54 continue;
55 }
56
57 flat.push(file);
58 }
59
60 return flat;
61 }
62
63 function readMeta(extensionName, extensionDirectory) {
64 const metadataFile = path.join(extensionDirectory, "extension.json");
65
66 if (!existsSync(metadataFile)) {
67 error(`Extension ${extensionName} does not have a "extension.json" file!`);
68 }
69
70 const metadata = JSON.parse(readFileSync(metadataFile, { encoding: "utf-8" }));
71 return metadata;
72 }
73
74 async function writeCacheIndex() {
75 const extensionsOutputArray = [];
76 const meta = [];
77 const extensions = readdirSync(extensionsPath);
78
79 for await (const extensionName of extensions) {
80 const extensionDirectory = path.resolve(extensionsPath, extensionName);
81 const isDirectory = lstatSync(extensionDirectory).isDirectory();
82
83 if (!isDirectory) {
84 continue;
85 }
86
87 console.log("Found extension: ", extensionName);
88
89 // const metadataFile = path.join(extensionDirectory, "extension.json");
90
91 // if (!existsSync(metadataFile)) {
92 // error(`Extension ${extensionName} does not have a "extension.json" file!`);
93 // }
94
95 // const metadata = JSON.parse(readFileSync(metadataFile, { encoding: "utf-8" }));
96 // const {
97 // main_directory = "./build",
98 // commands = `./${main_directory}/commands`,
99 // events = `./${main_directory}/events`,
100 // main = `./${main_directory}/index.js`,
101 // language = "typescript"
102 // } = metadata;
103
104 const {
105 main_directory = "./build",
106 commands = `./${main_directory}/commands`,
107 events = `./${main_directory}/events`,
108 main = `./${main_directory}/index.js`,
109 language = "typescript"
110 } = readMeta(extensionName, extensionDirectory);
111
112 const extensionPath = path.join(extensionDirectory, main);
113
114 const imported = await require(extensionPath);
115 const { default: ExtensionClass } = imported.__esModule ? imported : { default: imported };
116 const extension = new ExtensionClass(this.client);
117 let commandPaths = await extension.commands();
118 let eventPaths = await extension.events();
119
120 if (commandPaths === null) {
121 const directory = path.join(__dirname, "../extensions", extensionName, commands);
122
123 if (existsSync(directory)) {
124 commandPaths = getRecuriveJavaScriptFiles(directory);
125 }
126 }
127
128 if (eventPaths === null) {
129 const directory = path.join(__dirname, "../extensions", extensionName, events);
130
131 if (existsSync(directory)) {
132 eventPaths = getRecuriveJavaScriptFiles(directory);
133 }
134 }
135
136 extensionsOutputArray.push({
137 name: extensionName,
138 entry: extensionPath,
139 commands: commandPaths ?? [],
140 events: eventPaths ?? []
141 });
142
143 meta.push({
144 language
145 });
146 }
147
148 console.log("Overview of the extensions: ");
149 console.table(
150 extensionsOutputArray.map((e, i) => ({
151 name: e.name,
152 entry: e.entry.replace(path.resolve(__dirname, "../extensions"), "{ROOT}"),
153 commands: e.commands.length,
154 events: e.events.length,
155 language: meta[i].language
156 }))
157 );
158
159 const indexFile = path.join(__dirname, "../extensions/index.json");
160
161 writeFileSync(
162 indexFile,
163 JSON.stringify(
164 {
165 extensions: extensionsOutputArray
166 },
167 null,
168 4
169 )
170 );
171
172 console.log("Wrote cache index file: ", indexFile);
173 console.warn(
174 "Note: If you're getting import errors after caching extensions, please try first by removing or rebuilding them."
175 );
176 }
177
178 const MAX_CHARS = 7;
179
180 function actionLog(action, description) {
181 console.log(
182 chalk.green.bold(`${action}${action.length >= MAX_CHARS ? "" : " ".repeat(MAX_CHARS - action.length)} `),
183 description
184 );
185 }
186
187 function spawnSyncCatchExit(...args) {
188 actionLog("RUN", args[0]);
189 const { status } = spawnSync(...args);
190 if (status !== 0) process.exit(status);
191 }
192
193 async function buildExtensions() {
194 const startTime = Date.now();
195 const extensions = readdirSync(extensionsPath);
196 const workingDirectory = cwd();
197
198 for await (const extensionName of extensions) {
199 const extensionDirectory = path.resolve(extensionsPath, extensionName);
200 const isDirectory = lstatSync(extensionDirectory).isDirectory();
201
202 if (!isDirectory) {
203 continue;
204 }
205
206 chdir(path.join(extensionsPath, extensionName));
207
208 actionLog("DEPS", extensionName);
209 spawnSyncCatchExit("npm install -D", {
210 encoding: "utf-8",
211 shell: true,
212 stdio: "inherit"
213 });
214
215 actionLog("RELINK", extensionName);
216 spawnSyncCatchExit(`npm link --save ${path.relative(cwd(), path.resolve(__dirname, ".."))}`, {
217 encoding: "utf-8",
218 shell: true,
219 stdio: "inherit"
220 });
221
222 actionLog("BUILD", extensionName);
223 const { build_command } = readMeta(extensionName, extensionDirectory);
224
225 if (!build_command) {
226 console.log(chalk.cyan.bold("INFO "), "This extension doesn't require building.");
227 continue;
228 }
229
230 spawnSyncCatchExit(build_command, {
231 encoding: "utf-8",
232 shell: true,
233 stdio: "inherit"
234 });
235 }
236
237 actionLog("SUCCESS", `in ${((Date.now() - startTime) / 1000).toFixed(2)}s, built ${extensions.length} extensions`);
238 chdir(workingDirectory);
239 }
240
241 if (process.argv.includes("--clear-cache") || process.argv.includes("--clean") || process.argv.includes("--delcache")) {
242 const indexFile = path.join(__dirname, "../extensions/index.json");
243
244 if (!existsSync(indexFile)) {
245 error("No cached index file found!");
246 }
247
248 rmSync(indexFile);
249 console.log("Removed cached index file: ", indexFile);
250 } else if (process.argv.includes("--cache") || process.argv.includes("--index")) {
251 console.time("Finished in");
252 console.log("Creating cache index for all the installed extensions");
253 writeCacheIndex()
254 .then(() => console.timeEnd("Finished in"))
255 .catch(e => {
256 console.log(e);
257 console.timeEnd("Finished in");
258 });
259 } else if (process.argv.includes("--build")) {
260 console.log("Building installed extensions");
261 buildExtensions().catch(e => {
262 console.log(e);
263 process.exit(-1);
264 });
265 } else {
266 console.log("Usage:");
267 console.log(" node extensions.js <options>\n");
268 console.log("Options:");
269 console.log(" --build | Builds all the installed extensions, if needed.");
270 console.log(" --cache | Creates cache indexes for installed extensions, to improve the startup time.");
271 console.log(" --clean | Clears all installed extension cache.");
272 process.exit(-1);
273 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26