diff --git a/Makefile.am b/Makefile.am
index 0e8a447dea95..f281dec39490 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,12 +35,9 @@ 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
-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 \
@@ -72,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
@@ -140,7 +136,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) $(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 $@
@@ -170,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) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2
+ 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/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/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 b6fa83334eb3..b7caf41ec765 100755
--- a/contrib/macdeploy/macdeployqtplus
+++ b/contrib/macdeploy/macdeployqtplus
@@ -16,9 +16,14 @@
# along with this program. If not, see .
#
-import subprocess, sys, re, os, shutil, stat, os.path, time
-from string import Template
+import plistlib
+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
@@ -48,28 +53,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,
- 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")
@@ -85,7 +80,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
@@ -96,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)
@@ -116,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:
@@ -128,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])
@@ -139,25 +134,24 @@ 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")
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
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)
+ # 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")
@@ -167,17 +161,11 @@ 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"
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)
@@ -186,31 +174,27 @@ class DeploymentInfo(object):
if os.path.exists(pluginPath):
self.pluginPath = pluginPath
- def usesFramework(self, name):
- nameDot = "%s." % name
- libNameDot = "lib%s." % name
+ def usesFramework(self, name: str) -> bool:
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, verbose):
- if verbose >= 3:
- print("Inspecting with otool: " + binaryPath)
+def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]:
+ if verbose:
+ print(f"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:
- if verbose >= 1:
- sys.stderr.write(o_stderr)
- sys.stderr.flush()
- raise RuntimeError("otool failed with return code %d" % otool.returncode)
+ sys.stderr.write(otool.stderr)
+ sys.stderr.flush()
+ raise RuntimeError(f"otool failed with return code {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.
@@ -220,50 +204,50 @@ def getFrameworks(binaryPath, verbose):
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)
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))
+ run([installnametoolbin, "-"+action] + list(args), check=True)
-def changeInstallName(oldName, newName, binaryPath, verbose):
- if verbose >= 3:
+def changeInstallName(oldName: str, newName: str, binaryPath: str, verbose: int):
+ if verbose:
print("Using install_name_tool:")
print(" in", binaryPath)
print(" change reference", oldName)
print(" to", newName)
runInstallNameTool("change", oldName, newName, binaryPath)
-def changeIdentification(id, binaryPath, verbose):
- if verbose >= 3:
+def changeIdentification(id: str, binaryPath: str, verbose: int):
+ if verbose:
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:
+ if verbose:
print("Using strip:")
print(" stripped", binaryPath)
- subprocess.check_call([stripbin, "-x", binaryPath])
+ run([stripbin, "-x", binaryPath], check=True)
-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
+ 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
@@ -272,7 +256,7 @@ def copyFramework(framework, path, verbose):
os.makedirs(toDir)
shutil.copy2(fromPath, toPath)
- if verbose >= 3:
+ if verbose:
print("Copied:", fromPath)
print(" to:", toPath)
@@ -286,13 +270,12 @@ def copyFramework(framework, path, verbose):
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
@@ -301,7 +284,7 @@ def copyFramework(framework, path, verbose):
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)
@@ -309,13 +292,13 @@ def copyFramework(framework, path, verbose):
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)
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()
@@ -323,16 +306,14 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym
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
@@ -361,15 +342,15 @@ 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))
+ if len(frameworks) == 0:
+ 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)
-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:
@@ -379,10 +360,9 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
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"):
@@ -415,6 +395,42 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
# 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)
@@ -441,12 +457,15 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
# 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))
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)
@@ -455,7 +474,7 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
destinationPath = os.path.join(destinationDirectory, pluginName)
shutil.copy2(sourcePath, destinationPath)
- if verbose >= 3:
+ if verbose:
print("Copied:", sourcePath)
print(" to:", destinationPath)
@@ -471,147 +490,50 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
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.
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) 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("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("-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("-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")
+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.")
config = ap.parse_args()
-verbose = config.verbose[0]
+verbose = config.verbose
# ------------------------------------------------
app_bundle = config.app_bundle[0]
+appname = config.appname[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(f"Error: Could not find app bundle \"{app_bundle}\"\n")
sys.exit(1)
-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 \"%s\"\n" % (translations_dir))
- sys.exit(1)
-# ------------------------------------------------
-
-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 \"%s\"\n" % (p))
- sys.exit(1)
-
-# ------------------------------------------------
-
-if len(config.fancy) == 1:
- if verbose >= 3:
- 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.exit(1)
-
- p = config.fancy[0]
- if verbose >= 3:
- print("Fancy: Loading \"%s\"..." % 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.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 \"%s\"\n" % (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:
- if verbose >= 1:
- sys.stderr.write("Error: Bad format of fancy disk image plist at \"%s\"\n" % (p))
- sys.exit(1)
-
- if "background_picture" in fancy:
- bp = fancy["background_picture"]
- if verbose >= 3:
- print("Fancy: Resolving background picture \"%s\"..." % 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.exit(1)
- else:
- fancy["background_picture"] = bp
-else:
- fancy = None
-
# ------------------------------------------------
if os.path.exists("dist"):
- if verbose >= 2:
- print("+ Removing old dist folder +")
-
+ print("+ Removing existing dist folder +")
shutil.rmtree("dist")
-# ------------------------------------------------
-
-if len(config.volname) == 1:
- volname = config.volname[0]
-else:
- volname = app_bundle_name
+if os.path.exists(appname + ".dmg"):
+ print("+ Removing existing DMG +")
+ os.unlink(appname + ".dmg")
# ------------------------------------------------
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")
@@ -621,257 +543,154 @@ 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: %s\n" % str(e))
+ sys.stderr.write(f"Error: {str(e)}\n")
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: %s\n" % str(e))
+ sys.stderr.write(f"Error: {str(e)}\n")
sys.exit(1)
# ------------------------------------------------
-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_%s.qm" % 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)
- if not os.path.exists(p):
- if verbose >= 1:
- sys.stderr.write("Error: Could not find Qt translation file \"%s\"\n" % (lng_file))
- sys.exit(1)
+if config.translations_dir:
+ if not Path(config.translations_dir[0]).exists():
+ sys.stderr.write(f"Error: Could not find translation dir \"{config.translations_dir[0]}\"\n")
+ sys.exit(1)
+
+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:
+ 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 +")
+
+qt_conf="""[Paths]
+Translations=Resources
+Plugins=PlugIns
+"""
with open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") as f:
f.write(qt_conf.encode())
# ------------------------------------------------
-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))
+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 len(config.add_resources) > 0 and verbose >= 2:
- print("+ Adding additional resources +")
+if config.dmg is not None:
-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)
+ print("+ Preparing .dmg disk image +")
-# ------------------------------------------------
+ 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 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)
+ if verbose:
+ print("Creating temp image for modification...")
-# ------------------------------------------------
+ tempname: str = appname + ".temp.dmg"
-if config.dmg is not None:
+ run(["hdiutil", "create", tempname, "-srcfolder", "dist", "-format", "UDRW", "-size", str(size), "-volname", appname], check=True, universal_newlines=True)
- def runHDIUtil(verb, image_basename, **kwargs):
- hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"]
- if "capture_stdout" in kwargs:
- del kwargs["capture_stdout"]
- run = subprocess.check_output
- else:
- if verbose < 2:
- hdiutil_args.append("-quiet")
- elif verbose >= 3:
- hdiutil_args.append("-verbose")
- run = subprocess.check_call
-
- for key, value in kwargs.items():
- hdiutil_args.append("-" + key)
- if not value is True:
- hdiutil_args.append(str(value))
-
- 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 verbose:
+ print("Attaching temp image...")
+ output = run(["hdiutil", "attach", tempname, "-readwrite"], check=True, universal_newlines=True, stdout=PIPE).stdout
- 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 >= 3:
- 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 >= 3:
- 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:
- 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)
-
- m = re.search("/Volumes/(.+$)", output)
- disk_root = m.group(0)
- disk_name = m.group(1)
-
- if verbose >= 2:
- 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:
- 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)
- if verbose >= 2:
- 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)
-
- 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")
+ m = re.search(r"/Volumes/(.+$)", output)
+ disk_root = m.group(0)
+
+ print("+ Applying fancy settings +")
+
+ 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 +")
+
+ 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)
+
+ os.unlink(tempname)
# ------------------------------------------------
-if verbose >= 2:
- print("+ Done +")
+print("+ Done +")
sys.exit(0)
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
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,