From 00d1e293335061419de1ed8ace4cbd8dc16a16f0 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Sun, 10 Apr 2016 14:20:18 -0700 Subject: [PATCH] Switch from py2app to PyInstaller --- BUILD.md | 31 ++++----------------- install/build_osx.sh | 2 +- install/pyinstaller-osx.spec | 53 ++++++++++++++++++++++++++++++++++++ onionshare/helpers.py | 21 +++++++------- onionshare/strings.py | 2 +- onionshare_gui/common.py | 2 +- setup.py | 26 ------------------ 7 files changed, 71 insertions(+), 66 deletions(-) create mode 100644 install/pyinstaller-osx.spec diff --git a/BUILD.md b/BUILD.md index 088392bf..e33b975d 100644 --- a/BUILD.md +++ b/BUILD.md @@ -38,41 +38,20 @@ There is a PKBUILD available [here](https://aur.archlinux.org/packages/onionshar Install Xcode from the Mac App Store. Once it's installed, run it for the first time to set it up. -Install the [latest Python 3.x from python.org](https://www.python.org/downloads/). If you use the built-in version of python that comes with OS X, your .app might not run on other people's computers. +If you don't already have it installed, install [Homebrew](http://brew.sh/). -Download and install Qt5 from https://www.qt.io/download-open-source/. I downloaded `qt-unified-mac-x64-2.0.2-2-online.dmg`. There's no need to login to a Qt account during installation. Make sure you install the latest Qt 5.x for clang. - -Download the source code for [SIP](http://www.riverbankcomputing.co.uk/software/sip/download) and [PyQt](http://www.riverbankcomputing.co.uk/software/pyqt/download5). I downloaded `sip-4.17.tar.gz` and `PyQt-gpl-5.5.1.tar.gz`. - -Now extract the source code: +Install some dependencies using Homebrew: ```sh -tar xvf sip-4.17.tar.gz -tar xvf PyQt-gpl-5.5.1.tar.gz +brew install python3 pyqt5 qt5 ``` -Compile SIP: +Install some dependencies using pip3: ```sh -cd sip-4.17 -python3 configure.py --arch x86_64 -make -sudo make install -sudo make clean +sudo pip3 install pyinstaller flask stem ``` -Compile PyQt: - -```sh -cd ../PyQt-gpl-5.5.1 -python3 configure.py --qmake ~/Qt/5.5/clang_64/bin/qmake --sip /Library/Frameworks/Python.framework/Versions/3.5/bin/sip --disable=QtPositioning -make -sudo make install -sudo make clean -``` - -Finally, install some dependencies using pip3: `sudo pip3 install py2app flask stem` - Get the source code: ```sh diff --git a/install/build_osx.sh b/install/build_osx.sh index 10cf2609..2b4af0b5 100755 --- a/install/build_osx.sh +++ b/install/build_osx.sh @@ -9,7 +9,7 @@ rm -rf $ROOT/dist &>/dev/null 2>&1 # build the .app echo Building OnionShare.app -python3 setup.py py2app +pyinstaller install/pyinstaller-osx.spec if [ "$1" = "--sign" ]; then SIGNING_IDENTITY_APP="Developer ID Application: Micah Lee" diff --git a/install/pyinstaller-osx.spec b/install/pyinstaller-osx.spec new file mode 100644 index 00000000..da6e87c0 --- /dev/null +++ b/install/pyinstaller-osx.spec @@ -0,0 +1,53 @@ +# -*- mode: python -*- + +block_cipher = None + +a = Analysis( + ['osx_scripts/onionshare-gui'], + pathex=['.'], + binaries=None, + datas=[ + ('../images/*', 'images'), + ('../locale/*', 'locale'), + ('../onionshare/*.html', 'html'), + ('../version', '.') + ], + hiddenimports=[], + hookspath=[], + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher) + +pyz = PYZ( + a.pure, a.zipped_data, + cipher=block_cipher) + +exe = EXE( + pyz, + a.scripts, + exclude_binaries=True, + name='onionshare_gui', + debug=False, + strip=False, + upx=True, + console=False) + +coll = COLLECT( + exe, + a.binaries, + a.zipfiles, + a.datas, + strip=False, + upx=True, + name='onionshare_gui') + +app = BUNDLE( + coll, + name='OnionShare.app', + icon='install/onionshare.icns', + bundle_identifier='com.micahflee.onionshare', + info_plist={ + 'NSHighResolutionCapable': 'True' + }) diff --git a/onionshare/helpers.py b/onionshare/helpers.py index 806b14fa..cc89b6a5 100644 --- a/onionshare/helpers.py +++ b/onionshare/helpers.py @@ -26,15 +26,6 @@ def get_platform(): """ return platform.system() -if get_platform() == 'Darwin': - # this is hacky, but it ultimate ends up returning the absolute path to - # OnionShare.app/Contents/Resources, based on the location of helpers.py - helpers_path = os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe()))) - osx_resources_dir = os.path.dirname(os.path.dirname(helpers_path)) -else: - osx_resources_dir = None - - def get_onionshare_dir(): """ Returns the OnionShare directory. @@ -45,6 +36,14 @@ def get_onionshare_dir(): onionshare_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) return onionshare_dir +def get_osx_resource_path(filename): + """ + Returns the path a resource file in a frozen PyInstall app + """ + if get_platform() == 'Darwin': + # Resource path from frozen PyInstaller app + # https://pythonhosted.org/PyInstaller/#run-time-information + return os.path.join(os.path.join(os.path.dirname(sys._MEIPASS), 'Resources'), filename) def get_html_path(filename): """ @@ -52,7 +51,7 @@ def get_html_path(filename): """ p = get_platform() if p == 'Darwin': - prefix = os.path.join(osx_resources_dir, 'html') + prefix = get_osx_resource_path('html') else: prefix = get_onionshare_dir() return os.path.join(prefix, filename) @@ -66,7 +65,7 @@ def get_version(): if p == 'Linux': version_filename = os.path.join(sys.prefix, 'share/onionshare/version') elif p == 'Darwin': - version_filename = os.path.join(osx_resources_dir, 'version') + version_filename = get_osx_resource_path('version') else: version_filename = os.path.join(os.path.dirname(get_onionshare_dir()), 'version') return open(version_filename).read().strip() diff --git a/onionshare/strings.py b/onionshare/strings.py index 5ae03176..50e5835f 100644 --- a/onionshare/strings.py +++ b/onionshare/strings.py @@ -36,7 +36,7 @@ def load_strings(default="en"): if p == 'Linux': locale_dir = os.path.join(sys.prefix, 'share/onionshare/locale') elif p == 'Darwin': - locale_dir = os.path.join(helpers.osx_resources_dir, 'locale') + locale_dir = helpers.get_osx_resource_path('locale') else: locale_dir = os.path.join(os.path.dirname(helpers.get_onionshare_dir()), 'locale') diff --git a/onionshare_gui/common.py b/onionshare_gui/common.py index a0baa5a4..4b3c7cf7 100644 --- a/onionshare_gui/common.py +++ b/onionshare_gui/common.py @@ -44,7 +44,7 @@ def get_image_path(filename): if p == 'Linux': prefix = os.path.join(sys.prefix, 'share/onionshare/images') elif p == 'Darwin': - prefix = os.path.join(helpers.osx_resources_dir, 'images') + prefix = locale_dir = helpers.get_osx_resource_path('images') else: prefix = os.path.join(os.path.dirname(get_onionshare_gui_dir()), 'images') return os.path.join(prefix, filename) diff --git a/setup.py b/setup.py index 9694d712..3d59f5f1 100644 --- a/setup.py +++ b/setup.py @@ -96,32 +96,6 @@ if system == 'Linux': ] ) -elif system == 'Darwin': - setup( - name='OnionShare', - version=version, - description=description, - long_description=long_description, - app=['install/osx_scripts/onionshare-gui'], - data_files=[ - ('images', images), - ('locale', locale), - ('html', ['onionshare/index.html', 'onionshare/404.html']), - ('', ['version']) - ], - options={ - 'py2app': { - 'argv_emulation': True, - 'iconfile': 'install/onionshare.icns', - 'extra_scripts': ['install/osx_scripts/onionshare'], - 'includes': [ - 'PyQt5', 'PyQt5.QtCore', 'PyQt5.QtGui', 'PyQt5.QtWidgets', - 'jinja2', 'jinja2.ext', 'jinja2.ext.autoescape', 'sip'] - } - }, - setup_requires=['py2app', 'flask', 'stem'], - ) - elif system == 'Windows': import py2exe setup(