Inno Setup:删除以前版本安装的文件

问题描述 投票:0回答:2

我正在使用 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

 子文件夹的现有文件夹中(罕见但并非不可能),则某些用户文件有可能在升级时被删除.

有没有什么最佳实践可以避免这种麻烦?其他安装人员可以解决这些令人头痛的问题吗?谢谢。

java jar installation inno-setup upgrade
2个回答
5
投票
安装前您可以卸载之前的版本:

  • 如何在Inno Setup中自动卸载以前安装的版本?
  • 如何检测旧安装并提供删除?

如果无法完全卸载,则必须实施部分卸载。

理想的情况是对卸载程序日志进行逆向工程(

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 中除“data”子目录之外的整个应用程序文件夹。您可以从我对

DelTreeExceptSavesDir
事件函数的问题的回答中调用
CurStepChanged(ssInstall)
函数:

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;
    

1
投票
试试这个希望有效吗?

[InstallDelete] Type: filesandordirs; Name: "{app}\lib\dependency-A-1.2.3.jar"
    
© www.soinside.com 2019 - 2024. All rights reserved.