Inno Setup - Delete old/obsolete files on update
Inno Setup - Delete old/obsolete files on update
So, I realize that this question has been asked before. In fact I read through a good 10 of them before writing this, but none of them have a applicable solution and I'm hoping that nowadays someone has found something.
The problem:
My program is build with a script, creating all final files in a single folder.
Those files are included in inno like this:
[Files]
Source: "buildexe.win-amd64-3.6*"; Excludes: "*.key, *.log"; DestDir: "{app}";
Flags: ignoreversion recursesubdirs createallsubdirs
The application has been out there for a few months with different updates. There is no record anymore of old files, though it could be painstakingly re-assembled as we do have version control and I could build the old installers again.
From what I understand, you're meant to use the InstallDelete section to get rid of old files - however you are not meant to use wildcards and there is also no Excludes section to safeguard the single folder we have that may contain user data they may want to keep.
InstallDelete
Excludes
So, how do I get rid of old files? The application is 100 MB and a current user may have 300+ MB of old files that are no longer necessary, I'd love to clean that up.
TL;DR: I want the installer to either overwrite or delete all files in the application directory, except for one folder which contains user data.
Yeah, pretty much. I added a summary at the end to clarify this.
– Berserker
Jul 2 at 8:19
While the linked question is about uninstallation, the code in the answer can be used in installer too.
– Martin Prikryl
Jul 2 at 11:21
Seems like it would first delete everything, then write everything. Would be nice if only stuff gets deleted that won't get overwritten anyway.
– Berserker
Jul 2 at 11:25
That matters only, if you use flags that prevent overwritting an existing files if they exist already. If you overwrite files unconditionaly, I do not see any difference.
– Martin Prikryl
Jul 2 at 11:28
1 Answer
1
The easiest solution is to delete all files in the installation folder before the installation.
As you know, you can use [InstallDelete] section for that. But that does not allow you to exclude the "data" folder.
[InstallDelete]
You can code that Pascal Scripting instead. See Inno Setup - Delete whole application folder except for data subdirectory. You can call the DelTreeExceptSavesDir function from my answer to the that question from CurStepChanged(ssInstall) event function:
DelTreeExceptSavesDir
CurStepChanged(ssInstall)
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
begin
DelTreeExceptSavesDir(WizardDirValue);
end;
end;
If you really want to delete only obsolete files, to avoid deleting and re-creating existing files (what's not your case, as you are using ignoreversion flag anyway), you can use preprocessor to generate a list of files to be installed for the Pascal Scripting and use that to delete only really obsolete files.
ignoreversion
#pragma parseroption -p-
#define FileEntry(DestDir)
" FilesNotToBeDeleted.Add('" + LowerCase(DestDir) + "');n"
#define ProcessFile(Source, Dest, FindResult, FindHandle)
FindResult
?
Local[0] = FindGetFileName(FindHandle),
Local[1] = Source + "\" + Local[0],
Local[2] = Dest + "\" + Local[0],
(Local[0] != "." && Local[0] != ".."
? FileEntry(Local[2]) +
(DirExists(Local[1]) ? ProcessFolder(Local[1], Local[2]) : "")
: "") +
ProcessFile(Source, Dest, FindNext(FindHandle), FindHandle)
:
""
#define ProcessFolder(Source, Dest)
Local[0] = FindFirst(Source + "\*", faAnyFile),
ProcessFile(Source, Dest, Local[0], Local[0])
#pragma parseroption -p+
[Code]
var
FilesNotToBeDeleted: TStringList;
function InitializeSetup(): Boolean;
begin
FilesNotToBeDeleted := TStringList.Create;
FilesNotToBeDeleted.Add('data');
{#Trim(ProcessFolder('buildexe.win-amd64-3.6', ''))}
FilesNotToBeDeleted.Sorted := True;
Result := True;
end;
procedure DeleteObsoleteFiles(Path: string; RelativePath: string);
var
FindRec: TFindRec;
FilePath: string;
FileRelativePath: string;
begin
if FindFirst(Path + '*', FindRec) then
begin
try
repeat
if (FindRec.Name <> '.') and (FindRec.Name <> '..') then
begin
FilePath := Path + '' + FindRec.Name;
FileRelativePath := RelativePath + '' + FindRec.Name;
if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then
begin
DeleteObsoleteFiles(FilePath, FileRelativePath);
end;
if FilesNotToBeDeleted.IndexOf(Lowercase(FileRelativePath)) < 0 then
begin
if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then
begin
if RemoveDir(FilePath) then
begin
Log(Format('Deleted obsolete directory %s', [FilePath]));
end
else
begin
Log(Format('Failed to delete obsolete directory %s', [FilePath]));
end;
end
else
begin
if DeleteFile(FilePath) then
begin
Log(Format('Deleted obsolete file %s', [FilePath]));
end
else
begin
Log(Format('Failed to delete obsolete file %s', [FilePath]));
end;
end;
end;
end;
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end
else
begin
Log(Format('Failed to list %s', [Path]));
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
begin
Log('Looking for obsolete files...');
DeleteObsoleteFiles(WizardDirValue, '');
end;
end;
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
So you want to delete all files from the installation folder that were not installed by the update installer?
– Martin Prikryl
Jul 2 at 8:00