PyQt5 创建windows安装包的方式

NSIS和HM NIS Edit

NSIS下载
HM NIS Edit下载
NSIS MUI 的内置向导页面

Python封装使用

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# @Author     : forward_huan
# @Time       : 2022-07-23 13:29
# @Description:

import os
import shutil
import subprocess
import pack_exe

from datetime import datetime

from src.utils.version import get_version

nsi_text = """; Script generated by the HM NIS Edit Script Wizard.
; HM NIS Edit Wizard helper defines
!define PRODUCT_NAME "#PRODUCT_NAME#"
!define PRODUCT_VERSION "#PRODUCT_VERSION#"
!define PRODUCT_PUBLISHER "#AUTHOR#"
!define EXE_NAME "#EXE_NAME#"
!define INSTALL_ICON "#INSTALL_ICON#"
!define OUT_FILE "#OUT_FILE#"
!define INSTALL_DIR "#INSTALL_DIR#"
!define PRODUCT_DIR_REGKEY \ 
"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${EXE_NAME}.exe"
!define PRODUCT_UNINST_KEY \
"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
!define PRODUCT_STARTMENU_REGVAL "NSIS:StartMenuDir"

; MUI 1.67 compatible ------
!include "MUI.nsh"

; MUI Settings
!define MUI_ABORTWARNING
!define MUI_ICON "${INSTALL_ICON}"
!define MUI_UNICON "${NSISDIR}\\Contrib\\Graphics\\Icons\\modern-uninstall.ico"

; Welcome page
!insertmacro MUI_PAGE_WELCOME

; Directory page
!insertmacro MUI_PAGE_DIRECTORY

; Start menu page
var ICONS_GROUP
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "${PRODUCT_NAME}"
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${PRODUCT_STARTMENU_REGVAL}"
!insertmacro MUI_PAGE_STARTMENU Application $ICONS_GROUP

; Instfiles page
!insertmacro MUI_PAGE_INSTFILES

; Finish page
!define MUI_FINISHPAGE_RUN "$INSTDIR\\${EXE_NAME}.exe"
!insertmacro MUI_PAGE_FINISH

; Uninstaller pages
!insertmacro MUI_UNPAGE_INSTFILES

; Language files
!insertmacro MUI_LANGUAGE "SimpChinese"

; MUI end ------
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "${OUT_FILE}"
InstallDir "C:\\Software\\${INSTALL_DIR}"
InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
ShowInstDetails show
ShowUnInstDetails show

Section "MainSection" SEC01
#INSTALL_DATA#
; Shortcuts
  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
  CreateDirectory "$SMPROGRAMS\\$ICONS_GROUP"
  CreateShortCut \
  "$SMPROGRAMS\\$ICONS_GROUP\\${PRODUCT_NAME}.lnk""$INSTDIR\\${EXE_NAME}.exe"
  CreateShortCut "$DESKTOP\\${PRODUCT_NAME}.lnk""$INSTDIR\\${EXE_NAME}.exe"
  !insertmacro MUI_STARTMENU_WRITE_END
SectionEnd

Section -AdditionalIcons
  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
  CreateShortCut \
  "$SMPROGRAMS\\$ICONS_GROUP\\卸载${PRODUCT_NAME}.lnk" "$INSTDIR\\uninst.exe"
  !insertmacro MUI_STARTMENU_WRITE_END
SectionEnd

Section -Post
  WriteUninstaller "$INSTDIR\\uninst.exe"
  WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\\${EXE_NAME}.exe"
  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} \
  "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} \
  "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\\uninst.exe"
  WriteRegstr ${PRODUCT_UNINST_ROOT_KEY} \
  "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\\${EXE_NAME}.exe"
  WriteRegstr ${PRODUCT_UNINST_ROOT_KEY} \
  "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
  WriteRegstr ${PRODUCT_UNINST_ROOT_KEY} \
  "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
SectionEnd

Function un.onUninstSuccess
  HideWindow
  MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) 已成功地从你的计算机移除。"
FunctionEnd

Function un.onInit
  MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 \
  "你确实要完全移除 $(^Name), 其及所有的组件?" IDYES +2
  Abort
FunctionEnd

Section Uninstall
  !insertmacro MUI_STARTMENU_GETFOLDER "Application" $ICONS_GROUP
#UNINSTALL_DATA#
  Delete "$INSTDIR\\uninst.exe"
  Delete "$SMPROGRAMS\\$ICONS_GROUP\\卸载${PRODUCT_NAME}.lnk"
  Delete "$DESKTOP\\${PRODUCT_NAME}.lnk"
  Delete "$SMPROGRAMS\\$ICONS_GROUP\\${PRODUCT_NAME}.lnk"
  RMDir "$SMPROGRAMS\\$ICONS_GROUP"
  DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
  DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
  SetAutoClose true
SectionEnd
"""


