generate.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #!/usr/bin/env python3
  2. import os
  3. import optparse
  4. from hashlib import md5
  5. import brotli
  6. import datetime
  7. # 4GB maximum
  8. length_count = 4
  9. # encoding
  10. encoding = 'utf-8'
  11. # output: {path: (compressed_data, file_md5)}
  12. def generate_md5_table(folder: str, level) -> dict:
  13. res: dict = dict()
  14. curdir = os.curdir
  15. os.chdir(folder)
  16. for root, _, files in os.walk('.'):
  17. # remove ./
  18. for f in files:
  19. md5_generator = md5()
  20. full_path = os.path.join(root, f)
  21. print(f"Processing {full_path}...")
  22. f = open(full_path, "rb")
  23. content = f.read()
  24. content_compressed = brotli.compress(
  25. content, quality=level)
  26. md5_generator.update(content)
  27. md5_code = md5_generator.hexdigest().encode(encoding=encoding)
  28. res[full_path] = (content_compressed, md5_code)
  29. os.chdir(curdir)
  30. return res
  31. def write_package_metadata(md5_table: dict, output_folder: str, exe: str):
  32. output_path = os.path.join(output_folder, "data.bin")
  33. with open(output_path, "wb") as f:
  34. f.write("rustdesk".encode(encoding=encoding))
  35. for path in md5_table.keys():
  36. (compressed_data, md5_code) = md5_table[path]
  37. data_length = len(compressed_data)
  38. path = path.encode(encoding=encoding)
  39. # path length & path
  40. f.write((len(path)).to_bytes(length=length_count, byteorder='big'))
  41. f.write(path)
  42. # data length & compressed data
  43. f.write(data_length.to_bytes(
  44. length=length_count, byteorder='big'))
  45. f.write(compressed_data)
  46. # md5 code
  47. f.write(md5_code)
  48. # end
  49. f.write("rustdesk".encode(encoding=encoding))
  50. # executable
  51. f.write(exe.encode(encoding='utf-8'))
  52. print(f"Metadata has been written to {output_path}")
  53. def write_app_metadata(output_folder: str):
  54. output_path = os.path.join(output_folder, "app_metadata.toml")
  55. with open(output_path, "w") as f:
  56. f.write(f"timestamp = {int(datetime.datetime.now().timestamp() * 1000)}\n")
  57. print(f"App metadata has been written to {output_path}")
  58. def build_portable(output_folder: str, target: str):
  59. os.chdir(output_folder)
  60. if target:
  61. os.system("cargo build --release --target " + target)
  62. else:
  63. os.system("cargo build --release")
  64. # Linux: python3 generate.py -f ../rustdesk-portable-packer/test -o . -e ./test/main.py
  65. # Windows: python3 .\generate.py -f ..\rustdesk\flutter\build\windows\runner\Debug\ -o . -e ..\rustdesk\flutter\build\windows\runner\Debug\rustdesk.exe
  66. if __name__ == '__main__':
  67. parser = optparse.OptionParser()
  68. parser.add_option("-f", "--folder", dest="folder",
  69. help="folder to compress")
  70. parser.add_option("-o", "--output", dest="output_folder",
  71. help="the root of portable packer project, default is './'")
  72. parser.add_option("-e", "--executable", dest="executable",
  73. help="specify startup file in --folder, default is rustdesk.exe")
  74. parser.add_option("-t", "--target", dest="target",
  75. help="the target used by cargo")
  76. parser.add_option("-l", "--level", dest="level", type="int",
  77. help="compression level, default is 11, highest", default=11)
  78. (options, args) = parser.parse_args()
  79. folder = options.folder or './rustdesk'
  80. output_folder = os.path.abspath(options.output_folder or './')
  81. if not options.executable:
  82. options.executable = 'rustdesk.exe'
  83. if not options.executable.startswith(folder):
  84. options.executable = folder + '/' + options.executable
  85. exe: str = os.path.abspath(options.executable)
  86. if not exe.startswith(os.path.abspath(folder)):
  87. print("The executable must locate in source folder")
  88. exit(-1)
  89. exe = '.' + exe[len(os.path.abspath(folder)):]
  90. print("Executable path: " + exe)
  91. print("Compression level: " + str(options.level))
  92. md5_table = generate_md5_table(folder, options.level)
  93. write_package_metadata(md5_table, output_folder, exe)
  94. write_app_metadata(output_folder)
  95. build_portable(output_folder, options.target)