【问题标题】:Inno Setup: Removing files installed by previous versionInno Setup:删除以前版本安装的文件
【发布时间】:2017-09-01 20:48:10
【问题描述】:

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


    【解决方案1】:

    安装前可以先卸载之前的版本:


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

    理想的做法是对卸载程序日志 (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"
    

    而且您无法对卸载程序日志进行反向工程,您必须通过自己的方式复制其功能。

    您可以使用preprocessor 生成包含已安装依赖项的文件。将该文件安装到{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] section。但是如果您在安装文件夹中有一些带有配置的文件夹/文件,则不允许您排除它们。

    您可以改为编写 Pascal 脚本。见Inno Setup - Delete whole application folder except for data subdirectory。您可以从我对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;
    

    【讨论】:

      【解决方案2】:

      试试这个希望它有用吗?

      [InstallDelete]
      Type: filesandordirs; Name: "{app}\lib\dependency-A-1.2.3.jar"
      

      【讨论】:

      • 这是您在猜测的问题,还是您已将其作为可行解决方案进行分析/测试的代码? (“尝试”和“希望”这两个词强烈暗示前者。)
      • 我还没有测试它,我只是从阅读文档中得到它。
      • 它将在安装/解压缩文件之前运行。
      猜你喜欢
      • 2011-01-01
      • 1970-01-01
      • 2020-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-18
      • 2011-01-29
      相关资源
      最近更新 更多