Qt Installer Framework的解决方法不会覆盖现有安装

rat*_*der 4 qt qt-installer

这个问题是关于Qt Installer Framework的2.0版本.

此时,使用Qt安装程序框架的人员通常都知道,如果没有自定义,您就无法通过安装程序覆盖现有安装.这显然是为了解决使用Qt框架完成此事时发生的一些问题.

但是,对于较小的,相对简单的项目,覆盖是完全正确的,并且比预先手动运行维护工具更方便.

我正在寻找一个涉及自定义UI +组件脚本的解决方案,该脚本向目标目录页面添加一个允许用户使用的按钮

  1. 删除指定的目录(如果存在),或
  2. 在该目录中运行维护工具.

最好是能够在目标目录中运行维护工具,让它自动删除给定的包,我意识到这需要一点点.

我已阅读本网站上有关解决同一问题的其他问题的答案,但没有一个解决方案正常工作.我还想提一下,我有一个组件脚本启动并运行,但没有自定义UI.

rat*_*der 9

我终于找到了一个可行的解决方案.

你需要三件事来解决这个问题:

  1. 组件脚本,
  2. 目标目录页面的自定义UI,以及
  3. 一个控制器脚本,可以自动点击卸载程序.

我现在将逐字逐句列出对我有用的东西(用我的项目特定的东西).我的组件被调用Atlas4500 Tuner

config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Installer>
    <Name>Atlas4500 Tuner</Name>
    <Version>1.0.0</Version>
    <Title>Atlas4500 Tuner Installer</Title>
    <Publisher>EF Johnson Technologies</Publisher>
    <StartMenuDir>EF Johnson</StartMenuDir>
    <TargetDir>C:\Program Files (x86)\EF Johnson\Atlas4500 Tuner</TargetDir>
</Installer>
Run Code Online (Sandbox Code Playgroud)

packages/Atlas4500 Tuner/meta/package.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Package>
    <DisplayName>Atlas4500Tuner</DisplayName>
    <Description>Install the Atlas4500 Tuner</Description>
    <Version>1.0.0</Version>
    <ReleaseDate></ReleaseDate>
    <Default>true</Default>
    <Required>true</Required>
    <Script>installscript.qs</Script>
    <UserInterfaces>
        <UserInterface>targetwidget.ui</UserInterface>
    </UserInterfaces>
</Package>
Run Code Online (Sandbox Code Playgroud)

自定义组件脚本包/ Atlas4500 Tuner/meta/installscript.qs:

var targetDirectoryPage = null;

function Component() 
{
    installer.gainAdminRights();
    component.loaded.connect(this, this.installerLoaded);
}

Component.prototype.createOperations = function() 
{
    // Add the desktop and start menu shortcuts.
    component.createOperations();
    component.addOperation("CreateShortcut",
                           "@TargetDir@/Atlas4500Tuner.exe",
                           "@DesktopDir@/Atlas4500 Tuner.lnk",
                           "workingDirectory=@TargetDir@");

    component.addOperation("CreateShortcut",
                           "@TargetDir@/Atlas4500Tuner.exe",
                           "@StartMenuDir@/Atlas4500 Tuner.lnk",
                           "workingDirectory=@TargetDir@");
}

Component.prototype.installerLoaded = function()
{
    installer.setDefaultPageVisible(QInstaller.TargetDirectory, false);
    installer.addWizardPage(component, "TargetWidget", QInstaller.TargetDirectory);

    targetDirectoryPage = gui.pageWidgetByObjectName("DynamicTargetWidget");
    targetDirectoryPage.windowTitle = "Choose Installation Directory";
    targetDirectoryPage.description.setText("Please select where the Atlas4500 Tuner will be installed:");
    targetDirectoryPage.targetDirectory.textChanged.connect(this, this.targetDirectoryChanged);
    targetDirectoryPage.targetDirectory.setText(installer.value("TargetDir"));
    targetDirectoryPage.targetChooser.released.connect(this, this.targetChooserClicked);

    gui.pageById(QInstaller.ComponentSelection).entered.connect(this, this.componentSelectionPageEntered);
}

Component.prototype.targetChooserClicked = function()
{
    var dir = QFileDialog.getExistingDirectory("", targetDirectoryPage.targetDirectory.text);
    targetDirectoryPage.targetDirectory.setText(dir);
}

Component.prototype.targetDirectoryChanged = function()
{
    var dir = targetDirectoryPage.targetDirectory.text;
    if (installer.fileExists(dir) && installer.fileExists(dir + "/maintenancetool.exe")) {
        targetDirectoryPage.warning.setText("<p style=\"color: red\">Existing installation detected and will be overwritten.</p>");
    }
    else if (installer.fileExists(dir)) {
        targetDirectoryPage.warning.setText("<p style=\"color: red\">Installing in existing directory. It will be wiped on uninstallation.</p>");
    }
    else {
        targetDirectoryPage.warning.setText("");
    }
    installer.setValue("TargetDir", dir);
}

