[英]Inno Setup: Removing files installed by previous version
我正在使用Inno Setup為 Windows 打包 Java 應用程序; 應用程序樹是這樣的:
| MyApp.jar
\---lib
| dependency-A-1.2.3.jar
| dependency-B-2.3.4.jar
| dependency-Z-x.y.z.jar
我使用Ant事先准備好整個樹(所有文件和文件夾),包括lib
目錄(使用*.jar
通配符復制依賴項),然后我只需調用ISCC
:
[Files]
Source: "PreparedFolder\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
現在,每次用戶升級應用程序時,我都需要清理lib
目錄,因為我想刪除任何過時的依賴項。 我可以將以下部分添加到我的.iss
文件中:
[InstallDelete]
{app}\lib\*.jar
但我感覺不安全,因為如果用戶決定將應用程序安裝在包含非空lib
子文件夾(罕見但並非不可能)的現有文件夾中,則升級時可能會刪除一些用戶文件。
有沒有最佳實踐來避免這種麻煩? 其他安裝人員會解決這些問題嗎? 謝謝。
安裝前可以先卸載之前的版本:
如果您無法進行完全卸載,則必須實施部分卸載。
理想的做法是對卸載程序日志 ( unins000.dat
) 進行逆向工程,僅將安裝提取到lib
子文件夾並處理(撤消)它們。 但由於這是一個未記錄的二進制文件,因此可能很難做到。
如果您在[Files]
部分中維護要安裝的文件的明確列表,例如
[Files]
Source: "lib\dependency-A-1.2.3.jar"; Dest: "{app}\lib"
Source: "lib\dependency-B-2.3.4.jar"; Dest: "{app}\lib"
然后每當依賴項發生更改時,將以前的版本移動到[InstallDelete]
部分:
[Files]
Source: "lib\dependency-A-1.3.0.jar"; Dest: "{app}"
Source: "lib\dependency-B-2.3.4.jar"; Dest: "{app}"
[InstallDelete]
{app}\lib\dependency-A-1.2.3.jar
如果您使用通配符安裝依賴項,
[Files]
Source: "lib\*.jar"; Dest: "{app}\lib"
而且您無法對卸載程序日志進行反向工程,您必須通過自己的方式復制其功能。
您可以使用預處理器生成包含已安裝依賴項的文件。 將該文件安裝到{app}
文件夾並在安裝前處理該文件。
[Files]
Source: "MyApp.jar"; DestDir: "{app}"
Source: "lib\*.jar"; DestDir: "{app}\lib"
#define ProcessFile(Source, FindResult, FindHandle) \
Local[0] = FindGetFileName(FindHandle), \
Local[1] = Source + "\\" + Local[0], \
Local[2] = FindNext(FindHandle), \
"'" + Local[0] + "'#13#10" + \
(Local[2] ? ProcessFile(Source, Local[2], FindHandle) : "")
#define ProcessFolder(Source) \
Local[0] = FindFirst(Source + "\\*.jar", faAnyFile), \
ProcessFile(Source, Local[0], Local[0])
#define DepedenciesToInstall ProcessFolder("lib")
#define DependenciesLog "{app}\dependencies.log"
[UninstallDelete]
Type: files; Name: "{#DependenciesLog}"
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var
AppPath, DependenciesLogPath: string;
Dependencies: TArrayOfString;
Count, I: Integer;
begin
DependenciesLogPath := ExpandConstant('{#DependenciesLog}');
if CurStep = ssInstall then
begin
// If dependencies log already exists,
// remove the previously installed dependencies
if LoadStringsFromFile(DependenciesLogPath, Dependencies) then
begin
Count := GetArrayLength(Dependencies);
Log(Format('Loaded %d dependencies, deleting...', [Count]));
for I := 0 to Count - 1 do
DeleteFile(ExpandConstant('{app}\lib\' + Dependencies[I]));
end;
end
else
if CurStep = ssPostInstall then
begin
// Now that the app folder already exists,
// save dependencies log (to be processed by future upgrade)
if SaveStringToFile(DependenciesLogPath, {#DepedenciesToInstall}, False) then
begin
Log('Created dependencies log');
end
else
begin
Log('Failed to create dependencies log');
end;
end;
end;
另一種方法是刪除安裝文件夾中最新安裝程序未安裝的所有文件。
最簡單的解決方案是在安裝之前刪除安裝文件夾中的所有文件。
您可以為此使用[InstallDelete]
部分。 但是,如果您在安裝文件夾中有一些帶有配置的文件夾/文件,則不允許您排除它們。
您可以改為編寫 Pascal 腳本。 請參閱Inno Setup - 刪除除數據子目錄之外的整個應用程序文件夾。 您可以從我對CurStepChanged(ssInstall)
事件函數的該問題的回答中調用DelTreeExceptSavesDir
函數:
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
begin
DelTreeExceptSavesDir(WizardDirValue);
end;
end;
如果您真的只想刪除過時的文件,以避免刪除和重新創建現有文件,您可以使用預處理器生成要為 Pascal 腳本安裝的文件列表,並使用它來僅刪除真正過時的文件。
#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('build\exe.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;
試試這個希望它有效嗎?
[InstallDelete]
Type: filesandordirs; Name: "{app}\lib\dependency-A-1.2.3.jar"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.