当前位置: 首页 > news >正文

使用 Qt 打造高效的 .run 软件包管理器

在软件开发领域,.run 软件包因其便携性和自解压特性而备受青睐,特别是由 makeself 工具生成的 .run 软件包。这些软件包通常包含一个完整的程序或库,以及一个用于解压和安装的脚本。然而,手动管理这些软件包(尤其是进行安装、卸载和版本切换)可能会变得繁琐且容易出错。因此,开发一个高效的 .run 软件包管理器显得尤为重要。Qt 框架以其跨平台特性和丰富的功能集,成为开发桌面应用程序的理想选择。本文将详细介绍如何通过定义 UpdateInstaller 类,利用Qt 实现.run 软件包的安装、卸载及版本切换功能。

一、基础知识回顾
1. Qt 框架简介

Qt 是一个功能强大、跨平台的应用程序开发框架,广泛应用于GUI程序开发,同时也支持非GUI程序开发,如命令行工具和服务器。Qt的信号与槽机制是其独特的通信方式,允许对象之间进行松耦合通信。QProcess 类则是Qt提供的一个用于启动外部程序和与之交互的类,它可以捕获程序的输出和错误信息,并提供控制程序执行的方法。QProcess 非常适合用于执行系统命令、脚本或运行其他独立程序。

2. .run软件包概述

makeself 是一个简单的工具,用于创建自解压的 .run 软件包。这些软件包通常包含一个 bash 脚本,用于解压和安装软件包内容。.run 软件包的结构通常很简单,但功能强大,因为它们可以包含任何类型的文件,并且安装过程完全由用户定义的脚本控制。

常见的 .run 软件包操作包括安装(通过运行 .run 脚本并遵循其指示)和卸载(通常需要手动删除安装的文件或执行一个卸载脚本)。

参考:使用Makeself打造自解压的.run安装程序

二、UpdateInstaller 类设计
类概述

UpdateInstaller 类的设计目标是封装 QProcess 的功能,提供一个用户友好的接口来管理 .run 软件包,包括安装、卸载及版本切换功能。

UpdateInstaller 类是负责软件更新流程的核心类。它协调各个组件来执行下载、校验、备份、安装和错误处理等任务。这个类封装了更新过程的复杂性,使得外部调用者只需调用一个方法即可启动整个更新流程。

成员变量与属性
  • QProcess process_ :用于执行外部命令和脚本的进程对象。
  • InstallState state_:表示当前安装状态的枚举值。
  • QString currentPackageName_:当前正在安装或卸载的软件包名称。
  • QString currentPackageVersion_(可选):当前正在安装或管理的软件包版本(如果适用)。
  • bool isSilentMode_(可选):是否以静默模式运行,不输出详细日志。
成员方法
  1. install(const QString &packagePath, const QString &packageName, const QString &packageVersion = “”)

    • 参数:packagePath(.run软件包路径),packageName(软件包名称),packageVersion(可选,软件包版本)。
    • 功能:执行 .run 软件包的安装过程。构建并执行包含安装命令的字符串,同时更新安装状态。
  2. uninstall(const QString &packageName)

    • 参数:packageName(要卸载的软件包名称)。
    • 功能:执行软件包的卸载过程。构建并执行包含卸载命令的字符串。
  3. switchVersion(const QString &packageName, const QString &newVersion, const QString &passwd = “”)

    • 参数:packageName(软件包名称),newVersion(要切换到的版本),passwd(可选,用于sudo命令的密码)。
    • 功能:执行软件包的版本切换过程。注意,出于安全考虑,不建议在代码中硬编码密码,应通过安全方式获取用户输入。
  4. checkSoftwareFormat(const QString &packagePath)

    • 参数:packagePath( .run 软件包路径)。
    • 功能:验证.run软件包的有效性。可以读取文件头或特定标记来确认文件格式。
  5. myReadyReadStandardOutput()myReadyReadStandardError()

    • 功能:这两个槽函数分别处理 QProcess 的标准输出和错误输出。它们读取输出内容,并通过信号传递给外部调用者。
  6. processFinished(int exitCode, QProcess::ExitStatus exitStatus)

    • 功能:处理 QProcess 结束时的状态。根据退出码和退出状态更新安装状态,并通过信号通知外部调用者。
信号
  • messageOutput(const QString &msg):输出日志消息。
  • progressChanged(int percent)(可选):更新安装进度(如果可能的话)。
  • installStateChanged(int state):安装状态改变时发出。
错误处理与日志记录
  • 错误处理:在方法实现中,应捕获并处理可能的异常或错误状态,例如文件不存在、命令执行失败等。通过发出错误消息或更改安装状态来通知外部调用者。
  • 日志记录:可以扩展日志记录功能,以便更好地追踪和调试安装、卸载和版本切换过程中的问题。可以使用 Qt 的日志框架(如qDebug()qWarning()等)或自定义日志系统。
