Enhance schema synchronization by adding change detection and statistics tracking

This commit updates the `syncModelsWithWS` function to include detailed statistics on schema synchronization, tracking the number of added, updated, and unchanged files. The `syncDirectory` function is modified to read file contents and determine if changes exist before copying, utilizing a new utility function, `fileHasChanges`, for comparison. Additionally, a helper function, `readFileIfExists`, is introduced to handle file reading more gracefully. These enhancements improve the efficiency and clarity of the schema synchronization process.
This commit is contained in:
Tom Butcher 2026-08-24 19:04:15 +01:00
parent 8cd8ee6f94
commit e2a135aa3d

View File

@ -1,3 +1,4 @@
import { diffLines } from 'diff';
import fs from 'fs/promises'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
@ -11,24 +12,41 @@ async function syncModelsWithWS() {
console.log(`Syncing schemas from ${sourceDir} to ${targetDir}...`); console.log(`Syncing schemas from ${sourceDir} to ${targetDir}...`);
const stats = { copied: 0, added: 0, skipped: 0 };
try { try {
await syncDirectory(sourceDir, targetDir, sourceDir); await syncDirectory(sourceDir, targetDir, sourceDir, stats);
console.log('✅ Schema sync completed successfully!'); console.log(
`✅ Schema sync completed successfully! (${stats.added} added, ${stats.copied} updated, ${stats.skipped} unchanged)`
);
} catch (error) { } catch (error) {
console.error('❌ Error syncing schemas:', error); console.error('❌ Error syncing schemas:', error);
process.exit(1); process.exit(1);
} }
} }
async function syncDirectory(source, target, rootSource) { function fileHasChanges(oldContent, newContent) {
// Create target directory if it doesn't exist return diffLines(oldContent, newContent).some((part) => part.added || part.removed);
}
async function readFileIfExists(filePath) {
try {
return await fs.readFile(filePath, 'utf8');
} catch (error) {
if (error.code === 'ENOENT') {
return null;
}
throw error;
}
}
async function syncDirectory(source, target, rootSource, stats) {
try { try {
await fs.access(target); await fs.access(target);
} catch { } catch {
await fs.mkdir(target, { recursive: true }); await fs.mkdir(target, { recursive: true });
} }
// Read all items in source directory
const items = await fs.readdir(source, { withFileTypes: true }); const items = await fs.readdir(source, { withFileTypes: true });
for (const item of items) { for (const item of items) {
@ -36,12 +54,23 @@ async function syncDirectory(source, target, rootSource) {
const targetPath = path.join(target, item.name); const targetPath = path.join(target, item.name);
if (item.isDirectory()) { if (item.isDirectory()) {
// Recursively sync subdirectories await syncDirectory(sourcePath, targetPath, rootSource, stats);
await syncDirectory(sourcePath, targetPath, rootSource);
} else if (item.isFile()) { } else if (item.isFile()) {
// Copy file from source to target const sourceContent = await fs.readFile(sourcePath, 'utf8');
await fs.copyFile(sourcePath, targetPath); const targetContent = await readFileIfExists(targetPath);
console.log(` ✓ Copied: ${path.relative(rootSource, sourcePath)}`); const relativePath = path.relative(rootSource, sourcePath);
if (targetContent === null) {
await fs.writeFile(targetPath, sourceContent);
stats.added += 1;
console.log(` + Added: ${relativePath}`);
} else if (fileHasChanges(targetContent, sourceContent)) {
await fs.writeFile(targetPath, sourceContent);
stats.copied += 1;
console.log(` ✓ Updated: ${relativePath}`);
} else {
stats.skipped += 1;
}
} }
} }
} }