313 lines
12 KiB
Python
313 lines
12 KiB
Python
# -*- coding:utf-8 -*-
|
|
# @Time : 2024/08/28
|
|
# @Author : 寂静的羽夏(wingsummer)
|
|
# @FileName: makeinnopak.py
|
|
|
|
import argparse
|
|
import os
|
|
import shutil
|
|
import hashlib
|
|
import codecs
|
|
import subprocess
|
|
import platform
|
|
|
|
from colorama import Fore, Style
|
|
|
|
|
|
def run_command_interactive(command):
|
|
"""
|
|
Run a command interactively, printing its stdout in real-time.
|
|
|
|
:param command: List of command arguments (e.g., ["your_command", "arg1", "arg2"])
|
|
:return: The return code of the command
|
|
"""
|
|
process = subprocess.Popen(
|
|
command,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT, # Capture both stdout and stderr
|
|
text=True # Ensure the output is in text mode
|
|
)
|
|
|
|
while True:
|
|
output = process.stdout.readline()
|
|
if output == "" and process.poll() is not None:
|
|
break
|
|
if output:
|
|
print(Fore.GREEN + output.strip() + Style.RESET_ALL)
|
|
|
|
return_code = process.wait()
|
|
return return_code
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
prog="mkinnopak.py", description="A InnoSetup installer maker for WingHexExplorer2")
|
|
|
|
parser.add_argument(
|
|
"folder", help="A folder that has contained the binary build", type=str
|
|
)
|
|
parser.add_argument(
|
|
"-c", "--cc", help="Where ISCC.exe locates", default=r"C:\Program Files (x86)\Inno Setup 6\ISCC.exe", type=str
|
|
)
|
|
parser.add_argument(
|
|
"-o", "--output", help="Where to put the installer", type=str
|
|
)
|
|
parser.add_argument(
|
|
"--build", action="store_true", help="Build the installer"
|
|
)
|
|
parser.add_argument(
|
|
"--no-build", dest="build", action="store_false", help="Skip building the installer"
|
|
)
|
|
parser.set_defaults(build=True)
|
|
|
|
args = parser.parse_args()
|
|
|
|
# checking build toolkits
|
|
if (args.build and os.path.exists(args.cc) == False):
|
|
print(Fore.RED +
|
|
"[Error] InnoSetup is not installed on your system." + Style.RESET_ALL)
|
|
exit(-5)
|
|
|
|
package_name = "WingHexExplorer2"
|
|
exe_name = package_name + ".exe"
|
|
sym_name = package_name + ".pdb"
|
|
|
|
# start parsing build directory
|
|
projectdeb = os.path.abspath(args.folder)
|
|
|
|
buildinstaller = os.path.dirname(os.path.abspath(__file__))
|
|
projectbase = os.path.abspath(os.path.join(buildinstaller, "../.."))
|
|
|
|
cmake_cache = os.path.join(projectdeb, "CMakeCache.txt")
|
|
if (os.path.exists(cmake_cache) == False):
|
|
print(
|
|
Fore.RED + "[Error] This is not a CMake build directory!" + Style.RESET_ALL)
|
|
exit(-1)
|
|
|
|
deploy_exec = ""
|
|
|
|
with open(cmake_cache, 'r') as cmake_config:
|
|
while (True):
|
|
line = cmake_config.readline()
|
|
if not line:
|
|
break
|
|
if (line.startswith("WINDEPLOYQT_EXECUTABLE:FILEPATH")):
|
|
set = line.split('=', 1)
|
|
deploy_exec = set[1].strip('\n')
|
|
pass
|
|
|
|
version_file_src = os.path.join(projectdeb, "WINGHEX_VERSION")
|
|
if (os.path.exists(version_file_src) == False):
|
|
print(
|
|
Fore.RED + "[Error] WINGHEX_VERSION file not found, maybe not a CMake build directory!" + Style.RESET_ALL)
|
|
exit(-1)
|
|
|
|
version_qt_src = os.path.join(projectdeb, "QT_VERSION")
|
|
if (os.path.exists(version_qt_src) == False):
|
|
print(
|
|
Fore.RED + "[Error] QT_VERSION file not found, maybe not a CMake build directory!" + Style.RESET_ALL)
|
|
exit(-1)
|
|
|
|
with open(version_file_src, 'r') as version_file:
|
|
version = version_file.read()
|
|
|
|
with open(version_qt_src, 'r') as version_qt:
|
|
qt_version = version_qt.read()
|
|
|
|
debPath = os.path.join(projectdeb, "package")
|
|
if (os.path.exists(debPath) == True):
|
|
shutil.rmtree(debPath)
|
|
|
|
os.mkdir(debPath)
|
|
|
|
# ok, start copying files
|
|
exeDebPath = os.path.join(debPath, package_name)
|
|
os.mkdir(exeDebPath)
|
|
|
|
# check
|
|
exemain_src = ""
|
|
exesym_src = ""
|
|
exeplg_src = ""
|
|
exeplg_pdb = ""
|
|
|
|
if (os.path.exists(os.path.join(projectdeb, "WingHexExplorer2.sln"))):
|
|
exemain_src = os.path.join(projectdeb, "Release", exe_name)
|
|
exesym_src = os.path.join(projectdeb, "Release", sym_name)
|
|
exeplg_src = os.path.join(
|
|
projectdeb, "WingPlugin", "Release", "WingPlugin.dll")
|
|
exeplg_pdb = os.path.join(
|
|
projectdeb, "WingPlugin", "Release", "WingPlugin.pdb")
|
|
else:
|
|
exemain_src = os.path.join(projectdeb, exe_name)
|
|
exesym_src = os.path.join(projectdeb, sym_name)
|
|
exeplg_src = os.path.join(projectdeb, "WingPlugin", "WingPlugin.dll")
|
|
exeplg_pdb = os.path.join(projectdeb, "WingPlugin", "WingPlugin.pdb")
|
|
|
|
if (os.path.exists(exemain_src) == False):
|
|
print(
|
|
Fore.RED + "[Error] WingHexExplorer2.exe is not found!" + Style.RESET_ALL)
|
|
exit(-3)
|
|
|
|
# calculate the md5 checksum
|
|
with open(exemain_src, 'rb') as file_to_check:
|
|
data = file_to_check.read()
|
|
md5_returned = hashlib.md5(data).hexdigest().upper()
|
|
|
|
print(Fore.GREEN + ">> Get MD5: " + md5_returned + Style.RESET_ALL)
|
|
|
|
with open(os.path.join(exeDebPath, "Md5.txt"), 'w') as md5_file:
|
|
md5_file.write(md5_returned)
|
|
|
|
print(Fore.GREEN + ">> Constructing packages..." + Style.RESET_ALL)
|
|
os.mkdir(os.path.join(exeDebPath, "plugin"))
|
|
os.mkdir(os.path.join(exeDebPath, "scripts"))
|
|
os.mkdir(os.path.join(exeDebPath, "aslib"))
|
|
|
|
shutil.copy2(exemain_src, os.path.join(exeDebPath, exe_name))
|
|
shutil.copy2(exesym_src, os.path.join(exeDebPath, sym_name))
|
|
shutil.copy2(exeplg_src,
|
|
os.path.join(exeDebPath, "WingPlugin.dll"))
|
|
shutil.copyfile(exeplg_pdb, os.path.join(exeDebPath, "WingPlugin.pdb"))
|
|
|
|
shutil.copytree(os.path.join(buildinstaller, "share"),
|
|
os.path.join(exeDebPath, "share"))
|
|
|
|
shutil.copytree(os.path.join(projectdeb, "lang"),
|
|
os.path.join(exeDebPath, "lang"))
|
|
|
|
print(Fore.GREEN + ">> Copying License and other materials..." + Style.RESET_ALL)
|
|
|
|
material_files = ["LICENSE", "authorband.svg",
|
|
"licenseband.svg", "screenshot.png", "README.md"]
|
|
|
|
for f in material_files:
|
|
shutil.copyfile(os.path.join(projectbase, f),
|
|
os.path.join(exeDebPath, f))
|
|
|
|
shutil.copyfile(os.path.join(projectbase, "images", "author.jpg"),
|
|
os.path.join(exeDebPath, "author.jpg"))
|
|
|
|
# deploy the software
|
|
|
|
print(Fore.GREEN + ">> Copying finished, deploying the software..." + Style.RESET_ALL)
|
|
|
|
try:
|
|
subprocess.run([deploy_exec, os.path.join(exeDebPath, exe_name)], check=True,
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
except subprocess.CalledProcessError as e:
|
|
print(
|
|
Fore.RED + f"[Error] deploy package error: \n{e.stderr.decode('utf-8')}" + Style.RESET_ALL)
|
|
exit(-4)
|
|
except FileNotFoundError:
|
|
exit(-4)
|
|
|
|
# generate iss file
|
|
print(Fore.GREEN + ">> Copying finished, generate ISCC script..." + Style.RESET_ALL)
|
|
|
|
iss_content = fr"""
|
|
; Script generated by the mkinnopak.py by wingsummer.
|
|
|
|
#define MyAppName "{package_name}"
|
|
#define MyAppVersion "{version}"
|
|
#define MyAppPublisher "WingCloud"
|
|
#define MyAppURL "https://github.com/Wing-summer/WingHexExplorer2"
|
|
#define MyAppExeName "{exe_name}"
|
|
#define MyAppLicenseFile "{os.path.join(exeDebPath, "LICENSE")}"
|
|
#define MyAppExePath "{os.path.join(exeDebPath, exe_name)}"
|
|
#define MyOutputBaseFilename "{package_name}_Setup_v{version}_{platform.machine()}"
|
|
|
|
"""
|
|
iss_content += r"""
|
|
[Setup]
|
|
; NOTE: The value of AppId uniquely identifies this application.
|
|
; Do not use the same AppId value in installers for other applications.
|
|
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
|
AppId={{2D42FCEE-E47D-4BF5-B77F-CCEF0A1C669B}
|
|
AppName={#MyAppName}
|
|
AppVersion={#MyAppVersion}
|
|
;AppVerName={#MyAppName} {#MyAppVersion}
|
|
AppPublisher={#MyAppPublisher}
|
|
AppPublisherURL={#MyAppURL}
|
|
AppSupportURL={#MyAppURL}
|
|
AppUpdatesURL={#MyAppURL}
|
|
DefaultDirName={commonpf}\{#MyAppName}
|
|
DefaultGroupName={#MyAppName}
|
|
DisableProgramGroupPage=yes
|
|
LicenseFile={#MyAppLicenseFile}
|
|
OutputBaseFilename={#MyOutputBaseFilename}
|
|
Compression=lzma
|
|
SolidCompression=yes
|
|
ArchitecturesAllowed=x64compatible
|
|
ArchitecturesInstallIn64BitMode=x64compatible
|
|
|
|
[Languages]
|
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
|
Name: "chinesesimplified"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
|
|
|
|
[CustomMessages]
|
|
english.OpenWithWingHexExplorer=Open with WingHexExplorer2
|
|
chinesesimplified.OpenWithWingHexExplorer=使用羽云十六进制打开
|
|
|
|
[Tasks]
|
|
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
|
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
|
|
|
|
[Files]
|
|
Source: {#MyAppExePath}; DestDir: "{app}"; Flags: ignoreversion
|
|
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
|
|
|
"""
|
|
iss_content += fr'Source: "{exeDebPath}\*"; ' + \
|
|
r'DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: "*.iss,{#MyOutputBaseFilename}.exe,README.md"' + '\n'
|
|
iss_content += fr'Source: "{exeDebPath}\README.md"; ' + \
|
|
r'DestDir: "{app}"; Flags: isreadme'
|
|
|
|
iss_content += """
|
|
[Registry]
|
|
; Register the application as a handler for all file types
|
|
|
|
"""
|
|
|
|
iss_content += r'Root: HKCR; Subkey: "*\shell\OpenWithWingHexExplorer"; ValueType: expandsz; ValueName: ""; ValueData: {cm:OpenWithWingHexExplorer}; Flags: uninsdeletekey' + '\n'
|
|
iss_content += r'Root: HKCR; Subkey: "*\shell\OpenWithWingHexExplorer"; ValueType: expandsz; ValueName: "Icon"; ValueData: {app}\{#MyAppExeName}; Flags: uninsdeletekey' + '\n'
|
|
iss_content += r'Root: HKCR; Subkey: "*\shell\OpenWithWingHexExplorer\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey' + '\n'
|
|
iss_content += r'Root: HKCR; Subkey: ".wingpro"; ValueType: string; ValueName: ""; ValueData: "WingHexExplorer2" ;Flags: noerror uninsdeletevalue; ' + '\n'
|
|
iss_content += r'Root: HKCR; Subkey: "WingHexExplorer2\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},1"; Flags: noerror uninsdeletevalue; ' + '\n'
|
|
iss_content += r'Root: HKCR; Subkey: "WingHexExplorer2\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1""" ;Flags: noerror uninsdeletevalue; ' + '\n'
|
|
|
|
iss_content += r"""
|
|
[Icons]
|
|
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
|
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
|
|
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
|
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon
|
|
|
|
[Run]
|
|
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
|
"""
|
|
|
|
script_src = os.path.join(exeDebPath, "mkiss.iss")
|
|
with codecs.open(script_src, 'w', "utf-8-sig") as iss:
|
|
iss.write(iss_content)
|
|
|
|
if args.build == False:
|
|
exit(0)
|
|
|
|
print(Fore.GREEN + ">> Copying finished, running ISCC building..." + Style.RESET_ALL)
|
|
|
|
pak_out = ""
|
|
if args.output is None:
|
|
pak_out = os.path.join(exeDebPath, "..")
|
|
else:
|
|
pak_out = args.output
|
|
|
|
ret = run_command_interactive([args.cc, f'/O{pak_out}', script_src])
|
|
exit(ret)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
else:
|
|
print(
|
|
Fore.RED + "[Error] Please run this script in main mode" + Style.RESET_ALL)
|