mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-03 00:17:47 +00:00
fix(backup): create backups only when settings content changes
Previously, PUT /api/settings/:profile created a backup on every request regardless of whether the content actually changed. This led to hundreds of identical backup files accumulating in ~/.ccs/backups/. Changes: - Compare existing content with new content before creating backup - Reuse computed newContent for atomic write (DRY) - Make hook injection idempotent by checking content before write Fixes #433
This commit is contained in:
@@ -123,11 +123,17 @@ export function ensureProfileHooks(profileName: string): boolean {
|
|||||||
// Clean up any duplicates that may have accumulated (Windows path bug fix)
|
// Clean up any duplicates that may have accumulated (Windows path bug fix)
|
||||||
const hadDuplicates = deduplicateCcsHooks(settings);
|
const hadDuplicates = deduplicateCcsHooks(settings);
|
||||||
if (hadDuplicates) {
|
if (hadDuplicates) {
|
||||||
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
// Re-read file to compare with modified settings (deduplicateCcsHooks mutates in-place)
|
||||||
if (process.env.CCS_DEBUG) {
|
const newContent = JSON.stringify(settings, null, 2);
|
||||||
console.error(
|
const existingContent = fs.readFileSync(settingsPath, 'utf8');
|
||||||
info(`Removed duplicate WebSearch hooks from ${profileName}.settings.json`)
|
// Only write if content actually changed
|
||||||
);
|
if (newContent !== existingContent) {
|
||||||
|
fs.writeFileSync(settingsPath, newContent, 'utf8');
|
||||||
|
if (process.env.CCS_DEBUG) {
|
||||||
|
console.error(
|
||||||
|
info(`Removed duplicate WebSearch hooks from ${profileName}.settings.json`)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update timeout if needed
|
// Update timeout if needed
|
||||||
|
|||||||
@@ -156,16 +156,21 @@ router.put('/:profile', (req: Request, res: Response): void => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create backup only if file exists
|
// Create backup only if file exists AND content actually changed
|
||||||
let backupPath: string | undefined;
|
let backupPath: string | undefined;
|
||||||
|
const newContent = JSON.stringify(settings, null, 2) + '\n';
|
||||||
if (fileExists) {
|
if (fileExists) {
|
||||||
const backupDir = path.join(ccsDir, 'backups');
|
const existingContent = fs.readFileSync(settingsPath, 'utf8');
|
||||||
if (!fs.existsSync(backupDir)) {
|
// Only create backup if content differs
|
||||||
fs.mkdirSync(backupDir, { recursive: true });
|
if (existingContent !== newContent) {
|
||||||
|
const backupDir = path.join(ccsDir, 'backups');
|
||||||
|
if (!fs.existsSync(backupDir)) {
|
||||||
|
fs.mkdirSync(backupDir, { recursive: true });
|
||||||
|
}
|
||||||
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||||
|
backupPath = path.join(backupDir, `${profile}.${timestamp}.settings.json`);
|
||||||
|
fs.copyFileSync(settingsPath, backupPath);
|
||||||
}
|
}
|
||||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
||||||
backupPath = path.join(backupDir, `${profile}.${timestamp}.settings.json`);
|
|
||||||
fs.copyFileSync(settingsPath, backupPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure directory exists for new files
|
// Ensure directory exists for new files
|
||||||
@@ -175,7 +180,7 @@ router.put('/:profile', (req: Request, res: Response): void => {
|
|||||||
|
|
||||||
// Write new settings atomically
|
// Write new settings atomically
|
||||||
const tempPath = settingsPath + '.tmp';
|
const tempPath = settingsPath + '.tmp';
|
||||||
fs.writeFileSync(tempPath, JSON.stringify(settings, null, 2) + '\n');
|
fs.writeFileSync(tempPath, newContent);
|
||||||
fs.renameSync(tempPath, settingsPath);
|
fs.renameSync(tempPath, settingsPath);
|
||||||
|
|
||||||
const newStat = fs.statSync(settingsPath);
|
const newStat = fs.statSync(settingsPath);
|
||||||
|
|||||||
Reference in New Issue
Block a user