def get_dist_path(file_name):
    """ 获取安装包生成路径"""
    out = os.path.join(pack_exe.get_install_path(), "安装包")
    print("输出目录: ", out)
    if not os.path.exists(out):
        os.makedirs(out)
    time_str = datetime.now().strftime("%Y%m%d")
    return os.path.join(out, f"{file_name}_{time_str}.exe")


def get_install_path():
    """获取Python打包生成文件的路径"""
    out = pack_exe.get_install_path()
    if os.path.exists(out):
        shutil.rmtree(out)
    os.makedirs(out)
    return out


def create_install_data(file_path):
    """
    读取HM NIS Edit所需要添加文件的格式

    :param file_path:安装包所在目录
    return:
    """
    result = []
    len_start = len(file_path) + 1
    for root, dirs, files in os.walk(file_path):
        if root == file_path:
            result.append('SetOutPath "$INSTDIR"')
            result.append('SetOverwrite try')
        else:
            result.append(f'SetOutPath "$INSTDIR\\{str(root)[len_start:]}"')
        for file in files:
            result.append(f'File "{os.path.join(root, file)}"')
    return [f"  {item}" for item in result]


def create_uninstall_data(file_path):
    """
    读取HM NIS Edith所需要卸载文件的格式

    :param file_path: 安装包所在目录
    :return:
    """
    # 获取需要删除的文件和文件夹
    dir_data, file_data = [], []
    result = []
    len_start = len(file_path) + 1
    for root, dirs, files in os.walk(file_path):
        start_path = root[len_start:]
        if not start_path:
            dir_data.append(f'RMDir "$INSTDIR"')
        else:
            dir_data.append(f'RMDir "$INSTDIR\\{start_path}"')
        for file in files:
            file_data.append(
                f'Delete "$INSTDIR\\{os.path.join(start_path, file)}"')
    # 删除文件
    result.append('Delete "$INSTDIR\\uninst.exe"')
    result.extend(file_data)
    # 删除文件夹
    dir_data.reverse()
    result.extend(dir_data)
    return [f"{item}" for item in result]


def create_build_config(
        package_path, product_name, product_version, author,
        icon_path, exe_name, install_dir, out_file):
    install_data = create_install_data(package_path)
    uninstall_data = create_uninstall_data(package_path)
    nsi_info = str(nsi_text) \
        .replace("#PRODUCT_NAME#", product_name) \
        .replace("#PRODUCT_VERSION#", product_version) \
        .replace("#AUTHOR#", author) \
        .replace("#INSTALL_ICON#", icon_path) \
        .replace("#EXE_NAME#", exe_name) \
        .replace("#INSTALL_DIR#", install_dir) \
        .replace("#INSTALL_DATA#", "\n".join(install_data)) \
        .replace("#UNINSTALL_DATA#", "\n".join(uninstall_data)) \
        .replace("#OUT_FILE#", out_file)
    return nsi_info


def build(product_name, author, exe_name, install_dir,
          icon_path=pack_exe.get_logo_path()):
    install_path = get_install_path()
    nsi_path = os.path.join(install_path, f"{exe_name}.nsi")
    pack_exe.build(install_path, exe_name, False)
    product_version = get_version()
    out_name = f"{product_name}安装包_{product_version}"
    out_file = os.path.join(get_dist_path(out_name))
    build_config = create_build_config(
        os.path.join(install_path, exe_name), product_name, product_version,
        author, icon_path, exe_name, install_dir, out_file)
    with open(nsi_path, 'w')as f:
        f.write(build_config)
    command = f'"C:\\Program Files (x86)\\NSIS\\makensis.exe"' \
              f'/NOTIFYHWND 198772 {nsi_path}'
    print(command)

    proc = subprocess.Popen(command)
    proc.wait(60)

    # 删除生成的缓存文件
    os.remove(nsi_path)
    shutil.rmtree(install_path)
    print("生成安装包成功")


if __name__ == '__main__':
    build("菲菲专用办公套件", "Forward", "client", "OCRTool")

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值