Skip to content

added a patch to backup settings files in Windows Firmware Installer#330

Merged
nitin710 merged 3 commits intodevfrom
feat-windowsInstaller
Jan 30, 2026
Merged

added a patch to backup settings files in Windows Firmware Installer#330
nitin710 merged 3 commits intodevfrom
feat-windowsInstaller

Conversation

@nitin710
Copy link
Collaborator

@nitin710 nitin710 commented Jan 30, 2026

Description

  • current strategy
    • We currently copy all existing settings files with a modified name [original name]backup[timestamp]
    • We then copy all settings files with the new app version
    • For each new settings file, we perform a “equality” check with the backed up file. If the new file is the same as the backup, we delete the backup
    • If the files are not equal, we keep the backup
  • See Handling settings file updates in EmotiBit applications in drive for notes.

Requirements

  • None

Issues Referenced

  • Fixes # (issue)

Documentation update

  • None

Testing

  • tested to backup modified files
  • tested the backup path
  • tested uninstall removes all files
  • tested auto uninstall v1.12.2

Summary by CodeRabbit

  • New Features

    • Settings are backed up before install/upgrade, with identical backups auto-removed and a post-install notification if custom settings remain.
    • Installer preserves user settings across MSI-based upgrades and includes app fonts during install.
    • Uninstall now removes app folders and cleans up parent directory when empty.
  • Chores

    • Version bumped to 1.14.5.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 30, 2026

Walkthrough