Component.prototype.componentSelectionPageEntered = function()
{
    var dir = installer.value("TargetDir");
    if (installer.fileExists(dir) && installer.fileExists(dir + "/maintenancetool.exe")) {
        installer.execute(dir + "/maintenancetool.exe", "--script=" + dir + "/scripts/auto_uninstall.qs");
    }
}
Run Code Online (Sandbox Code Playgroud)

自定义目标目录小部件包/ Atlas4500 Tuner/meta/targetwidget.ui:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>TargetWidget</class>
 <widget class="QWidget" name="TargetWidget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>491</width>
    <height>190</height>
   </rect>
  </property>
  <property name="sizePolicy">
   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
    <horstretch>0</horstretch>
    <verstretch>0</verstretch>
   </sizepolicy>
  </property>
  <property name="minimumSize">
   <size>
    <width>491</width>
    <height>190</height>
   </size>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <widget class="QLabel" name="description">
     <property name="text">
      <string/>
     </property>
    </widget>
   </item>
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout">
     <item>
      <widget class="QLineEdit" name="targetDirectory">
       <property name="readOnly">
        <bool>true</bool>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QToolButton" name="targetChooser">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <property name="minimumSize">
        <size>
         <width>0</width>
         <height>0</height>
        </size>
       </property>
       <property name="text">
        <string>...</string>
       </property>
      </widget>
     </item>
    </layout>
   </item>
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout_2">
     <property name="topMargin">
      <number>0</number>
     </property>
     <item>
      <widget class="QLabel" name="warning">
       <property name="enabled">
        <bool>true</bool>
       </property>
       <property name="text">
        <string>TextLabel</string>
       </property>
      </widget>
     </item>
     <item>
      <spacer name="horizontalSpacer">
       <property name="orientation">
        <enum>Qt::Horizontal</enum>
       </property>
       <property name="sizeHint" stdset="0">
        <size>
         <width>40</width>
         <height>20</height>
        </size>
       </property>
      </spacer>
     </item>
    </layout>
   </item>
   <item>
    <spacer name="verticalSpacer">
     <property name="orientation">
      <enum>Qt::Vertical</enum>
     </property>
     <property name="sizeHint" stdset="0">
      <size>
       <width>20</width>
       <height>122</height>
      </size>
     </property>
    </spacer>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>
Run Code Online (Sandbox Code Playgroud)

packages/Atlas4500 Tuner/data/scripts/auto_uninstall.qs:

// Controller script to pass to the uninstaller to get it to run automatically.
// It's passed to the maintenance tool during installation if there is already an
// installation present with: <target dir>/maintenancetool.exe --script=<target dir>/scripts/auto_uninstall.qs.
// This is required so that the user doesn't have to see/deal with the uninstaller in the middle of
// an installation.

function Controller()
{
    gui.clickButton(buttons.NextButton);
    gui.clickButton(buttons.NextButton);

    installer.uninstallationFinished.connect(this, this.uninstallationFinished);
}

Controller.prototype.uninstallationFinished = function()
{
    gui.clickButton(buttons.NextButton);
}

Controller.prototype.FinishedPageCallback = function()
{
    gui.clickButton(buttons.FinishButton);
}
Run Code Online (Sandbox Code Playgroud)

这里的想法是检测当前目录是否包含安装,如果是,则使用只需单击它的控制器脚本运行该目录中的维护工具.

请注意,我将控制器脚本放在脚本目录中,该脚本目录是实际组件数据的一部分.如果你有多个组件,你可能会做一些更干净的事情,但这就是我正在使用的.

您应该能够自己复制这些文件,只需调整字符串即可使其正常工作.


Ske*_*ird 9

我找到了一种在没有嵌入式控制器脚本的情况下使用有理编码器解决方案的方法!

您所要做的就是使用purge命令启动维护工具并将其发送yes到其标准输入。installer.execute(dir + "/maintenancetool.exe", "--script=" + dir + "/scripts/auto_uninstall.qs");因此,将组件脚本中的这一行替换为这一行installer.execute(dir + "/maintenancetool.exe", ["purge"], "yes");

这样,安装就会被替换,并且 Windows 中的添加/删除程序 UI 不会包含任何重复项。

对于 Windows 用户,请确保原始安装目录未被终端打开。如果是,该目录将不会被删除并且安装将失败。该目录将保持处于错误状态,在重新启动会话之前您无法删除或访问它。


小智 5

添加到rationalcoderSkeird的答案中,当在安装程序框架版本4中使用purge命令时,您不能只传递Yes到stdin,您将收到output device is not associated with a terminal错误,并且维护工具将不执行任何操作。您需要使用-cor--confirm参数。

所以替换:

installer.execute(dir + "/maintenancetool.exe", "--script=" + dir + "/scripts/auto_uninstall.qs");
Run Code Online (Sandbox Code Playgroud)

或者

installer.execute(dir + "/maintenancetool.exe", ["purge"], "yes");
Run Code Online (Sandbox Code Playgroud)

installer.execute(dir + "/maintenancetool.exe", ["purge", "-c"]);
Run Code Online (Sandbox Code Playgroud)