三、实现 UpdateInstaller 类
1. 环境准备

在开始实现 UpdateInstaller 类之前,请确保 Qt 开发环境已经搭建完毕,并且有一个示例 .run 软件包用于测试。Qt 的官方文档提供了详细的安装指南,而.run软件包可以通过任何提供此类软件包的网站或资源获取。

2. 代码实现

以下是 UpdateInstaller 类的实现示例,包括处理 QProcess 的输出和错误、更新安装状态以及实现一些基本的验证和错误处理机制。

#include <QCoreApplication>
#include <QProcess>
#include <QObject>
#include <QString>
#include <QByteArray>
#include <QDebug>
#include <QFile>
#include <QFileInfo>class UpdateInstaller : public QObject {Q_OBJECTpublic:enum InstallState {InstallState_Verifying = 0,InstallState_Uncompressing,InstallState_Configuring,InstallState_Completed,InstallState_Failed};UpdateInstaller(QObject *parent = nullptr): QObject(parent), state_(InstallState_Verifying), process_(new QProcess(this)) {connect(process_, &QProcess::readyReadStandardOutput, this, &UpdateInstaller::myReadyReadStandardOutput);connect(process_, &QProcess::readyReadStandardError, this, &UpdateInstaller::myReadyReadStandardError);connect(process_, &QProcess::finished, this, &UpdateInstaller::processFinished);}~UpdateInstaller() {}void install(const QString &path, const QString &name) {if (!QFile::exists(path)) {emit messageOutput("File does not exist.");return;}QString command = QString("sudo sh %1 -target /opt/app/%2").arg(path).arg(name);process_->start(command);emit installStateChanged(InstallState_Verifying);}static bool uninstall(const QString &name) {QString command = QString("sudo rm -rf /opt/app/%1").arg(name);int result = system(command.toStdString().c_str());return result == 0;}static void switchVersion(const QString &ver, const QString &passwd = "") {// 出于安全考虑,不建议在代码中硬编码密码// 这里仅作为示例,实际使用中应通过安全方式获取密码QString command = QString("echo %1 | sudo -S sh /opt/app/some_package/setup.sh install %2").arg(passwd).arg(ver);QProcess::startDetached(command); // 使用 startDetached 以避免阻塞主线程}static bool checkSoftwareFormat(const QString &path) {QFile file(path);if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {return false;}QByteArray header = file.read(100); // 读取前100个字节作为示例return header.contains("makeself"); // 假设 makeself 是有效的包标识}signals:void messageOutput(const QString &msg);void progressChanged(int percent);void installStateChanged(int state);public slots:void myReadyReadStandardOutput() {QByteArray output = process_->readAllStandardOutput();emit messageOutput(QString::fromUtf8(output));}void myReadyReadStandardError() {QByteArray error = process_->readAllStandardError();emit messageOutput(QString::fromUtf8(error));}void processFinished(int exitCode, QProcess::ExitStatus exitStatus) {if (exitStatus == QProcess::NormalExit && exitCode == 0) {emit installStateChanged(InstallState_Completed);emit messageOutput("Installation completed successfully.");} else {emit installStateChanged(InstallState_Failed);emit messageOutput("Installation failed with exit code " + QString::number(exitCode));}}private:QProcess *process_;InstallState state_;
};int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);UpdateInstaller installer;QObject::connect(&installer, &UpdateInstaller::messageOutput, [](const QString &msg){qDebug() << "Message Output:" << msg;});QObject::connect(&installer, &UpdateInstaller::progressChanged, [](int percent){qDebug() << "Progress Changed:" << percent << "%";});QObject::connect(&installer, &UpdateInstaller::installStateChanged, [](int state){switch (state) {case UpdateInstaller::InstallState_Verifying:qDebug() << "Verifying package...";break;case UpdateInstaller::InstallState_Uncompressing:qDebug() << "Uncompressing package...";break;case UpdateInstaller::InstallState_Configuring:qDebug() << "Configuring package...";break;case UpdateInstaller::InstallState_Completed:qDebug() << "Installation completed.";break;case UpdateInstaller::InstallState_Failed:qDebug() << "Installation failed.";break;default:qDebug() << "Unknown install state:" << state;}});QString packagePath = "/path/to/package.run";QString packageName = "example_package";if (UpdateInstaller::checkSoftwareFormat(packagePath)) {installer.install(packagePath, packageName);} else {qDebug() << "Invalid software format.";}return a.exec();
}