Adds a comprehensive settings backup and cleanup system to the Inno Setup script and bumps the project version. New global variables (BackedUpFilesCount, BackupTimestamp), functions and procedures manage locating, timestamping, backing up (JSON/XML/TTF), and cleaning up backups; backups are stored in timestamped folders. PrepareToInstall now calls BackupAllSettingsFiles before MSI uninstall logic; CurStepChanged performs post-install cleanup and user notification. Adds UninstallDelete entries and updates [Files] to include data/*.ttf and backup-ready placeholders. Updates version constant to "1.14.5".

Possibly related PRs

  • EmotiBit/ofxEmotiBit PR 329 — Modified EmotiBitInstaller.iss PrepareToInstall/MSI migration logic that this PR further extends with settings backup/cleanup integration.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the primary change: adding backup functionality for settings files. It directly reflects the main objective and the most significant addition in the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@EmotiBitInstaller/EmotiBitInstaller.iss`:
- Around line 86-96: The SETTINGS_FILE_COUNT constant is a fragile manual count
that can fall out of sync with the number of cases in GetSettingsFileInfo; add a
defensive runtime assertion and/or an inline comment to prevent mismatch: update
GetSettingsFileInfo to include a comment referencing SETTINGS_FILE_COUNT and add
a validation (e.g., compare the number of cases returned or the length of the
settings list against SETTINGS_FILE_COUNT) that logs or raises an error if they
differ so BackedUpFilesCount/backup cleanup logic cannot silently skip files.
- Around line 183-194: GetSettingsFileInfo currently lacks a default branch so
an out-of-range Index can leave FileName and DestDir uninitialized; update the
GetSettingsFileInfo procedure to add a default case that assigns safe fallback
values (e.g., empty FileName and a safe DestDir or a clearly named error file)
and optionally logs or raises an error/exception to fail fast when Index is
invalid, ensuring callers (backup/cleanup) never receive uninitialized strings.

…o adds a patch to remove all emotibit directories on uninstall (was an issue if upgrading from MSI to INNO installer)
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@EmotiBitInstaller/EmotiBitInstaller.iss`:
- Around line 227-250: Backup currently uses RenameFile in BackupFile (called
from BackupAllSettingsFiles during PrepareToInstall) which moves originals
before the user-facing MSI uninstall prompt; change behavior to preserve
originals by replacing RenameFile with FileCopy in BackupFile so backups are
copies, and/or move the call to BackupAllSettingsFiles out of PrepareToInstall
into CurStepChanged handling for ssInstall so backups occur after cancelable
prompts; update logging to reflect copy vs move and ensure BackedUpFilesCount
increments only on successful FileCopy.

Comment on lines +227 to +250
procedure BackupFile(FilePath: String);
var
BackupPath, BackupDir: String;
begin
if not FileExists(FilePath) then
begin
Log('No file to backup: ' + FilePath);
Exit;
end;

BackupPath := GetBackupFilePath(FilePath);
BackupDir := ExtractFilePath(BackupPath);

if not DirExists(BackupDir) then
ForceDirectories(BackupDir);

if RenameFile(FilePath, BackupPath) then
begin
Log('Backed up: ' + FilePath + ' -> ' + BackupPath);
BackedUpFilesCount := BackedUpFilesCount + 1;
end
else
Log('Warning: Failed to backup ' + FilePath);
end;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd /tmp && find . -name "*.iss" -type f 2>/dev/null | head -20

Repository: EmotiBit/ofxEmotiBit

Length of output: 46


🏁 Script executed:

git ls-files | grep -i "emotibits" | head -20

Repository: EmotiBit/ofxEmotiBit

Length of output: 46


🏁 Script executed:

git ls-files | grep -i "\.iss$"

Repository: EmotiBit/ofxEmotiBit

Length of output: 103


🏁 Script executed:

wc -l EmotiBitInstaller/EmotiBitInstaller.iss

Repository: EmotiBit/ofxEmotiBit

Length of output: 107


🏁 Script executed:

sed -n '227,250p' EmotiBitInstaller/EmotiBitInstaller.iss

Repository: EmotiBit/ofxEmotiBit

Length of output: 635


🏁 Script executed:

sed -n '399,404p' EmotiBitInstaller/EmotiBitInstaller.iss

Repository: EmotiBit/ofxEmotiBit

Length of output: 356


🏁 Script executed:

grep -n "PrepareToInstall" EmotiBitInstaller/EmotiBitInstaller.iss

Repository: EmotiBit/ofxEmotiBit

Length of output: 129


🏁 Script executed:

grep -n "BackupAllSettingsFiles\|RestoreSettings\|CancelledInstallation" EmotiBitInstaller/EmotiBitInstaller.iss

Repository: EmotiBit/ofxEmotiBit

Length of output: 133


🏁 Script executed:

sed -n '391,410p' EmotiBitInstaller/EmotiBitInstaller.iss

Repository: EmotiBit/ofxEmotiBit

Length of output: 705


🏁 Script executed:

sed -n '284,310p' EmotiBitInstaller/EmotiBitInstaller.iss

Repository: EmotiBit/ofxEmotiBit

Length of output: 850


🏁 Script executed:

grep -n "CurStepChanged\|function.*Cancel\|procedure.*Abort\|procedure.*Restore" EmotiBitInstaller/EmotiBitInstaller.iss

Repository: EmotiBit/ofxEmotiBit

Length of output: 189


🏁 Script executed:

grep -n "ssInstall\|ssFinished\|Result :=" EmotiBitInstaller/EmotiBitInstaller.iss | head -20

Repository: EmotiBit/ofxEmotiBit

Length of output: 766


🏁 Script executed:

sed -n '371,390p' EmotiBitInstaller/EmotiBitInstaller.iss

Repository: EmotiBit/ofxEmotiBit

Length of output: 762


🏁 Script executed:

sed -n '371,550p' EmotiBitInstaller/EmotiBitInstaller.iss | grep -A 30 "CurStepChanged"

Repository: EmotiBit/ofxEmotiBit

Length of output: 2150


🏁 Script executed:

grep -n "RenameFile\|FileCopy\|DeleteFile\|MoveFile" EmotiBitInstaller/EmotiBitInstaller.iss

Repository: EmotiBit/ofxEmotiBit

Length of output: 199


🏁 Script executed:

grep -n "procedure.*Restore\|function.*Restore\|RestoreFile\|RestoreSettings" EmotiBitInstaller/EmotiBitInstaller.iss

Repository: EmotiBit/ofxEmotiBit

Length of output: 46


🌐 Web query:

Inno Setup RenameFile vs FileCopy behavior and differences

💡 Result:

RenameFile (move/rename)

  • What it does: Renames (or moves) an existing file or directory from OldName to NewName. (documentation.help)
  • If destination exists: Fails (returns False) if NewName already exists. (documentation.help)
  • Cross-drive behavior: Works like a filesystem rename/move, so it’s not suitable for moving across different drives/volumes (typical “move to another drive” needs copy+delete). (stackoverflow.com)
  • Practical implications: Usually fast/atomic on the same volume (metadata change, no data duplication). But it will fail if the source is in use/locked, or if permissions block the operation (same as any OS-level rename).

FileCopy (copy)

  • What it does: Copies ExistingFile to NewFile and preserves timestamp and file attributes. (documentation.help)
  • If destination exists: Controlled by FailIfExists:
  • Directories: It’s a single-file operation; it does not create the destination folder (so the target path must already exist). (stackoverflow.com)
  • Practical implications: Slower and uses extra disk I/O/space (because it duplicates data), but it’s the correct building block for “move across drives” (copy + then DeleteFile), which RenameFile can’t reliably do. (stackoverflow.com)

Rule of thumb

  • Use RenameFile when you want a true rename/move on the same volume and you want it to fail if the destination already exists. (documentation.help)
  • Use FileCopy when you want a duplicate, need optional overwrite control, or you may be moving between different drives (copy+delete). (documentation.help)

Citations:


🌐 Web query:

Inno Setup PrepareToInstall abort cancel hook restore files rollback

💡 Result:

1) “Abort/cancel” from PrepareToInstall (the supported hook)

PrepareToInstall is explicitly meant to stop Setup before the actual install phase starts. To abort, return a non-empty string (shown on the “Preparing to Install” page). If a restart is required, also set NeedsRestart := True. Setup then exits with a dedicated exit code (7/8). [1][2]

function PrepareToInstall(var NeedsRestart: Boolean): String;
begin
  if SomePrecheckFailed then
    Result := 'Cannot proceed (reason...)';  // abort before installing anything
end;

If you need to force a “restart required” outcome:

function PrepareToInstall(var NeedsRestart: Boolean): String;
begin
  NeedsRestart := True;
  Result := 'A restart is required before updating. Please reboot and try again.';
end;

2) “Abort during install” with rollback (only works in specific events)

Abort; only terminates Setup (with normal cleanup/rollback behavior) when called from certain event functions—most importantly CurStepChanged(ssInstall) for aborting during the install phase. [3]

procedure CurStepChanged(CurStep: TSetupStep);
begin
  if CurStep = ssInstall then
    if MustStopNow then
      Abort;  // causes Setup to stop and roll back what it can
end;

3) About “restore files / rollback overwritten files”

Inno Setup’s “Rolling back changes” is not a full transactional restore of overwritten files in every scenario (especially upgrades + partial file replacement failures). Practically, you should assume you cannot rely on rollback to restore previous versions of files that were already overwritten, so design to avoid starting file replacement unless you’re sure you can finish. This is why the safest pattern is to detect the problem before ssInstall (via PrepareToInstall) and stop early. [1]

For the specific “locked file during silent upgrade” case, one suggested workaround is to detect (e.g., by analyzing your /LOG) that Restart Manager couldn’t avoid a reboot, and then abort at CurStepChanged(ssInstall) before more replacement happens. [1]


Sources:
[1] Stack Overflow discussion of silent update + locked file + rollback limitations/workarounds (stackoverflow.com)
[2] Inno Setup help: PrepareToInstall behavior + dedicated exit codes (jrsoftware.org)
[3] Inno Setup help: Abort only exits Setup when called from specific events (incl. CurStepChanged(ssInstall)) (documentation.help)

Citations:


Backup moves files before the cancelable MSI uninstall prompt—if cancelled, the app loses original settings.

RenameFile moves the original settings to a backup folder. BackupAllSettingsFiles() is called at the start of PrepareToInstall, but the user-facing MSI uninstall confirmation prompt (which allows cancellation) happens after. If the user cancels there, files remain in the backup folder and the app loses its original settings files.

Switch to FileCopy to keep original files in place while creating a safety backup, or defer BackupAllSettingsFiles() until after all cancelable prompts by moving it to CurStepChanged(ssInstall).

💡 Safer backup approach (copy instead of move)
-  if RenameFile(FilePath, BackupPath) then
+  if FileCopy(FilePath, BackupPath, False) then
   begin
     Log('Backed up: ' + FilePath + ' -> ' + BackupPath);
     BackedUpFilesCount := BackedUpFilesCount + 1;
   end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
procedure BackupFile(FilePath: String);
var
BackupPath, BackupDir: String;
begin
if not FileExists(FilePath) then
begin
Log('No file to backup: ' + FilePath);
Exit;
end;
BackupPath := GetBackupFilePath(FilePath);
BackupDir := ExtractFilePath(BackupPath);
if not DirExists(BackupDir) then
ForceDirectories(BackupDir);
if RenameFile(FilePath, BackupPath) then
begin
Log('Backed up: ' + FilePath + ' -> ' + BackupPath);
BackedUpFilesCount := BackedUpFilesCount + 1;
end
else
Log('Warning: Failed to backup ' + FilePath);
end;
procedure BackupFile(FilePath: String);
var
BackupPath, BackupDir: String;
begin
if not FileExists(FilePath) then
begin
Log('No file to backup: ' + FilePath);
Exit;
end;
BackupPath := GetBackupFilePath(FilePath);
BackupDir := ExtractFilePath(BackupPath);
if not DirExists(BackupDir) then
ForceDirectories(BackupDir);
if FileCopy(FilePath, BackupPath, False) then
begin
Log('Backed up: ' + FilePath + ' -> ' + BackupPath);
BackedUpFilesCount := BackedUpFilesCount + 1;
end
else
Log('Warning: Failed to backup ' + FilePath);
end;
🤖 Prompt for AI Agents
In `@EmotiBitInstaller/EmotiBitInstaller.iss` around lines 227 - 250, Backup
currently uses RenameFile in BackupFile (called from BackupAllSettingsFiles
during PrepareToInstall) which moves originals before the user-facing MSI
uninstall prompt; change behavior to preserve originals by replacing RenameFile
with FileCopy in BackupFile so backups are copies, and/or move the call to
BackupAllSettingsFiles out of PrepareToInstall into CurStepChanged handling for
ssInstall so backups occur after cancelable prompts; update logging to reflect
copy vs move and ensure BackedUpFilesCount increments only on successful
FileCopy.

@nitin710 nitin710 changed the base branch from master to dev January 30, 2026 22:47
@nitin710 nitin710 merged commit 37ee29b into dev Jan 30, 2026
15 checks passed
@nitin710 nitin710 deleted the feat-windowsInstaller branch January 30, 2026 22:48
@nitin710 nitin710 changed the title added a patch to backup settings files added a patch to backup settings files in Windows Firmware Installer Jan 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant