Merge branch 'pyinstaller'

This commit is contained in:
Micah Lee 2017-02-21 17:16:16 -08:00
commit ab20311f6e
No known key found for this signature in database
GPG key ID: 403C2657CD994F73
36 changed files with 143 additions and 150 deletions

View file

@ -34,35 +34,23 @@ For ArchLinux: There is a PKBUILD available [here](https://aur.archlinux.org/pac
Install Xcode from the Mac App Store. Once it's installed, run it for the first time to set it up. Install Xcode from the Mac App Store. Once it's installed, run it for the first time to set it up.
If you don't already have it installed, install [Homebrew](http://brew.sh/). Download and install Python 3.5.2 from https://www.python.org/downloads/release/python-352/ (note that a pyinstaller bug prevents you from using Python 3.6). I downloaded `python-3.5.2-macosx10.6.pkg`.
Install some dependencies using Homebrew: Download and install Qt 5.7.1 for macOS offline installer from https://www.qt.io/download-open-source/. I downloaded `qt-opensource-mac-x64-clang-5.7.1.dmg`. (You can skip making an account in the installer.)
Now install some python dependencies with pip (note, there's issues building a .app if you install this in a virtualenv):
```sh ```sh
brew install python3 pyqt5 qt5 sudo pip3 install -r install/requirements.txt
``` ```
Install some dependencies using pip3: You can run both the CLI and GUI versions of OnionShare without building an bundle:
```sh
sudo pip3 install flask stem
```
After that you can try both the CLI and the GUI version of OnionShare:
```sh ```sh
./dev_scripts/onionshare ./dev_scripts/onionshare
./dev_scripts/onionshare-gui ./dev_scripts/onionshare-gui
``` ```
If you want to build a Mac OS X app bundle:
Install the latest development version of cx_Freeze:
* Download a [snapshot](https://bitbucket.org/anthony_tuininga/cx_freeze/downloads) of the latest development version of cx_Freeze, extract it, and cd into the folder you extracted it to
* Build the package: `python3 setup.py bdist_wheel`
* Install it with pip: `sudo pip3 install dist/cx_Freeze-5.0-cp35-cp35m-macosx_10_11_x86_64.whl`
To build the app bundle: To build the app bundle:
```sh ```sh
@ -83,9 +71,13 @@ Now you should have `dist/OnionShare.pkg`.
### Setting up your dev environment ### Setting up your dev environment
Download the latest Python 3.6.x, 32-bit (x86) from https://www.python.org/downloads/. I downloaded `python-3.6.0.exe`. When installing it, make sure to check the "Add Python 3.6 to PATH" checkbox on the first page of the installer. Download the latest Python 3.5.2, 32-bit (x86) from https://www.python.org/downloads/release/python-352/ (note that there's a pyinstaller/pywin32 bug that prevents 3.6.x from working). I downloaded `python-3.5.2.exe`. When installing it, make sure to check the "Add Python 3.5 to PATH" checkbox on the first page of the installer.
Open a command prompt and install dependencies with pip: `pip install flask stem PyQt5` Open a command prompt, cd to the onionshare folder, and install dependencies with pip:
```cmd
pip3 install -r install\requirements-windows.txt
```
Download and install Qt5 from https://www.qt.io/download-open-source/. I downloaded `qt-unified-windows-x86-2.0.4-online.exe`. There's no need to login to a Qt account during installation. Make sure you install the latest Qt 5.x. I installed Qt 5.7. Download and install Qt5 from https://www.qt.io/download-open-source/. I downloaded `qt-unified-windows-x86-2.0.4-online.exe`. There's no need to login to a Qt account during installation. Make sure you install the latest Qt 5.x. I installed Qt 5.7.
@ -96,19 +88,17 @@ python dev_scripts\onionshare
python dev_scripts\onionshare-gui python dev_scripts\onionshare-gui
``` ```
If you want to build an .exe: If you want to build a .exe:
These instructions include adding folders to the path in Windows. To do this, go to Start and type "advanced system settings", and open "View advanced system settings" in the Control Panel. Click Environment Variables. Under "System variables" double-click on Path. From there you can add and remove folders that are available in the PATH. These instructions include adding folders to the path in Windows. To do this, go to Start and type "advanced system settings", and open "View advanced system settings" in the Control Panel. Click Environment Variables. Under "System variables" double-click on Path. From there you can add and remove folders that are available in the PATH.
Download and install the [Microsoft Visual C++ 2008 Redistributable Package (x86)](http://www.microsoft.com/en-us/download/details.aspx?id=29). Download and install the 32-bit [Visual C++ Redistributable for Visual Studio 2015](https://www.microsoft.com/en-US/download/details.aspx?id=48145). I downloaded `vc_redist.x86.exe`.
Installing cx_Freeze with support for Python 3.5 is annoying. Here are the steps (thanks https://github.com/sekrause/cx_Freeze-Wheels): Download and install the standalone [Windows 10 SDK](https://dev.windows.com/en-us/downloads/windows-10-sdk). Note that you may not need this if you already have Visual Studio. Add the following directories to the path:
* Download and install the Visual C++ Build Tools 2005 from http://go.microsoft.com/fwlink/?LinkId=691126. I downloaded `visualcppbuildtools_full.exe`. * `C:\Program Files (x86)\Windows Kits\10\bin\x86`
* Install the python wheel package: `pip install wheel` * `C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x86`
* Download a [snapshot](https://bitbucket.org/anthony_tuininga/cx_freeze/downloads) of the latest development version of cx_Freeze, extract it, and cd into the folder you extracted it to * `C:\Users\user\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\PyQt5\Qt\bin`
* Build the package: `python setup.py bdist_wheel`
* Install it with pip: `pip install dist\cx_Freeze-5.0-cp35-cp35m-win32.whl`
If you want to build the installer: If you want to build the installer:
@ -119,17 +109,12 @@ If you want to sign binaries with Authenticode:
* You'll need a code signing certificate. I roughly followed [this guide](http://blog.assarbad.net/20110513/startssl-code-signing-certificate/) to make one using my StartSSL account. * You'll need a code signing certificate. I roughly followed [this guide](http://blog.assarbad.net/20110513/startssl-code-signing-certificate/) to make one using my StartSSL account.
* Once you get a code signing key and certificate and covert it to a pfx file, import it into your certificate store. * Once you get a code signing key and certificate and covert it to a pfx file, import it into your certificate store.
* Windows 7:
* Go to http://msdn.microsoft.com/en-us/vstudio/aa496123 and install the latest .NET Framework. I installed `.NET Framework 4.6`.
* Go to http://www.microsoft.com/en-us/download/confirmation.aspx?id=8279 and install the Windows SDK.
* Add `C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin` to the path.
* Windows 10:
* Go to https://dev.windows.com/en-us/downloads/windows-10-sdk and install the standalone Windows 10 SDK. Note that you may not need this if you already have Visual Studio.
* Add `C:\Program Files (x86)\Windows Kits\10\bin\x86` to the path.
### To make a .exe: ### To make a .exe:
* Open a command prompt, cd into the onionshare directory, and type: `python setup.py build`. `onionshare.exe`, `onionshare-gui.exe`, and all of their supporting files will get created inside the `build\exe.win32-3.5` folder. For PyInstaller to work, you might need to edit `Scripts\pyinstaller-script.py` in your Python 3.5 folder, to work around [this bug](https://stackoverflow.com/questions/31808180/installing-pyinstaller-via-pip-leads-to-failed-to-create-process) in pip.
* Open a command prompt, cd into the onionshare directory, and type: `pyinstaller install\pyinstaller.spec`. `onionshare.exe`, `onionshare-gui.exe`, and all of their supporting files will get created inside the `build` folder.
### To build the installer: ### To build the installer:

View file

@ -3,7 +3,7 @@
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
cd $DIR cd $DIR
VERSION=`cat resources/version.txt` VERSION=`cat share/version.txt`
# clean up from last build # clean up from last build
rm -r deb_dist >/dev/null 2>&1 rm -r deb_dist >/dev/null 2>&1

View file

@ -1,5 +1,5 @@
REM build onionshare.exe, onionshare-gui.exe REM build onionshare.exe, onionshare-gui.exe
python setup.py build pyinstaller install\pyinstaller.spec -y
REM sign onionshare.exe, onionshare-gui.exe REM sign onionshare.exe, onionshare-gui.exe
signtool.exe sign /v /d "OnionShare" /a /tr http://timestamp.globalsign.com/scripts/timstamp.dll /fd sha256 build\exe.win32-3.5\onionshare.exe signtool.exe sign /v /d "OnionShare" /a /tr http://timestamp.globalsign.com/scripts/timstamp.dll /fd sha256 build\exe.win32-3.5\onionshare.exe

View file

@ -9,7 +9,7 @@ rm -rf $ROOT/build $ROOT/dist &>/dev/null 2>&1
# build the .app # build the .app
echo Building OnionShare.app echo Building OnionShare.app
python3 setup.py bdist_mac pyinstaller install/pyinstaller.spec
if [ "$1" = "--release" ]; then if [ "$1" = "--release" ]; then
mkdir -p dist mkdir -p dist

View file

@ -3,7 +3,7 @@
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
cd $DIR cd $DIR
VERSION=`cat resources/version.txt` VERSION=`cat share/version.txt`
# clean up from last build # clean up from last build
rm -r build dist >/dev/null 2>&1 rm -r build dist >/dev/null 2>&1

View file

@ -7,7 +7,7 @@
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
cd $DIR cd $DIR
VERSION=`cat resources/version.txt` VERSION=`cat share/version.txt`
rm -rf deb_dist >/dev/null 2>&1 rm -rf deb_dist >/dev/null 2>&1
python3 setup.py --command-packages=stdeb.command sdist_dsc python3 setup.py --command-packages=stdeb.command sdist_dsc

61
install/pyinstaller.spec Normal file
View file

@ -0,0 +1,61 @@
# -*- mode: python -*-
import platform
p = platform.system()
version = open('share/version.txt').read().strip()
a = Analysis(
['scripts/onionshare-gui'],
pathex=['.'],
binaries=None,
datas=[
('../share/license.txt', 'share'),
('../share/version.txt', 'share'),
('../share/wordlist.txt', 'share'),
('../share/images/*', 'share/images'),
('../share/locale/*', 'share/locale'),
('../share/html/*', 'share/html')
],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=['jinja2.asyncsupport'],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=None)
pyz = PYZ(
a.pure, a.zipped_data,
cipher=None)
exe = EXE(
pyz,
a.scripts,
exclude_binaries=True,
name='onionshare',
debug=False,
strip=False,
upx=True,
console=False)
coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
name='onionshare')
if p == 'Darwin':
app = BUNDLE(
coll,
name='OnionShare.app',
icon='install/onionshare.icns',
bundle_identifier='com.micahflee.onionshare',
info_plist={
'CFBundleShortVersionString': version,
'NSHighResolutionCapable': 'True'
}
)

View file

@ -0,0 +1,13 @@
click==6.7
Flask==0.12
future==0.16.0
itsdangerous==0.24
Jinja2==2.9.5
MarkupSafe==0.23
pefile==2016.3.28
PyInstaller==3.2.1
pypiwin32==219
PyQt5==5.8
sip==4.19.1
stem==1.5.4
Werkzeug==0.11.15

10
install/requirements.txt Normal file
View file

@ -0,0 +1,10 @@
click==6.7
Flask==0.12
itsdangerous==0.24
Jinja2==2.9.5
MarkupSafe==0.23
PyInstaller==3.2.1
PyQt5==5.7.1
sip==4.19
stem==1.5.4
Werkzeug==0.11.15

View file

@ -37,16 +37,21 @@ def get_resource_path(filename):
if getattr(sys, 'onionshare_dev_mode', False): if getattr(sys, 'onionshare_dev_mode', False):
# Look for resources directory relative to python file # Look for resources directory relative to python file
resources_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))), 'resources') prefix = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))), 'share')
elif p == 'Linux' and sys.argv and sys.argv[0].startswith(sys.prefix): elif p == 'Linux' and sys.argv and sys.argv[0].startswith(sys.prefix):
# OnionShare is installed systemwide in Linux # OnionShare is installed systemwide in Linux
resources_dir = os.path.join(sys.prefix, 'share/onionshare') prefix = os.path.join(sys.prefix, 'share/onionshare')
elif getattr(sys, 'frozen', False): # Check if app is "frozen" with cx_Freeze
# http://cx-freeze.readthedocs.io/en/latest/faq.html#using-data-files
resources_dir = os.path.join(os.path.dirname(sys.executable), 'resources')
return os.path.join(resources_dir, filename) elif getattr(sys, 'frozen', False):
# Check if app is "frozen"
# https://pythonhosted.org/PyInstaller/#run-time-information
if p == 'Darwin':
prefix = os.path.join(sys._MEIPASS, 'share')
elif p == 'Windows':
prefix = os.path.join(os.path.dirname(sys.executable), 'share')
return os.path.join(prefix, filename)
def get_version(): def get_version():

