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.
 
 
 
 

270 lines
10 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. sys.path.append('dupeguru')
  8. import os
  9. import os.path as op
  10. from optparse import OptionParser
  11. import shutil
  12. import compileall
  13. import sysconfig
  14. from setuptools import setup, Extension
  15. from hscommon import sphinxgen
  16. from hscommon.build import (
  17. add_to_pythonpath, print_and_do, copy_packages, filereplace,
  18. get_module_version, move_all, copy_all, OSXAppStructure,
  19. fix_qt_resource_file, build_cocoa_ext, copy_embeddable_python_dylib,
  20. collect_stdlib_dependencies
  21. )
  22. from hscommon import loc
  23. from hscommon.plat import ISOSX
  24. from hscommon.util import ensure_folder, delete_files_with_pattern
  25. def parse_args():
  26. usage = "usage: %prog [options]"
  27. parser = OptionParser(usage=usage)
  28. parser.add_option(
  29. '--clean', action='store_true', dest='clean',
  30. help="Clean build folder before building"
  31. )
  32. parser.add_option(
  33. '--doc', action='store_true', dest='doc',
  34. help="Build only the help file"
  35. )
  36. parser.add_option(
  37. '--dev', action='store_true', dest='dev', default=False,
  38. help="If this flag is set, will configure for dev builds."
  39. )
  40. parser.add_option(
  41. '--loc', action='store_true', dest='loc',
  42. help="Build only localization"
  43. )
  44. parser.add_option(
  45. '--cocoa-ext', action='store_true', dest='cocoa_ext',
  46. help="Build only Cocoa extensions"
  47. )
  48. parser.add_option(
  49. '--cocoa-compile', action='store_true', dest='cocoa_compile',
  50. help="Build only Cocoa executable"
  51. )
  52. parser.add_option(
  53. '--updatepot', action='store_true', dest='updatepot',
  54. help="Generate .pot files from source code."
  55. )
  56. parser.add_option(
  57. '--mergepot', action='store_true', dest='mergepot',
  58. help="Update all .po files based on .pot files."
  59. )
  60. parser.add_option(
  61. '--normpo', action='store_true', dest='normpo',
  62. help="Normalize all PO files (do this before commit)."
  63. )
  64. (options, args) = parser.parse_args()
  65. return options
  66. def cocoa_app():
  67. app_path = 'build/dupeGuru.app'
  68. return OSXAppStructure(app_path)
  69. def build_cocoa(dev):
  70. build_localizations()
  71. build_cocoa_proxy_module()
  72. build_cocoa_bridging_interfaces()
  73. app_version = get_module_version('core')
  74. cocoa_project_path = 'cocoa'
  75. filereplace(op.join(cocoa_project_path, 'InfoTemplate.plist'), op.join('build', 'Info.plist'), version=app_version)
  76. copy_embeddable_python_dylib('build')
  77. if not op.exists('build/PythonHeaders'):
  78. os.symlink(op.dirname(sysconfig.get_config_h_filename()), 'build/PythonHeaders')
  79. build_help()
  80. pydep_folder = op.join('build', 'py')
  81. if not op.exists(pydep_folder):
  82. os.mkdir(pydep_folder)
  83. shutil.copy(op.join(cocoa_project_path, 'dg_cocoa.py'), 'build')
  84. tocopy = [
  85. 'dupeguru/core', 'dupeguru/hscommon', 'cocoa/inter', 'cocoalib/cocoa', 'objp', 'send2trash', 'hsaudiotag',
  86. ]
  87. copy_packages(tocopy, pydep_folder, create_links=dev)
  88. sys.path.insert(0, 'build')
  89. # ModuleFinder can't seem to correctly detect the multiprocessing dependency, so we have
  90. # to manually specify it.
  91. extra_deps = ['multiprocessing']
  92. collect_stdlib_dependencies('build/dg_cocoa.py', pydep_folder, extra_deps=extra_deps)
  93. del sys.path[0]
  94. # Views are not referenced by python code, so they're not found by the collector.
  95. copy_all('build/inter/*.so', op.join(pydep_folder, 'inter'))
  96. if not dev:
  97. # Important: Don't ever run delete_files_with_pattern('*.py') on dev builds because you'll
  98. # be deleting all py files in symlinked folders.
  99. compileall.compile_dir(pydep_folder, force=True, legacy=True)
  100. delete_files_with_pattern(pydep_folder, '*.py')
  101. delete_files_with_pattern(pydep_folder, '__pycache__')
  102. print_and_do('xcodebuild')
  103. def build_help():
  104. print("Generating Help")
  105. current_path = op.abspath('dupeguru')
  106. help_basepath = op.join(current_path, 'help', 'en')
  107. help_destpath = op.join(current_path, '..', 'build', 'help')
  108. changelog_path = op.join(current_path, 'help', 'changelog')
  109. tixurl = "https://github.com/hsoft/dupeguru/issues/{}"
  110. confrepl = {'language': 'en'}
  111. changelogtmpl = op.join(current_path, 'help', 'changelog.tmpl')
  112. conftmpl = op.join(current_path, 'help', 'conf.tmpl')
  113. sphinxgen.gen(help_basepath, help_destpath, changelog_path, tixurl, confrepl, conftmpl, changelogtmpl)
  114. def build_localizations():
  115. if not op.exists('locale'):
  116. os.symlink('dupeguru/locale', 'locale')
  117. loc.compile_all_po('locale')
  118. loc.generate_cocoa_strings_from_xib(op.join('cocoa', 'Base.lproj'))
  119. loc.localize_all_stringsfiles(op.join('cocoa', 'Base.lproj'), 'cocoa')
  120. loc.generate_cocoa_strings_from_xib(op.join('cocoalib', 'Base.lproj'))
  121. loc.localize_all_stringsfiles(op.join('cocoalib', 'Base.lproj'), 'cocoalib')
  122. locale_dest = op.join('build', 'locale')
  123. if op.exists(locale_dest):
  124. shutil.rmtree(locale_dest)
  125. shutil.copytree('locale', locale_dest, ignore=shutil.ignore_patterns('*.po', '*.pot'))
  126. def build_updatepot():
  127. print("Updating Cocoa strings file.")
  128. loc.generate_cocoa_strings_from_code('cocoalib', 'cocoalib/en.lproj')
  129. loc.generate_cocoa_strings_from_code('cocoa', 'cocoa/en.lproj')
  130. def build_mergepot():
  131. print("Updating .po files using .pot files")
  132. loc.merge_pots_into_pos(op.join('cocoalib', 'locale'))
  133. def build_normpo():
  134. loc.normalize_all_pos(op.join('cocoalib', 'locale'))
  135. def build_cocoa_proxy_module():
  136. print("Building Cocoa Proxy")
  137. import objp.p2o
  138. objp.p2o.generate_python_proxy_code('cocoalib/cocoa/CocoaProxy.h', 'build/CocoaProxy.m')
  139. build_cocoa_ext(
  140. "CocoaProxy", 'cocoalib/cocoa',
  141. [
  142. 'cocoalib/cocoa/CocoaProxy.m', 'build/CocoaProxy.m', 'build/ObjP.m',
  143. 'cocoalib/HSErrorReportWindow.m'
  144. ],
  145. ['AppKit', 'CoreServices'],
  146. ['cocoalib', 'cocoa/autogen']
  147. )
  148. def build_cocoa_bridging_interfaces():
  149. print("Building Cocoa Bridging Interfaces")
  150. import objp.o2p
  151. import objp.p2o
  152. add_to_pythonpath('cocoa')
  153. add_to_pythonpath('cocoalib')
  154. from cocoa.inter import (
  155. PyGUIObject, GUIObjectView, PyColumns, ColumnsView, PyOutline,
  156. OutlineView, PySelectableList, SelectableListView, PyTable, TableView, PyBaseApp,
  157. PyTextField, ProgressWindowView, PyProgressWindow
  158. )
  159. from inter.deletion_options import PyDeletionOptions, DeletionOptionsView
  160. from inter.details_panel import PyDetailsPanel, DetailsPanelView
  161. from inter.directory_outline import PyDirectoryOutline, DirectoryOutlineView
  162. from inter.prioritize_dialog import PyPrioritizeDialog, PrioritizeDialogView
  163. from inter.prioritize_list import PyPrioritizeList, PrioritizeListView
  164. from inter.problem_dialog import PyProblemDialog
  165. from inter.ignore_list_dialog import PyIgnoreListDialog, IgnoreListDialogView
  166. from inter.result_table import PyResultTable, ResultTableView
  167. from inter.stats_label import PyStatsLabel, StatsLabelView
  168. from inter.app import PyDupeGuru, DupeGuruView
  169. allclasses = [
  170. PyGUIObject, PyColumns, PyOutline, PySelectableList, PyTable, PyBaseApp,
  171. PyDetailsPanel, PyDirectoryOutline, PyPrioritizeDialog, PyPrioritizeList, PyProblemDialog,
  172. PyIgnoreListDialog, PyDeletionOptions, PyResultTable, PyStatsLabel, PyDupeGuru,
  173. PyTextField, PyProgressWindow
  174. ]
  175. for class_ in allclasses:
  176. objp.o2p.generate_objc_code(class_, 'cocoa/autogen', inherit=True)
  177. allclasses = [
  178. GUIObjectView, ColumnsView, OutlineView, SelectableListView, TableView,
  179. DetailsPanelView, DirectoryOutlineView, PrioritizeDialogView, PrioritizeListView,
  180. IgnoreListDialogView, DeletionOptionsView, ResultTableView, StatsLabelView,
  181. ProgressWindowView, DupeGuruView
  182. ]
  183. clsspecs = [objp.o2p.spec_from_python_class(class_) for class_ in allclasses]
  184. objp.p2o.generate_python_proxy_code_from_clsspec(clsspecs, 'build/CocoaViews.m')
  185. build_cocoa_ext('CocoaViews', 'cocoa/inter', ['build/CocoaViews.m', 'build/ObjP.m'])
  186. def build_pe_modules():
  187. print("Building PE Modules")
  188. exts = [
  189. Extension(
  190. "_block",
  191. [op.join('dupeguru', 'core', 'pe', 'modules', 'block.c'), op.join('dupeguru', 'core', 'pe', 'modules', 'common.c')]
  192. ),
  193. Extension(
  194. "_cache",
  195. [op.join('dupeguru', 'core', 'pe', 'modules', 'cache.c'), op.join('dupeguru', 'core', 'pe', 'modules', 'common.c')]
  196. ),
  197. ]
  198. exts.append(Extension(
  199. "_block_osx",
  200. [op.join('dupeguru', 'core', 'pe', 'modules', 'block_osx.m'), op.join('dupeguru', 'core', 'pe', 'modules', 'common.c')],
  201. extra_link_args=[
  202. "-framework", "CoreFoundation",
  203. "-framework", "Foundation",
  204. "-framework", "ApplicationServices",
  205. ]
  206. ))
  207. setup(
  208. script_args=['build_ext', '--inplace'],
  209. ext_modules=exts,
  210. )
  211. move_all('_block*', op.join('dupeguru', 'core', 'pe'))
  212. move_all('_cache*', op.join('dupeguru', 'core', 'pe'))
  213. def build_normal(dev):
  214. print("Building dupeGuru with UI cocoa")
  215. add_to_pythonpath('.')
  216. build_pe_modules()
  217. build_cocoa(dev)
  218. def main():
  219. options = parse_args()
  220. if options.dev:
  221. print("Building in Dev mode")
  222. if options.clean:
  223. for path in ['build', op.join('cocoa', 'build'), op.join('cocoa', 'autogen')]:
  224. if op.exists(path):
  225. shutil.rmtree(path)
  226. if not op.exists('build'):
  227. os.mkdir('build')
  228. if options.doc:
  229. build_help()
  230. elif options.loc:
  231. build_localizations()
  232. elif options.updatepot:
  233. build_updatepot()
  234. elif options.mergepot:
  235. build_mergepot()
  236. elif options.normpo:
  237. build_normpo()
  238. elif options.cocoa_ext:
  239. build_cocoa_proxy_module()
  240. build_cocoa_bridging_interfaces()
  241. elif options.cocoa_compile:
  242. os.chdir('cocoa')
  243. print_and_do('{0} waf configure && {0} waf'.format(sys.executable))
  244. os.chdir('..')
  245. cocoa_app().copy_executable('cocoa/build/dupeGuru')
  246. else:
  247. build_normal(options.dev)
  248. if __name__ == '__main__':
  249. main()