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")