From ba179e572d36645d2623017de5eb273417e45b46 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Wed, 16 Jan 2019 01:07:23 -0800 Subject: [PATCH 01/17] build: Drop macports support It's untested / unmaintained, according to theuni. https://github.com/bitcoin/bitcoin/pull/14920/files#r246964938 --- configure.ac | 11 ----------- contrib/macdeploy/macdeployqtplus | 6 ------ 2 files changed, 17 deletions(-) diff --git a/configure.ac b/configure.ac index 6bba0543d3ce..2c87e1e8cdbd 100644 --- a/configure.ac +++ b/configure.ac @@ -538,17 +538,6 @@ case $host in TARGET_OS=darwin if test x$cross_compiling != xyes; then BUILD_OS=darwin - AC_CHECK_PROG([PORT],port, port) - if test x$PORT = xport; then - dnl add default macports paths - CPPFLAGS="$CPPFLAGS -isystem /opt/local/include" - LIBS="$LIBS -L/opt/local/lib" - if test -d /opt/local/include/db48; then - CPPFLAGS="$CPPFLAGS -I/opt/local/include/db48" - LIBS="$LIBS -L/opt/local/lib/db48" - fi - fi - AC_PATH_PROGS([RSVG_CONVERT], [rsvg-convert rsvg],rsvg-convert) AC_CHECK_PROG([BREW],brew, brew) if test x$BREW = xbrew; then diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index b6fa83334eb3..7e1d0ccf4f46 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -172,12 +172,6 @@ class DeploymentInfo(object): if os.path.exists(os.path.join(parentDir, "translations")): # Classic layout, e.g. "/usr/local/Trolltech/Qt-4.x.x" self.qtPath = parentDir - elif os.path.exists(os.path.join(parentDir, "share", "qt4", "translations")): - # MacPorts layout, e.g. "/opt/local/share/qt4" - self.qtPath = os.path.join(parentDir, "share", "qt4") - elif os.path.exists(os.path.join(os.path.dirname(parentDir), "share", "qt4", "translations")): - # Newer Macports layout - self.qtPath = os.path.join(os.path.dirname(parentDir), "share", "qt4") else: self.qtPath = os.getenv("QTDIR", None) From a65bea52b729f8a37c3ed98dc42160939b28c340 Mon Sep 17 00:00:00 2001 From: fanquake Date: Tue, 16 Jul 2019 10:40:31 +0800 Subject: [PATCH 02/17] scripts: add type annotations to macdeployqtplus --- contrib/macdeploy/macdeployqtplus | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 7e1d0ccf4f46..05992b21afa3 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -19,6 +19,7 @@ import subprocess, sys, re, os, shutil, stat, os.path, time from string import Template from argparse import ArgumentParser +from typing import List, Optional # This is ported from the original macdeployqt with modifications @@ -85,7 +86,7 @@ class FrameworkInfo(object): bundleBinaryDirectory = "Contents/MacOS" @classmethod - def fromOtoolLibraryLine(cls, line): + def fromOtoolLibraryLine(cls, line: str) -> Optional['FrameworkInfo']: # Note: line must be trimmed if line == "": return None @@ -152,7 +153,7 @@ class FrameworkInfo(object): return info class ApplicationBundleInfo(object): - def __init__(self, path): + def __init__(self, path: str): self.path = path appName = "PIVX-Qt" self.binaryPath = os.path.join(path, "Contents", "MacOS", appName) @@ -167,7 +168,7 @@ class DeploymentInfo(object): self.pluginPath = None self.deployedFrameworks = [] - def detectQtPath(self, frameworkDirectory): + def detectQtPath(self, frameworkDirectory: str): parentDir = os.path.dirname(frameworkDirectory) if os.path.exists(os.path.join(parentDir, "translations")): # Classic layout, e.g. "/usr/local/Trolltech/Qt-4.x.x" @@ -180,7 +181,7 @@ class DeploymentInfo(object): if os.path.exists(pluginPath): self.pluginPath = pluginPath - def usesFramework(self, name): + def usesFramework(self, name: str) -> bool: nameDot = "%s." % name libNameDot = "lib%s." % name for framework in self.deployedFrameworks: @@ -192,7 +193,7 @@ class DeploymentInfo(object): return True return False -def getFrameworks(binaryPath, verbose): +def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]: if verbose >= 3: print("Inspecting with otool: " + binaryPath) otoolbin=os.getenv("OTOOL", "otool") @@ -221,11 +222,11 @@ def getFrameworks(binaryPath, verbose): return libraries -def runInstallNameTool(action, *args): +def runInstallNameTool(action: str, *args): installnametoolbin=os.getenv("INSTALLNAMETOOL", "install_name_tool") subprocess.check_call([installnametoolbin, "-"+action] + list(args)) -def changeInstallName(oldName, newName, binaryPath, verbose): +def changeInstallName(oldName: str, newName: str, binaryPath: str, verbose: int): if verbose >= 3: print("Using install_name_tool:") print(" in", binaryPath) @@ -233,21 +234,21 @@ def changeInstallName(oldName, newName, binaryPath, verbose): print(" to", newName) runInstallNameTool("change", oldName, newName, binaryPath) -def changeIdentification(id, binaryPath, verbose): +def changeIdentification(id: str, binaryPath: str, verbose: int): if verbose >= 3: print("Using install_name_tool:") print(" change identification in", binaryPath) print(" to", id) runInstallNameTool("id", id, binaryPath) -def runStrip(binaryPath, verbose): +def runStrip(binaryPath: str, verbose: int): stripbin=os.getenv("STRIP", "strip") if verbose >= 3: print("Using strip:") print(" stripped", binaryPath) subprocess.check_call([stripbin, "-x", binaryPath]) -def copyFramework(framework, path, verbose): +def copyFramework(framework: FrameworkInfo, path: str, verbose: int) -> Optional[str]: if framework.sourceFilePath.startswith("Qt"): #standard place for Nokia Qt installer's frameworks fromPath = "/Library/Frameworks/" + framework.sourceFilePath @@ -309,7 +310,7 @@ def copyFramework(framework, path, verbose): return toPath -def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploymentInfo=None): +def deployFrameworks(frameworks: List[FrameworkInfo], bundlePath: str, binaryPath: str, strip: bool, verbose: int, deploymentInfo: Optional[DeploymentInfo] = None) -> DeploymentInfo: if deploymentInfo is None: deploymentInfo = DeploymentInfo() @@ -355,7 +356,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym return deploymentInfo -def deployFrameworksForAppBundle(applicationBundle, strip, verbose): +def deployFrameworksForAppBundle(applicationBundle: ApplicationBundleInfo, strip: bool, verbose: int) -> DeploymentInfo: frameworks = getFrameworks(applicationBundle.binaryPath, verbose) if len(frameworks) == 0 and verbose >= 1: print("Warning: Could not find any external frameworks to deploy in %s." % (applicationBundle.path)) @@ -363,7 +364,7 @@ def deployFrameworksForAppBundle(applicationBundle, strip, verbose): else: return deployFrameworks(frameworks, applicationBundle.path, applicationBundle.binaryPath, strip, verbose) -def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose): +def deployPlugins(appBundleInfo: ApplicationBundleInfo, deploymentInfo: DeploymentInfo, strip: bool, verbose: int): # Lookup available plugins, exclude unneeded plugins = [] if deploymentInfo.pluginPath is None: @@ -712,7 +713,7 @@ elif config.sign: if config.dmg is not None: - def runHDIUtil(verb, image_basename, **kwargs): + def runHDIUtil(verb: str, image_basename: str, **kwargs) -> int: hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"] if "capture_stdout" in kwargs: del kwargs["capture_stdout"] From a3873ea628c4d81781b8852647dfbf6725ef010b Mon Sep 17 00:00:00 2001 From: fanquake Date: Tue, 16 Jul 2019 10:42:33 +0800 Subject: [PATCH 03/17] scripts: use format() in macdeployqtplus --- contrib/macdeploy/macdeployqtplus | 64 +++++++++++++++---------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 05992b21afa3..9eb6927407c4 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -49,18 +49,18 @@ class FrameworkInfo(object): return False def __str__(self): - return """ Framework name: %s - Framework directory: %s - Framework path: %s - Binary name: %s - Binary directory: %s - Binary path: %s - Version: %s - Install name: %s - Deployed install name: %s - Source file Path: %s - Deployed Directory (relative to bundle): %s -""" % (self.frameworkName, + return """ Framework name: {} + Framework directory: {} + Framework path: {} + Binary name: {} + Binary directory: {} + Binary path: {} + Version: {} + Install name: {} + Deployed install name: {} + Source file Path: {} + Deployed Directory (relative to bundle): {} +""".format(self.frameworkName, self.frameworkDirectory, self.frameworkPath, self.binaryName, @@ -182,8 +182,8 @@ class DeploymentInfo(object): self.pluginPath = pluginPath def usesFramework(self, name: str) -> bool: - nameDot = "%s." % name - libNameDot = "lib%s." % name + nameDot = "{}.".format(name) + libNameDot = "lib{}.".format(name) for framework in self.deployedFrameworks: if framework.endswith(".framework"): if framework.startswith(nameDot): @@ -203,7 +203,7 @@ def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]: if verbose >= 1: sys.stderr.write(o_stderr) sys.stderr.flush() - raise RuntimeError("otool failed with return code %d" % otool.returncode) + raise RuntimeError("otool failed with return code {}".format(otool.returncode)) otoolLines = o_stdout.split("\n") otoolLines.pop(0) # First line is the inspected binary @@ -359,7 +359,7 @@ def deployFrameworks(frameworks: List[FrameworkInfo], bundlePath: str, binaryPat def deployFrameworksForAppBundle(applicationBundle: ApplicationBundleInfo, strip: bool, verbose: int) -> DeploymentInfo: frameworks = getFrameworks(applicationBundle.binaryPath, verbose) if len(frameworks) == 0 and verbose >= 1: - print("Warning: Could not find any external frameworks to deploy in %s." % (applicationBundle.path)) + print("Warning: Could not find any external frameworks to deploy in {}.".format(applicationBundle.path)) return DeploymentInfo() else: return deployFrameworks(frameworks, applicationBundle.path, applicationBundle.binaryPath, strip, verbose) @@ -504,7 +504,7 @@ app_bundle = config.app_bundle[0] if not os.path.exists(app_bundle): if verbose >= 1: - sys.stderr.write("Error: Could not find app bundle \"%s\"\n" % (app_bundle)) + sys.stderr.write("Error: Could not find app bundle \"{}\"\n".format(app_bundle)) sys.exit(1) app_bundle_name = os.path.splitext(os.path.basename(app_bundle))[0] @@ -516,7 +516,7 @@ if config.translations_dir and config.translations_dir[0]: translations_dir = config.translations_dir[0] else: if verbose >= 1: - sys.stderr.write("Error: Could not find translation dir \"%s\"\n" % (translations_dir)) + sys.stderr.write("Error: Could not find translation dir \"{}\"\n".format(translations_dir)) sys.exit(1) # ------------------------------------------------ @@ -525,7 +525,7 @@ for p in config.add_resources: print("Checking for \"%s\"..." % p) if not os.path.exists(p): if verbose >= 1: - sys.stderr.write("Error: Could not find additional resource file \"%s\"\n" % (p)) + sys.stderr.write("Error: Could not find additional resource file \"{}\"\n".format(p)) sys.exit(1) # ------------------------------------------------ @@ -542,10 +542,10 @@ if len(config.fancy) == 1: p = config.fancy[0] if verbose >= 3: - print("Fancy: Loading \"%s\"..." % p) + print("Fancy: Loading \"{}\"...".format(p)) if not os.path.exists(p): if verbose >= 1: - sys.stderr.write("Error: Could not find fancy disk image plist at \"%s\"\n" % (p)) + sys.stderr.write("Error: Could not find fancy disk image plist at \"{}\"\n".format(p)) sys.exit(1) try: @@ -553,7 +553,7 @@ if len(config.fancy) == 1: fancy = plistlib.load(fp, fmt=plistlib.FMT_XML) except: if verbose >= 1: - sys.stderr.write("Error: Could not parse fancy disk image plist at \"%s\"\n" % (p)) + sys.stderr.write("Error: Could not parse fancy disk image plist at \"{}\"\n".format(p)) sys.exit(1) try: @@ -567,18 +567,18 @@ if len(config.fancy) == 1: assert isinstance(value, list) and len(value) == 2 and isinstance(value[0], int) and isinstance(value[1], int) except: if verbose >= 1: - sys.stderr.write("Error: Bad format of fancy disk image plist at \"%s\"\n" % (p)) + sys.stderr.write("Error: Bad format of fancy disk image plist at \"{}\"\n".format(p)) sys.exit(1) if "background_picture" in fancy: bp = fancy["background_picture"] if verbose >= 3: - print("Fancy: Resolving background picture \"%s\"..." % bp) + print("Fancy: Resolving background picture \"{}\"...".format(bp)) if not os.path.exists(bp): bp = os.path.join(os.path.dirname(p), bp) if not os.path.exists(bp): if verbose >= 1: - sys.stderr.write("Error: Could not find background picture at \"%s\" or \"%s\"\n" % (fancy["background_picture"], bp)) + sys.stderr.write("Error: Could not find background picture at \"{}\" or \"{}\"\n".format(fancy["background_picture"], bp)) sys.exit(1) else: fancy["background_picture"] = bp @@ -629,7 +629,7 @@ try: config.plugins = False except RuntimeError as e: if verbose >= 1: - sys.stderr.write("Error: %s\n" % str(e)) + sys.stderr.write("Error: {}\n".format(str(e))) sys.exit(1) # ------------------------------------------------ @@ -642,7 +642,7 @@ if config.plugins: deployPlugins(applicationBundle, deploymentInfo, config.strip, verbose) except RuntimeError as e: if verbose >= 1: - sys.stderr.write("Error: %s\n" % str(e)) + sys.stderr.write("Error: {}\n".format(str(e))) sys.exit(1) # ------------------------------------------------ @@ -658,14 +658,14 @@ else: else: sys.stderr.write("Error: Could not find Qt translation path\n") sys.exit(1) - add_qt_tr = ["qt_%s.qm" % lng for lng in config.add_qt_tr[0].split(",")] + add_qt_tr = ["qt_{}.qm".format(lng) for lng in config.add_qt_tr[0].split(",")] for lng_file in add_qt_tr: p = os.path.join(qt_tr_dir, lng_file) if verbose >= 3: - print("Checking for \"%s\"..." % p) + print("Checking for \"{}\"...".format(p)) if not os.path.exists(p): if verbose >= 1: - sys.stderr.write("Error: Could not find Qt translation file \"%s\"\n" % (lng_file)) + sys.stderr.write("Error: Could not find Qt translation file \"{}\"\n".format(lng_file)) sys.exit(1) # ------------------------------------------------ @@ -706,8 +706,8 @@ if config.sign and 'CODESIGNARGS' not in os.environ: print("You must set the CODESIGNARGS environment variable. Skipping signing.") elif config.sign: if verbose >= 1: - print("Code-signing app bundle %s"%(target,)) - subprocess.check_call("codesign --force %s %s"%(os.environ['CODESIGNARGS'], target), shell=True) + print("Code-signing app bundle {}".format(target)) + subprocess.check_call("codesign --force {} {}".format(os.environ['CODESIGNARGS'], target), shell=True) # ------------------------------------------------ From c854f781b1e00d4d501ffc4027005d085a8ea009 Mon Sep 17 00:00:00 2001 From: fanquake Date: Tue, 16 Jul 2019 10:44:38 +0800 Subject: [PATCH 04/17] scripts: misc cleanups in macdeployqtplus --- contrib/macdeploy/macdeployqtplus | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 9eb6927407c4..a2588c975fe0 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -147,7 +147,6 @@ class FrameworkInfo(object): info.sourceContentsDirectory = os.path.join(info.frameworkPath, "Contents") info.sourceVersionContentsDirectory = os.path.join(info.frameworkPath, "Versions", info.version, "Contents") info.destinationResourcesDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Resources") - info.destinationContentsDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Contents") info.destinationVersionContentsDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Versions", info.version, "Contents") return info @@ -727,7 +726,7 @@ if config.dmg is not None: for key, value in kwargs.items(): hdiutil_args.append("-" + key) - if not value is True: + if value is not True: hdiutil_args.append(str(value)) return run(hdiutil_args, universal_newlines=True) From 1c44ecfa222c21f37de3f98807153b0d1e48c517 Mon Sep 17 00:00:00 2001 From: fanquake Date: Tue, 16 Jul 2019 10:48:19 +0800 Subject: [PATCH 05/17] scripts: filter more qt plugins we don't use in macdeployqtplus phonon is no longer a part of Qt as of version 5 --- contrib/macdeploy/macdeployqtplus | 47 ++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index a2588c975fe0..4b3f92467e57 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -373,10 +373,9 @@ def deployPlugins(appBundleInfo: ApplicationBundleInfo, deploymentInfo: Deployme if pluginDirectory == "designer": # Skip designer plugins continue - elif pluginDirectory == "phonon" or pluginDirectory == "phonon_backend": - # Deploy the phonon plugins only if phonon is in use - if not deploymentInfo.usesFramework("phonon"): - continue + elif pluginDirectory == "printsupport": + # Skip printsupport plugins + continue elif pluginDirectory == "sqldrivers": # Deploy the sql plugins only if QtSql is in use if not deploymentInfo.usesFramework("QtSql"): @@ -409,6 +408,42 @@ def deployPlugins(appBundleInfo: ApplicationBundleInfo, deploymentInfo: Deployme # Deploy the mediaservice plugins only if QtMultimediaWidgets is in use if not deploymentInfo.usesFramework("QtMultimediaWidgets"): continue + elif pluginDirectory == "canbus": + # Deploy the canbus plugins only if QtSerialBus is in use + if not deploymentInfo.usesFramework("QtSerialBus"): + continue + elif pluginDirectory == "webview": + # Deploy the webview plugins only if QtWebView is in use + if not deploymentInfo.usesFramework("QtWebView"): + continue + elif pluginDirectory == "gamepads": + # Deploy the webview plugins only if QtGamepad is in use + if not deploymentInfo.usesFramework("QtGamepad"): + continue + elif pluginDirectory == "geoservices": + # Deploy the webview plugins only if QtLocation is in use + if not deploymentInfo.usesFramework("QtLocation"): + continue + elif pluginDirectory == "texttospeech": + # Deploy the texttospeech plugins only if QtTextToSpeech is in use + if not deploymentInfo.usesFramework("QtTextToSpeech"): + continue + elif pluginDirectory == "virtualkeyboard": + # Deploy the virtualkeyboard plugins only if QtVirtualKeyboard is in use + if not deploymentInfo.usesFramework("QtVirtualKeyboard"): + continue + elif pluginDirectory == "sceneparsers": + # Deploy the virtualkeyboard plugins only if Qt3DCore is in use + if not deploymentInfo.usesFramework("Qt3DCore"): + continue + elif pluginDirectory == "renderplugins": + # Deploy the renderplugins plugins only if Qt3DCore is in use + if not deploymentInfo.usesFramework("Qt3DCore"): + continue + elif pluginDirectory == "geometryloaders": + # Deploy the geometryloaders plugins only if Qt3DCore is in use + if not deploymentInfo.usesFramework("Qt3DCore"): + continue for pluginName in filenames: pluginPath = os.path.join(pluginDirectory, pluginName) @@ -435,6 +470,10 @@ def deployPlugins(appBundleInfo: ApplicationBundleInfo, deploymentInfo: Deployme # Deploy the accessible qtquick plugin only if QtQuick is in use if not deploymentInfo.usesFramework("QtQuick"): continue + elif pluginPath == "platforminputcontexts/libqtvirtualkeyboardplugin.dylib": + # Deploy the virtualkeyboardplugin plugin only if QtVirtualKeyboard is in use + if not deploymentInfo.usesFramework("QtVirtualKeyboard"): + continue plugins.append((pluginDirectory, pluginName)) From c2ee6354b4be882d27b82f6711ca83a8f9a08994 Mon Sep 17 00:00:00 2001 From: fanquake Date: Sat, 7 Nov 2020 22:43:58 -0800 Subject: [PATCH 06/17] build: automatically determine macOS translations Rather than using OSX_QT_TRANSLATIONS which must be manually updated, and we forget to update anyway, automatically find and copy available translations from the translations directory. --- Makefile.am | 5 +-- contrib/macdeploy/macdeployqtplus | 63 +++++++++++-------------------- 2 files changed, 23 insertions(+), 45 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0e8a447dea95..3420f7c79921 100644 --- a/Makefile.am +++ b/Makefile.am @@ -40,7 +40,6 @@ OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed -OSX_QT_TRANSLATIONS = da,de,es,hu,ru,uk,zh_CN,zh_TW DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md) DIST_CONTRIB = $(top_srcdir)/contrib/pivx-cli.bash-completion \ @@ -140,7 +139,7 @@ osx_volname: if BUILD_DARWIN $(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) $(OSX_BACKGROUND_IMAGE) - $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -add-qt-tr $(OSX_QT_TRANSLATIONS) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 -volname $(OSX_VOLNAME) + $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 -volname $(OSX_VOLNAME) $(OSX_BACKGROUND_IMAGE).png: contrib/macdeploy/$(OSX_BACKGROUND_SVG) sed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < "$<" | $(RSVG_CONVERT) -f png -d 36 -p 36 -o $@ @@ -174,7 +173,7 @@ $(APP_DIST_DIR)/.DS_Store: $(OSX_DSSTORE_GEN) $(PYTHON) $< "$@" "$(OSX_VOLNAME)" $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/PIVX-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING) - INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2 + INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -verbose 2 deploydir: $(APP_DIST_EXTRAS) endif diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 4b3f92467e57..555c9ee9b7e2 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -17,8 +17,9 @@ # import subprocess, sys, re, os, shutil, stat, os.path, time -from string import Template from argparse import ArgumentParser +from pathlib import Path +from string import Template from typing import List, Optional # This is ported from the original macdeployqt with modifications @@ -527,8 +528,7 @@ ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, h ap.add_argument("-sign", dest="sign", action="store_true", default=False, help="sign .app bundle with codesign tool") ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image; if basename is not specified, a camel-cased version of the app name is used") ap.add_argument("-fancy", nargs=1, metavar="plist", default=[], help="make a fancy looking disk image using the given plist file with instructions; requires -dmg to work") -ap.add_argument("-add-qt-tr", nargs=1, metavar="languages", default=[], help="add Qt translation files to the bundle's resources; the language list must be separated with commas, not with whitespace") -ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translation files") +ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translations. Base translations will automatically be added to the bundle's resources.") ap.add_argument("-add-resources", nargs="+", metavar="path", default=[], help="list of additional files or folders to be copied into the bundle's resources; must be the last argument") ap.add_argument("-volname", nargs=1, metavar="volname", default=[], help="custom volume name for dmg") @@ -548,15 +548,6 @@ if not os.path.exists(app_bundle): app_bundle_name = os.path.splitext(os.path.basename(app_bundle))[0] # ------------------------------------------------ -translations_dir = None -if config.translations_dir and config.translations_dir[0]: - if os.path.exists(config.translations_dir[0]): - translations_dir = config.translations_dir[0] - else: - if verbose >= 1: - sys.stderr.write("Error: Could not find translation dir \"{}\"\n".format(translations_dir)) - sys.exit(1) -# ------------------------------------------------ for p in config.add_resources: if verbose >= 3: @@ -685,26 +676,24 @@ if config.plugins: # ------------------------------------------------ -if len(config.add_qt_tr) == 0: - add_qt_tr = [] -else: - if translations_dir is not None: - qt_tr_dir = translations_dir - else: - if deploymentInfo.qtPath is not None: - qt_tr_dir = os.path.join(deploymentInfo.qtPath, "translations") - else: - sys.stderr.write("Error: Could not find Qt translation path\n") - sys.exit(1) - add_qt_tr = ["qt_{}.qm".format(lng) for lng in config.add_qt_tr[0].split(",")] - for lng_file in add_qt_tr: - p = os.path.join(qt_tr_dir, lng_file) - if verbose >= 3: - print("Checking for \"{}\"...".format(p)) - if not os.path.exists(p): - if verbose >= 1: - sys.stderr.write("Error: Could not find Qt translation file \"{}\"\n".format(lng_file)) - sys.exit(1) +if config.translations_dir: + if not Path(config.translations_dir[0]).exists(): + sys.stderr.write("Error: Could not find translation dir \"{}\"\n".format(config.translations_dir[0])) + sys.exit(1) + +if verbose >= 2: + print("+ Adding Qt translations +") + +translations = Path(config.translations_dir[0]) + +regex = re.compile('qt_[a-z]*(.qm|_[A-Z]*.qm)') + +lang_files = [x for x in translations.iterdir() if regex.match(x.name)] + +for file in lang_files: + if verbose >= 3: + print(file.as_posix(), "->", os.path.join(applicationBundle.resourcesPath, file.name)) + shutil.copy2(file.as_posix(), os.path.join(applicationBundle.resourcesPath, file.name)) # ------------------------------------------------ @@ -716,16 +705,6 @@ with open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") as f: # ------------------------------------------------ -if len(add_qt_tr) > 0 and verbose >= 2: - print("+ Adding Qt translations +") - -for lng_file in add_qt_tr: - if verbose >= 3: - print(os.path.join(qt_tr_dir, lng_file), "->", os.path.join(applicationBundle.resourcesPath, lng_file)) - shutil.copy2(os.path.join(qt_tr_dir, lng_file), os.path.join(applicationBundle.resourcesPath, lng_file)) - -# ------------------------------------------------ - if len(config.add_resources) > 0 and verbose >= 2: print("+ Adding additional resources +") From 4312410f9da1d28d1d1693ff79d46a927b1d6700 Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 9 Nov 2020 10:50:19 +0800 Subject: [PATCH 07/17] macdeploy: remove codesigning argument --- contrib/macdeploy/macdeployqtplus | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 555c9ee9b7e2..b4497cd73e74 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -515,17 +515,12 @@ ap = ArgumentParser(description="""Improved version of macdeployqt. Outputs a ready-to-deploy app in a folder "dist" and optionally wraps it in a .dmg file. Note, that the "dist" folder will be deleted before deploying on each run. -Optionally, Qt translation files (.qm) and additional resources can be added to the bundle. - -Also optionally signs the .app bundle; set the CODESIGNARGS environment variable to pass arguments -to the codesign tool. -E.g. CODESIGNARGS='--sign "Developer ID Application: ..." --keychain /encrypted/foo.keychain'""") +Optionally, Qt translation files (.qm) and additional resources can be added to the bundle.""") ap.add_argument("app_bundle", nargs=1, metavar="app-bundle", help="application bundle to be deployed") ap.add_argument("-verbose", type=int, nargs=1, default=[1], metavar="<0-3>", help="0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug") ap.add_argument("-no-plugins", dest="plugins", action="store_false", default=True, help="skip plugin deployment") ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, help="don't run 'strip' on the binaries") -ap.add_argument("-sign", dest="sign", action="store_true", default=False, help="sign .app bundle with codesign tool") ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image; if basename is not specified, a camel-cased version of the app name is used") ap.add_argument("-fancy", nargs=1, metavar="plist", default=[], help="make a fancy looking disk image using the given plist file with instructions; requires -dmg to work") ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translations. Base translations will automatically be added to the bundle's resources.") @@ -719,15 +714,6 @@ for p in config.add_resources: # ------------------------------------------------ -if config.sign and 'CODESIGNARGS' not in os.environ: - print("You must set the CODESIGNARGS environment variable. Skipping signing.") -elif config.sign: - if verbose >= 1: - print("Code-signing app bundle {}".format(target)) - subprocess.check_call("codesign --force {} {}".format(os.environ['CODESIGNARGS'], target), shell=True) - -# ------------------------------------------------ - if config.dmg is not None: def runHDIUtil(verb: str, image_basename: str, **kwargs) -> int: From d111cdf3059e7119d2888bf07f68794cc08895ee Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 9 Nov 2020 10:51:20 +0800 Subject: [PATCH 08/17] macdeploy: remove add-resources argument --- contrib/macdeploy/macdeployqtplus | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index b4497cd73e74..89598db88f3c 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -515,7 +515,7 @@ ap = ArgumentParser(description="""Improved version of macdeployqt. Outputs a ready-to-deploy app in a folder "dist" and optionally wraps it in a .dmg file. Note, that the "dist" folder will be deleted before deploying on each run. -Optionally, Qt translation files (.qm) and additional resources can be added to the bundle.""") +Optionally, Qt translation files (.qm) can be added to the bundle.""") ap.add_argument("app_bundle", nargs=1, metavar="app-bundle", help="application bundle to be deployed") ap.add_argument("-verbose", type=int, nargs=1, default=[1], metavar="<0-3>", help="0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug") @@ -524,7 +524,6 @@ ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, h ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image; if basename is not specified, a camel-cased version of the app name is used") ap.add_argument("-fancy", nargs=1, metavar="plist", default=[], help="make a fancy looking disk image using the given plist file with instructions; requires -dmg to work") ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translations. Base translations will automatically be added to the bundle's resources.") -ap.add_argument("-add-resources", nargs="+", metavar="path", default=[], help="list of additional files or folders to be copied into the bundle's resources; must be the last argument") ap.add_argument("-volname", nargs=1, metavar="volname", default=[], help="custom volume name for dmg") config = ap.parse_args() @@ -544,16 +543,6 @@ app_bundle_name = os.path.splitext(os.path.basename(app_bundle))[0] # ------------------------------------------------ -for p in config.add_resources: - if verbose >= 3: - print("Checking for \"%s\"..." % p) - if not os.path.exists(p): - if verbose >= 1: - sys.stderr.write("Error: Could not find additional resource file \"{}\"\n".format(p)) - sys.exit(1) - -# ------------------------------------------------ - if len(config.fancy) == 1: if verbose >= 3: print("Fancy: Importing plistlib...") @@ -700,20 +689,6 @@ with open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") as f: # ------------------------------------------------ -if len(config.add_resources) > 0 and verbose >= 2: - print("+ Adding additional resources +") - -for p in config.add_resources: - t = os.path.join(applicationBundle.resourcesPath, os.path.basename(p)) - if verbose >= 3: - print(p, "->", t) - if os.path.isdir(p): - shutil.copytree(p, t, symlinks=True) - else: - shutil.copy2(p, t) - -# ------------------------------------------------ - if config.dmg is not None: def runHDIUtil(verb: str, image_basename: str, **kwargs) -> int: From 56ab77a4386a89297c053ca60159c17c332c3c72 Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 9 Nov 2020 11:10:39 +0800 Subject: [PATCH 09/17] macdeploy: have a single level of logging output 4 different levels of verbosity is overkill for a fairly simple script, which was always being run at 2 in any case. --- Makefile.am | 4 +- contrib/macdeploy/macdeployqtplus | 137 ++++++++++++------------------ 2 files changed, 57 insertions(+), 84 deletions(-) diff --git a/Makefile.am b/Makefile.am index 3420f7c79921..fff03c7a9886 100644 --- a/Makefile.am +++ b/Makefile.am @@ -139,7 +139,7 @@ osx_volname: if BUILD_DARWIN $(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) $(OSX_BACKGROUND_IMAGE) - $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 -volname $(OSX_VOLNAME) + $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -volname $(OSX_VOLNAME) $(OSX_BACKGROUND_IMAGE).png: contrib/macdeploy/$(OSX_BACKGROUND_SVG) sed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < "$<" | $(RSVG_CONVERT) -f png -d 36 -p 36 -o $@ @@ -173,7 +173,7 @@ $(APP_DIST_DIR)/.DS_Store: $(OSX_DSSTORE_GEN) $(PYTHON) $< "$@" "$(OSX_VOLNAME)" $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/PIVX-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING) - INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -verbose 2 + INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) deploydir: $(APP_DIST_EXTRAS) endif diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 89598db88f3c..6294880491d3 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -194,16 +194,15 @@ class DeploymentInfo(object): return False def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]: - if verbose >= 3: + if verbose: print("Inspecting with otool: " + binaryPath) otoolbin=os.getenv("OTOOL", "otool") otool = subprocess.Popen([otoolbin, "-L", binaryPath], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) o_stdout, o_stderr = otool.communicate() if otool.returncode != 0: - if verbose >= 1: - sys.stderr.write(o_stderr) - sys.stderr.flush() - raise RuntimeError("otool failed with return code {}".format(otool.returncode)) + sys.stderr.write(o_stderr) + sys.stderr.flush() + raise RuntimeError("otool failed with return code {}".format(otool.returncode)) otoolLines = o_stdout.split("\n") otoolLines.pop(0) # First line is the inspected binary @@ -215,7 +214,7 @@ def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]: line = line.replace("@loader_path", os.path.dirname(binaryPath)) info = FrameworkInfo.fromOtoolLibraryLine(line.strip()) if info is not None: - if verbose >= 3: + if verbose: print("Found framework:") print(info) libraries.append(info) @@ -227,7 +226,7 @@ def runInstallNameTool(action: str, *args): subprocess.check_call([installnametoolbin, "-"+action] + list(args)) def changeInstallName(oldName: str, newName: str, binaryPath: str, verbose: int): - if verbose >= 3: + if verbose: print("Using install_name_tool:") print(" in", binaryPath) print(" change reference", oldName) @@ -235,7 +234,7 @@ def changeInstallName(oldName: str, newName: str, binaryPath: str, verbose: int) runInstallNameTool("change", oldName, newName, binaryPath) def changeIdentification(id: str, binaryPath: str, verbose: int): - if verbose >= 3: + if verbose: print("Using install_name_tool:") print(" change identification in", binaryPath) print(" to", id) @@ -243,7 +242,7 @@ def changeIdentification(id: str, binaryPath: str, verbose: int): def runStrip(binaryPath: str, verbose: int): stripbin=os.getenv("STRIP", "strip") - if verbose >= 3: + if verbose: print("Using strip:") print(" stripped", binaryPath) subprocess.check_call([stripbin, "-x", binaryPath]) @@ -267,7 +266,7 @@ def copyFramework(framework: FrameworkInfo, path: str, verbose: int) -> Optional os.makedirs(toDir) shutil.copy2(fromPath, toPath) - if verbose >= 3: + if verbose: print("Copied:", fromPath) print(" to:", toPath) @@ -281,13 +280,12 @@ def copyFramework(framework: FrameworkInfo, path: str, verbose: int) -> Optional linkto = framework.version if not os.path.exists(linkfrom): os.symlink(linkto, linkfrom) - if verbose >= 2: - print("Linked:", linkfrom, "->", linkto) + print("Linked:", linkfrom, "->", linkto) fromResourcesDir = framework.sourceResourcesDirectory if os.path.exists(fromResourcesDir): toResourcesDir = os.path.join(path, framework.destinationResourcesDirectory) shutil.copytree(fromResourcesDir, toResourcesDir, symlinks=True) - if verbose >= 3: + if verbose: print("Copied resources:", fromResourcesDir) print(" to:", toResourcesDir) fromContentsDir = framework.sourceVersionContentsDirectory @@ -296,7 +294,7 @@ def copyFramework(framework: FrameworkInfo, path: str, verbose: int) -> Optional if os.path.exists(fromContentsDir): toContentsDir = os.path.join(path, framework.destinationVersionContentsDirectory) shutil.copytree(fromContentsDir, toContentsDir, symlinks=True) - if verbose >= 3: + if verbose: print("Copied Contents:", fromContentsDir) print(" to:", toContentsDir) elif framework.frameworkName.startswith("libQtGui"): # Copy qt_menu.nib (applies to non-framework layout) @@ -304,7 +302,7 @@ def copyFramework(framework: FrameworkInfo, path: str, verbose: int) -> Optional qtMenuNibDestinationPath = os.path.join(path, "Contents", "Resources", "qt_menu.nib") if os.path.exists(qtMenuNibSourcePath) and not os.path.exists(qtMenuNibDestinationPath): shutil.copytree(qtMenuNibSourcePath, qtMenuNibDestinationPath, symlinks=True) - if verbose >= 3: + if verbose: print("Copied for libQtGui:", qtMenuNibSourcePath) print(" to:", qtMenuNibDestinationPath) @@ -318,16 +316,14 @@ def deployFrameworks(frameworks: List[FrameworkInfo], bundlePath: str, binaryPat framework = frameworks.pop(0) deploymentInfo.deployedFrameworks.append(framework.frameworkName) - if verbose >= 2: - print("Processing", framework.frameworkName, "...") + print("Processing", framework.frameworkName, "...") # Get the Qt path from one of the Qt frameworks if deploymentInfo.qtPath is None and framework.isQtFramework(): deploymentInfo.detectQtPath(framework.frameworkDirectory) if framework.installName.startswith("@executable_path") or framework.installName.startswith(bundlePath): - if verbose >= 2: - print(framework.frameworkName, "already deployed, skipping.") + print(framework.frameworkName, "already deployed, skipping.") continue # install_name_tool the new id into the binary @@ -358,7 +354,7 @@ def deployFrameworks(frameworks: List[FrameworkInfo], bundlePath: str, binaryPat def deployFrameworksForAppBundle(applicationBundle: ApplicationBundleInfo, strip: bool, verbose: int) -> DeploymentInfo: frameworks = getFrameworks(applicationBundle.binaryPath, verbose) - if len(frameworks) == 0 and verbose >= 1: + if len(frameworks) == 0: print("Warning: Could not find any external frameworks to deploy in {}.".format(applicationBundle.path)) return DeploymentInfo() else: @@ -479,8 +475,7 @@ def deployPlugins(appBundleInfo: ApplicationBundleInfo, deploymentInfo: Deployme plugins.append((pluginDirectory, pluginName)) for pluginDirectory, pluginName in plugins: - if verbose >= 2: - print("Processing plugin", os.path.join(pluginDirectory, pluginName), "...") + print("Processing plugin", os.path.join(pluginDirectory, pluginName), "...") sourcePath = os.path.join(deploymentInfo.pluginPath, pluginDirectory, pluginName) destinationDirectory = os.path.join(appBundleInfo.pluginPath, pluginDirectory) @@ -489,7 +484,7 @@ def deployPlugins(appBundleInfo: ApplicationBundleInfo, deploymentInfo: Deployme destinationPath = os.path.join(destinationDirectory, pluginName) shutil.copy2(sourcePath, destinationPath) - if verbose >= 3: + if verbose: print("Copied:", sourcePath) print(" to:", destinationPath) @@ -518,7 +513,7 @@ Note, that the "dist" folder will be deleted before deploying on each run. Optionally, Qt translation files (.qm) can be added to the bundle.""") ap.add_argument("app_bundle", nargs=1, metavar="app-bundle", help="application bundle to be deployed") -ap.add_argument("-verbose", type=int, nargs=1, default=[1], metavar="<0-3>", help="0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug") +ap.add_argument("-verbose", nargs="?", const=True, help="Output additional debugging information") ap.add_argument("-no-plugins", dest="plugins", action="store_false", default=True, help="skip plugin deployment") ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, help="don't run 'strip' on the binaries") ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image; if basename is not specified, a camel-cased version of the app name is used") @@ -528,15 +523,14 @@ ap.add_argument("-volname", nargs=1, metavar="volname", default=[], help="custom config = ap.parse_args() -verbose = config.verbose[0] +verbose = config.verbose # ------------------------------------------------ app_bundle = config.app_bundle[0] if not os.path.exists(app_bundle): - if verbose >= 1: - sys.stderr.write("Error: Could not find app bundle \"{}\"\n".format(app_bundle)) + sys.stderr.write("Error: Could not find app bundle \"{}\"\n".format(app_bundle)) sys.exit(1) app_bundle_name = os.path.splitext(os.path.basename(app_bundle))[0] @@ -544,29 +538,26 @@ app_bundle_name = os.path.splitext(os.path.basename(app_bundle))[0] # ------------------------------------------------ if len(config.fancy) == 1: - if verbose >= 3: + if verbose: print("Fancy: Importing plistlib...") try: import plistlib except ImportError: - if verbose >= 1: - sys.stderr.write("Error: Could not import plistlib which is required for fancy disk images.\n") + sys.stderr.write("Error: Could not import plistlib which is required for fancy disk images.\n") sys.exit(1) p = config.fancy[0] - if verbose >= 3: + if verbose: print("Fancy: Loading \"{}\"...".format(p)) if not os.path.exists(p): - if verbose >= 1: - sys.stderr.write("Error: Could not find fancy disk image plist at \"{}\"\n".format(p)) + sys.stderr.write("Error: Could not find fancy disk image plist at \"{}\"\n".format(p)) sys.exit(1) try: with open(p, 'rb') as fp: fancy = plistlib.load(fp, fmt=plistlib.FMT_XML) except: - if verbose >= 1: - sys.stderr.write("Error: Could not parse fancy disk image plist at \"{}\"\n".format(p)) + sys.stderr.write("Error: Could not parse fancy disk image plist at \"{}\"\n".format(p)) sys.exit(1) try: @@ -579,19 +570,17 @@ if len(config.fancy) == 1: for key, value in fancy["items_position"].items(): assert isinstance(value, list) and len(value) == 2 and isinstance(value[0], int) and isinstance(value[1], int) except: - if verbose >= 1: - sys.stderr.write("Error: Bad format of fancy disk image plist at \"{}\"\n".format(p)) + sys.stderr.write("Error: Bad format of fancy disk image plist at \"{}\"\n".format(p)) sys.exit(1) if "background_picture" in fancy: bp = fancy["background_picture"] - if verbose >= 3: + if verbose: print("Fancy: Resolving background picture \"{}\"...".format(bp)) if not os.path.exists(bp): bp = os.path.join(os.path.dirname(p), bp) if not os.path.exists(bp): - if verbose >= 1: - sys.stderr.write("Error: Could not find background picture at \"{}\" or \"{}\"\n".format(fancy["background_picture"], bp)) + sys.stderr.write("Error: Could not find background picture at \"{}\" or \"{}\"\n".format(fancy["background_picture"], bp)) sys.exit(1) else: fancy["background_picture"] = bp @@ -601,8 +590,7 @@ else: # ------------------------------------------------ if os.path.exists("dist"): - if verbose >= 2: - print("+ Removing old dist folder +") + print("+ Removing old dist folder +") shutil.rmtree("dist") @@ -617,9 +605,8 @@ else: target = os.path.join("dist", "PIVX-Qt.app") -if verbose >= 2: - print("+ Copying source bundle +") -if verbose >= 3: +print("+ Copying source bundle +") +if verbose: print(app_bundle, "->", target) os.mkdir("dist") @@ -629,33 +616,28 @@ applicationBundle = ApplicationBundleInfo(target) # ------------------------------------------------ -if verbose >= 2: - print("+ Deploying frameworks +") +print("+ Deploying frameworks +") try: deploymentInfo = deployFrameworksForAppBundle(applicationBundle, config.strip, verbose) if deploymentInfo.qtPath is None: deploymentInfo.qtPath = os.getenv("QTDIR", None) if deploymentInfo.qtPath is None: - if verbose >= 1: - sys.stderr.write("Warning: Could not detect Qt's path, skipping plugin deployment!\n") + sys.stderr.write("Warning: Could not detect Qt's path, skipping plugin deployment!\n") config.plugins = False except RuntimeError as e: - if verbose >= 1: - sys.stderr.write("Error: {}\n".format(str(e))) + sys.stderr.write("Error: {}\n".format(str(e))) sys.exit(1) # ------------------------------------------------ if config.plugins: - if verbose >= 2: - print("+ Deploying plugins +") + print("+ Deploying plugins +") try: deployPlugins(applicationBundle, deploymentInfo, config.strip, verbose) except RuntimeError as e: - if verbose >= 1: - sys.stderr.write("Error: {}\n".format(str(e))) + sys.stderr.write("Error: {}\n".format(str(e))) sys.exit(1) # ------------------------------------------------ @@ -665,8 +647,7 @@ if config.translations_dir: sys.stderr.write("Error: Could not find translation dir \"{}\"\n".format(config.translations_dir[0])) sys.exit(1) -if verbose >= 2: - print("+ Adding Qt translations +") +print("+ Adding Qt translations +") translations = Path(config.translations_dir[0]) @@ -675,14 +656,13 @@ regex = re.compile('qt_[a-z]*(.qm|_[A-Z]*.qm)') lang_files = [x for x in translations.iterdir() if regex.match(x.name)] for file in lang_files: - if verbose >= 3: + if verbose: print(file.as_posix(), "->", os.path.join(applicationBundle.resourcesPath, file.name)) shutil.copy2(file.as_posix(), os.path.join(applicationBundle.resourcesPath, file.name)) # ------------------------------------------------ -if verbose >= 2: - print("+ Installing qt.conf +") +print("+ Installing qt.conf +") with open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") as f: f.write(qt_conf.encode()) @@ -697,9 +677,7 @@ if config.dmg is not None: del kwargs["capture_stdout"] run = subprocess.check_output else: - if verbose < 2: - hdiutil_args.append("-quiet") - elif verbose >= 3: + if verbose: hdiutil_args.append("-verbose") run = subprocess.check_call @@ -710,11 +688,10 @@ if config.dmg is not None: return run(hdiutil_args, universal_newlines=True) - if verbose >= 2: - if fancy is None: - print("+ Creating .dmg disk image +") - else: - print("+ Preparing .dmg disk image +") + if fancy is None: + print("+ Creating .dmg disk image +") + else: + print("+ Preparing .dmg disk image +") if config.dmg != "": dmg_name = config.dmg @@ -728,7 +705,7 @@ if config.dmg is not None: except subprocess.CalledProcessError as e: sys.exit(e.returncode) else: - if verbose >= 3: + if verbose: print("Determining size of \"dist\"...") size = 0 for path, dirs, files in os.walk("dist"): @@ -736,14 +713,14 @@ if config.dmg is not None: size += os.path.getsize(os.path.join(path, file)) size += int(size * 0.15) - if verbose >= 3: + if verbose: print("Creating temp image for modification...") try: runHDIUtil("create", dmg_name + ".temp", srcfolder="dist", format="UDRW", size=size, volname=volname, ov=True) except subprocess.CalledProcessError as e: sys.exit(e.returncode) - if verbose >= 3: + if verbose: print("Attaching temp image...") try: output = runHDIUtil("attach", dmg_name + ".temp", readwrite=True, noverify=True, noautoopen=True, capture_stdout=True) @@ -754,13 +731,12 @@ if config.dmg is not None: disk_root = m.group(0) disk_name = m.group(1) - if verbose >= 2: - print("+ Applying fancy settings +") + print("+ Applying fancy settings +") if "background_picture" in fancy: bg_path = os.path.join(disk_root, ".background", os.path.basename(fancy["background_picture"])) os.mkdir(os.path.dirname(bg_path)) - if verbose >= 3: + if verbose: print(fancy["background_picture"], "->", bg_path) shutil.copy2(fancy["background_picture"], bg_path) else: @@ -822,18 +798,16 @@ if config.dmg is not None: params["background_commands"] = bgscript.substitute({"bgpic" : os.path.basename(bg_path), "disk" : params["disk"]}) s = appscript.substitute(params) - if verbose >= 2: - print("Running AppleScript:") - print(s) + print("Running AppleScript:") + print(s) p = subprocess.Popen(['osascript', '-'], stdin=subprocess.PIPE) p.communicate(input=s.encode('utf-8')) if p.returncode: print("Error running osascript.") - if verbose >= 2: - print("+ Finalizing .dmg disk image +") - time.sleep(5) + print("+ Finalizing .dmg disk image +") + time.sleep(5) try: runHDIUtil("convert", dmg_name + ".temp", format="UDBZ", o=dmg_name + ".dmg", ov=True) @@ -844,7 +818,6 @@ if config.dmg is not None: # ------------------------------------------------ -if verbose >= 2: - print("+ Done +") +print("+ Done +") sys.exit(0) From 4da04d755d0c9f1c73e3a97aca34a5fbcf7cc559 Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 9 Nov 2020 11:18:14 +0800 Subject: [PATCH 10/17] macdeploy: assume plistlib is available We already require Python 3.5 or later --- contrib/macdeploy/macdeployqtplus | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 6294880491d3..2119f2000b10 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -16,6 +16,7 @@ # along with this program. If not, see . # +import plistlib import subprocess, sys, re, os, shutil, stat, os.path, time from argparse import ArgumentParser from pathlib import Path @@ -538,13 +539,6 @@ app_bundle_name = os.path.splitext(os.path.basename(app_bundle))[0] # ------------------------------------------------ if len(config.fancy) == 1: - if verbose: - print("Fancy: Importing plistlib...") - try: - import plistlib - except ImportError: - sys.stderr.write("Error: Could not import plistlib which is required for fancy disk images.\n") - sys.exit(1) p = config.fancy[0] if verbose: From 7cdb5bba3b23c59226fe4c1b0559263a85525c88 Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 9 Nov 2020 01:47:21 -0800 Subject: [PATCH 11/17] macdeploy: consolidate .DS_Store generation Rather than two lots of logic doing roughly the same thing, dependent on if you're compiling on Linux or macOS, combine the .DS store generation into macdeployqtplus. This also removes the -fancy and -volname options. --- Makefile.am | 12 +- contrib/macdeploy/README.md | 8 +- contrib/macdeploy/fancy.plist | 32 ---- contrib/macdeploy/macdeployqtplus | 269 ++++++++++-------------------- 4 files changed, 97 insertions(+), 224 deletions(-) delete mode 100644 contrib/macdeploy/fancy.plist diff --git a/Makefile.am b/Makefile.am index fff03c7a9886..f281dec39490 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,9 +35,7 @@ OSX_DMG = $(OSX_VOLNAME).dmg OSX_BACKGROUND_SVG=background.svg OSX_BACKGROUND_IMAGE=background.tiff OSX_BACKGROUND_IMAGE_DPIS=36 72 -OSX_DSSTORE_GEN=$(top_srcdir)/contrib/macdeploy/custom_dsstore.py OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus -OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed @@ -71,9 +69,8 @@ LINUX_PACKAGING = $(top_srcdir)/share/pixmaps/pivx16.xpm \ $(top_srcdir)/share/pixmaps/pivx32.xpm \ $(top_srcdir)/share/pixmaps/pivx128.png -OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \ +OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_INSTALLER_ICONS) \ $(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_SVG) \ - $(OSX_DSSTORE_GEN) \ $(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \ $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh @@ -139,7 +136,7 @@ osx_volname: if BUILD_DARWIN $(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) $(OSX_BACKGROUND_IMAGE) - $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -volname $(OSX_VOLNAME) + $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) $(OSX_VOLNAME) -translations-dir=$(QT_TRANSLATION_DIR) -dmg $(OSX_BACKGROUND_IMAGE).png: contrib/macdeploy/$(OSX_BACKGROUND_SVG) sed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < "$<" | $(RSVG_CONVERT) -f png -d 36 -p 36 -o $@ @@ -169,11 +166,8 @@ $(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE): $(OSX_BACKGROUND_IMAGE_DPIF $(MKDIR_P) $(@D) $(TIFFCP) -c none $(OSX_BACKGROUND_IMAGE_DPIFILES) $@ -$(APP_DIST_DIR)/.DS_Store: $(OSX_DSSTORE_GEN) - $(PYTHON) $< "$@" "$(OSX_VOLNAME)" - $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/PIVX-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING) - INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) + INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) $(OSX_VOLNAME) -translations-dir=$(QT_TRANSLATION_DIR) deploydir: $(APP_DIST_EXTRAS) endif diff --git a/contrib/macdeploy/README.md b/contrib/macdeploy/README.md index e17d4ee2aa3f..28fa3c1daf00 100644 --- a/contrib/macdeploy/README.md +++ b/contrib/macdeploy/README.md @@ -6,11 +6,7 @@ The `macdeployqtplus` script should not be run manually. Instead, after building make deploy ``` -During the deployment process, the disk image window will pop up briefly -when the fancy settings are applied. This is normal, please do not interfere, -the process will unmount the DMG and cleanup before finishing. - -When complete, it will have produced `PIVX-Qt.dmg`. +When complete, it will have produced `PIVX-Core.dmg`. ## SDK Extraction @@ -111,7 +107,7 @@ broken. Only the compression feature is currently used. Ideally, the creation co and `genisoimage` would no longer be necessary. Background images and other features can be added to DMG files by inserting a -`.DS_Store` before creation. This is generated by the script `contrib/macdeploy/custom_dsstore.py`. +`.DS_Store` during creation. As of OS X 10.9 Mavericks, using an Apple-blessed key to sign binaries is a requirement in order to satisfy the new Gatekeeper requirements. Because this private key cannot be diff --git a/contrib/macdeploy/fancy.plist b/contrib/macdeploy/fancy.plist deleted file mode 100644 index 20021f5d1ff0..000000000000 --- a/contrib/macdeploy/fancy.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - window_bounds - - 300 - 300 - 800 - 620 - - background_picture - background.tiff - icon_size - 96 - applications_symlink - - items_position - - Applications - - 370 - 156 - - PIVX-Qt.app - - 128 - 156 - - - - diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 2119f2000b10..ead8358e8d92 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -17,10 +17,11 @@ # import plistlib -import subprocess, sys, re, os, shutil, stat, os.path, time +import subprocess, sys, re, os, shutil, stat, os.path from argparse import ArgumentParser +from ds_store import DSStore +from mac_alias import Alias from pathlib import Path -from string import Template from typing import List, Optional # This is ported from the original macdeployqt with modifications @@ -514,13 +515,12 @@ Note, that the "dist" folder will be deleted before deploying on each run. Optionally, Qt translation files (.qm) can be added to the bundle.""") ap.add_argument("app_bundle", nargs=1, metavar="app-bundle", help="application bundle to be deployed") +ap.add_argument("appname", nargs=1, metavar="appname", help="name of the app being deployed") ap.add_argument("-verbose", nargs="?", const=True, help="Output additional debugging information") ap.add_argument("-no-plugins", dest="plugins", action="store_false", default=True, help="skip plugin deployment") ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, help="don't run 'strip' on the binaries") -ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image; if basename is not specified, a camel-cased version of the app name is used") -ap.add_argument("-fancy", nargs=1, metavar="plist", default=[], help="make a fancy looking disk image using the given plist file with instructions; requires -dmg to work") +ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image") ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translations. Base translations will automatically be added to the bundle's resources.") -ap.add_argument("-volname", nargs=1, metavar="volname", default=[], help="custom volume name for dmg") config = ap.parse_args() @@ -534,53 +534,6 @@ if not os.path.exists(app_bundle): sys.stderr.write("Error: Could not find app bundle \"{}\"\n".format(app_bundle)) sys.exit(1) -app_bundle_name = os.path.splitext(os.path.basename(app_bundle))[0] - -# ------------------------------------------------ - -if len(config.fancy) == 1: - - p = config.fancy[0] - if verbose: - print("Fancy: Loading \"{}\"...".format(p)) - if not os.path.exists(p): - sys.stderr.write("Error: Could not find fancy disk image plist at \"{}\"\n".format(p)) - sys.exit(1) - - try: - with open(p, 'rb') as fp: - fancy = plistlib.load(fp, fmt=plistlib.FMT_XML) - except: - sys.stderr.write("Error: Could not parse fancy disk image plist at \"{}\"\n".format(p)) - sys.exit(1) - - try: - assert "window_bounds" not in fancy or (isinstance(fancy["window_bounds"], list) and len(fancy["window_bounds"]) == 4) - assert "background_picture" not in fancy or isinstance(fancy["background_picture"], str) - assert "icon_size" not in fancy or isinstance(fancy["icon_size"], int) - assert "applications_symlink" not in fancy or isinstance(fancy["applications_symlink"], bool) - if "items_position" in fancy: - assert isinstance(fancy["items_position"], dict) - for key, value in fancy["items_position"].items(): - assert isinstance(value, list) and len(value) == 2 and isinstance(value[0], int) and isinstance(value[1], int) - except: - sys.stderr.write("Error: Bad format of fancy disk image plist at \"{}\"\n".format(p)) - sys.exit(1) - - if "background_picture" in fancy: - bp = fancy["background_picture"] - if verbose: - print("Fancy: Resolving background picture \"{}\"...".format(bp)) - if not os.path.exists(bp): - bp = os.path.join(os.path.dirname(p), bp) - if not os.path.exists(bp): - sys.stderr.write("Error: Could not find background picture at \"{}\" or \"{}\"\n".format(fancy["background_picture"], bp)) - sys.exit(1) - else: - fancy["background_picture"] = bp -else: - fancy = None - # ------------------------------------------------ if os.path.exists("dist"): @@ -590,10 +543,7 @@ if os.path.exists("dist"): # ------------------------------------------------ -if len(config.volname) == 1: - volname = config.volname[0] -else: - volname = app_bundle_name +appname = config.appname[0] # ------------------------------------------------ @@ -663,6 +613,50 @@ with open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") as f: # ------------------------------------------------ +print("+ Generating .DS_Store +") + +output_file = os.path.join("dist", ".DS_Store") + +ds = DSStore.open(output_file, 'w+') + +ds['.']['bwsp'] = { + 'WindowBounds': '{{300, 280}, {500, 343}}', + 'PreviewPaneVisibility': False, +} + +icvp = { + 'gridOffsetX': 0.0, + 'textSize': 12.0, + 'viewOptionsVersion': 1, + 'backgroundImageAlias': b'\x00\x00\x00\x00\x02\x1a\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\x94\\\xb0H+\x00\x05\x00\x00\x00\x98\x0fbackground.tiff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x99\xd19\xb0\xf8\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\r\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b.background\x00\x00\x10\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x11\x00\x08\x00\x00\xd19\xb0\xf8\x00\x00\x00\x01\x00\x04\x00\x00\x00\x98\x00\x0e\x00 \x00\x0f\x00b\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x00.\x00t\x00i\x00f\x00f\x00\x0f\x00\x02\x00\x00\x00\x12\x00\x1c/.background/background.tiff\x00\x14\x01\x02\x00\x00\x00\x00\x01\x02\x00\x02\x00\x00\x0cMacintosh HD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x97\xab\xc3H+\x00\x00\x01\x88[\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02u\xab\x8d\xd1\x94\\\xb0devrddsk\xff\xff\xff\xff\x00\x00\t \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04pivx\x00\x10\x00\x08\x00\x00\xce\x97\xab\xc3\x00\x00\x00\x11\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x01\x00\x14\x01\x88[\x88\x00\x16\xa9\t\x00\x08\xfaR\x00\x08\xfaQ\x00\x02d\x8e\x00\x0e\x00\x02\x00\x00\x00\x0f\x00\x1a\x00\x0c\x00M\x00a\x00c\x00i\x00n\x00t\x00o\x00s\x00h\x00 \x00H\x00D\x00\x13\x00\x01/\x00\x00\x15\x00\x02\x00\x14\xff\xff\x00\x00\xff\xff\x00\x00', + 'backgroundColorBlue': 1.0, + 'iconSize': 96.0, + 'backgroundColorGreen': 1.0, + 'arrangeBy': 'none', + 'showIconPreview': True, + 'gridSpacing': 100.0, + 'gridOffsetY': 0.0, + 'showItemInfo': False, + 'labelOnBottom': True, + 'backgroundType': 2, + 'backgroundColorRed': 1.0 +} +alias = Alias().from_bytes(icvp['backgroundImageAlias']) +alias.volume.name = appname +alias.volume.posix_path = '/Volumes/' + appname +icvp['backgroundImageAlias'] = alias.to_bytes() +ds['.']['icvp'] = icvp + +ds['.']['vSrn'] = ('long', 1) + +ds['Applications']['Iloc'] = (370, 156) +ds['PIVX-Qt.app']['Iloc'] = (128, 156) + +ds.flush() +ds.close() + +# ------------------------------------------------ + if config.dmg is not None: def runHDIUtil(verb: str, image_basename: str, **kwargs) -> int: @@ -682,133 +676,54 @@ if config.dmg is not None: return run(hdiutil_args, universal_newlines=True) - if fancy is None: - print("+ Creating .dmg disk image +") - else: - print("+ Preparing .dmg disk image +") + print("+ Preparing .dmg disk image +") - if config.dmg != "": - dmg_name = config.dmg - else: - spl = app_bundle_name.split(" ") - dmg_name = spl[0] + "".join(p.capitalize() for p in spl[1:]) - - if fancy is None: - try: - runHDIUtil("create", dmg_name, srcfolder="dist", format="UDBZ", volname=volname, ov=True) - except subprocess.CalledProcessError as e: - sys.exit(e.returncode) - else: - if verbose: - print("Determining size of \"dist\"...") - size = 0 - for path, dirs, files in os.walk("dist"): - for file in files: - size += os.path.getsize(os.path.join(path, file)) - size += int(size * 0.15) + if verbose: + print("Determining size of \"dist\"...") + size = 0 + for path, dirs, files in os.walk("dist"): + for file in files: + size += os.path.getsize(os.path.join(path, file)) + size += int(size * 0.15) - if verbose: - print("Creating temp image for modification...") - try: - runHDIUtil("create", dmg_name + ".temp", srcfolder="dist", format="UDRW", size=size, volname=volname, ov=True) - except subprocess.CalledProcessError as e: - sys.exit(e.returncode) + if verbose: + print("Creating temp image for modification...") + try: + runHDIUtil("create", appname + ".temp", srcfolder="dist", format="UDRW", size=size, volname=appname, ov=True) + except subprocess.CalledProcessError as e: + sys.exit(e.returncode) - if verbose: - print("Attaching temp image...") - try: - output = runHDIUtil("attach", dmg_name + ".temp", readwrite=True, noverify=True, noautoopen=True, capture_stdout=True) - except subprocess.CalledProcessError as e: - sys.exit(e.returncode) + if verbose: + print("Attaching temp image...") + try: + output = runHDIUtil("attach", appname + ".temp", readwrite=True, noverify=True, noautoopen=True, capture_stdout=True) + except subprocess.CalledProcessError as e: + sys.exit(e.returncode) - m = re.search("/Volumes/(.+$)", output) - disk_root = m.group(0) - disk_name = m.group(1) + m = re.search(r"/Volumes/(.+$)", output) + disk_root = m.group(0) - print("+ Applying fancy settings +") + print("+ Applying fancy settings +") - if "background_picture" in fancy: - bg_path = os.path.join(disk_root, ".background", os.path.basename(fancy["background_picture"])) - os.mkdir(os.path.dirname(bg_path)) - if verbose: - print(fancy["background_picture"], "->", bg_path) - shutil.copy2(fancy["background_picture"], bg_path) - else: - bg_path = None - - if fancy.get("applications_symlink", False): - os.symlink("/Applications", os.path.join(disk_root, "Applications")) - - # The Python appscript package broke with OSX 10.8 and isn't being fixed. - # So we now build up an AppleScript string and use the osascript command - # to make the .dmg file pretty: - appscript = Template( """ - on run argv - tell application "Finder" - tell disk "$disk" - open - set current view of container window to icon view - set toolbar visible of container window to false - set statusbar visible of container window to false - set the bounds of container window to {$window_bounds} - set theViewOptions to the icon view options of container window - set arrangement of theViewOptions to not arranged - set icon size of theViewOptions to $icon_size - $background_commands - $items_positions - close -- close/reopen works around a bug... - open - update without registering applications - delay 5 - eject - end tell - end tell - end run - """) - - itemscript = Template('set position of item "${item}" of container window to {${position}}') - items_positions = [] - if "items_position" in fancy: - for name, position in fancy["items_position"].items(): - params = { "item" : name, "position" : ",".join([str(p) for p in position]) } - items_positions.append(itemscript.substitute(params)) - - params = { - "disk" : volname, - "window_bounds" : "300,300,800,620", - "icon_size" : "96", - "background_commands" : "", - "items_positions" : "\n ".join(items_positions) - } - if "window_bounds" in fancy: - params["window_bounds"] = ",".join([str(p) for p in fancy["window_bounds"]]) - if "icon_size" in fancy: - params["icon_size"] = str(fancy["icon_size"]) - if bg_path is not None: - # Set background file, then call SetFile to make it invisible. - # (note: making it invisible first makes set background picture fail) - bgscript = Template("""set background picture of theViewOptions to file ".background:$bgpic" - do shell script "SetFile -a V /Volumes/$disk/.background/$bgpic" """) - params["background_commands"] = bgscript.substitute({"bgpic" : os.path.basename(bg_path), "disk" : params["disk"]}) - - s = appscript.substitute(params) - print("Running AppleScript:") - print(s) - - p = subprocess.Popen(['osascript', '-'], stdin=subprocess.PIPE) - p.communicate(input=s.encode('utf-8')) - if p.returncode: - print("Error running osascript.") - - print("+ Finalizing .dmg disk image +") - time.sleep(5) - - try: - runHDIUtil("convert", dmg_name + ".temp", format="UDBZ", o=dmg_name + ".dmg", ov=True) - except subprocess.CalledProcessError as e: - sys.exit(e.returncode) - - os.unlink(dmg_name + ".temp.dmg") + bg_path = os.path.join(disk_root, ".background", os.path.basename('background.tiff')) + os.mkdir(os.path.dirname(bg_path)) + if verbose: + print('background.tiff', "->", bg_path) + shutil.copy2('background.tiff', bg_path) + + os.symlink("/Applications", os.path.join(disk_root, "Applications")) + + print("+ Finalizing .dmg disk image +") + + subprocess.run(["hdiutil", "detach", "/Volumes/{}".format(appname)], universal_newlines=True) + + try: + runHDIUtil("convert", appname + ".temp", format="UDBZ", o=appname + ".dmg", ov=True) + except subprocess.CalledProcessError as e: + print(e) + sys.exit(e.returncode) + + os.unlink(appname + ".temp.dmg") # ------------------------------------------------ From 023d3ca304f69c9ea7a59784d3cf272d00648fe7 Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 9 Nov 2020 17:49:11 +0800 Subject: [PATCH 12/17] macdeploy: move qt_conf to where it's used --- contrib/macdeploy/macdeployqtplus | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index ead8358e8d92..623f0f865c92 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -502,11 +502,6 @@ def deployPlugins(appBundleInfo: ApplicationBundleInfo, deploymentInfo: Deployme if dependency.frameworkName not in deploymentInfo.deployedFrameworks: deployFrameworks([dependency], appBundleInfo.path, destinationPath, strip, verbose, deploymentInfo) -qt_conf="""[Paths] -Translations=Resources -Plugins=PlugIns -""" - ap = ArgumentParser(description="""Improved version of macdeployqt. Outputs a ready-to-deploy app in a folder "dist" and optionally wraps it in a .dmg file. @@ -608,6 +603,11 @@ for file in lang_files: print("+ Installing qt.conf +") +qt_conf="""[Paths] +Translations=Resources +Plugins=PlugIns +""" + with open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") as f: f.write(qt_conf.encode()) From 8bcfd5817c337ad468caacd26a44cc60cb093ef3 Mon Sep 17 00:00:00 2001 From: fanquake Date: Tue, 10 Nov 2020 21:16:27 -0800 Subject: [PATCH 13/17] macdeploy: remove existing PIVX-Core.dmg if present --- contrib/macdeploy/macdeployqtplus | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 623f0f865c92..3a7d68ab362e 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -524,6 +524,7 @@ verbose = config.verbose # ------------------------------------------------ app_bundle = config.app_bundle[0] +appname = config.appname[0] if not os.path.exists(app_bundle): sys.stderr.write("Error: Could not find app bundle \"{}\"\n".format(app_bundle)) @@ -532,13 +533,12 @@ if not os.path.exists(app_bundle): # ------------------------------------------------ if os.path.exists("dist"): - print("+ Removing old dist folder +") - + print("+ Removing existing dist folder +") shutil.rmtree("dist") -# ------------------------------------------------ - -appname = config.appname[0] +if os.path.exists(appname + ".dmg"): + print("+ Removing existing DMG +") + os.unlink(appname + ".dmg") # ------------------------------------------------ From faf77c31f6b0fb4c23c6cc40f4d21698a0e6bbe0 Mon Sep 17 00:00:00 2001 From: fanquake Date: Wed, 11 Nov 2020 15:29:00 +0800 Subject: [PATCH 14/17] macdeploy: remove runHDIUtil in favor of directly calling subprocess.run --- contrib/macdeploy/macdeployqtplus | 54 +++++++++---------------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 3a7d68ab362e..50297c2da74e 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -17,11 +17,12 @@ # import plistlib -import subprocess, sys, re, os, shutil, stat, os.path +import sys, re, os, shutil, stat, os.path from argparse import ArgumentParser from ds_store import DSStore from mac_alias import Alias from pathlib import Path +from subprocess import PIPE, run from typing import List, Optional # This is ported from the original macdeployqt with modifications @@ -199,14 +200,13 @@ def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]: if verbose: print("Inspecting with otool: " + binaryPath) otoolbin=os.getenv("OTOOL", "otool") - otool = subprocess.Popen([otoolbin, "-L", binaryPath], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) - o_stdout, o_stderr = otool.communicate() + otool = run([otoolbin, "-L", binaryPath], stdout=PIPE, stderr=PIPE, universal_newlines=True) if otool.returncode != 0: - sys.stderr.write(o_stderr) + sys.stderr.write(otool.stderr) sys.stderr.flush() raise RuntimeError("otool failed with return code {}".format(otool.returncode)) - otoolLines = o_stdout.split("\n") + otoolLines = otool.stdout.split("\n") otoolLines.pop(0) # First line is the inspected binary if ".framework" in binaryPath or binaryPath.endswith(".dylib"): otoolLines.pop(0) # Frameworks and dylibs list themselves as a dependency. @@ -225,7 +225,7 @@ def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]: def runInstallNameTool(action: str, *args): installnametoolbin=os.getenv("INSTALLNAMETOOL", "install_name_tool") - subprocess.check_call([installnametoolbin, "-"+action] + list(args)) + run([installnametoolbin, "-"+action] + list(args), check=True) def changeInstallName(oldName: str, newName: str, binaryPath: str, verbose: int): if verbose: @@ -247,7 +247,7 @@ def runStrip(binaryPath: str, verbose: int): if verbose: print("Using strip:") print(" stripped", binaryPath) - subprocess.check_call([stripbin, "-x", binaryPath]) + run([stripbin, "-x", binaryPath], check=True) def copyFramework(framework: FrameworkInfo, path: str, verbose: int) -> Optional[str]: if framework.sourceFilePath.startswith("Qt"): @@ -659,23 +659,6 @@ ds.close() if config.dmg is not None: - def runHDIUtil(verb: str, image_basename: str, **kwargs) -> int: - hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"] - if "capture_stdout" in kwargs: - del kwargs["capture_stdout"] - run = subprocess.check_output - else: - if verbose: - hdiutil_args.append("-verbose") - run = subprocess.check_call - - for key, value in kwargs.items(): - hdiutil_args.append("-" + key) - if value is not True: - hdiutil_args.append(str(value)) - - return run(hdiutil_args, universal_newlines=True) - print("+ Preparing .dmg disk image +") if verbose: @@ -688,17 +671,14 @@ if config.dmg is not None: if verbose: print("Creating temp image for modification...") - try: - runHDIUtil("create", appname + ".temp", srcfolder="dist", format="UDRW", size=size, volname=appname, ov=True) - except subprocess.CalledProcessError as e: - sys.exit(e.returncode) + + tempname = appname + ".temp.dmg" + + run(["hdiutil", "create", tempname, "-srcfolder", "dist", "-format", "UDRW", "-size", str(size), "-volname", appname], check=True, universal_newlines=True) if verbose: print("Attaching temp image...") - try: - output = runHDIUtil("attach", appname + ".temp", readwrite=True, noverify=True, noautoopen=True, capture_stdout=True) - except subprocess.CalledProcessError as e: - sys.exit(e.returncode) + output = run(["hdiutil", "attach", tempname, "-readwrite"], check=True, universal_newlines=True, stdout=PIPE).stdout m = re.search(r"/Volumes/(.+$)", output) disk_root = m.group(0) @@ -715,15 +695,11 @@ if config.dmg is not None: print("+ Finalizing .dmg disk image +") - subprocess.run(["hdiutil", "detach", "/Volumes/{}".format(appname)], universal_newlines=True) + run(["hdiutil", "detach", "/Volumes/{}".format(appname)], universal_newlines=True) - try: - runHDIUtil("convert", appname + ".temp", format="UDBZ", o=appname + ".dmg", ov=True) - except subprocess.CalledProcessError as e: - print(e) - sys.exit(e.returncode) + run(["hdiutil", "convert", tempname, "-format", "UDZO", "-o", appname, "-imagekey", "zlib-level=9"], check=True, universal_newlines=True) - os.unlink(appname + ".temp.dmg") + os.unlink(tempname) # ------------------------------------------------ From 013305d8d2aba7db163fd7870debaf389a926bde Mon Sep 17 00:00:00 2001 From: fanquake Date: Fri, 13 Nov 2020 15:38:03 +0800 Subject: [PATCH 15/17] macdeploy: use Python 3.6 --- contrib/macdeploy/macdeployqtplus | 76 +++++++++++++------------------ 1 file changed, 32 insertions(+), 44 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 50297c2da74e..b7caf41ec765 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -53,28 +53,18 @@ class FrameworkInfo(object): return False def __str__(self): - return """ Framework name: {} - Framework directory: {} - Framework path: {} - Binary name: {} - Binary directory: {} - Binary path: {} - Version: {} - Install name: {} - Deployed install name: {} - Source file Path: {} - Deployed Directory (relative to bundle): {} -""".format(self.frameworkName, - self.frameworkDirectory, - self.frameworkPath, - self.binaryName, - self.binaryDirectory, - self.binaryPath, - self.version, - self.installName, - self.deployedInstallName, - self.sourceFilePath, - self.destinationDirectory) + return f""" Framework name: {frameworkName} + Framework directory: {self.frameworkDirectory} + Framework path: {self.frameworkPath} + Binary name: {self.binaryName} + Binary directory: {self.binaryDirectory} + Binary path: {self.binaryPath} + Version: {self.version} + Install name: {self.installName} + Deployed install name: {self.deployedInstallName} + Source file Path: {self.sourceFilePath} + Deployed Directory (relative to bundle): {self.destinationDirectory} +""" def isDylib(self): return self.frameworkName.endswith(".dylib") @@ -101,7 +91,7 @@ class FrameworkInfo(object): m = cls.reOLine.match(line) if m is None: - raise RuntimeError("otool line could not be parsed: " + line) + raise RuntimeError(f"otool line could not be parsed: {line}") path = m.group(1) @@ -121,7 +111,7 @@ class FrameworkInfo(object): info.version = "-" info.installName = path - info.deployedInstallName = "@executable_path/../Frameworks/" + info.binaryName + info.deployedInstallName = f"@executable_path/../Frameworks/{info.binaryName}" info.sourceFilePath = path info.destinationDirectory = cls.bundleFrameworkDirectory else: @@ -133,7 +123,7 @@ class FrameworkInfo(object): break i += 1 if i == len(parts): - raise RuntimeError("Could not find .framework or .dylib in otool line: " + line) + raise RuntimeError(f"Could not find .framework or .dylib in otool line: {line}") info.frameworkName = parts[i] info.frameworkDirectory = "/".join(parts[:i]) @@ -144,7 +134,7 @@ class FrameworkInfo(object): info.binaryPath = os.path.join(info.binaryDirectory, info.binaryName) info.version = parts[i+2] - info.deployedInstallName = "@executable_path/../Frameworks/" + os.path.join(info.frameworkName, info.binaryPath) + info.deployedInstallName = f"@executable_path/../Frameworks/{os.path.join(info.frameworkName, info.binaryPath)}" info.destinationDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, info.binaryDirectory) info.sourceResourcesDirectory = os.path.join(info.frameworkPath, "Resources") @@ -158,10 +148,10 @@ class FrameworkInfo(object): class ApplicationBundleInfo(object): def __init__(self, path: str): self.path = path - appName = "PIVX-Qt" - self.binaryPath = os.path.join(path, "Contents", "MacOS", appName) + # for backwards compatibility reasons, this must remain as PIVX-Qt + self.binaryPath = os.path.join(path, "Contents", "MacOS", "PIVX-Qt") if not os.path.exists(self.binaryPath): - raise RuntimeError("Could not find bundle binary for " + path) + raise RuntimeError(f"Could not find bundle binary for {path}") self.resourcesPath = os.path.join(path, "Contents", "Resources") self.pluginPath = os.path.join(path, "Contents", "PlugIns") @@ -185,26 +175,24 @@ class DeploymentInfo(object): self.pluginPath = pluginPath def usesFramework(self, name: str) -> bool: - nameDot = "{}.".format(name) - libNameDot = "lib{}.".format(name) for framework in self.deployedFrameworks: if framework.endswith(".framework"): - if framework.startswith(nameDot): + if framework.startswith(f"{name}."): return True elif framework.endswith(".dylib"): - if framework.startswith(libNameDot): + if framework.startswith(f"lib{name}."): return True return False def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]: if verbose: - print("Inspecting with otool: " + binaryPath) + print(f"Inspecting with otool: {binaryPath}") otoolbin=os.getenv("OTOOL", "otool") otool = run([otoolbin, "-L", binaryPath], stdout=PIPE, stderr=PIPE, universal_newlines=True) if otool.returncode != 0: sys.stderr.write(otool.stderr) sys.stderr.flush() - raise RuntimeError("otool failed with return code {}".format(otool.returncode)) + raise RuntimeError(f"otool failed with return code {otool.returncode}") otoolLines = otool.stdout.split("\n") otoolLines.pop(0) # First line is the inspected binary @@ -252,14 +240,14 @@ def runStrip(binaryPath: str, verbose: int): def copyFramework(framework: FrameworkInfo, path: str, verbose: int) -> Optional[str]: if framework.sourceFilePath.startswith("Qt"): #standard place for Nokia Qt installer's frameworks - fromPath = "/Library/Frameworks/" + framework.sourceFilePath + fromPath = f"/Library/Frameworks/{framework.sourceFilePath}" else: fromPath = framework.sourceFilePath toDir = os.path.join(path, framework.destinationDirectory) toPath = os.path.join(toDir, framework.binaryName) if not os.path.exists(fromPath): - raise RuntimeError("No file at " + fromPath) + raise RuntimeError(f"No file at {fromPath}") if os.path.exists(toPath): return None # Already there @@ -357,7 +345,7 @@ def deployFrameworks(frameworks: List[FrameworkInfo], bundlePath: str, binaryPat def deployFrameworksForAppBundle(applicationBundle: ApplicationBundleInfo, strip: bool, verbose: int) -> DeploymentInfo: frameworks = getFrameworks(applicationBundle.binaryPath, verbose) if len(frameworks) == 0: - print("Warning: Could not find any external frameworks to deploy in {}.".format(applicationBundle.path)) + print(f"Warning: Could not find any external frameworks to deploy in {applicationBundle.path}.") return DeploymentInfo() else: return deployFrameworks(frameworks, applicationBundle.path, applicationBundle.binaryPath, strip, verbose) @@ -527,7 +515,7 @@ app_bundle = config.app_bundle[0] appname = config.appname[0] if not os.path.exists(app_bundle): - sys.stderr.write("Error: Could not find app bundle \"{}\"\n".format(app_bundle)) + sys.stderr.write(f"Error: Could not find app bundle \"{app_bundle}\"\n") sys.exit(1) # ------------------------------------------------ @@ -565,7 +553,7 @@ try: sys.stderr.write("Warning: Could not detect Qt's path, skipping plugin deployment!\n") config.plugins = False except RuntimeError as e: - sys.stderr.write("Error: {}\n".format(str(e))) + sys.stderr.write(f"Error: {str(e)}\n") sys.exit(1) # ------------------------------------------------ @@ -576,14 +564,14 @@ if config.plugins: try: deployPlugins(applicationBundle, deploymentInfo, config.strip, verbose) except RuntimeError as e: - sys.stderr.write("Error: {}\n".format(str(e))) + sys.stderr.write(f"Error: {str(e)}\n") sys.exit(1) # ------------------------------------------------ if config.translations_dir: if not Path(config.translations_dir[0]).exists(): - sys.stderr.write("Error: Could not find translation dir \"{}\"\n".format(config.translations_dir[0])) + sys.stderr.write(f"Error: Could not find translation dir \"{config.translations_dir[0]}\"\n") sys.exit(1) print("+ Adding Qt translations +") @@ -672,7 +660,7 @@ if config.dmg is not None: if verbose: print("Creating temp image for modification...") - tempname = appname + ".temp.dmg" + tempname: str = appname + ".temp.dmg" run(["hdiutil", "create", tempname, "-srcfolder", "dist", "-format", "UDRW", "-size", str(size), "-volname", appname], check=True, universal_newlines=True) @@ -695,7 +683,7 @@ if config.dmg is not None: print("+ Finalizing .dmg disk image +") - run(["hdiutil", "detach", "/Volumes/{}".format(appname)], universal_newlines=True) + run(["hdiutil", "detach", f"/Volumes/{appname}"], universal_newlines=True) run(["hdiutil", "convert", tempname, "-format", "UDZO", "-o", appname, "-imagekey", "zlib-level=9"], check=True, universal_newlines=True) From d8e2baf28c17c7aa8771449c20383720271640b8 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 8 Jan 2021 13:55:33 -0800 Subject: [PATCH 16/17] doc: Add explicit macdeployqtplus dependencies install step This change is required on macOS 11 Big Sur. --- doc/build-osx.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/build-osx.md b/doc/build-osx.md index 6cd31d2a7031..56777b83abde 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -24,6 +24,11 @@ If you want to build the disk image with `make deploy` (.dmg / optional), you ne brew install librsvg +and [`macdeployqtplus`](../contrib/macdeploy/README.md) dependencies: +```shell +pip3 install ds_store mac_alias +``` + Berkeley DB ----------- It is recommended to use Berkeley DB 4.8. If you have to build it yourself, From a68c7d5cb3507bf4dcb03c94104d134daddd93a0 Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 30 Nov 2020 15:39:09 +0800 Subject: [PATCH 17/17] depends: mac_alias 2.2.0 --- depends/packages/native_mac_alias.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/native_mac_alias.mk b/depends/packages/native_mac_alias.mk index e60b99dccc98..783f87ca7c04 100644 --- a/depends/packages/native_mac_alias.mk +++ b/depends/packages/native_mac_alias.mk @@ -1,8 +1,8 @@ package=native_mac_alias -$(package)_version=2.0.7 +$(package)_version=2.2.0 $(package)_download_path=https://github.com/al45tair/mac_alias/archive/ $(package)_file_name=v$($(package)_version).tar.gz -$(package)_sha256_hash=6f606d3b6bccd2112aeabf1a063f5b5ece87005a5d7e97c8faca23b916e88838 +$(package)_sha256_hash=421e6d7586d1f155c7db3e7da01ca0dacc9649a509a253ad7077b70174426499 $(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages define $(package)_build_cmds