123
setup.py
View file

@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
import os, sys, platform, tempfile import os, sys, platform, tempfile
from distutils.core import setup
def file_list(path): def file_list(path):
files = [] files = []
@ -28,7 +29,7 @@ def file_list(path):
files.append(os.path.join(path, filename)) files.append(os.path.join(path, filename))
return files return files
version = open('resources/version.txt').read().strip() version = open('share/version.txt').read().strip()
description = ( description = (
"""OnionShare lets you securely and anonymously share a file of any size with someone. """ """OnionShare lets you securely and anonymously share a file of any size with someone. """
"""It works by starting a web server, making it accessible as a Tor hidden service, """ """It works by starting a web server, making it accessible as a Tor hidden service, """
@ -45,104 +46,22 @@ url = 'https://github.com/micahflee/onionshare'
license = 'GPL v3' license = 'GPL v3'
keywords = 'onion, share, onionshare, tor, anonymous, web server' keywords = 'onion, share, onionshare, tor, anonymous, web server'
p = platform.system() setup(
name='onionshare', version=version,
# Windows and Mac description=description, long_description=long_description,
if p == 'Windows' or p == 'Darwin': author=author, author_email=author_email,
from cx_Freeze import setup, Executable url=url, license=license, keywords=keywords,
packages=['onionshare', 'onionshare_gui'],
if p == 'Windows': include_package_data=True,
executables = [ scripts=['install/scripts/onionshare', 'install/scripts/onionshare-gui'],
Executable('install/scripts/onionshare', data_files=[
icon='install/onionshare.ico', (os.path.join(sys.prefix, 'share/applications'), ['install/onionshare.desktop']),
base=None), (os.path.join(sys.prefix, 'share/appdata'), ['install/onionshare.appdata.xml']),
Executable('install/scripts/onionshare-gui', (os.path.join(sys.prefix, 'share/pixmaps'), ['install/onionshare80.xpm']),
icon='install/onionshare.ico', (os.path.join(sys.prefix, 'share/onionshare'), file_list('share')),
shortcutName='OnionShare', (os.path.join(sys.prefix, 'share/onionshare/images'), file_list('share/images')),
shortcutDir='ProgramMenuFolder', (os.path.join(sys.prefix, 'share/onionshare/locale'), file_list('share/locale')),
base='Win32GUI') (os.path.join(sys.prefix, 'share/onionshare/html'), file_list('share/html')),
] ('/usr/share/nautilus-python/extensions/', ['install/scripts/onionshare-nautilus.py'])
custom_info_plist = '' ]
)
elif p == 'Darwin':
executables = [
Executable('install/scripts/onionshare-gui'),
Executable('install/scripts/onionshare')
]
# Write the correct version into Info.plist
f = tempfile.NamedTemporaryFile(mode='w')
custom_info_plist = f.name
f.write(open('install/Info.plist').read().replace('{VERSION}', str(version)))
f.flush()
setup(
name='OnionShare', version=version,
description=description, long_description=long_description,
author=author, author_email=author_email,
url=url, license=license, keywords=keywords,
options={
'build_exe': {
'packages': ['jinja2.ext'],
'excludes': [],
'include_files': ['resources']
},
'bdist_mac': {
'iconfile': 'install/onionshare.icns',
'bundle_name': 'OnionShare',
'qt_menu_nib': '/usr/local/Cellar/qt5/5.6.1-1/plugins/platforms',
'custom_info_plist': custom_info_plist
}
},
executables=executables
)
# Linux
else:
from setuptools import setup
setup(
name='onionshare', version=version,
description=description, long_description=long_description,
author=author, author_email=author_email,
url=url, license=license, keywords=keywords,
packages=['onionshare', 'onionshare_gui'],
include_package_data=True,
scripts=['install/scripts/onionshare', 'install/scripts/onionshare-gui'],
data_files=[
(os.path.join(sys.prefix, 'share/applications'), ['install/onionshare.desktop']),
(os.path.join(sys.prefix, 'share/appdata'), ['install/onionshare.appdata.xml']),
(os.path.join(sys.prefix, 'share/pixmaps'), ['install/onionshare80.xpm']),
(os.path.join(sys.prefix, 'share/onionshare'), [
'resources/version.txt',
'resources/wordlist.txt'
]),
(os.path.join(sys.prefix, 'share/onionshare/images'), [
'resources/images/logo.png',
'resources/images/drop_files.png',
'resources/images/server_stopped.png',
'resources/images/server_started.png',
'resources/images/server_working.png'
]),
(os.path.join(sys.prefix, 'share/onionshare/locale'), [
'resources/locale/cs.json',
'resources/locale/de.json',
'resources/locale/en.json',
'resources/locale/eo.json',
'resources/locale/es.json',
'resources/locale/fi.json',
'resources/locale/fr.json',
'resources/locale/it.json',
'resources/locale/nl.json',
'resources/locale/no.json',
'resources/locale/pt.json',
'resources/locale/ru.json',
'resources/locale/tr.json'
]),
(os.path.join(sys.prefix, 'share/onionshare/html'), [
'resources/html/index.html',
'resources/html/denied.html',
'resources/html/404.html'
]),
('/usr/share/nautilus-python/extensions/', ['install/scripts/onionshare-nautilus.py']),
]
)

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

Before

Width:  |  Height:  |  Size: 346 B

After

Width:  |  Height:  |  Size: 346 B

View file

Before

Width:  |  Height:  |  Size: 286 B

After

Width:  |  Height:  |  Size: 286 B

View file

Before

Width:  |  Height:  |  Size: 338 B

After

Width:  |  Height:  |  Size: 338 B

View file

@ -22,7 +22,7 @@ from onionshare import helpers, strings
# Stub get_resource_path so it finds the correct path while running tests # Stub get_resource_path so it finds the correct path while running tests
def get_resource_path(filename): def get_resource_path(filename):
resources_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'resources') resources_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'share')
path = os.path.join(resources_dir, filename) path = os.path.join(resources_dir, filename)
return path return path
helpers.get_resource_path = get_resource_path helpers.get_resource_path = get_resource_path