Skip to content

Commit 2ee5f73

Browse files
Fix Install button not appearing for VM and tools scripts
- Update checkScriptExists to preserve subdirectory structure for tools and VM scripts - Set ctExists=true for tools and VM scripts when files exist (not just CT scripts) - Add missing compareScriptContent method to JavaScript version - Remove all VW script references as they don't exist - Fixes issue where Install button only showed Load Script button after downloading VM/tools scripts
1 parent 881456e commit 2ee5f73

File tree

1 file changed

+142
-21
lines changed

1 file changed

+142
-21
lines changed

src/server/services/scriptDownloader.js

Lines changed: 142 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Real JavaScript implementation for script downloading
22
import { join } from 'path';
3-
import { writeFile, mkdir, access } from 'fs/promises';
3+
import { writeFile, mkdir, access, readFile } from 'fs/promises';
44

55
export class ScriptDownloaderService {
66
constructor() {
@@ -112,16 +112,6 @@ export class ScriptDownloaderService {
112112
await this.ensureDirectoryExists(join(this.scriptsDirectory, finalTargetDir));
113113
filePath = join(this.scriptsDirectory, finalTargetDir, fileName);
114114
await writeFile(filePath, content, 'utf-8');
115-
} else if (scriptPath.startsWith('vw/')) {
116-
targetDir = 'vw';
117-
// Preserve subdirectory structure for VW scripts
118-
const subPath = scriptPath.replace('vw/', '');
119-
const subDir = subPath.includes('/') ? subPath.substring(0, subPath.lastIndexOf('/')) : '';
120-
finalTargetDir = subDir ? join(targetDir, subDir) : targetDir;
121-
// Ensure the subdirectory exists
122-
await this.ensureDirectoryExists(join(this.scriptsDirectory, finalTargetDir));
123-
filePath = join(this.scriptsDirectory, finalTargetDir, fileName);
124-
await writeFile(filePath, content, 'utf-8');
125115
} else {
126116
// Handle other script types (fallback to ct directory)
127117
targetDir = 'ct';
@@ -201,12 +191,6 @@ export class ScriptDownloaderService {
201191
const subDir = subPath.includes('/') ? subPath.substring(0, subPath.lastIndexOf('/')) : '';
202192
finalTargetDir = subDir ? join(targetDir, subDir) : targetDir;
203193
filePath = join(this.scriptsDirectory, finalTargetDir, fileName);
204-
} else if (scriptPath.startsWith('vw/')) {
205-
targetDir = 'vw';
206-
const subPath = scriptPath.replace('vw/', '');
207-
const subDir = subPath.includes('/') ? subPath.substring(0, subPath.lastIndexOf('/')) : '';
208-
finalTargetDir = subDir ? join(targetDir, subDir) : targetDir;
209-
filePath = join(this.scriptsDirectory, finalTargetDir, fileName);
210194
} else {
211195
targetDir = 'ct';
212196
finalTargetDir = targetDir;
@@ -244,23 +228,39 @@ export class ScriptDownloaderService {
244228

245229
if (fileName) {
246230
let targetDir;
231+
let finalTargetDir;
232+
let filePath;
233+
247234
if (scriptPath.startsWith('ct/')) {
248235
targetDir = 'ct';
236+
finalTargetDir = targetDir;
237+
filePath = join(this.scriptsDirectory, targetDir, fileName);
249238
} else if (scriptPath.startsWith('tools/')) {
250239
targetDir = 'tools';
240+
// Preserve subdirectory structure for tools scripts
241+
const subPath = scriptPath.replace('tools/', '');
242+
const subDir = subPath.includes('/') ? subPath.substring(0, subPath.lastIndexOf('/')) : '';
243+
finalTargetDir = subDir ? join(targetDir, subDir) : targetDir;
244+
filePath = join(this.scriptsDirectory, finalTargetDir, fileName);
251245
} else if (scriptPath.startsWith('vm/')) {
252246
targetDir = 'vm';
247+
// Preserve subdirectory structure for VM scripts
248+
const subPath = scriptPath.replace('vm/', '');
249+
const subDir = subPath.includes('/') ? subPath.substring(0, subPath.lastIndexOf('/')) : '';
250+
finalTargetDir = subDir ? join(targetDir, subDir) : targetDir;
251+
filePath = join(this.scriptsDirectory, finalTargetDir, fileName);
253252
} else {
254253
targetDir = 'ct'; // Default fallback
254+
finalTargetDir = targetDir;
255+
filePath = join(this.scriptsDirectory, targetDir, fileName);
255256
}
256257

257-
const filePath = join(this.scriptsDirectory, targetDir, fileName);
258-
259258
try {
260259
await access(filePath);
261-
files.push(`${targetDir}/${fileName}`);
260+
files.push(`${finalTargetDir}/${fileName}`);
262261

263-
if (scriptPath.startsWith('ct/')) {
262+
// Set ctExists for all script types (CT, tools, vm) for UI consistency
263+
if (scriptPath.startsWith('ct/') || scriptPath.startsWith('tools/') || scriptPath.startsWith('vm/')) {
264264
ctExists = true;
265265
}
266266
} catch {
@@ -292,6 +292,127 @@ export class ScriptDownloaderService {
292292
return { ctExists: false, installExists: false, files: [] };
293293
}
294294
}
295+
296+
async compareScriptContent(script) {
297+
this.initializeConfig();
298+
const differences = [];
299+
let hasDifferences = false;
300+
301+
try {
302+
// First check if any local files exist
303+
const localFilesExist = await this.checkScriptExists(script);
304+
if (!localFilesExist.ctExists && !localFilesExist.installExists) {
305+
// No local files exist, so no comparison needed
306+
return { hasDifferences: false, differences: [] };
307+
}
308+
309+
// If we have local files, proceed with comparison
310+
// Use Promise.all to run comparisons in parallel
311+
const comparisonPromises = [];
312+
313+
// Compare scripts only if they exist locally
314+
if (localFilesExist.ctExists && script.install_methods?.length) {
315+
for (const method of script.install_methods) {
316+
if (method.script) {
317+
const scriptPath = method.script;
318+
const fileName = scriptPath.split('/').pop();
319+
320+
if (fileName) {
321+
let targetDir;
322+
let finalTargetDir;
323+
324+
if (scriptPath.startsWith('ct/')) {
325+
targetDir = 'ct';
326+
finalTargetDir = targetDir;
327+
} else if (scriptPath.startsWith('tools/')) {
328+
targetDir = 'tools';
329+
// Preserve subdirectory structure for tools scripts
330+
const subPath = scriptPath.replace('tools/', '');
331+
const subDir = subPath.includes('/') ? subPath.substring(0, subPath.lastIndexOf('/')) : '';
332+
finalTargetDir = subDir ? join(targetDir, subDir) : targetDir;
333+
} else if (scriptPath.startsWith('vm/')) {
334+
targetDir = 'vm';
335+
// Preserve subdirectory structure for VM scripts
336+
const subPath = scriptPath.replace('vm/', '');
337+
const subDir = subPath.includes('/') ? subPath.substring(0, subPath.lastIndexOf('/')) : '';
338+
finalTargetDir = subDir ? join(targetDir, subDir) : targetDir;
339+
} else {
340+
continue; // Skip unknown script types
341+
}
342+
343+
comparisonPromises.push(
344+
this.compareSingleFile(scriptPath, `${finalTargetDir}/${fileName}`)
345+
.then(result => {
346+
if (result.hasDifferences) {
347+
hasDifferences = true;
348+
differences.push(result.filePath);
349+
}
350+
})
351+
.catch(() => {
352+
// Don't add to differences if there's an error reading files
353+
})
354+
);
355+
}
356+
}
357+
}
358+
}
359+
360+
// Compare install script only if it exists locally
361+
if (localFilesExist.installExists) {
362+
const installScriptName = `${script.slug}-install.sh`;
363+
const installScriptPath = `install/${installScriptName}`;
364+
365+
comparisonPromises.push(
366+
this.compareSingleFile(installScriptPath, installScriptPath)
367+
.then(result => {
368+
if (result.hasDifferences) {
369+
hasDifferences = true;
370+
differences.push(result.filePath);
371+
}
372+
})
373+
.catch(() => {
374+
// Don't add to differences if there's an error reading files
375+
})
376+
);
377+
}
378+
379+
// Wait for all comparisons to complete
380+
await Promise.all(comparisonPromises);
381+
382+
return { hasDifferences, differences };
383+
} catch (error) {
384+
console.error('Error comparing script content:', error);
385+
return { hasDifferences: false, differences: [] };
386+
}
387+
}
388+
389+
async compareSingleFile(remotePath, filePath) {
390+
try {
391+
const localPath = join(this.scriptsDirectory, filePath);
392+
393+
// Read local content
394+
const localContent = await readFile(localPath, 'utf-8');
395+
396+
// Download remote content
397+
const remoteContent = await this.downloadFileFromGitHub(remotePath);
398+
399+
// Apply modification only for CT scripts, not for other script types
400+
let modifiedRemoteContent;
401+
if (remotePath.startsWith('ct/')) {
402+
modifiedRemoteContent = this.modifyScriptContent(remoteContent);
403+
} else {
404+
modifiedRemoteContent = remoteContent; // Don't modify tools or vm scripts
405+
}
406+
407+
// Compare content
408+
const hasDifferences = localContent !== modifiedRemoteContent;
409+
410+
return { hasDifferences, filePath };
411+
} catch (error) {
412+
console.error(`Error comparing file ${filePath}:`, error);
413+
return { hasDifferences: false, filePath };
414+
}
415+
}
295416
}
296417

297418
export const scriptDownloaderService = new ScriptDownloaderService();

0 commit comments

Comments
 (0)