yllaw 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/plugin.js +117 -48
package/package.json
CHANGED
package/src/plugin.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const fs = require('fs-extra');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const { spawn } = require('child_process');
|
|
3
4
|
const simpleGit = require('simple-git');
|
|
4
5
|
const chalk = require('chalk');
|
|
5
6
|
const { getPluginsDir, loadConfig, loadInstalled, saveInstalled } = require('./config');
|
|
@@ -68,6 +69,99 @@ async function findPluginFiles(dir) {
|
|
|
68
69
|
return results;
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Build a plugin entry (.server.lua(u) or folder) to .rbxm using Rojo.
|
|
74
|
+
* Generates a temporary project.json, runs `rojo build`, returns the result.
|
|
75
|
+
* @returns {{ rbxmPath: string, name: string } | null}
|
|
76
|
+
*/
|
|
77
|
+
async function buildToRbxm(entry) {
|
|
78
|
+
let pluginName;
|
|
79
|
+
if (entry.type === 'folder') {
|
|
80
|
+
pluginName = entry.name;
|
|
81
|
+
} else {
|
|
82
|
+
pluginName = entry.name
|
|
83
|
+
.replace(/\.server\.luau$/, '')
|
|
84
|
+
.replace(/\.server\.lua$/, '');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const parentDir = path.dirname(entry.path);
|
|
88
|
+
const entryBasename = path.basename(entry.path);
|
|
89
|
+
const projectPath = path.join(parentDir, `_yllaw_build.project.json`);
|
|
90
|
+
const rbxmPath = path.join(parentDir, `${pluginName}.rbxm`);
|
|
91
|
+
|
|
92
|
+
await fs.writeJson(projectPath, {
|
|
93
|
+
name: pluginName,
|
|
94
|
+
tree: { "$path": entryBasename },
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const success = await new Promise((resolve) => {
|
|
99
|
+
const rojo = spawn('rojo', ['build', projectPath, '-o', rbxmPath], {
|
|
100
|
+
stdio: 'pipe',
|
|
101
|
+
shell: true,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
let stderr = '';
|
|
105
|
+
rojo.stderr.on('data', (data) => { stderr += data.toString(); });
|
|
106
|
+
rojo.on('close', (code) => {
|
|
107
|
+
if (code !== 0 && stderr) {
|
|
108
|
+
log.error(`Rojo build failed: ${stderr.trim()}`);
|
|
109
|
+
}
|
|
110
|
+
resolve(code === 0);
|
|
111
|
+
});
|
|
112
|
+
rojo.on('error', () => resolve(false));
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (!success) return null;
|
|
116
|
+
return { rbxmPath, name: `${pluginName}.rbxm` };
|
|
117
|
+
} finally {
|
|
118
|
+
await fs.remove(projectPath);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Install plugin entries to the plugins directory.
|
|
124
|
+
* For .rbxm files: copy directly.
|
|
125
|
+
* For .server.lua(u) / folders: build to .rbxm via Rojo, fallback to direct copy.
|
|
126
|
+
* @returns {Array} installed file records
|
|
127
|
+
*/
|
|
128
|
+
async function installEntries(pluginEntries, pluginsDir, logPrefix = '') {
|
|
129
|
+
const installedFiles = [];
|
|
130
|
+
|
|
131
|
+
for (const entry of pluginEntries) {
|
|
132
|
+
if (entry.type === 'file' && entry.name.endsWith('.rbxm')) {
|
|
133
|
+
const dest = path.join(pluginsDir, entry.name);
|
|
134
|
+
await fs.copy(entry.path, dest, { overwrite: true });
|
|
135
|
+
installedFiles.push({ type: 'file', name: entry.name });
|
|
136
|
+
log.ok(`${logPrefix}${entry.name} -> ${pluginsDir}`);
|
|
137
|
+
} else {
|
|
138
|
+
const result = await buildToRbxm(entry);
|
|
139
|
+
if (result) {
|
|
140
|
+
const dest = path.join(pluginsDir, result.name);
|
|
141
|
+
await fs.copy(result.rbxmPath, dest, { overwrite: true });
|
|
142
|
+
installedFiles.push({ type: 'file', name: result.name });
|
|
143
|
+
log.ok(`${logPrefix}${entry.name} -> ${result.name} -> ${pluginsDir}`);
|
|
144
|
+
await fs.remove(result.rbxmPath);
|
|
145
|
+
} else {
|
|
146
|
+
log.warn(`Rojo build failed for ${entry.name}, copying as-is`);
|
|
147
|
+
if (entry.type === 'folder') {
|
|
148
|
+
const dest = path.join(pluginsDir, entry.name);
|
|
149
|
+
await fs.copy(entry.path, dest, { overwrite: true });
|
|
150
|
+
await fs.remove(path.join(dest, '.git'));
|
|
151
|
+
installedFiles.push({ type: 'folder', name: entry.name });
|
|
152
|
+
} else {
|
|
153
|
+
const dest = path.join(pluginsDir, entry.name);
|
|
154
|
+
await fs.copy(entry.path, dest, { overwrite: true });
|
|
155
|
+
installedFiles.push({ type: 'file', name: entry.name });
|
|
156
|
+
}
|
|
157
|
+
log.ok(`${logPrefix}${entry.name} -> ${pluginsDir}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return installedFiles;
|
|
163
|
+
}
|
|
164
|
+
|
|
71
165
|
/**
|
|
72
166
|
* Parse git spec: "https://example.com/repo.git@version"
|
|
73
167
|
*/
|
|
@@ -180,21 +274,7 @@ async function installPlugin(name, version, sources) {
|
|
|
180
274
|
const pluginsDir = getPluginsDir();
|
|
181
275
|
await fs.ensureDir(pluginsDir);
|
|
182
276
|
|
|
183
|
-
const installedFiles =
|
|
184
|
-
for (const entry of pluginEntries) {
|
|
185
|
-
if (entry.type === 'folder') {
|
|
186
|
-
const dest = path.join(pluginsDir, entry.name);
|
|
187
|
-
await fs.copy(entry.path, dest, { overwrite: true });
|
|
188
|
-
await fs.remove(path.join(dest, '.git'));
|
|
189
|
-
installedFiles.push({ type: 'folder', name: entry.name });
|
|
190
|
-
log.ok(`${entry.name}/ -> ${pluginsDir}`);
|
|
191
|
-
} else {
|
|
192
|
-
const dest = path.join(pluginsDir, entry.name);
|
|
193
|
-
await fs.copy(entry.path, dest, { overwrite: true });
|
|
194
|
-
installedFiles.push({ type: 'file', name: entry.name });
|
|
195
|
-
log.ok(`${entry.name} -> ${pluginsDir}`);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
277
|
+
const installedFiles = await installEntries(pluginEntries, pluginsDir);
|
|
198
278
|
|
|
199
279
|
// Update installed.json
|
|
200
280
|
const installed = await loadInstalled();
|
|
@@ -237,21 +317,7 @@ async function installPluginFromGitSpec(name, spec, options = {}) {
|
|
|
237
317
|
if (pluginEntries.length > 0) {
|
|
238
318
|
const pluginsDir = getPluginsDir();
|
|
239
319
|
await fs.ensureDir(pluginsDir);
|
|
240
|
-
const installedFiles = [];
|
|
241
|
-
for (const entry of pluginEntries) {
|
|
242
|
-
if (entry.type === 'folder') {
|
|
243
|
-
const dest = path.join(pluginsDir, entry.name);
|
|
244
|
-
await fs.copy(entry.path, dest, { overwrite: true });
|
|
245
|
-
await fs.remove(path.join(dest, '.git'));
|
|
246
|
-
installedFiles.push({ type: 'folder', name: entry.name });
|
|
247
|
-
log.ok(`[DEV] ${entry.name}/ -> ${pluginsDir}`);
|
|
248
|
-
} else {
|
|
249
|
-
const dest = path.join(pluginsDir, entry.name);
|
|
250
|
-
await fs.copy(entry.path, dest, { overwrite: true });
|
|
251
|
-
installedFiles.push({ type: 'file', name: entry.name });
|
|
252
|
-
log.ok(`[DEV] ${entry.name} -> ${pluginsDir}`);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
320
|
+
const installedFiles = await installEntries(pluginEntries, pluginsDir, '[DEV] ');
|
|
255
321
|
const installed = await loadInstalled();
|
|
256
322
|
installed[name] = {
|
|
257
323
|
version: displayRef,
|
|
@@ -278,21 +344,7 @@ async function installPluginFromGitSpec(name, spec, options = {}) {
|
|
|
278
344
|
const pluginsDir = getPluginsDir();
|
|
279
345
|
await fs.ensureDir(pluginsDir);
|
|
280
346
|
|
|
281
|
-
const installedFiles =
|
|
282
|
-
for (const entry of pluginEntries) {
|
|
283
|
-
if (entry.type === 'folder') {
|
|
284
|
-
const dest = path.join(pluginsDir, entry.name);
|
|
285
|
-
await fs.copy(entry.path, dest, { overwrite: true });
|
|
286
|
-
await fs.remove(path.join(dest, '.git'));
|
|
287
|
-
installedFiles.push({ type: 'folder', name: entry.name });
|
|
288
|
-
log.ok(`${entry.name}/ -> ${pluginsDir}`);
|
|
289
|
-
} else {
|
|
290
|
-
const dest = path.join(pluginsDir, entry.name);
|
|
291
|
-
await fs.copy(entry.path, dest, { overwrite: true });
|
|
292
|
-
installedFiles.push({ type: 'file', name: entry.name });
|
|
293
|
-
log.ok(`${entry.name} -> ${pluginsDir}`);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
347
|
+
const installedFiles = await installEntries(pluginEntries, pluginsDir);
|
|
296
348
|
|
|
297
349
|
// Update installed.json
|
|
298
350
|
const installed = await loadInstalled();
|
|
@@ -419,14 +471,31 @@ async function updatePlugin(name) {
|
|
|
419
471
|
return false;
|
|
420
472
|
}
|
|
421
473
|
|
|
422
|
-
if
|
|
474
|
+
// Check if plugin files still exist on disk
|
|
475
|
+
const pluginsDir = getPluginsDir();
|
|
476
|
+
let missing = false;
|
|
477
|
+
if (entry.files) {
|
|
478
|
+
for (const fileEntry of entry.files) {
|
|
479
|
+
const fileName = typeof fileEntry === 'string' ? fileEntry : fileEntry.name;
|
|
480
|
+
if (!await fs.pathExists(path.join(pluginsDir, fileName))) {
|
|
481
|
+
missing = true;
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (latestTag === entry.version && !missing) {
|
|
423
488
|
log.info(`${name}: up to date (${entry.version})`);
|
|
424
489
|
return true;
|
|
425
490
|
}
|
|
426
491
|
|
|
427
|
-
|
|
492
|
+
if (missing) {
|
|
493
|
+
log.info(`${name}: files missing, reinstalling (${latestTag})`);
|
|
494
|
+
} else {
|
|
495
|
+
log.ok(`${name}: ${entry.version} -> ${latestTag}`);
|
|
496
|
+
}
|
|
428
497
|
|
|
429
|
-
// Reinstall
|
|
498
|
+
// Reinstall
|
|
430
499
|
const spec = `${entry.url}@${latestTag}`;
|
|
431
500
|
return await installPluginFromGitSpec(name, spec);
|
|
432
501
|
}
|