You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

265 lines
8.9 KiB

  1. # Copyright 2017 Virgil Dupras
  2. #
  3. # This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
  4. # which should be included with this package. The terms are also available at
  5. # http://www.gnu.org/licenses/gpl-3.0.html
  6. import sys
  7. import os
  8. import os.path as op
  9. import compileall
  10. import shutil
  11. import json
  12. from argparse import ArgumentParser
  13. import platform
  14. import distro
  15. import re
  16. from hscommon.build import (
  17. print_and_do,
  18. copy_packages,
  19. build_debian_changelog,
  20. get_module_version,
  21. filereplace,
  22. copy,
  23. setup_package_argparser,
  24. copy_all,
  25. )
  26. def parse_args():
  27. parser = ArgumentParser()
  28. setup_package_argparser(parser)
  29. return parser.parse_args()
  30. def copy_files_to_package(destpath, packages, with_so):
  31. # when with_so is true, we keep .so files in the package, and otherwise, we don't. We need this
  32. # flag because when building debian src pkg, we *don't* want .so files (they're compiled later)
  33. # and when we're packaging under Arch, we're packaging a binary package, so we want them.
  34. if op.exists(destpath):
  35. shutil.rmtree(destpath)
  36. os.makedirs(destpath)
  37. shutil.copy("run.py", op.join(destpath, "run.py"))
  38. extra_ignores = ["*.so"] if not with_so else None
  39. copy_packages(packages, destpath, extra_ignores=extra_ignores)
  40. # include locale files if they are built otherwise exit as it will break
  41. # the localization
  42. if not op.exists("build/locale"):
  43. print('Locale files are missing. Have you run "build.py --loc"? Exiting...')
  44. return
  45. # include help files if they are built otherwise exit as they should be included?
  46. if not op.exists("build/help"):
  47. print('Help files are missing. Have you run "build.py --doc"? Exiting...')
  48. return
  49. shutil.copytree(op.join("build", "help"), op.join(destpath, "help"))
  50. shutil.copytree(op.join("build", "locale"), op.join(destpath, "locale"))
  51. compileall.compile_dir(destpath)
  52. def package_debian_distribution(distribution):
  53. app_version = get_module_version("core")
  54. version = "{}~{}".format(app_version, distribution)
  55. destpath = op.join("build", "dupeguru-{}".format(version))
  56. srcpath = op.join(destpath, "src")
  57. packages = ["hscommon", "core", "qtlib", "qt", "send2trash", "hsaudiotag"]
  58. copy_files_to_package(srcpath, packages, with_so=False)
  59. os.mkdir(op.join(destpath, "modules"))
  60. copy_all(op.join("core", "pe", "modules", "*.*"), op.join(destpath, "modules"))
  61. copy(
  62. op.join("qt", "pe", "modules", "block.c"),
  63. op.join(destpath, "modules", "block_qt.c"),
  64. )
  65. copy(
  66. op.join("pkg", "debian", "build_pe_modules.py"),
  67. op.join(destpath, "build_pe_modules.py"),
  68. )
  69. debdest = op.join(destpath, "debian")
  70. debskel = op.join("pkg", "debian")
  71. os.makedirs(debdest)
  72. debopts = json.load(open(op.join(debskel, "dupeguru.json")))
  73. for fn in ["compat", "copyright", "dirs", "rules", "source"]:
  74. copy(op.join(debskel, fn), op.join(debdest, fn))
  75. filereplace(op.join(debskel, "control"), op.join(debdest, "control"), **debopts)
  76. filereplace(op.join(debskel, "Makefile"), op.join(destpath, "Makefile"), **debopts)
  77. filereplace(
  78. op.join(debskel, "dupeguru.desktop"),
  79. op.join(debdest, "dupeguru.desktop"),
  80. **debopts
  81. )
  82. changelogpath = op.join("help", "changelog")
  83. changelog_dest = op.join(debdest, "changelog")
  84. project_name = debopts["pkgname"]
  85. from_version = "2.9.2"
  86. build_debian_changelog(
  87. changelogpath,
  88. changelog_dest,
  89. project_name,
  90. from_version=from_version,
  91. distribution=distribution,
  92. )
  93. shutil.copy(op.join("images", "dgse_logo_128.png"), srcpath)
  94. os.chdir(destpath)
  95. cmd = "dpkg-buildpackage -F -us -uc"
  96. os.system(cmd)
  97. os.chdir("../..")
  98. def package_debian():
  99. print("Packaging for Debian/Ubuntu")
  100. for distribution in ["unstable"]:
  101. package_debian_distribution(distribution)
  102. def package_arch():
  103. # For now, package_arch() will only copy the source files into build/. It copies less packages
  104. # than package_debian because there are more python packages available in Arch (so we don't
  105. # need to include them).
  106. print("Packaging for Arch")
  107. srcpath = op.join("build", "dupeguru-arch")
  108. packages = [
  109. "hscommon",
  110. "core",
  111. "qtlib",
  112. "qt",
  113. "send2trash",
  114. "hsaudiotag",
  115. ]
  116. copy_files_to_package(srcpath, packages, with_so=True)
  117. shutil.copy(op.join("images", "dgse_logo_128.png"), srcpath)
  118. debopts = json.load(open(op.join("pkg", "arch", "dupeguru.json")))
  119. filereplace(
  120. op.join("pkg", "arch", "dupeguru.desktop"),
  121. op.join(srcpath, "dupeguru.desktop"),
  122. **debopts
  123. )
  124. def package_source_txz():
  125. print("Creating git archive")
  126. app_version = get_module_version("core")
  127. name = "dupeguru-src-{}.tar".format(app_version)
  128. base_path = os.getcwd()
  129. build_path = op.join(base_path, "build")
  130. dest = op.join(build_path, name)
  131. print_and_do("git archive -o {} HEAD".format(dest))
  132. print_and_do("xz {}".format(dest))
  133. def package_windows():
  134. app_version = get_module_version("core")
  135. arch = platform.architecture()[0]
  136. # Information to pass to pyinstaller and NSIS
  137. match = re.search("[0-9]+.[0-9]+.[0-9]+", app_version)
  138. version_array = match.group(0).split(".")
  139. match = re.search("[0-9]+", arch)
  140. bits = match.group(0)
  141. if bits == "64":
  142. arch = "x64"
  143. else:
  144. arch = "x86"
  145. # include locale files if they are built otherwise exit as it will break
  146. # the localization
  147. if not op.exists("build/locale"):
  148. print('Locale files are missing. Have you run "build.py --loc"? Exiting...')
  149. return
  150. # include help files if they are built otherwise exit as they should be included?
  151. if not op.exists("build/help"):
  152. print('Help files are missing. Have you run "build.py --doc"? Exiting...')
  153. return
  154. # create version information file from template
  155. try:
  156. version_template = open("win_version_info.temp", "r")
  157. version_info = version_template.read()
  158. version_template.close()
  159. version_info_file = open("win_version_info.txt", "w")
  160. version_info_file.write(
  161. version_info.format(
  162. version_array[0], version_array[1], version_array[2], bits
  163. )
  164. )
  165. version_info_file.close()
  166. except Exception:
  167. print("Error creating version info file, exiting...")
  168. return
  169. # run pyinstaller from here:
  170. import PyInstaller.__main__
  171. # UCRT dlls are included if the system has the windows kit installed
  172. PyInstaller.__main__.run(
  173. [
  174. "--name=dupeguru-win{0}".format(bits),
  175. "--windowed",
  176. "--noconfirm",
  177. "--icon=images/dgse_logo.ico",
  178. "--add-data=build/locale;locale",
  179. "--add-data=build/help;help",
  180. "--version-file=win_version_info.txt",
  181. "--paths=C:\\Program Files (x86)\\Windows Kits\\10\\Redist\\ucrt\\DLLs\\{0}".format(
  182. arch
  183. ),
  184. "run.py",
  185. ]
  186. )
  187. # remove version info file
  188. os.remove("win_version_info.txt")
  189. # Call NSIS (TODO update to not use hardcoded path)
  190. cmd = (
  191. '"C:\\Program Files (x86)\\NSIS\\Bin\\makensis.exe" '
  192. "/DVERSIONMAJOR={0} /DVERSIONMINOR={1} /DVERSIONPATCH={2} /DBITS={3} setup.nsi"
  193. )
  194. print_and_do(cmd.format(version_array[0], version_array[1], version_array[2], bits))
  195. def package_macos():
  196. # include locale files if they are built otherwise exit as it will break
  197. # the localization
  198. if not op.exists("build/locale"):
  199. print('Locale files are missing. Have you run "build.py --loc"? Exiting...')
  200. return
  201. # include help files if they are built otherwise exit as they should be included?
  202. if not op.exists("build/help"):
  203. print('Help files are missing. Have you run "build.py --doc"? Exiting...')
  204. return
  205. # run pyinstaller from here:
  206. import PyInstaller.__main__
  207. PyInstaller.__main__.run(
  208. [
  209. "--name=dupeguru",
  210. "--windowed",
  211. "--noconfirm",
  212. "--icon=images/dupeguru.icns",
  213. "--osx-bundle-identifier=com.hardcoded-software.dupeguru",
  214. "--add-data=build/locale:locale",
  215. "--add-data=build/help:help",
  216. "run.py",
  217. ]
  218. )
  219. def main():
  220. args = parse_args()
  221. if args.src_pkg:
  222. print("Creating source package for dupeGuru")
  223. package_source_txz()
  224. return
  225. print("Packaging dupeGuru with UI qt")
  226. if sys.platform == "win32":
  227. package_windows()
  228. elif sys.platform == "darwin":
  229. package_macos()
  230. else:
  231. if not args.arch_pkg:
  232. distname = distro.id()
  233. else:
  234. distname = "arch"
  235. if distname == "arch":
  236. package_arch()
  237. else:
  238. package_debian()
  239. if __name__ == "__main__":
  240. main()