注意事项

  1. 错误处理:在实际应用中,错误处理应更加详细和健壮,比如处理不同的错误码、提供用户友好的错误信息等。
  2. 安全性:确保执行的脚本和路径是可信的,避免潜在的安全风险。特别是在处理密码时,应避免在代码中硬编码密码,而应通过安全方式获取用户输入。
  3. 日志记录:可以扩展日志记录功能,以便更好地追踪和调试安装、卸载和版本切换过程中的问题。
  4. 跨平台支持:当前示例针对类Unix系统(如 Linux 和 macOS),对于Windows系统,可能需要不同的实现逻辑。特别是路径和命令的处理方式可能会有所不同。
  5. 进度更新:在实际应用中,进度更新需要根据具体的安装步骤进行解析和更新。可能需要从被执行的脚本中获取进度信息,并通过信号和槽机制将其传递给用户界面。

UpdateInstaller类设计细节优化与完善

相关文章:

使用 Qt 打造高效的 .run 软件包管理器

在软件开发领域&#xff0c;.run 软件包因其便携性和自解压特性而备受青睐&#xff0c;特别是由 makeself 工具生成的 .run 软件包。这些软件包通常包含一个完整的程序或库&#xff0c;以及一个用于解压和安装的脚本。然而&#xff0c;手动管理这些软件包&#xff08;尤其是进行…...

python学opencv|读取视频(二)制作gif

【1】引言 前述已经完成了图像和视频的读取学习&#xff0c;本次课学习制作gif格式动图。 【2】教程 实际上想制作gif格式动图是一个顺理成章的操作&#xff0c;完成了图像和视频的处理&#xff0c;那就自然而然会对gif的处理也产生兴趣。 不过在opencv官网、matplotlib官网…...

19. Three.js案例-创建一个带有纹理映射的旋转平面

19. Three.js案例-创建一个带有纹理映射的旋转平面 实现效果 知识点 WebGLRenderer (WebGL渲染器) WebGLRenderer 是 Three.js 中用于渲染场景的主要类。它利用 WebGL 技术在浏览器中绘制 3D 图形。 构造器 new THREE.WebGLRenderer(parameters)参数类型描述parametersobj…...

ASP.NET|日常开发中常用属性详解

JAVA &#xff5c;日常开发中常用属性详解 前言一、控件属性&#xff08;以 TextBox 控件为例&#xff09;1.1 Text 属性&#xff1a;1.2 MaxLength 属性&#xff1a;1.3 ReadOnly 属性&#xff1a;1.4 IsPostBack 属性&#xff08;在ASP.NET Web Forms 中&#xff09;&#xf…...

vscode CMakeLists中对opencv eigen的引用方法

CMakeLists.txt 项目模式&#xff08;只有一个main函数入口&#xff09; cmake_minimum_required(VERSION 3.5)project(vsin01 VERSION 0.1 LANGUAGES CXX)set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON)set(OpenCV_DIR G:/MinGW_Opencv/opencv4.10/opencv…...

使用Goland对6.5840项目进行go build出现异常

使用Goland对6.5840项目进行go build出现异常 Lab地址: https://pdos.csail.mit.edu/6.824/labs/lab-mr.html项目地址: git://g.csail.mit.edu/6.5840-golabs-2024 6.5840运行环境: mac系统 goland git clone git://g.csail.mit.edu/6.5840-golabs-2024 6.5840 cd 6.5840/src…...

Plugin - 插件开发06_开源项目JPom中的插件实现机制

文章目录 Pre工程结构概述1. 插件接口与实现分析2. 插件工厂初始化分析3. 插件项包装类解析4. 插件工厂方法解析5. 插件加载与资源释放机制6. 实现类小结附PluginFactory Pre 插件 - 通过SPI方式实现插件管理 插件 - 一份配置&#xff0c;离插件机制只有一步之遥 插件 - 插件…...

关于成功插入 SQLite 但没有数据的问题

背景 技术栈&#xff1a;SpringBoot Mybatis-flex SQLite 项目中集成了SQLite&#xff0c;配置如下&#xff1a; spring:datasource:url: jdbc:sqlite::resource:db/project.dbdriver-class-name: org.sqlite.JDBC在进行测试时&#xff0c;使用Mybatis-flex往表中插入数据&…...

单片机+Qt上位机

目录 一、引言 通信方式 优势 案例 常见问题及解决方法 二、单片机与 Qt 上位机的通信方式 &#xff08;一&#xff09;使用 QT 上位机和 STC 单片机实现串口通信 三、单片机 Qt 上位机的优势 &#xff08;一&#xff09;高效便捷的 USB 通信上位机解决方案 &#xf…...

C++ 类和对象(中)

1.类的六个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;其实并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下六个默认成员函数。 默认成员函数&#xff1a;用户没有显式实现&#xff0c;编…...

在做题中学习(79):最小K个数

