Files
xuwenwei d3b6026bfd Initial commit: RustDesk 1.4.7 macOS desktop port
- Filled empty libs/hbb_common/ submodule (cloned from rustdesk/hbb_common)
- Patched Flutter 3.44 / Dart 3.12 compatibility:
  * flutter/lib/generated_bridge.dart: asTypedList with cast<>, DartPort=Int64
  * flutter/lib/common.dart: DialogTheme->DialogThemeData, TabBarTheme->TabBarThemeData
  * flutter/pubspec.yaml: extended_text 14.0.0->15.0.2, google_fonts override 5.0.0
  * flutter/macos/Runner/Configs/Release.xcconfig: EXCLUDED_ARCHS=x86_64
- Build verified: cargo check + cargo build --features flutter + cargo build --release --features flutter
- Verified flutter build macos --debug and --release both produce working .app
- Verified .dmg installer (27MB arm64) created via hdiutil
- Build deps: Xcode 26.5, CocoaPods 1.16.2, Flutter 3.44, VCPKG arm64-osx
2026-06-08 21:43:20 +08:00

109 lines
4.2 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import optparse
from hashlib import md5
import brotli
import datetime
# 4GB maximum
length_count = 4
# encoding
encoding = 'utf-8'
# output: {path: (compressed_data, file_md5)}
def generate_md5_table(folder: str, level) -> dict:
res: dict = dict()
curdir = os.curdir
os.chdir(folder)
for root, _, files in os.walk('.'):
# remove ./
for f in files:
md5_generator = md5()
full_path = os.path.join(root, f)
print(f"Processing {full_path}...")
f = open(full_path, "rb")
content = f.read()
content_compressed = brotli.compress(
content, quality=level)
md5_generator.update(content)
md5_code = md5_generator.hexdigest().encode(encoding=encoding)
res[full_path] = (content_compressed, md5_code)
os.chdir(curdir)
return res
def write_package_metadata(md5_table: dict, output_folder: str, exe: str):
output_path = os.path.join(output_folder, "data.bin")
with open(output_path, "wb") as f:
f.write("rustdesk".encode(encoding=encoding))
for path in md5_table.keys():
(compressed_data, md5_code) = md5_table[path]
data_length = len(compressed_data)
path = path.encode(encoding=encoding)
# path length & path
f.write((len(path)).to_bytes(length=length_count, byteorder='big'))
f.write(path)
# data length & compressed data
f.write(data_length.to_bytes(
length=length_count, byteorder='big'))
f.write(compressed_data)
# md5 code
f.write(md5_code)
# end
f.write("rustdesk".encode(encoding=encoding))
# executable
f.write(exe.encode(encoding='utf-8'))
print(f"Metadata has been written to {output_path}")
def write_app_metadata(output_folder: str):
output_path = os.path.join(output_folder, "app_metadata.toml")
with open(output_path, "w") as f:
f.write(f"timestamp = {int(datetime.datetime.now().timestamp() * 1000)}\n")
print(f"App metadata has been written to {output_path}")
def build_portable(output_folder: str, target: str):
os.chdir(output_folder)
if target:
os.system("cargo build --locked --release --target " + target)
else:
os.system("cargo build --locked --release")
# Linux: python3 generate.py -f ../rustdesk-portable-packer/test -o . -e ./test/main.py
# Windows: python3 .\generate.py -f ..\rustdesk\flutter\build\windows\runner\Debug\ -o . -e ..\rustdesk\flutter\build\windows\runner\Debug\rustdesk.exe
if __name__ == '__main__':
parser = optparse.OptionParser()
parser.add_option("-f", "--folder", dest="folder",
help="folder to compress")
parser.add_option("-o", "--output", dest="output_folder",
help="the root of portable packer project, default is './'")
parser.add_option("-e", "--executable", dest="executable",
help="specify startup file in --folder, default is rustdesk.exe")
parser.add_option("-t", "--target", dest="target",
help="the target used by cargo")
parser.add_option("-l", "--level", dest="level", type="int",
help="compression level, default is 11, highest", default=11)
(options, args) = parser.parse_args()
folder = options.folder or './rustdesk'
output_folder = os.path.abspath(options.output_folder or './')
if not options.executable:
options.executable = 'rustdesk.exe'
if not options.executable.startswith(folder):
options.executable = folder + '/' + options.executable
exe: str = os.path.abspath(options.executable)
if not exe.startswith(os.path.abspath(folder)):
print("The executable must locate in source folder")
exit(-1)
exe = '.' + exe[len(os.path.abspath(folder)):]
print("Executable path: " + exe)
print("Compression level: " + str(options.level))
md5_table = generate_md5_table(folder, options.level)
write_package_metadata(md5_table, output_folder, exe)
write_app_metadata(output_folder)
build_portable(output_folder, options.target)