bgipfs
Version:
BuidlGuidl IPFS CLI
107 lines (106 loc) • 4.07 kB
JavaScript
/* eslint-disable no-await-in-loop */
import { promises as fs } from 'node:fs';
import path from 'node:path';
import readline from 'node:readline';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export class TemplateManager {
backupDir;
templateDir;
workingDir;
constructor(workingDir = '.') {
this.templateDir = path.join(__dirname, '../../templates');
this.workingDir = workingDir;
this.backupDir = path.join(this.workingDir, 'config-backup');
}
async copyAllTemplates(force = false) {
try {
const files = await fs.readdir(this.templateDir);
const rl = await this.createReadlineInterface();
let needsAction = false;
// First pass - check status of all files
for (const file of files) {
const sourcePath = path.join(this.templateDir, file);
const targetPath = path.join(this.workingDir, file);
try {
await fs.access(targetPath);
const identical = await this.compareFiles(sourcePath, targetPath);
if (identical) {
console.log(`✓ ${file}: up to date`);
}
else {
console.log(`❗ ${file}: exists but the local file is different to the template`);
needsAction = true;
}
}
catch {
console.log(`⨯ ${file}: missing`);
needsAction = true;
}
}
if (!needsAction) {
console.log('\nAll template files are up to date!');
rl.close();
return;
}
// Second pass - handle required changes
console.log('\nProcessing required changes...');
for (const file of files) {
await this.handleTemplateFile(file, rl, force);
}
rl.close();
}
catch (error) {
throw new Error(`Failed to copy templates: ${error.message}`);
}
}
async backupFile(sourcePath, filename) {
await fs.mkdir(this.backupDir, { recursive: true });
const timestamp = new Date().toISOString().replaceAll(/[.:]/g, '-');
const backupPath = path.join(this.backupDir, `${filename}.${timestamp}`);
await fs.copyFile(sourcePath, backupPath);
}
async compareFiles(path1, path2) {
try {
const content1 = await fs.readFile(path1, 'utf8');
const content2 = await fs.readFile(path2, 'utf8');
return content1 === content2;
}
catch {
return false;
}
}
async confirmOverwrite(file, rl) {
const answer = await new Promise((resolve) => {
rl.question(`${file} has local changes. Do you want to overwrite? (y/N) `, resolve);
});
return answer.toLowerCase() === 'y';
}
async createReadlineInterface() {
return readline.createInterface({
input: process.stdin,
output: process.stdout,
});
}
async handleTemplateFile(file, rl, force) {
const sourcePath = path.join(this.templateDir, file);
const targetPath = path.join(this.workingDir, file);
try {
await fs.access(targetPath);
if (await this.compareFiles(sourcePath, targetPath)) {
console.log(`Skipping ${file} as it is identical`);
return; // Skip if files are identical
}
if (!force && !(await this.confirmOverwrite(file, rl))) {
return;
}
await this.backupFile(targetPath, file);
console.log(`Backed up ${file} to ${this.backupDir}`);
}
catch {
// File doesn't exist, continue to copy
}
await fs.copyFile(sourcePath, targetPath);
}
}