解法&#xff1a;快速选择算法 说明&#xff1a;堆排序也是经典解决问题的算法&#xff0c;但时间复杂度为&#xff1a;O(NlogK)&#xff0c;K为k个元素 而将要介绍的快速选择算法的时间复杂度为: O(N) 先看我的前两篇文章&#xff0c;分别学习&#xff1a;数组分三块&#…...

spark3 sql优化:同一个表关联多次,优化方案

目录 1.合并查询2.使用 JOIN 条件的过滤优化3.使用 Map-side Join 或 Broadcast Join4.使用 Partitioning 和 Bucketing5.利用 DataFrame API 进行优化假设 A 和 B 已经加载为 DataFramePerform left joins with specific conditions6.使用缓存或持久化7.避免笛卡尔积总结 1.合…...

JavaWeb学习(4)(四大域、HttpSession原理(面试)、SessionAPI、Session实现验证码功能)

目录 一、web四大域。 &#xff08;1&#xff09;基本介绍。 &#xff08;2&#xff09;RequestScope。(请求域) &#xff08;3&#xff09;SessionScope。(会话域) &#xff08;4&#xff09;ApplicationScope。(应用域) &#xff08;5&#xff09;PageScope。(页面域) 二、Ht…...

Ubuntu22.04系统源码编译OpenCV 4.10.0(包含opencv_contrib)

因项目需要使用不同版本的OpenCV&#xff0c;而本地的Ubuntu22.04系统装了ROS2自带OpenCV 4.5.4的版本&#xff0c;于是编译一个OpenCV 4.10.0&#xff08;带opencv_contrib&#xff09;版本&#xff0c;给特定的项目使用&#xff0c;这就不用换个设备后重新安装OpenCV 了&…...

【Unity高级】在编辑器中如何让物体围绕一个点旋转固定角度

本文介绍如何在编辑器里让物体围绕一个点旋转固定角度&#xff0c;比如上图里的Cube是围绕白色圆盘的中心旋转45度的。 目标&#xff1a; 创建一个在 Unity 编辑器中使用的旋转工具&#xff0c;使开发者能够在编辑模式下快速旋转一个物体。 实现思路&#xff1a; 编辑模式下…...

2024.11.29——[HCTF 2018]WarmUp 1

拿到题&#xff0c;发现是一张图&#xff0c;查看源代码发现了被注释掉的提示 <!-- source.php--> step 1 在url传参看看这个文件&#xff0c;发现了这道题的源码 step 2 开始审计代码&#xff0c;分析关键函数 //mb_strpos($haystack,$needle,$offset,$encoding):int|…...

AGameModeBase和游戏模式方法

AGameModeBase和游戏模式方法有着密切的关系&#xff1a; AGameModeBase是游戏模式的基础类&#xff1a; 它提供了控制游戏规则的基本框架包含了一系列管理游戏流程的核心方法是所有自定义游戏模式类的父类 主要的游戏模式方法包括&#xff1a; // 游戏初始化时调用 virtua…...

Swift 扩展

Swift 扩展 Swift 是一种强大的编程语言&#xff0c;由苹果公司开发&#xff0c;用于iOS、macOS、watchOS和tvOS应用程序的开发。自2014年发布以来&#xff0c;Swift因其易于阅读和编写的语法、现代化的设计以及出色的性能而广受欢迎。本文将探讨Swift的一些关键特性&#xff…...

【NebulaGraph】官方查询语言nGQL教程1 (四)

【NebulaGraph】官方查询语言nGQL教程1 1. 课程信息2. 查找路径FIND PATH2.1 补充说明FIND PATH2.2 例子 1. 课程信息 课程地址: https://www.bilibili.com/video/BV1PT411P7w8/?spm_id_from333.337.search-card.all.click&vd_source240d9002f7c7e3da63cd9a975639409a …...

阿里云负载均衡SLB实践

基于上篇文章继续&#xff0c;如果你使用的是阿里云等云平台&#xff0c;通过配置nginxkeepAlived行不通&#xff0c;因为阿里云服务器不支持你虚拟出ip提供给外部访问&#xff0c;需要使用阿里云的负载均衡产品 对应的产品有三个系列 1、应用场景 ALB: 主要是对应应用层的7层…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...

pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决

问题&#xff1a; pgsql数据库通过备份数据库文件进行还原时&#xff0c;如果表中有自增序列&#xff0c;还原后可能会出现重复的序列&#xff0c;此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”&#xff0c;…...

数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)

目录 &#x1f50d; 若用递归计算每一项&#xff0c;会发生什么&#xff1f; Horners Rule&#xff08;霍纳法则&#xff09; 第一步&#xff1a;我们从最原始的泰勒公式出发 第二步&#xff1a;从形式上重新观察展开式 &#x1f31f; 第三步&#xff1a;引出霍纳法则&…...