changes to contrib, .travis.yml

This commit is contained in:
zebra-lucky 2018-06-28 19:05:18 +03:00
parent 073adbed62
commit c7622d757b
38 changed files with 2001 additions and 643 deletions

View File

@ -1,14 +1,77 @@
sudo: false
sudo: required
language: python
python:
- "3.5"
- "3.6"
services:
- docker
addons:
apt:
packages:
- libusb-1.0-0-dev
- libudev-dev
matrix:
include:
- if: tag =~ .+
os: osx
language: ruby
osx_image: xcode7.3
- os: linux
python: "3.4"
- os: linux
python: "3.5"
- if: NOT tag =~ .+
os: linux
python: "3.6"
before_install:
- source contrib/zcash/travis/electrum_zcash_version_env.sh
- echo electrum-zcash version is $ELECTRUM_ZCASH_VERSION
- mkdir -p build && cp contrib/zcash/travis/* ./build/
- if [[ -n $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'osx' ]]; then
./build/before_install-osx.sh;
fi
- if [[ -n $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'linux' ]] && [[ $TRAVIS_PYTHON_VERSION == '3.4' ]]; then
./build/before_install-linux.sh;
fi
- if [[ -n $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'linux' ]] && [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then
./build/before_install-linux-apk.sh;
fi
install:
- pip install tox
- pip install tox-travis
- pip install python-coveralls
- if [[ -z $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'linux' ]]; then
pip install tox; pip install tox-travis;
fi
script:
- tox
after_success:
- if [ "$TRAVIS_BRANCH" = "master" ]; then pip install pycurl requests && contrib/make_locale; fi
- coveralls
- if [[ -z $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'linux' ]];then
tox;
fi
- if [[ -n $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'osx' ]]; then
./build/travis-build-osx.sh ;
fi
- if [[ -n $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'linux' ]] && [[ $TRAVIS_PYTHON_VERSION == '3.4' ]]; then
./build/travis-build-linux.sh;
fi
- if [[ -n $TRAVIS_TAG ]] && [[ $TRAVIS_OS_NAME == 'linux' ]] && [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then
./build/travis-build-linux-apk.sh;
fi
deploy:
- provider: releases
api_key:
secure: ipcWAaqrPrgXX+L86AEq/VkfJ81j3RvDF1b+BUcPCmU/HB0UE6Eg8TTtGZ/LPZXUfcsmhLCS9zinwSh8HTYjJ1fd+yVv7V7xFrp1vRuxTE06JNwPETOOZRAk/sMlOfKU2T0rw8iyW4qhfCHO0r6Dqmb6/0psARrq0bxihKWfI+eemVLdMJPzCJABSwKOrPWK01j6FCehvlPyFnRy/Ti0sAy8JYSJ/r+ICN08qHZTVrskquEE/Bds9E3Js3Jc/tZSCPhw+/u6t34zVnFAGvEnhcgHZFDuooCl2BR02jBNpkgjHSjGUEDjom85J+FKRAg+9mDU+wH9X0s+uf4O+AIVQH4COhWjbcqviX+PyHzG8kT6uVnIj39yLmgIAhDXVfjVgy8lfb8M6pS1ajhZB1C4fwHU6ef98xk4BhTlWbex6nvko5cy8lituezfD8U8JQhbv4KSz+xRpOIspUXj1KnHTaJhBEizxFi60MX+mlKRXeKIpSqveEPZnKuqkpnOb3K8BTM8Ca2UjYagasrV7ix4w+SCAmAjF+Tdtqf8LMht1mSn+zeB32ZsnyWnL74HPWqw6/StdlS5HSxlvmfl2UnxH77e5EPGNI0KGUPG6vQcUxBg9B1tv7iruNgYJThT54sE3zWy+6eFJy5XCGkZuiS2ETiL31h+9CEwGWRsR6L6+tA=
file:
- build/electrum-zcash/dist/electrum-zcash-$ELECTRUM_ZCASH_VERSION-macosx.dmg
on:
repo: zebra-lucky/electrum-zcash
tags: true
condition: "$TRAVIS_OS_NAME = osx"
- provider: releases
api_key:
secure: ipcWAaqrPrgXX+L86AEq/VkfJ81j3RvDF1b+BUcPCmU/HB0UE6Eg8TTtGZ/LPZXUfcsmhLCS9zinwSh8HTYjJ1fd+yVv7V7xFrp1vRuxTE06JNwPETOOZRAk/sMlOfKU2T0rw8iyW4qhfCHO0r6Dqmb6/0psARrq0bxihKWfI+eemVLdMJPzCJABSwKOrPWK01j6FCehvlPyFnRy/Ti0sAy8JYSJ/r+ICN08qHZTVrskquEE/Bds9E3Js3Jc/tZSCPhw+/u6t34zVnFAGvEnhcgHZFDuooCl2BR02jBNpkgjHSjGUEDjom85J+FKRAg+9mDU+wH9X0s+uf4O+AIVQH4COhWjbcqviX+PyHzG8kT6uVnIj39yLmgIAhDXVfjVgy8lfb8M6pS1ajhZB1C4fwHU6ef98xk4BhTlWbex6nvko5cy8lituezfD8U8JQhbv4KSz+xRpOIspUXj1KnHTaJhBEizxFi60MX+mlKRXeKIpSqveEPZnKuqkpnOb3K8BTM8Ca2UjYagasrV7ix4w+SCAmAjF+Tdtqf8LMht1mSn+zeB32ZsnyWnL74HPWqw6/StdlS5HSxlvmfl2UnxH77e5EPGNI0KGUPG6vQcUxBg9B1tv7iruNgYJThT54sE3zWy+6eFJy5XCGkZuiS2ETiL31h+9CEwGWRsR6L6+tA=
file:
- build/electrum-zcash/dist/Electrum-Zcash-$ELECTRUM_ZCASH_VERSION.tar.gz
- build/electrum-zcash/dist/electrum-zcash-$ELECTRUM_ZCASH_VERSION-setup-win32.exe
- build/electrum-zcash/dist/electrum-zcash-$ELECTRUM_ZCASH_VERSION-setup-win64.exe
- build/electrum-zcash/bin/Electrum_Zcash-$ELECTRUM_ZCASH_APK_VERSION-release-unsigned.apk
on:
repo: zebra-lucky/electrum-zcash
tags: true
condition: "$TRAVIS_OS_NAME = linux"
notifications:
slack:
secure: g2tFyXklhL4WOD/jQ8nxiOBqVv2F26iE4aVgvpclQ/9Fnh6jXEk3jCXyMqt39fcbB4Hka2wPr4n5uWH3tRaChFpwK5LQS5vuymllloqdxAShgIXXciZ1k/Ka1K+mxMEPJriQm4MT5AvzcLVSkJ0i5LYW8nWgG7+fTEullWS4hlPLC77C36iK2CWDaxfFqqe8oPTdsCVbik8HQ62ZWDM6Sh6TZbQD7F9eUBmiwwQhRB2BMxPkWghwQ//FRJ+PIpg7PtWRru/JjNg3adOsHnwlltqUVAolacZCbpxDKFR+GLpYmLkMrwdnVA7apZ2In/yo25ByAkxshCgw45lmGB0dtC1zeAe3Get9eGP5w3o9Zedj5T5esX0BNArDK70C+kTXcPeJaRRQJPrs5OYXRPKjD+uiJqe1fIFSmhdM6vvuMPdyA1z0Fd0/9G2O/Qi8tFxcFmM8n6JQGfD9ojOQF8fPYcHM9gsOgNU9J2PfV3RnRtv3VZogxs4azKG2M8JhD/lwqZBNi4FgdllW6NE7+5TB2KX07xy/zx0m81u8k6J228sAuiRsUBcpmW7pqlqLIENMzwV8pDcA93Ps0EWJKWbzRi+hIEkBnaFE9WHY0GcKuW0TCrnonZ4FOnJNO/G9HzxvQ97bcJDvhUloJ2pBBsH0P4IZ1RlDXFpc5DqTT2qxZSo=

View File

@ -1,38 +0,0 @@
Windows Binary Builds
=====================
These scripts can be used for cross-compilation of Windows Electrum executables from Linux/Wine.
Produced binaries are deterministic so you should be able to generate binaries that match the official releases.
Usage:
1. Install the following dependencies:
- dirmngr
- gpg
- Wine (>= v2)
For example:
```
$ sudo apt-get install wine-development dirmngr gnupg2
$ sudo ln -sf /usr/bin/wine-development /usr/local/bin/wine
$ wine --version
wine-2.0 (Debian 2.0-3+b2)
```
or
```
$ pacman -S wine gnupg
$ wine --version
wine-2.21
```
2. Make sure `/opt` is writable by the current user.
3. Run `build.sh`.
4. The generated binaries are in `./dist`.

View File

@ -1,86 +0,0 @@
#!/bin/bash
NAME_ROOT=electrum
PYTHON_VERSION=3.5.4
if [ "$#" -gt 0 ]; then
BRANCH="$1"
fi
# These settings probably don't need any change
export WINEPREFIX=/opt/wine64
export PYTHONDONTWRITEBYTECODE=1
export PYTHONHASHSEED=22
PYHOME=c:/python$PYTHON_VERSION
PYTHON="wine $PYHOME/python.exe -OO -B"
# Let's begin!
cd `dirname $0`
set -e
cd tmp
for repo in electrum electrum-locale electrum-icons; do
if [ -d $repo ]; then
cd $repo
git pull
git checkout master
cd ..
else
URL=https://github.com/spesmilo/$repo.git
git clone -b master $URL $repo
fi
done
pushd electrum-locale
for i in ./locale/*; do
dir=$i/LC_MESSAGES
mkdir -p $dir
msgfmt --output-file=$dir/electrum.mo $i/electrum.po || true
done
popd
pushd electrum
git checkout $BRANCH
VERSION=`git describe --tags`
echo "Last commit: $VERSION"
find -exec touch -d '2000-11-11T11:11:11+00:00' {} +
popd
rm -rf $WINEPREFIX/drive_c/electrum
cp -r electrum $WINEPREFIX/drive_c/electrum
cp electrum/LICENCE .
cp -r electrum-locale/locale $WINEPREFIX/drive_c/electrum/lib/
cp electrum-icons/icons_rc.py $WINEPREFIX/drive_c/electrum/gui/qt/
# Install frozen dependencies
$PYTHON -m pip install -r ../../requirements.txt
pushd $WINEPREFIX/drive_c/electrum
$PYTHON setup.py install
popd
cd ..
rm -rf dist/
# build standalone and portable versions
wine "C:/python$PYTHON_VERSION/scripts/pyinstaller.exe" --noconfirm --ascii --name $NAME_ROOT-$VERSION -w deterministic.spec
# set timestamps in dist, in order to make the installer reproducible
pushd dist
find -exec touch -d '2000-11-11T11:11:11+00:00' {} +
popd
# build NSIS installer
# $VERSION could be passed to the electrum.nsi script, but this would require some rewriting in the script iself.
wine "$WINEPREFIX/drive_c/Program Files (x86)/NSIS/makensis.exe" /DPRODUCT_VERSION=$VERSION electrum.nsi
cd dist
mv electrum-setup.exe $NAME_ROOT-$VERSION-setup.exe
cd ..
echo "Done."
md5sum dist/electrum*exe

View File

@ -1,23 +0,0 @@
#!/bin/bash
# Lucky number
export PYTHONHASHSEED=22
here=$(dirname "$0")
echo "Clearing $here/build and $here/dist..."
rm $here/build/* -rf
rm $here/dist/* -rf
$here/prepare-wine.sh && \
$here/prepare-pyinstaller.sh && \
$here/prepare-hw.sh || exit 1
echo "Resetting modification time in C:\Python..."
# (Because of some bugs in pyinstaller)
pushd /opt/wine64/drive_c/python*
find -exec touch -d '2000-11-11T11:11:11+00:00' {} +
popd
ls -l /opt/wine64/drive_c/python*
$here/build-electrum-git.sh && \
echo "Done."

View File

@ -1,122 +0,0 @@
# -*- mode: python -*-
from PyInstaller.utils.hooks import collect_data_files, collect_submodules
import sys
for i, x in enumerate(sys.argv):
if x == '--name':
cmdline_name = sys.argv[i+1]
break
else:
raise BaseException('no name')
home = 'C:\\electrum\\'
# see https://github.com/pyinstaller/pyinstaller/issues/2005
hiddenimports = []
hiddenimports += collect_submodules('trezorlib')
hiddenimports += collect_submodules('btchip')
hiddenimports += collect_submodules('keepkeylib')
datas = [
(home+'lib/currencies.json', 'electrum'),
(home+'lib/servers.json', 'electrum'),
(home+'lib/servers_testnet.json', 'electrum'),
(home+'lib/wordlist/english.txt', 'electrum/wordlist'),
(home+'lib/locale', 'electrum/locale'),
(home+'plugins', 'electrum_plugins'),
]
datas += collect_data_files('trezorlib')
datas += collect_data_files('btchip')
datas += collect_data_files('keepkeylib')
# We don't put these files in to actually include them in the script but to make the Analysis method scan them for imports
a = Analysis([home+'electrum',
home+'gui/qt/main_window.py',
home+'gui/text.py',
home+'lib/util.py',
home+'lib/wallet.py',
home+'lib/simple_config.py',
home+'lib/bitcoin.py',
home+'lib/dnssec.py',
home+'lib/commands.py',
home+'plugins/cosigner_pool/qt.py',
home+'plugins/email_requests/qt.py',
home+'plugins/trezor/client.py',
home+'plugins/trezor/qt.py',
home+'plugins/keepkey/qt.py',
home+'plugins/ledger/qt.py',
#home+'packages/requests/utils.py'
],
datas=datas,
#pathex=[home+'lib', home+'gui', home+'plugins'],
hiddenimports=hiddenimports,
hookspath=[])
# http://stackoverflow.com/questions/19055089/pyinstaller-onefile-warning-pyconfig-h-when-importing-scipy-or-scipy-signal
for d in a.datas:
if 'pyconfig' in d[0]:
a.datas.remove(d)
break
# hotfix for #3171 (pre-Win10 binaries)
a.binaries = [x for x in a.binaries if not x[1].lower().startswith(r'c:\windows')]
pyz = PYZ(a.pure)
#####
# "standalone" exe with all dependencies packed into it
exe_standalone = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
name=os.path.join('build\\pyi.win32\\electrum', cmdline_name + ".exe"),
debug=False,
strip=None,
upx=False,
icon=home+'icons/electrum.ico',
console=False)
# console=True makes an annoying black box pop up, but it does make Electrum output command line commands, with this turned off no output will be given but commands can still be used
exe_portable = EXE(
pyz,
a.scripts,
a.binaries,
a.datas + [ ('is_portable', 'README.md', 'DATA' ) ],
name=os.path.join('build\\pyi.win32\\electrum', cmdline_name + "-portable.exe"),
debug=False,
strip=None,
upx=False,
icon=home+'icons/electrum.ico',
console=False)
#####
# exe and separate files that NSIS uses to build installer "setup" exe
exe_dependent = EXE(
pyz,
a.scripts,
exclude_binaries=True,
name=os.path.join('build\\pyi.win32\\electrum', cmdline_name),
debug=False,
strip=None,
upx=False,
icon=home+'icons/electrum.ico',
console=False)
coll = COLLECT(
exe_dependent,
a.binaries,
a.zipfiles,
a.datas,
strip=None,
upx=True,
debug=False,
icon=home+'icons/electrum.ico',
console=False,
name=os.path.join('dist', 'electrum'))

View File

@ -1,28 +0,0 @@
#!/bin/bash
TREZOR_GIT_URL=https://github.com/trezor/python-trezor.git
KEEPKEY_GIT_URL=https://github.com/keepkey/python-keepkey.git
BTCHIP_GIT_URL=https://github.com/LedgerHQ/btchip-python.git
BRANCH=master
PYTHON_VERSION=3.5.4
# These settings probably don't need any change
export WINEPREFIX=/opt/wine64
PYHOME=c:/python$PYTHON_VERSION
PYTHON="wine $PYHOME/python.exe -OO -B"
# Let's begin!
cd `dirname $0`
set -e
cd tmp
$PYTHON -m pip install setuptools --upgrade
$PYTHON -m pip install cython --upgrade
$PYTHON -m pip install trezor==0.7.16 --upgrade
$PYTHON -m pip install keepkey==4.0.2 --upgrade
$PYTHON -m pip install btchip-python==0.1.24 --upgrade

View File

@ -1,24 +0,0 @@
#!/bin/bash
PYTHON_VERSION=3.5.4
PYINSTALLER_GIT_URL=https://github.com/ecdsa/pyinstaller.git
BRANCH=fix_2952
export WINEPREFIX=/opt/wine64
PYHOME=c:/python$PYTHON_VERSION
PYTHON="wine $PYHOME/python.exe -OO -B"
cd `dirname $0`
set -e
cd tmp
if [ ! -d "pyinstaller" ]; then
git clone -b $BRANCH $PYINSTALLER_GIT_URL pyinstaller
fi
cd pyinstaller
git pull
git checkout $BRANCH
$PYTHON setup.py install
cd ..
wine "C:/python$PYTHON_VERSION/scripts/pyinstaller.exe" -v

View File

@ -1,113 +0,0 @@
#!/bin/bash
# Please update these carefully, some versions won't work under Wine
NSIS_URL=https://prdownloads.sourceforge.net/nsis/nsis-3.02.1-setup.exe?download
NSIS_SHA256=736c9062a02e297e335f82252e648a883171c98e0d5120439f538c81d429552e
PYTHON_VERSION=3.5.4
## These settings probably don't need change
export WINEPREFIX=/opt/wine64
#export WINEARCH='win32'
PYHOME=c:/python$PYTHON_VERSION
PYTHON="wine $PYHOME/python.exe -OO -B"
# based on https://superuser.com/questions/497940/script-to-verify-a-signature-with-gpg
verify_signature() {
local file=$1 keyring=$2 out=
if out=$(gpg --no-default-keyring --keyring "$keyring" --status-fd 1 --verify "$file" 2>/dev/null) &&
echo "$out" | grep -qs "^\[GNUPG:\] VALIDSIG "; then
return 0
else
echo "$out" >&2
exit 0
fi
}
verify_hash() {
local file=$1 expected_hash=$2 out=
actual_hash=$(sha256sum $file | awk '{print $1}')
if [ "$actual_hash" == "$expected_hash" ]; then
return 0
else
echo "$file $actual_hash (unexpected hash)" >&2
exit 0
fi
}
# Let's begin!
cd `dirname $0`
set -e
# Clean up Wine environment
echo "Cleaning $WINEPREFIX"
rm -rf $WINEPREFIX
echo "done"
wine 'wineboot'
echo "Cleaning tmp"
rm -rf tmp
mkdir -p tmp
echo "done"
cd tmp
# Install Python
# note: you might need "sudo apt-get install dirmngr" for the following
# keys from https://www.python.org/downloads/#pubkeys
KEYRING_PYTHON_DEV=keyring-electrum-build-python-dev.gpg
gpg --no-default-keyring --keyring $KEYRING_PYTHON_DEV --recv-keys 531F072D39700991925FED0C0EDDC5F26A45C816 26DEA9D4613391EF3E25C9FF0A5B101836580288 CBC547978A3964D14B9AB36A6AF053F07D9DC8D2 C01E1CAD5EA2C4F0B8E3571504C367C218ADD4FF 12EF3DC38047DA382D18A5B999CDEA9DA4135B38 8417157EDBE73D9EAC1E539B126EB563A74B06BF DBBF2EEBF925FAADCF1F3FFFD9866941EA5BBD71 2BA0DB82515BBB9EFFAC71C5C9BE28DEE6DF025C 0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D C9B104B3DD3AA72D7CCB1066FB9921286F5E1540 97FC712E4C024BBEA48A61ED3A5CA953F73C700D 7ED10B6531D7C8E1BC296021FC624643487034E5
for msifile in core dev exe lib pip tools; do
echo "Installing $msifile..."
wget "https://www.python.org/ftp/python/$PYTHON_VERSION/win32/${msifile}.msi"
wget "https://www.python.org/ftp/python/$PYTHON_VERSION/win32/${msifile}.msi.asc"
verify_signature "${msifile}.msi.asc" $KEYRING_PYTHON_DEV
wine msiexec /i "${msifile}.msi" /qb TARGETDIR=C:/python$PYTHON_VERSION
done
# upgrade pip
$PYTHON -m pip install pip --upgrade
# Install PyWin32
$PYTHON -m pip install pypiwin32
# Install PyQt
$PYTHON -m pip install PyQt5
## Install pyinstaller
#$PYTHON -m pip install pyinstaller==3.3
# Install ZBar
#wget -q -O zbar.exe "https://sourceforge.net/projects/zbar/files/zbar/0.10/zbar-0.10-setup.exe/download"
#wine zbar.exe
# install Cryptodome
$PYTHON -m pip install pycryptodomex
# install PySocks
$PYTHON -m pip install win_inet_pton
# install websocket (python2)
$PYTHON -m pip install websocket-client
# Upgrade setuptools (so Electrum can be installed later)
$PYTHON -m pip install setuptools --upgrade
# Install NSIS installer
wget -q -O nsis.exe "$NSIS_URL"
verify_hash nsis.exe $NSIS_SHA256
wine nsis.exe /S
# Install UPX
#wget -O upx.zip "https://downloads.sourceforge.net/project/upx/upx/3.08/upx308w.zip"
#unzip -o upx.zip
#cp upx*/upx.exe .
# add dlls needed for pyinstaller:
cp $WINEPREFIX/drive_c/python$PYTHON_VERSION/Lib/site-packages/PyQt5/Qt/bin/* $WINEPREFIX/drive_c/python$PYTHON_VERSION/
echo "Wine is configured. Please run prepare-pyinstaller.sh"

View File

@ -0,0 +1,38 @@
#!/usr/bin/env python3
import sys
import requests
def check_restriction(p, r):
# See: https://www.python.org/dev/peps/pep-0496/
# Hopefully we don't need to parse the whole microlanguage
if "extra" in r and "[" not in p:
return False
for marker in ["os_name", "platform_release", "sys_platform", "platform_system"]:
if marker in r:
return True
for p in sys.stdin.read().split():
p = p.strip()
if not p:
continue
assert "==" in p, "This script expects a list of packages with pinned version, e.g. package==1.2.3, not {}".format(p)
p, v = p.rsplit("==", 1)
try:
data = requests.get("https://pypi.org/pypi/{}/{}/json".format(p, v)).json()["info"]
except ValueError:
raise Exception("Package could not be found: {}=={}".format(p, v))
try:
for r in data["requires_dist"]:
if ";" not in r:
continue
d, restricted = r.split(";", 1)
if check_restriction(d, restricted):
print(d, sep=" ")
print("Installing {} from {} although it is only needed for {}".format(d, p, restricted), file=sys.stderr)
except TypeError:
# Has no dependencies at all
continue

View File

@ -0,0 +1,61 @@
pip==9.0.3 \
--hash=sha256:7bf48f9a693be1d58f49f7af7e0ae9fe29fd671cde8a55e6edca3581c4ef5796 \
--hash=sha256:c3ede34530e0e0b2381e7363aded78e0c33291654937e7373032fda04e8803e5
pycryptodomex==3.6.0 \
--hash=sha256:023432d6938c17bd8ff5c4a3efcac7923e3724a42655e011580a84db0be0903b \
--hash=sha256:11756a831e0cc2549fb67be50aca040495d7e20a47b2ab1cf77f0db6eaae75e0 \
--hash=sha256:18837dbf05ed97bcb169b1f5465ec2569985f25c787cc91d89b363217f31f63b \
--hash=sha256:1d815ac94211ae6b15a92dc8242eb81369214e4c6805d4ff663a14f7707f0212 \
--hash=sha256:27533f616df0da5964c1a1b9506b0d6c09f90dd5d22e44773871a1cba9fddede \
--hash=sha256:2c2894facf93b6a99a8c2c34b9d998bbd79db32dedb06d89dc8ab0c198fad687 \
--hash=sha256:38feac59199ce6146a77550671c2db66ec48ce100688489640485dd658d7cf65 \
--hash=sha256:398d7631c286572b0edf2a8fea00ce5ec2c140d0159e16096296ecbb2b62192b \
--hash=sha256:3d0b011a1514db2bee5db6dd02cc2672f2cb490df57652d3e506069e1129ed01 \
--hash=sha256:41a5bd025c4d93d7ef8147709da5ec0ef9101b963ca52851a67befea8c94f9ec \
--hash=sha256:5a854546fe8d6081cae9a1c1980862e2f0477f81117c123a82468aefc3d4db5c \
--hash=sha256:73ae29574d19e76a3033e93e88d4bfe7decce11da45f5e3fc695dfb7899dae53 \
--hash=sha256:7433a59ce37d376d593424e8d3587dfd4d4bf294b5e787f4b22be875af1b82a1 \
--hash=sha256:7597afd495ece825cd0de04e237d45d32554443f32cb332e2de0e0adc08d76e1 \
--hash=sha256:87630254a6ca33c98dcd590e02c70edf3af3b755c06d7a991421955c00f4e8c2 \
--hash=sha256:8e59e995a417e86b11ddb66d95e975bc012290989d8f8b1696a7956b990c29ee \
--hash=sha256:9a56672ae636de779563fe793cb6a473296f4f06e86c5e065e7a1378c4eb498f \
--hash=sha256:adce464e726d2742275fcedf58cd2c099bc8d6daab49331fec9f59e4d6160cab \
--hash=sha256:b28998827c363ebb445a3b5b98946a3df68ef9059ed0cd6d13c3d9b4b4b6c944 \
--hash=sha256:bb2c76cabe94335247c562d58a54eb62088b1ae93f0417785738508d2319dd48 \
--hash=sha256:c63a12f6c3b17305ace17529b6a2afe60808e01beb5e0b8414532f28cfdbea4c \
--hash=sha256:cd7fc58c11afc299e2aeb11827b940fb3715ba2e5ab5a6a5693af095742e9b4c \
--hash=sha256:ce93300534b1c282e6c8971252f8e5887d20d8669e0af3d2a06cef1d47a03e97 \
--hash=sha256:d893c16f187c6f175cc5b84e1743cab1bc45f48b4fd52e8815e5e632eb55bb9d \
--hash=sha256:e185783b0461ae62cf7143117e8603363dfe66820436ed29ca18c8a4010d3252 \
--hash=sha256:f934e15b59c3073e8957ab5b027bb32b38b04bc03aa5180610b2bb6164c43b3b \
--hash=sha256:ffc2b73e58bb44515cce14faa395c427c8e0bbdc6bac9a4e7674c7135d6ffad5
PyQt5==5.10.1 \
--hash=sha256:1e652910bd1ffd23a3a48c510ecad23a57a853ed26b782cd54b16658e6f271ac \
--hash=sha256:4db7113f464c733a99fcb66c4c093a47cf7204ad3f8b3bda502efcc0839ac14b \
--hash=sha256:9c17ab3974c1fc7bbb04cc1c9dae780522c0ebc158613f3025fccae82227b5f7 \
--hash=sha256:f6035baa009acf45e5f460cf88f73580ad5dc0e72330029acd99e477f20a5d61
setuptools==39.0.1 \
--hash=sha256:8010754433e3211b9cdbbf784b50f30e80bf40fc6b05eb5f865fab83300599b8 \
--hash=sha256:bec7badf0f60e7fc8153fac47836edc41b74e5d541d7692e614e635720d6a7c7
SIP==4.19.8 \
--hash=sha256:09f9a4e6c28afd0bafedb26ffba43375b97fe7207bd1a0d3513f79b7d168b331 \
--hash=sha256:105edaaa1c8aa486662226360bd3999b4b89dd56de3e314d82b83ed0587d8783 \
--hash=sha256:1bb10aac55bd5ab0e2ee74b3047aa2016cfa7932077c73f602a6f6541af8cd51 \
--hash=sha256:265ddf69235dd70571b7d4da20849303b436192e875ce7226be7144ca702a45c \
--hash=sha256:52074f7cb5488e8b75b52f34ec2230bc75d22986c7fe5cd3f2d266c23f3349a7 \
--hash=sha256:5ff887a33839de8fc77d7f69aed0259b67a384dc91a1dc7588e328b0b980bde2 \
--hash=sha256:74da4ddd20c5b35c19cda753ce1e8e1f71616931391caeac2de7a1715945c679 \
--hash=sha256:7d69e9cf4f8253a3c0dfc5ba6bb9ac8087b8239851f22998e98cb35cfe497b68 \
--hash=sha256:97bb93ee0ef01ba90f57be2b606e08002660affd5bc380776dd8b0fcaa9e093a \
--hash=sha256:cf98150a99e43fda7ae22abe655b6f202e491d6291486548daa56cb15a2fcf85 \
--hash=sha256:d9023422127b94d11c1a84bfa94933e959c484f2c79553c1ef23c69fe00d25f8 \
--hash=sha256:e72955e12f4fccf27aa421be383453d697b8a44bde2cc26b08d876fd492d0174
six==1.11.0 \
--hash=sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9 \
--hash=sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb
websocket-client==0.47.0 \
--hash=sha256:188b68b14fdb2d8eb1a111f21b9ffd2dbf1dbc4e4c1d28cf2c37cdbf1dd1cae6 \
--hash=sha256:a453dc4dfa6e0db3d8fd7738a308a88effe6240c59f3226eb93e8f020c216149
wheel==0.31.0 \
--hash=sha256:1ae8153bed701cb062913b72429bcf854ba824f973735427681882a688cb55ce \
--hash=sha256:9cdc8ab2cc9c3c2e2727a4b67c22881dbb0e1c503d592992594c5e131c867107

View File

@ -0,0 +1,119 @@
btchip-python==0.1.26 \
--hash=sha256:427d67c5b4f4709605c51dd91d5d44a2ad8f541693673817765271e4b3a1461e
certifi==2018.1.18 \
--hash=sha256:14131608ad2fd56836d33a71ee60fa1c82bc9d2c8d98b7bdbc631fe1b3cd1296 \
--hash=sha256:edbc3f203427eef571f79a7692bb160a2b0f7ccaa31953e99bd17e307cf63f7d
chardet==3.0.4 \
--hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
--hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691
click==6.7 \
--hash=sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d \
--hash=sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b
Cython==0.28.1 \
--hash=sha256:0a44c3645a84724d4f7f7c1126f3807cad14271f210bb1a9a15bfd330c8d20b9 \
--hash=sha256:152ee5f345012ca3bb7cc71da2d3736ee20f52cd8476e4d49e5e25c5a4102b12 \
--hash=sha256:15cbde95cdf6a346c63c0b38b895aa3186d0a49adcaf42b9e19c4cb0473cb921 \
--hash=sha256:175273eb6a90af364b9b2aea74e3c3eebcde9caec02d617cd8886c0933ec3304 \
--hash=sha256:1a434e7621ca6671ce949893fef94b13a580853ba976e729f68dda5ab270ee8a \
--hash=sha256:1da199a5be7c486ee89b4a8bda7f00f9fd98b800d9af3a1fe3fc63e68dadea85 \
--hash=sha256:26196ff8fe00e7c4c5815a310c368edfc1a1c8a3c90ac9220435d1b01e795cf7 \
--hash=sha256:2b73b062658511167dde37a51acb80ae6ddea1ffa284ebdbc47a900f21e63c70 \
--hash=sha256:2b9aa64473fefbe988e36a30915732a0e2a75ffe0f3e81a70e3f8d367c2e4119 \
--hash=sha256:32638aefc164404ac70e5f86558cd3aece34df17db16da905abf5e664073bae4 \
--hash=sha256:330c95c03e39835976d1410f5fa877b75fcc5c50dc146d4c02377fc719b1f8c9 \
--hash=sha256:38b499fa317cf6939e46317457240553b13e974f08ed387523f10af26e269f6c \
--hash=sha256:3c60caa0075aa1f1c5e10b5352d2e8bb9a18361ce9fca50fa7d4baea67804ade \
--hash=sha256:3fc9b945541cadb5a10316e48b5e73f4b6f635b7d30156f502b66f3766545b23 \
--hash=sha256:427299c47cfe04d97f9f09ea55570c05898a87b64caf6ddebb529b6f64e5d228 \
--hash=sha256:4e07e619af85e7c1ec2344ecab558929bb4acbca25f8f170d07dc677e8ee413f \
--hash=sha256:5010e048fb9791522fe626bd40137b8a847ba77a6e656bb64d6d7acdc45ece32 \
--hash=sha256:70bc2806fc9e5affcf74c0d4fa12cba57ffb94cdfc28b975692c8df56ea86402 \
--hash=sha256:7cdd5303121024269610236876d9f4beb6a909a1ea5d7bc48e7bbf5d8774a3f2 \
--hash=sha256:80856aa45004514a3ff5e102bd18fbd5230d234311de1f83d4e5b97ef42f6c93 \
--hash=sha256:996ae959ab2600b8ad4c80981afc32e89b42d0abe3234c48e960e40180459cb2 \
--hash=sha256:b5c2e31be55bc61d3c758889d06b16d84f4fda944832fbed63c113ec2dbc5f97 \
--hash=sha256:c39b3a042bf5ded7c8336c82b1fa817e1f46a7ef16d41d66b3d3340e7a3b60ed \
--hash=sha256:d08f5dd2fbf7d1506c9d986a8352b2423170002ddb635b184d2a916d2b5df0d6 \
--hash=sha256:d2b636c16931663aeb8ffb91cf871a912e66e7200755ce68aa8c502c16eb366f \
--hash=sha256:e27e12834ac315c7d67ca697a325d42ff8395e9b82fb62c8665bb583eb0df589 \
--hash=sha256:e312dd688b97e9f97199a8e4ba18b65db2747157630761d27193a18761b23fed \
--hash=sha256:e47bbe74d6c87fab2e22f1580aa3e4a8e7482b4265b1fc76685fc49f90e18f99 \
--hash=sha256:ea113ff58e96152738e646b8ee77b41d3994735df77bee0a26cd413a67e03c0f \
--hash=sha256:ea22d79133583b5b0f856dbfda097363228ae0a3d77431deaba90634e5d4853a
ecdsa==0.13 \
--hash=sha256:40d002cf360d0e035cf2cb985e1308d41aaa087cbfc135b2dc2d844296ea546c \
--hash=sha256:64cf1ee26d1cde3c73c6d7d107f835fed7c6a2904aef9eac223d57ad800c43fa
hidapi==0.7.99.post21 \
--hash=sha256:1ac170f4d601c340f2cd52fd06e85c5e77bad7ceac811a7bb54b529f7dc28c24 \
--hash=sha256:8d3be666f464347022e2b47caf9132287885d9eacc7895314fc8fefcb4e42946 \
--hash=sha256:b4b1f6aff0192e9be153fe07c1b7576cb7a1ff52e78e3f76d867be95301a8e87 \
--hash=sha256:bf03f06f586ce7d8aeb697a94b7dba12dc9271aae92d7a8d4486360ff711a660 \
--hash=sha256:c76de162937326fcd57aa399f94939ce726242323e65c15c67e183da1f6c26f7 \
--hash=sha256:d4ad1e46aef98783a9e6274d523b8b1e766acfc3d72828cd44a337564d984cfa \
--hash=sha256:d4b5787a04613503357606bb10e59c3e2c1114fa00ee328b838dd257f41cbd7b \
--hash=sha256:e0be1aa6566979266a8fc845ab0e18613f4918cf2c977fe67050f5dc7e2a9a97 \
--hash=sha256:edfb16b16a298717cf05b8c8a9ad1828b6ff3de5e93048ceccd74e6ae4ff0922
idna==2.6 \
--hash=sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f \
--hash=sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4
keepkey==4.0.2 \
--hash=sha256:cddee60ae405841cdff789cbc54168ceaeb2282633420f2be155554c25c69138
libusb1==1.6.4 \
--hash=sha256:8c930d9c1d037d9c83924c82608aa6a1adcaa01ca0e4a23ee0e8e18d7eee670d
mnemonic==0.18 \
--hash=sha256:02a7306a792370f4a0c106c2cf1ce5a0c84b9dbd7e71c6792fdb9ad88a727f1d
pbkdf2==1.3 \
--hash=sha256:ac6397369f128212c43064a2b4878038dab78dab41875364554aaf2a684e6979
pip==9.0.3 \
--hash=sha256:7bf48f9a693be1d58f49f7af7e0ae9fe29fd671cde8a55e6edca3581c4ef5796 \
--hash=sha256:c3ede34530e0e0b2381e7363aded78e0c33291654937e7373032fda04e8803e5
protobuf==3.5.2.post1 \
--hash=sha256:01ccd6d03449ae75b779fb5bf4ed62177d61afe3c5e6465ccf3f8b2e1a84afbe \
--hash=sha256:1d92cc30b0b46cced33adde5853d920179eb5ea8eecdee9552502a7f29cc3f21 \
--hash=sha256:242e4c7ae565267a8bc8b92d707177f915607ea4bd73244bec6cbf4a49b96661 \
--hash=sha256:3b60685732bd0cbdc802dfcb6071efbcf5d927ce3127c13c33ea1a8efae3aa76 \
--hash=sha256:3f655e1f99c3e14d56ca900af1b9a4715b691319a295cc38939d7f77eabd5e7c \
--hash=sha256:560a38e692a69957a70ba0e5839aa67430efd63072bf91b0539dac19055694cd \
--hash=sha256:5c1c8f6a0a68a874e3beff89255959dd80fad45870e96c88944a1b81a22dd5f5 \
--hash=sha256:628a3bf0794a8b3cabb18db11eb67cc10e0cc6e5525d557ae7b682bb73fa2018 \
--hash=sha256:7222d6616108b33ad6cbeff8117062a73c43cdc8fa8f64f6a322ebeb663e710e \
--hash=sha256:76ef6ca3c50e4cfd044861586d5f1b352e0fe7f17f883df6c165bad5b4d0e10a \
--hash=sha256:7c193e6964e752bd056735594826c5b03274ceb8f07349d3ae47d9766250ba96 \
--hash=sha256:869e12bcfb5759e683f53ec1dd6155b7be034065431da289f0cb4510040a0799 \
--hash=sha256:905414e5ea6cdb78d8730f66335755152b46685fcb9fc2f2134024e3ea9e8dcc \
--hash=sha256:ac0067e3c60737865ed72bb7416e02297d229d960902802d874c0e167128c809 \
--hash=sha256:adf716a89c9cc1891ead79a861c427071ef59172f0e11967b00565a9547b3bd0 \
--hash=sha256:bcfa99f5a82f5eaaf6e5cee5bfdca5a1670f5740aec1d93dae170645ed1a16b0 \
--hash=sha256:cc94079ae6cbcea5ae194464a30f3223f075e06a0446f52bca9ddbeb6e9f412a \
--hash=sha256:d5d9edfdc5a3a01d06062d677b121081629782edf0e05ca1be14f15bb947eeee \
--hash=sha256:e269ab7a50bf0fa6fe6a88ea7dcc7a1079ae9450d9ab9b7730ac32916d55508b \
--hash=sha256:e7fd33a3474cbe18fd5b5620784a0fa21fcae3e402b1806e29c6b450c7f61706
pyblake2==1.1.1 \
--hash=sha256:11c1d9d94cbaf5a4834aadf7f57bcb29eae1d174721269f242ca891f62cd6502 \
--hash=sha256:427e7e91d644c3b9952e84145e211e4e3197fc4a3a0dbbd87b6da6b6cfa0a0df \
--hash=sha256:4903d64e1a24f0cf2f8b8a1e0aaab12898951112b370ab9600651a4be4387c99 \
--hash=sha256:6886b050521aed0293b2f67a3e1da74ea6080e4be19b57d9e1ae3d6ff10e223a \
--hash=sha256:8cc4198ce61dddd33c9e66a216fc70be04fab66d02baa79e6bdebd83f16af57e \
--hash=sha256:8ec8e9087d13c99b354ab6d8b4cadb1758633db5946ff95a6bc7ac538b6d7b3d \
--hash=sha256:a785faf939810dca4aef525b6f59890fdcabdef09228cb30f4d77c3021707846 \
--hash=sha256:e51b86e685045e2f8896d581b230effb1cc69f1134e11318f3607d98fa5ba95c \
--hash=sha256:f51051de4eb27dc63c525a562daf9ead14e3e3583f096b9b90d3a360b5ca4995
requests==2.18.4 \
--hash=sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b \
--hash=sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e
rlp==0.6.0 \
--hash=sha256:87879a0ba1479b760cee98af165de2eee95258b261faa293199f60742be96f34
setuptools==39.0.1 \
--hash=sha256:8010754433e3211b9cdbbf784b50f30e80bf40fc6b05eb5f865fab83300599b8 \
--hash=sha256:bec7badf0f60e7fc8153fac47836edc41b74e5d541d7692e614e635720d6a7c7
six==1.11.0 \
--hash=sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9 \
--hash=sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb
trezor==0.9.1 \
--hash=sha256:a481191011bade98f1e9f1201e7c72a83945050657bbc90dc4ac32dc8b8b46a4
urllib3==1.22 \
--hash=sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b \
--hash=sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f
wheel==0.31.0 \
--hash=sha256:1ae8153bed701cb062913b72429bcf854ba824f973735427681882a688cb55ce \
--hash=sha256:9cdc8ab2cc9c3c2e2727a4b67c22881dbb0e1c503d592992594c5e131c867107

View File

@ -0,0 +1,69 @@
certifi==2018.1.18 \
--hash=sha256:14131608ad2fd56836d33a71ee60fa1c82bc9d2c8d98b7bdbc631fe1b3cd1296 \
--hash=sha256:edbc3f203427eef571f79a7692bb160a2b0f7ccaa31953e99bd17e307cf63f7d
chardet==3.0.4 \
--hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
--hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691
dnspython==1.15.0 \
--hash=sha256:40f563e1f7a7b80dc5a4e76ad75c23da53d62f1e15e6e517293b04e1f84ead7c \
--hash=sha256:861e6e58faa730f9845aaaa9c6c832851fbf89382ac52915a51f89c71accdd31
ecdsa==0.13 \
--hash=sha256:40d002cf360d0e035cf2cb985e1308d41aaa087cbfc135b2dc2d844296ea546c \
--hash=sha256:64cf1ee26d1cde3c73c6d7d107f835fed7c6a2904aef9eac223d57ad800c43fa
idna==2.6 \
--hash=sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f \
--hash=sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4
jsonrpclib-pelix==0.3.1 \
--hash=sha256:5417b1508d5a50ec64f6e5b88907f111155d52607b218ff3ba9a777afb2e49e3 \
--hash=sha256:bd89a6093bc4d47dc8a096197aacb827359944a4533be5193f3845f57b9f91b4
pbkdf2==1.3 \
--hash=sha256:ac6397369f128212c43064a2b4878038dab78dab41875364554aaf2a684e6979
pip==9.0.3 \
--hash=sha256:7bf48f9a693be1d58f49f7af7e0ae9fe29fd671cde8a55e6edca3581c4ef5796 \
--hash=sha256:c3ede34530e0e0b2381e7363aded78e0c33291654937e7373032fda04e8803e5
protobuf==3.5.2.post1 \
--hash=sha256:01ccd6d03449ae75b779fb5bf4ed62177d61afe3c5e6465ccf3f8b2e1a84afbe \
--hash=sha256:1d92cc30b0b46cced33adde5853d920179eb5ea8eecdee9552502a7f29cc3f21 \
--hash=sha256:242e4c7ae565267a8bc8b92d707177f915607ea4bd73244bec6cbf4a49b96661 \
--hash=sha256:3b60685732bd0cbdc802dfcb6071efbcf5d927ce3127c13c33ea1a8efae3aa76 \
--hash=sha256:3f655e1f99c3e14d56ca900af1b9a4715b691319a295cc38939d7f77eabd5e7c \
--hash=sha256:560a38e692a69957a70ba0e5839aa67430efd63072bf91b0539dac19055694cd \
--hash=sha256:5c1c8f6a0a68a874e3beff89255959dd80fad45870e96c88944a1b81a22dd5f5 \
--hash=sha256:628a3bf0794a8b3cabb18db11eb67cc10e0cc6e5525d557ae7b682bb73fa2018 \
--hash=sha256:7222d6616108b33ad6cbeff8117062a73c43cdc8fa8f64f6a322ebeb663e710e \
--hash=sha256:76ef6ca3c50e4cfd044861586d5f1b352e0fe7f17f883df6c165bad5b4d0e10a \
--hash=sha256:7c193e6964e752bd056735594826c5b03274ceb8f07349d3ae47d9766250ba96 \
--hash=sha256:869e12bcfb5759e683f53ec1dd6155b7be034065431da289f0cb4510040a0799 \
--hash=sha256:905414e5ea6cdb78d8730f66335755152b46685fcb9fc2f2134024e3ea9e8dcc \
--hash=sha256:ac0067e3c60737865ed72bb7416e02297d229d960902802d874c0e167128c809 \
--hash=sha256:adf716a89c9cc1891ead79a861c427071ef59172f0e11967b00565a9547b3bd0 \
--hash=sha256:bcfa99f5a82f5eaaf6e5cee5bfdca5a1670f5740aec1d93dae170645ed1a16b0 \
--hash=sha256:cc94079ae6cbcea5ae194464a30f3223f075e06a0446f52bca9ddbeb6e9f412a \
--hash=sha256:d5d9edfdc5a3a01d06062d677b121081629782edf0e05ca1be14f15bb947eeee \
--hash=sha256:e269ab7a50bf0fa6fe6a88ea7dcc7a1079ae9450d9ab9b7730ac32916d55508b \
--hash=sha256:e7fd33a3474cbe18fd5b5620784a0fa21fcae3e402b1806e29c6b450c7f61706
pyaes==1.6.1 \
--hash=sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f
PySocks==1.6.8 \
--hash=sha256:3fe52c55890a248676fd69dc9e3c4e811718b777834bcaab7a8125cf9deac672
qrcode==6.0 \
--hash=sha256:037b0db4c93f44586e37f84c3da3f763874fcac85b2974a69a98e399ac78e1bf \
--hash=sha256:de4ffc15065e6ff20a551ad32b6b41264f3c75275675406ddfa8e3530d154be3
requests==2.18.4 \
--hash=sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b \
--hash=sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e
setuptools==39.0.1 \
--hash=sha256:8010754433e3211b9cdbbf784b50f30e80bf40fc6b05eb5f865fab83300599b8 \
--hash=sha256:bec7badf0f60e7fc8153fac47836edc41b74e5d541d7692e614e635720d6a7c7
six==1.11.0 \
--hash=sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9 \
--hash=sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb
urllib3==1.22 \
--hash=sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b \
--hash=sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f
wheel==0.31.0 \
--hash=sha256:1ae8153bed701cb062913b72429bcf854ba824f973735427681882a688cb55ce \
--hash=sha256:9cdc8ab2cc9c3c2e2727a4b67c22881dbb0e1c503d592992594c5e131c867107
colorama==0.3.9 \
--hash=sha256:463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda \
--hash=sha256:48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1

View File

@ -1,22 +0,0 @@
#!/bin/bash
# Run this after a new release to update dependencies
venv_dir=~/.electrum-venv
contrib=$(dirname "$0")
which virtualenv > /dev/null 2>&1 || { echo "Please install virtualenv" && exit 1; }
rm $venv_dir -rf
virtualenv $venv_dir
source $venv_dir/bin/activate
echo "Installing dependencies"
pushd $contrib/..
python setup.py install
popd
pip freeze | sed '/^Electrum/ d' > $contrib/requirements.txt
echo "Updated requirements"

View File

@ -1,51 +0,0 @@
#!/usr/bin/python2
import re
import os
from versions import version, version_win, version_mac, version_android, version_apk
from versions import download_template, download_page
with open(download_template) as f:
string = f.read()
string = string.replace("##VERSION##", version)
string = string.replace("##VERSION_WIN##", version_win)
string = string.replace("##VERSION_MAC##", version_mac)
string = string.replace("##VERSION_ANDROID##", version_android)
string = string.replace("##VERSION_APK##", version_apk)
files = {
'tgz': "Electrum-%s.tar.gz" % version,
'zip': "Electrum-%s.zip" % version,
'mac': "electrum-%s.dmg" % version_mac,
'win': "electrum-%s.exe" % version_win,
'win_setup': "electrum-%s-setup.exe" % version_win,
'win_portable': "electrum-%s-portable.exe" % version_win,
}
for k, n in files.items():
path = "dist/%s"%n
link = "https://download.electrum.org/%s/%s"%(version,n)
if not os.path.exists(path):
os.system("wget -q %s -O %s" % (link, path))
if not os.path.getsize(path):
os.unlink(path)
string = re.sub("<div id=\"%s\">(.*?)</div>"%k, '', string, flags=re.DOTALL + re.MULTILINE)
continue
sigpath = path + '.asc'
siglink = link + '.asc'
if not os.path.exists(sigpath):
os.system("wget -q %s -O %s" % (siglink, sigpath))
if not os.path.getsize(sigpath):
os.unlink(sigpath)
string = re.sub("<div id=\"%s\">(.*?)</div>"%k, '', string, flags=re.DOTALL + re.MULTILINE)
continue
if os.system("gpg --verify %s"%sigpath) != 0:
raise BaseException(sigpath)
string = string.replace("##link_%s##"%k, link)
with open(download_page,'w') as f:
f.write(string)

View File

@ -1,6 +0,0 @@
#!/bin/bash
rm -rf dist
export PYTHONHASHSEED=22
VERSION=`git describe --tags`
pyinstaller --noconfirm --ascii --name $VERSION contrib/osx.spec
hdiutil create -fs HFS+ -volname "Electrum" -srcfolder dist/Electrum.app dist/electrum-$VERSION.dmg

View File

@ -1,82 +0,0 @@
# -*- mode: python -*-
from PyInstaller.utils.hooks import collect_data_files, collect_submodules
import sys
for i, x in enumerate(sys.argv):
if x == '--name':
VERSION = sys.argv[i+1]
break
else:
raise BaseException('no version')
home = '/Users/voegtlin/electrum/'
block_cipher=None
# see https://github.com/pyinstaller/pyinstaller/issues/2005
hiddenimports = []
hiddenimports += collect_submodules('trezorlib')
hiddenimports += collect_submodules('btchip')
hiddenimports += collect_submodules('keepkeylib')
datas = [
(home+'lib/currencies.json', 'electrum'),
(home+'lib/servers.json', 'electrum'),
(home+'lib/wordlist/english.txt', 'electrum/wordlist'),
(home+'lib/locale', 'electrum/locale'),
(home+'plugins', 'electrum_plugins'),
]
datas += collect_data_files('trezorlib')
datas += collect_data_files('btchip')
datas += collect_data_files('keepkeylib')
# We don't put these files in to actually include them in the script but to make the Analysis method scan them for imports
a = Analysis([home+'electrum',
home+'gui/qt/main_window.py',
home+'gui/text.py',
home+'lib/util.py',
home+'lib/wallet.py',
home+'lib/simple_config.py',
home+'lib/bitcoin.py',
home+'lib/dnssec.py',
home+'lib/commands.py',
home+'plugins/cosigner_pool/qt.py',
home+'plugins/email_requests/qt.py',
home+'plugins/trezor/client.py',
home+'plugins/trezor/qt.py',
home+'plugins/keepkey/qt.py',
home+'plugins/ledger/qt.py',
],
datas=datas,
hiddenimports=hiddenimports,
hookspath=[])
# http://stackoverflow.com/questions/19055089/pyinstaller-onefile-warning-pyconfig-h-when-importing-scipy-or-scipy-signal
for d in a.datas:
if 'pyconfig' in d[0]:
a.datas.remove(d)
break
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.datas,
name='Electrum',
debug=False,
strip=False,
upx=True,
icon=home+'electrum.icns',
console=False)
app = BUNDLE(exe,
version = VERSION,
name='Electrum.app',
icon=home+'electrum.icns',
bundle_identifier=None,
info_plist = {
'NSHighResolutionCapable':'True'
}
)

View File

@ -0,0 +1,4 @@
Cython>=0.27
trezor>=0.9.0
keepkey
btchip-python

View File

@ -0,0 +1,9 @@
pyaes>=0.1a1
ecdsa>=0.9
pbkdf2
requests
qrcode
protobuf
dnspython
jsonrpclib-pelix
PySocks>=1.6.6

725
contrib/sign-releases.py Executable file
View File

@ -0,0 +1,725 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Sign releases on github, make/upload ppa to launchpad.net
NOTE on ppa: To build a ppa you may need to install some more packages.
On ubuntu:
sudo apt-get install devscripts libssl-dev python3-dev \
debhelper python3-setuptools dh-python
NOTE on apk signing: To create a keystore and sign the apk you need to install
java-8-openjdk, or java-7-openjdk on older systems.
To create a keystore run the following command:
mkdir ~/.jks && keytool -genkey -v -keystore ~/.jks/keystore \
-alias electrum.z.cash -keyalg RSA -keysize 2048 \
-validity 10000
Then it shows a warning about the proprietary format and a command to migrate:
keytool -importkeystore -srckeystore ~/.jks/keystore \
-destkeystore ~/.jks/keystore -deststoretype pkcs12
Manual signing:
jarsigner -verbose \
-tsa http://sha256timestamp.ws.symantec.com/sha256/timestamp \
-sigalg SHA1withRSA -digestalg SHA1 \
-sigfile zcash-electrum \
-keystore ~/.jks/keystore \
Electrum_Zcash-3.0.6.1-release-unsigned.apk \
electrum.z.cash
Zipalign from Android SDK build tools is also required (set path to bin in
settings file or with key -z). To install:
wget http://dl.google.com/android/android-sdk_r24-linux.tgz \
&& tar xzf android-sdk_r24-linux.tgz \
&& rm android-sdk_r24-linux.tgz \
&& (while sleep 3; do echo "y"; done) \
| android-sdk-linux/tools/android update sdk -u -a -t \
'tools, platform-tools-preview, build-tools-23.0.1' \
&& (while sleep 3; do echo "y"; done) \
| android-sdk-linux/tools/android update sdk -u -a -t \
'tools, platform-tools, build-tools-27.0.3'
Manual zip aligning:
android-sdk-linux/build-tools/27.0.3/zipalign -v 4 \
Electrum_Zcash-3.0.6.1-release-unsigned.apk \
Electrum_Zcash-3.0.6.1-release.apk
About script settings:
Settings is read from options, then config file is read.
If setting is already set from options, then it value does
not changes.
Config file can have one repo form or multiple repo form.
In one repo form config settings read from root JSON object.
Keys are "repo", "keyid", "token", "count", "sign_drafts",
and others, which is corresponding to program options.
Example:
{
"repo": "value"
...
}
In multiple repo form, if root "default_repo" key is set, then code
try to read "repos" key as list and cycle through it to find suitable
repo, or if no repo is set before, then "default_repo" is used to match.
If match found, then that list object is used ad one repo form config.
Example:
{
"default_repo": "value"
"repos": [
{
"repo": "value"
...
}
]
}
"""
import os
import os.path
import re
import sys
import time
import getpass
import shutil
import hashlib
import tempfile
import json
import zipfile
from subprocess import check_call, CalledProcessError
from functools import cmp_to_key
from time import localtime, strftime
try:
import click
import certifi
import gnupg
import dateutil.parser
import colorama
from colorama import Fore, Style
from github_release import (get_releases, gh_asset_download,
gh_asset_upload, gh_asset_delete)
from urllib3 import PoolManager
except ImportError as e:
print('Import error:', e)
print('To run script install required packages with the next command:\n\n'
'pip install githubrelease python-gnupg pyOpenSSL cryptography idna'
' certifi python-dateutil click colorama requests LinkHeader')
sys.exit(1)
HTTP = PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where())
FNULL = open(os.devnull, 'w')
HOME_DIR = os.path.expanduser('~')
CONFIG_NAME = '.sign-releases'
SEARCH_COUNT = 1
SHA_FNAME = 'SHA256SUMS.txt'
# make_ppa related definitions
PPA_SERIES = {
'trusty': '14.04.1',
'xenial': '16.04.1',
'artful': '17.10.1',
'bionic': '18.04.1',
}
PEP440_PUBVER_PATTERN = re.compile('^((\d+)!)?'
'((\d+)(\.\d+)*)'
'([a-zA-Z]+\d+)?'
'((\.[a-zA-Z]+\d+)*)$')
REL_NOTES_PATTERN = re.compile('^#.+?(^[^#].+?)^#.+?', re.M | re.S)
SDIST_NAME_PATTERN = re.compile('^Electrum-Zcash-(.*).tar.gz$')
SDIST_DIR_TEMPLATE = 'Electrum-Zcash-{version}'
PPA_SOURCE_NAME = 'electrum-zcash'
PPA_ORIG_NAME_TEMPLATE = '%s_{version}.orig.tar.gz' % PPA_SOURCE_NAME
CHANGELOG_TEMPLATE = """%s ({ppa_version}) {series}; urgency=medium
{changes} -- {uid} {time}""" % PPA_SOURCE_NAME
PPA_FILES_TEMPLATE = '%s_{0}{1}' % PPA_SOURCE_NAME
LP_API_URL='https://api.launchpad.net/1.0'
LP_SERIES_TEMPLATE = '%s/ubuntu/{0}' % LP_API_URL
LP_ARCHIVES_TEMPLATE = '%s/~{user}/+archive/ubuntu/{ppa}' % LP_API_URL
# sing_apk related definitions
JKS_KEYSTORE = os.path.join(HOME_DIR, '.jks/keystore')
JKS_ALIAS = 'electrum.z.cash'
JKS_STOREPASS = 'JKS_STOREPASS'
JKS_KEYPASS = 'JKS_KEYPASS'
KEYTOOL_ARGS = ['keytool', '-list', '-storepass:env', JKS_STOREPASS]
JARSIGNER_ARGS = [
'jarsigner', '-verbose',
'-tsa', 'http://sha256timestamp.ws.symantec.com/sha256/timestamp',
'-sigalg', 'SHA1withRSA', '-digestalg', 'SHA1',
'-sigfile', 'zcash-electrum',
'-storepass:env', JKS_STOREPASS,
'-keypass:env', JKS_KEYPASS,
]
UNSIGNED_APK_PATTERN = re.compile('^Electrum_Zcash-(.*)-release-unsigned.apk$')
SIGNED_APK_TEMPLATE = 'Electrum_Zcash-{version}-release.apk'
os.environ['QUILT_PATCHES'] = 'debian/patches'
def pep440_to_deb(version):
"""Convert PEP 440 public version to deb upstream version"""
ver_match = PEP440_PUBVER_PATTERN.match(version)
if not ver_match:
raise Exception('Version "%s" does not comply with PEP 440' % version)
g = ver_match.group
deb_ver = ''
deb_ver += ('%s:' % g(2)) if g(1) else ''
deb_ver += g(3)
deb_ver += ('~%s' % g(6)) if g(6) else ''
deb_ver += ('%s' % g(7)) if g(7) else ''
return deb_ver
def compare_published_times(a, b):
"""Releases list sorting comparsion function (last published first)"""
a = a['published_at']
b = b['published_at']
if not a and not b:
return 0
elif not a:
return -1
elif not b:
return 1
a = dateutil.parser.parse(a)
b = dateutil.parser.parse(b)
if a > b:
return -1
elif b > a:
return 1
else:
return 0
def sha256_checksum(filename, block_size=65536):
"""Gather sha256 hash on filename"""
sha256 = hashlib.sha256()
with open(filename, 'rb') as f:
for block in iter(lambda: f.read(block_size), b''):
sha256.update(block)
return sha256.hexdigest()
def read_config():
"""Read and parse JSON from config file from HOME dir"""
config_path = os.path.join(HOME_DIR, CONFIG_NAME)
if not os.path.isfile(config_path):
return {}
try:
with open(config_path, 'r') as f:
data = f.read()
return json.loads(data)
except Exception as e:
print('Error: Cannot read config file:', e)
return {}
def get_next_ppa_num(ppa, source_package_name, ppa_upstr_version, series_name):
"""Calculate next ppa num (if older ppa versions whas published earlier)"""
user, ppa_name = ppa.split('/')
archives_url = LP_ARCHIVES_TEMPLATE.format(user=user, ppa=ppa_name)
series_url = LP_SERIES_TEMPLATE.format(series_name)
query = {
'ws.op': 'getPublishedSources',
'distro_series': series_url,
'order_by_date': 'true',
'source_name': source_package_name,
}
resp = HTTP.request('GET', archives_url, fields=query)
if resp.status != 200:
raise Exception('Launchpad API error %s %s', (resp.status,
resp.reason))
data = json.loads(resp.data.decode('utf-8'))
entries = data['entries']
if len(entries) == 0:
return 1
for e in entries:
ppa_version = e['source_package_version']
version_match = re.match('%s-0ppa(\d+)~ubuntu' % ppa_upstr_version,
ppa_version)
if version_match:
return int(version_match.group(1)) + 1
return 1
class ChdirTemporaryDirectory(object):
"""Create tmp dir, chdir to it and remove on exit"""
def __enter__(self):
self.prev_wd = os.getcwd()
self.name = tempfile.mkdtemp()
os.chdir(self.name)
return self.name
def __exit__(self, exc_type, exc_value, traceback):
os.chdir(self.prev_wd)
shutil.rmtree(self.name)
class SignApp(object):
def __init__(self, **kwargs):
"""Get app settings from options, from curdir git, from config file"""
ask_passphrase = kwargs.pop('ask_passphrase', None)
self.sign_drafts = kwargs.pop('sign_drafts', False)
self.force = kwargs.pop('force', False)
self.tag_name = kwargs.pop('tag_name', None)
self.repo = kwargs.pop('repo', None)
self.ppa = kwargs.pop('ppa', None)
self.token = kwargs.pop('token', None)
self.keyid = kwargs.pop('keyid', None)
self.count = kwargs.pop('count', None)
self.dry_run = kwargs.pop('dry_run', False)
self.no_ppa = kwargs.pop('no_ppa', False)
self.verbose = kwargs.pop('verbose', False)
self.jks_keystore = kwargs.pop('jks_keystore', False)
self.jks_alias = kwargs.pop('jks_alias', False)
self.zipalign_path = kwargs.pop('zipalign_path', False)
self.config = {}
config_data = read_config()
default_repo = config_data.get('default_repo', None)
if default_repo:
if not self.repo:
self.repo = default_repo
for config in config_data.get('repos', []):
config_repo = config.get('repo', None)
if config_repo and config_repo == self.repo:
self.config = config
break
else:
self.config = config_data
if self.config:
self.repo = self.repo or self.config.get('repo', None)
self.ppa = self.ppa or self.config.get('ppa', None)
self.token = self.token or self.config.get('token', None)
self.keyid = self.keyid or self.config.get('keyid', None)
self.count = self.count or self.config.get('count', None) \
or SEARCH_COUNT
self.sign_drafts = self.sign_drafts \
or self.config.get('sign_drafts', False)
self.no_ppa = self.no_ppa \
or self.config.get('no_ppa', False)
self.verbose = self.verbose or self.config.get('verbose', None)
self.jks_keystore = self.jks_keystore \
or self.config.get('jks_keystore', JKS_KEYSTORE)
self.jks_alias = self.jks_alias \
or self.config.get('jks_alias', JKS_ALIAS)
self.zipalign_path = self.zipalign_path \
or self.config.get('zipalign_path', None)
if not self.repo:
print('no repo found, exit')
sys.exit(1)
if self.token:
os.environ['GITHUB_TOKEN'] = self.token
if not os.environ.get('GITHUB_TOKEN', None):
print('GITHUB_TOKEN environment var not set, exit')
sys.exit(1)
if self.keyid:
self.keyid = self.keyid.split('/')[-1]
self.passphrase = None
self.gpg = gnupg.GPG()
if not self.keyid:
print('no keyid set, exit')
sys.exit(1)
keylist = self.gpg.list_keys(True, keys=[self.keyid])
if not keylist:
print('no key with keyid %s found, exit' % self.keyid)
sys.exit(1)
self.uid = ', '.join(keylist[0].get('uids', ['No uid found']))
if ask_passphrase:
while not self.passphrase:
self.read_passphrase()
elif not self.check_key():
while not self.passphrase:
self.read_passphrase()
if self.zipalign_path:
try:
check_call(self.zipalign_path, stderr=FNULL)
except CalledProcessError:
pass
self.read_jks_storepass()
self.read_jks_keypass()
def read_jks_storepass(self):
"""Read JKS storepass and keypass"""
while not JKS_STOREPASS in os.environ:
storepass = getpass.getpass('%sInput %s keystore password:%s ' %
(Fore.GREEN,
self.jks_keystore,
Style.RESET_ALL))
os.environ[JKS_STOREPASS] = storepass
try:
check_call(KEYTOOL_ARGS + ['-keystore', self.jks_keystore],
stdout=FNULL, stderr=FNULL)
except CalledProcessError:
print('%sWrong keystore password%s' %
(Fore.RED, Style.RESET_ALL))
del os.environ[JKS_STOREPASS]
def read_jks_keypass(self):
while not JKS_KEYPASS in os.environ:
keypass = getpass.getpass('%sInput alias password for <%s> '
'[Enter if same as for keystore]:%s ' %
(Fore.YELLOW,
self.jks_alias,
Style.RESET_ALL))
if not keypass:
os.environ[JKS_KEYPASS] = os.environ[JKS_STOREPASS]
else:
os.environ[JKS_KEYPASS] = keypass
with ChdirTemporaryDirectory() as tmpdir:
test_file = 'testfile.txt'
test_zipfile = 'testzip.zip'
with open(test_file, 'w') as fdw:
fdw.write('testcontent')
test_zf = zipfile.ZipFile(test_zipfile, mode='w')
test_zf.write(test_file)
test_zf.close()
sign_args = ['-keystore', self.jks_keystore,
test_zipfile, self.jks_alias]
try:
check_call(JARSIGNER_ARGS + sign_args, stdout=FNULL)
except CalledProcessError:
print('%sWrong key alias password%s' %
(Fore.RED, Style.RESET_ALL))
del os.environ[JKS_KEYPASS]
def read_passphrase(self):
"""Read passphrase for gpg key until check_key is passed"""
passphrase = getpass.getpass('%sInput passphrase for Key: %s %s:%s ' %
(Fore.GREEN,
self.keyid,
self.uid,
Style.RESET_ALL))
if self.check_key(passphrase):
self.passphrase = passphrase
def check_key(self, passphrase=None):
"""Try to sign test string, and if some data signed retun True"""
signed_data = self.gpg.sign('test message to check passphrase',
keyid=self.keyid, passphrase=passphrase)
if signed_data.data and self.gpg.verify(signed_data.data).valid:
return True
print('%sWrong passphrase!%s' % (Fore.RED, Style.RESET_ALL))
return False
def sign_file_name(self, name, detach=True):
"""Sign file with self.keyid, place signature in deteached .asc file"""
with open(name, 'rb') as fdrb:
signed_data = self.gpg.sign_file(fdrb,
keyid=self.keyid,
passphrase=self.passphrase,
detach=detach)
with open('%s.asc' % name, 'wb') as fdw:
fdw.write(signed_data.data)
def sign_release(self, release, other_names, asc_names, is_newest_release):
"""Download/sign unsigned assets, upload .asc counterparts.
Create SHA256SUMS.txt with all assets included and upload it
with SHA256SUMS.txt.asc counterpart.
"""
repo = self.repo
tag = release.get('tag_name', None)
if not tag:
print('Release have no tag name, skip release\n')
return
with ChdirTemporaryDirectory() as tmpdir:
with open(SHA_FNAME, 'w') as fdw:
sdist_match = None
for name in other_names:
if name == SHA_FNAME:
continue
gh_asset_download(repo, tag, name)
if not self.no_ppa:
sdist_match = sdist_match \
or SDIST_NAME_PATTERN.match(name)
apk_match = UNSIGNED_APK_PATTERN.match(name)
if apk_match:
unsigned_name = name
name = self.sign_apk(unsigned_name, apk_match.group(1))
gh_asset_upload(repo, tag, name, dry_run=self.dry_run)
gh_asset_delete(repo, tag, unsigned_name,
dry_run=self.dry_run)
if not '%s.asc' % name in asc_names or self.force:
self.sign_file_name(name)
if self.force:
gh_asset_delete(repo, tag, '%s.asc' % name,
dry_run=self.dry_run)
gh_asset_upload(repo, tag, '%s.asc' % name,
dry_run=self.dry_run)
sumline = '%s %s\n' % (sha256_checksum(name), name)
fdw.write(sumline)
self.sign_file_name(SHA_FNAME, detach=False)
gh_asset_delete(repo, tag, '%s.asc' % SHA_FNAME,
dry_run=self.dry_run)
gh_asset_upload(repo, tag, '%s.asc' % SHA_FNAME,
dry_run=self.dry_run)
if sdist_match and is_newest_release:
self.make_ppa(sdist_match, tmpdir)
def sign_apk(self, unsigned_name, version):
"""Sign unsigned release apk"""
if not (JKS_STOREPASS in os.environ and JKS_KEYPASS in os.environ):
raise Exception('Found unsigned apk and no zipalign path set')
name = SIGNED_APK_TEMPLATE.format(version=version)
print('Signing apk: %s' % name)
apk_args = ['-keystore', self.jks_keystore,
unsigned_name, self.jks_alias]
if self.verbose:
check_call(JARSIGNER_ARGS + apk_args)
check_call([self.zipalign_path, '-v', '4', unsigned_name, name])
else:
check_call(JARSIGNER_ARGS + apk_args, stdout=FNULL)
check_call([self.zipalign_path, '-v', '4', unsigned_name, name],
stdout=FNULL)
return name
def make_ppa(self, sdist_match, tmpdir):
"""Build, sign and upload dsc to launchpad.net ppa from sdist.tar.gz"""
with ChdirTemporaryDirectory() as ppa_tmpdir:
sdist_name = sdist_match.group(0)
version = sdist_match.group(1)
ppa_upstr_version = pep440_to_deb(version)
ppa_orig_name = PPA_ORIG_NAME_TEMPLATE.format(
version=ppa_upstr_version)
series = list(map(lambda x: x[0],
sorted(PPA_SERIES.items(), key=lambda x: x[1])))
sdist_dir = SDIST_DIR_TEMPLATE.format(version=version)
sdist_dir = os.path.join(ppa_tmpdir, sdist_dir)
debian_dir = os.path.join(sdist_dir, 'debian')
changelog_name = os.path.join(debian_dir, 'changelog')
relnotes_name = os.path.join(sdist_dir, 'RELEASE-NOTES')
print('Found sdist: %s, version: %s' % (sdist_name, version))
print(' Copying sdist to %s, extracting' % ppa_orig_name)
shutil.copy(os.path.join(tmpdir, sdist_name),
os.path.join(ppa_tmpdir, ppa_orig_name))
check_call(['tar', '-xzvf', ppa_orig_name], stdout=FNULL)
with open(relnotes_name, 'r') as rnfd:
changes = rnfd.read()
changes_match = REL_NOTES_PATTERN.match(changes)
if changes_match and len(changes_match.group(1)) > 0:
changes = changes_match.group(1).split('\n')
for i in range(len(changes)):
if changes[i] == '':
continue
elif changes[i][0] != ' ':
changes[i] = ' %s' % changes[i]
elif len(changes[i]) > 1 and changes[i][1] != ' ':
changes[i] = ' %s' % changes[i]
changes = '\n'.join(changes)
else:
changes = '\n * Porting to ppa\n\n'
os.chdir(sdist_dir)
print(' Making PPAs for series: %s' % (', '.join(series)))
now_formatted = strftime('%a, %d %b %Y %H:%M:%S %z', localtime())
for s in series:
ppa_num = get_next_ppa_num(self.ppa, PPA_SOURCE_NAME,
ppa_upstr_version, s)
rel_version = PPA_SERIES[s]
ppa_version = '%s-0ppa%s~ubuntu%s' % (ppa_upstr_version,
ppa_num, rel_version)
ppa_dsc = os.path.join(ppa_tmpdir, PPA_FILES_TEMPLATE.format(
ppa_version, '.dsc'))
ppa_chgs = os.path.join(ppa_tmpdir, PPA_FILES_TEMPLATE.format(
ppa_version, '_source.changes'))
changelog = CHANGELOG_TEMPLATE.format(ppa_version=ppa_version,
series=s,
changes=changes,
uid=self.uid,
time=now_formatted)
with open(changelog_name, 'w') as chlfd:
chlfd.write(changelog)
print(' Make %s ppa, Signing with key: %s, %s' %
(ppa_version, self.keyid, self.uid))
if self.verbose:
check_call(['debuild', '-S'])
else:
check_call(['debuild', '-S'], stdout=FNULL)
print(' Upload %s ppa to %s' % (ppa_version, self.ppa))
if self.dry_run:
print(' Dry run: dput ppa:%s %s' % (self.ppa, ppa_chgs))
else:
check_call(['dput', ('ppa:%s' % self.ppa), ppa_chgs],
stdout=FNULL)
print('\n')
def search_and_sign_unsinged(self):
"""Search through last 'count' releases with assets without
.asc counterparts or releases withouth SHA256SUMS.txt.asc
"""
print('Sign releases on repo: %s' % self.repo)
print(' With key: %s, %s\n' % (self.keyid, self.uid))
releases = get_releases(self.repo)
if self.tag_name:
releases = [r for r in releases
if r.get('tag_name', None) == self.tag_name]
if len(releases) == 0:
print('No release with tag "%s" found, exit' % self.tag_name)
sys.exit(1)
elif not self.sign_drafts:
releases = [r for r in releases if not r.get('draft', False)]
# cycle through releases sorted by by publication date
releases.sort(key=cmp_to_key(compare_published_times))
for r in releases[:self.count]:
tag_name = r.get('tag_name', 'No tag_name')
is_draft = r.get('draft', False)
is_prerelease = r.get('prerelease', False)
created_at = r.get('created_at', '')
msg = 'Found %s%s tagged: %s, created at: %s' % (
'draft ' if is_draft else '',
'prerelease' if is_prerelease else 'release',
tag_name,
created_at
)
if not is_draft:
msg += ', published at: %s' % r.get('published_at', '')
print(msg)
asset_names = [a['name'] for a in r['assets']]
if not asset_names:
print(' No assets found, skip release\n')
continue
asc_names = [a for a in asset_names if a.endswith('.asc')]
other_names = [a for a in asset_names if not a.endswith('.asc')]
need_to_sign = False
if asset_names and not asc_names:
need_to_sign = True
if not need_to_sign:
for name in other_names:
if not '%s.asc' % name in asc_names:
need_to_sign = True
break
if not need_to_sign:
need_to_sign = '%s.asc' % SHA_FNAME not in asc_names
if need_to_sign or self.force:
self.sign_release(r, other_names, asc_names, r==releases[0])
else:
print(' Seems already signed, skip release\n')
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
@click.command(context_settings=CONTEXT_SETTINGS)
@click.option('-a', '--jks-alias',
help='jks key alias')
@click.option('-c', '--count', type=int,
help='Number of recently published releases to sign')
@click.option('-d', '--sign-drafts', is_flag=True,
help='Sing draft releases first')
@click.option('-f', '--force', is_flag=True,
help='Sing already signed releases')
@click.option('-g', '--tag-name',
help='Sing only release tagged with tag name')
@click.option('-k', '--keyid',
help='gnupg keyid')
@click.option('-K', '--jks-keystore',
help='jks keystore path')
@click.option('-l', '--ppa',
help='PPA in format uzername/ppa')
@click.option('-L', '--no-ppa', is_flag=True,
help='Do not make launchpad ppa')
@click.option('-n', '--dry-run', is_flag=True,
help='Do not uload signed files')
@click.option('-p', '--ask-passphrase', is_flag=True,
help='Ask to enter passphrase')
@click.option('-r', '--repo',
help='Repository in format username/reponame')
@click.option('-s', '--sleep', type=int,
help='Sleep number of seconds before signing')
@click.option('-t', '--token',
help='GigHub access token, to be set as'
' GITHUB_TOKEN environmet variable')
@click.option('-v', '--verbose', is_flag=True,
help='Make more verbose output')
@click.option('-z', '--zipalign-path',
help='zipalign path')
def main(**kwargs):
app = SignApp(**kwargs)
sleep = kwargs.pop('sleep', None)
if (sleep):
print('Sleep for %s seconds' % sleep)
time.sleep(sleep)
app.search_and_sign_unsinged()
if __name__ == '__main__':
colorama.init()
main()

View File

@ -1,18 +0,0 @@
#!/usr/bin/python2
import os
import getpass
if __name__ == '__main__':
os.chdir("dist")
password = getpass.getpass("Password:")
for f in os.listdir('.'):
if f.endswith('asc'):
continue
os.system( "gpg --sign --armor --detach --passphrase \"%s\" %s"%(password, f) )
os.chdir("..")

View File

@ -0,0 +1,161 @@
# -*- mode: python -*-
import sys
from PyInstaller.utils.hooks import collect_data_files, collect_submodules
for i, x in enumerate(sys.argv):
if x == '--name':
cmdline_name = sys.argv[i+1]
break
else:
raise Exception('no name')
hiddenimports = collect_submodules('trezorlib')
hiddenimports += collect_submodules('btchip')
hiddenimports += collect_submodules('keepkeylib')
hiddenimports += collect_submodules('websocket')
hiddenimports += [
'lib',
'lib.base_wizard',
'lib.plot',
'lib.qrscanner',
'lib.websockets',
'gui.qt',
'plugins',
'plugins.hw_wallet.qt',
'plugins.audio_modem.qt',
'plugins.cosigner_pool.qt',
'plugins.digitalbitbox.qt',
'plugins.email_requests.qt',
'plugins.keepkey.qt',
'plugins.labels.qt',
'plugins.trezor.qt',
'plugins.ledger.qt',
'plugins.virtualkeyboard.qt',
]
datas = [
('lib/servers.json', 'electrum_zcash'),
('lib/servers_testnet.json', 'electrum_zcash'),
('lib/servers_regtest.json', 'electrum_zcash'),
('lib/currencies.json', 'electrum_zcash'),
('lib/checkpoints.json', 'electrum_zcash'),
('lib/locale', 'electrum_zcash/locale'),
('lib/wordlist', 'electrum_zcash/wordlist'),
('C:\\zbarw', '.'),
]
datas += collect_data_files('trezorlib')
datas += collect_data_files('btchip')
datas += collect_data_files('keepkeylib')
binaries = [('C:/Python34/libusb-1.0.dll', '.')]
# https://github.com/pyinstaller/pyinstaller/wiki/Recipe-remove-tkinter-tcl
sys.modules['FixTk'] = None
excludes = ['FixTk', 'tcl', 'tk', '_tkinter', 'tkinter', 'Tkinter']
excludes += [
'PyQt5.QtCLucene',
'PyQt5.Qt5CLucene',
'PyQt5.QtDesigner',
'PyQt5.QtDesignerComponents',
'PyQt5.QtHelp',
'PyQt5.QtLocation',
'PyQt5.QtMultimedia',
'PyQt5.QtMultimediaQuick_p',
'PyQt5.QtMultimediaWidgets',
'PyQt5.QtNetwork',
'PyQt5.QtOpenGL',
'PyQt5.QtPositioning',
'PyQt5.QtPrintSupport',
'PyQt5.QtQml',
'PyQt5.QtQuick',
'PyQt5.QtQuickParticles',
'PyQt5.QtQuickWidgets',
'PyQt5.QtSensors',
'PyQt5.QtSerialPort',
'PyQt5.QtSql',
'PyQt5.Qt5Sql',
'PyQt5.QtTest',
'PyQt5.QtWebChannel',
'PyQt5.QtWebKit',
'PyQt5.QtWebKitWidgets',
'PyQt5.QtWebSockets',
'PyQt5.QtXml',
'PyQt5.QtXmlPatterns',
'PyQt5.QtWebProcess',
'PyQt5.QtWinExtras',
]
a = Analysis(['electrum-zcash'],
pathex=['plugins'],
hiddenimports=hiddenimports,
datas=datas,
binaries=binaries,
excludes=excludes,
runtime_hooks=['pyi_runtimehook.py'])
# http://stackoverflow.com/questions/19055089/
for d in a.datas:
if 'pyconfig' in d[0]:
a.datas.remove(d)
break
# Add TOC to electrum_zcash, electrum_zcash_gui, electrum_zcash_plugins
for p in sorted(a.pure):
if p[0].startswith('lib') and p[2] == 'PYMODULE':
a.pure += [('electrum_zcash%s' % p[0][3:] , p[1], p[2])]
if p[0].startswith('gui') and p[2] == 'PYMODULE':
a.pure += [('electrum_zcash_gui%s' % p[0][3:] , p[1], p[2])]
if p[0].startswith('plugins') and p[2] == 'PYMODULE':
a.pure += [('electrum_zcash_plugins%s' % p[0][7:] , p[1], p[2])]
pyz = PYZ(a.pure)
exe = EXE(pyz,
a.scripts,
exclude_binaries=True,
debug=False,
strip=False,
upx=False,
console=False,
icon='icons/electrum-zcash.ico',
name=os.path.join('build\\pyi.win32\\electrum', cmdline_name))
# exe with console output
conexe = EXE(pyz,
a.scripts,
exclude_binaries=True,
debug=False,
strip=False,
upx=False,
console=True,
icon='icons/electrum-zcash.ico',
name=os.path.join('build\\pyi.win32\\electrum',
'console-%s' % cmdline_name))
# trezorctl separate executable
tctl_a = Analysis(['C:/Python34/Scripts/trezorctl'],
hiddenimports=['pkgutil'],
excludes=excludes,
runtime_hooks=['pyi_tctl_runtimehook.py'])
tctl_pyz = PYZ(tctl_a.pure)
tctl_exe = EXE(tctl_pyz,
tctl_a.scripts,
exclude_binaries=True,
debug=False,
strip=False,
upx=False,
console=True,
name=os.path.join('build\\pyi.win32\\electrum', 'trezorctl.exe'))
coll = COLLECT(exe, conexe, tctl_exe,
a.binaries,
a.datas,
strip=False,
upx=False,
name=os.path.join('dist', 'electrum-zcash'))

View File

@ -1,22 +1,24 @@
;--------------------------------
;Include Modern UI
!include "TextFunc.nsh" ;Needed for the $GetSize fuction. I know, doesn't sound logical, it isn't.
!include "TextFunc.nsh" ;Needed for the $GetSize function. I know, doesn't sound logical, it isn't.
!include "MUI2.nsh"
!include "x64.nsh"
;--------------------------------
;Variables
!define PRODUCT_NAME "Electrum"
!define PRODUCT_WEB_SITE "https://github.com/spesmilo/electrum"
!define PRODUCT_NAME "Electrum-Zcash"
!define PRODUCT_WEB_SITE "https://github.com/zebra-lucky/electrum-zcash"
!define PRODUCT_PUBLISHER "Electrum Technologies GmbH"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define BUILD_ARCH "${WINEARCH}"
;--------------------------------
;General
;Name and file
Name "${PRODUCT_NAME}"
OutFile "dist/electrum-setup.exe"
OutFile "dist/electrum-zcash-${PRODUCT_VERSION}-setup-${BUILD_ARCH}.exe"
;Default installation folder
InstallDir "$PROGRAMFILES\${PRODUCT_NAME}"
@ -72,7 +74,7 @@
!define MUI_ABORTWARNING
!define MUI_ABORTWARNING_TEXT "Are you sure you wish to abort the installation of ${PRODUCT_NAME}?"
!define MUI_ICON "tmp\electrum\icons\electrum.ico"
!define MUI_ICON "icons\electrum-zcash.ico"
;--------------------------------
;Pages
@ -99,6 +101,16 @@ Function .onInit
SetErrorLevel 740 ;ERROR_ELEVATION_REQUIRED
Quit
${EndIf}
${If} ${RunningX64}
SetRegView 64
StrCpy $INSTDIR "$PROGRAMFILES64\${PRODUCT_NAME}"
${Else}
${If} ${BUILD_ARCH} == "win64"
MessageBox MB_OK|MB_ICONSTOP "Can not Install 64-bit App On 32-bit OS!"
Abort
${EndIf}
${EndIf}
FunctionEnd
Section
@ -108,10 +120,10 @@ Section
RMDir /r "$INSTDIR\*.*"
Delete "$DESKTOP\${PRODUCT_NAME}.lnk"
Delete "$SMPROGRAMS\${PRODUCT_NAME}\*.*"
;Files to pack into the installer
File /r "dist\electrum\*.*"
File "..\..\icons\electrum.ico"
File /r "dist\electrum-zcash\*.*"
File "icons\electrum-zcash.ico"
;Store installation folder
WriteRegStr HKCU "Software\${PRODUCT_NAME}" "" $INSTDIR
@ -122,29 +134,29 @@ Section
;Create desktop shortcut
DetailPrint "Creating desktop shortcut..."
CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" ""
CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-zcash-${PRODUCT_VERSION}.exe" ""
;Create start-menu items
DetailPrint "Creating start-menu items..."
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" "" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" 0
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME} Testnet.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" "--testnet" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" 0
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-zcash-${PRODUCT_VERSION}.exe" "" "$INSTDIR\electrum-zcash-${PRODUCT_VERSION}.exe" 0
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME} Testnet.lnk" "$INSTDIR\electrum-zcash-${PRODUCT_VERSION}.exe" "--testnet" "$INSTDIR\electrum-zcash-${PRODUCT_VERSION}.exe" 0
;Links bitcoin: URI's to Electrum
WriteRegStr HKCU "Software\Classes\bitcoin" "" "URL:bitcoin Protocol"
WriteRegStr HKCU "Software\Classes\bitcoin" "URL Protocol" ""
WriteRegStr HKCU "Software\Classes\bitcoin" "DefaultIcon" "$\"$INSTDIR\electrum.ico, 0$\""
WriteRegStr HKCU "Software\Classes\bitcoin\shell\open\command" "" "$\"$INSTDIR\electrum-${PRODUCT_VERSION}.exe$\" $\"%1$\""
;Links zcash: URI's to Electrum
WriteRegStr HKCU "Software\Classes\zcash" "" "URL:zcash Protocol"
WriteRegStr HKCU "Software\Classes\zcash" "URL Protocol" ""
WriteRegStr HKCU "Software\Classes\zcash" "DefaultIcon" "$\"$INSTDIR\electrum-zcash.ico, 0$\""
WriteRegStr HKCU "Software\Classes\zcash\shell\open\command" "" "$\"$INSTDIR\electrum-zcash-${PRODUCT_VERSION}.exe$\" $\"%1$\""
;Adds an uninstaller possibilty to Windows Uninstall or change a program section
;Adds an uninstaller possibility to Windows Uninstall or change a program section
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\electrum.ico"
WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\electrum-zcash.ico"
;Fixes Windows broken size estimates
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
@ -167,7 +179,7 @@ Section "Uninstall"
Delete "$SMPROGRAMS\${PRODUCT_NAME}\*.*"
RMDir "$SMPROGRAMS\${PRODUCT_NAME}"
DeleteRegKey HKCU "Software\Classes\bitcoin"
DeleteRegKey HKCU "Software\Classes\zcash"
DeleteRegKey HKCU "Software\${PRODUCT_NAME}"
DeleteRegKey HKCU "${PRODUCT_UNINST_KEY}"
SectionEnd

158
contrib/zcash/osx.spec Normal file
View File

@ -0,0 +1,158 @@
# -*- mode: python -*-
import os
import os.path
import sys
from PyInstaller.utils.hooks import collect_data_files, collect_submodules
for i, x in enumerate(sys.argv):
if x == '--name':
cmdline_name = sys.argv[i+1]
break
else:
raise Exception('no name')
PY36BINDIR = os.environ.get('PY36BINDIR')
hiddenimports = collect_submodules('trezorlib')
hiddenimports += collect_submodules('btchip')
hiddenimports += collect_submodules('keepkeylib')
hiddenimports += collect_submodules('websocket')
hiddenimports += [
'lib',
'lib.base_wizard',
'lib.plot',
'lib.qrscanner',
'lib.websockets',
'gui.qt',
'plugins',
'plugins.hw_wallet.qt',
'plugins.audio_modem.qt',
'plugins.cosigner_pool.qt',
'plugins.digitalbitbox.qt',
'plugins.email_requests.qt',
'plugins.keepkey.qt',
'plugins.labels.qt',
'plugins.trezor.qt',
'plugins.ledger.qt',
'plugins.virtualkeyboard.qt',
]
datas = [
('lib/servers.json', 'electrum_zcash'),
('lib/servers_testnet.json', 'electrum_zcash'),
('lib/servers_regtest.json', 'electrum_zcash'),
('lib/currencies.json', 'electrum_zcash'),
('lib/checkpoints.json', 'electrum_zcash'),
('lib/locale', 'electrum_zcash/locale'),
('lib/wordlist', 'electrum_zcash/wordlist'),
]
datas += collect_data_files('trezorlib')
datas += collect_data_files('btchip')
datas += collect_data_files('keepkeylib')
binaries = [('../libusb-1.0.dylib', '.')]
# https://github.com/pyinstaller/pyinstaller/wiki/Recipe-remove-tkinter-tcl
sys.modules['FixTk'] = None
excludes = ['FixTk', 'tcl', 'tk', '_tkinter', 'tkinter', 'Tkinter']
excludes += [
'PyQt5.QtCLucene',
'PyQt5.Qt5CLucene',
'PyQt5.QtDesigner',
'PyQt5.QtDesignerComponents',
'PyQt5.QtHelp',
'PyQt5.QtLocation',
'PyQt5.QtMultimedia',
'PyQt5.QtMultimediaQuick_p',
'PyQt5.QtMultimediaWidgets',
'PyQt5.QtNetwork',
'PyQt5.QtOpenGL',
'PyQt5.QtPositioning',
'PyQt5.QtPrintSupport',
'PyQt5.QtQml',
'PyQt5.QtQuick',
'PyQt5.QtQuickParticles',
'PyQt5.QtQuickWidgets',
'PyQt5.QtSensors',
'PyQt5.QtSerialPort',
'PyQt5.QtSql',
'PyQt5.Qt5Sql',
'PyQt5.QtTest',
'PyQt5.QtWebChannel',
'PyQt5.QtWebKit',
'PyQt5.QtWebKitWidgets',
'PyQt5.QtWebSockets',
'PyQt5.QtXml',
'PyQt5.QtXmlPatterns',
'PyQt5.QtWebProcess',
'PyQt5.QtWinExtras',
]
a = Analysis(['electrum-zcash'],
pathex=['plugins'],
hiddenimports=hiddenimports,
datas=datas,
binaries=binaries,
excludes=excludes,
runtime_hooks=['pyi_runtimehook.py'])
# http://stackoverflow.com/questions/19055089/
for d in a.datas:
if 'pyconfig' in d[0]:
a.datas.remove(d)
break
# Add TOC to electrum_zcash, electrum_zcash_gui, electrum_zcash_plugins
for p in sorted(a.pure):
if p[0].startswith('lib') and p[2] == 'PYMODULE':
a.pure += [('electrum_zcash%s' % p[0][3:] , p[1], p[2])]
if p[0].startswith('gui') and p[2] == 'PYMODULE':
a.pure += [('electrum_zcash_gui%s' % p[0][3:] , p[1], p[2])]
if p[0].startswith('plugins') and p[2] == 'PYMODULE':
a.pure += [('electrum_zcash_plugins%s' % p[0][7:] , p[1], p[2])]
pyz = PYZ(a.pure)
exe = EXE(pyz,
a.scripts,
exclude_binaries=True,
debug=False,
strip=False,
upx=False,
console=False,
icon='icons/electrum-zcash.ico',
name=os.path.join('build/electrum-zcash/electrum-zcash', cmdline_name))
# trezorctl separate bin
tctl_a = Analysis([os.path.join(PY36BINDIR, 'trezorctl')],
hiddenimports=['pkgutil'],
excludes=excludes,
runtime_hooks=['pyi_tctl_runtimehook.py'])
tctl_pyz = PYZ(tctl_a.pure)
tctl_exe = EXE(tctl_pyz,
tctl_a.scripts,
exclude_binaries=True,
debug=False,
strip=False,
upx=False,
console=True,
name=os.path.join('build/electrum-zcash/electrum-zcash', 'trezorctl.bin'))
coll = COLLECT(exe, tctl_exe,
a.binaries,
a.datas,
strip=False,
upx=False,
name=os.path.join('dist', 'electrum-zcash'))
app = BUNDLE(coll,
name=os.path.join('dist', 'Electrum-Zcash.app'),
appname="Electrum-Zcash",
icon='electrum-zcash.icns',
version = 'ELECTRUM_VERSION')

View File

@ -0,0 +1,88 @@
# -*- coding: utf-8 -*-
"""PyInstaller runtime hook"""
import imp
import sys
import pkgutil
_old_find_module = imp.find_module
def _new_find_module(name, *args, **kwargs):
if name in ['lib', 'gui', 'plugins']:
return (None, name, ('', '', 5))
else:
return _old_find_module(name, *args, **kwargs)
imp.find_module = _new_find_module
_old_load_module = imp.load_module
def _new_load_module(name, file, pathname, description):
if pathname in ['lib', 'gui', 'plugins']:
return __import__(name)
else:
return _old_load_module(name, file, pathname, description)
imp.load_module = _new_load_module
PLUGINS_PREFIX = 'electrum_zcash_plugins'
KEYSTORE_PLUGINS = [
'hw_wallet',
'digitalbitbox',
'keepkey',
'ledger',
'trezor',
]
OTHER_PLUGINS= [
'audio_modem',
'cosigner_pool',
'email_requests',
'labels',
'virtualkeyboard',
]
OTHER_PLUGINS = list(map(lambda p: '%s.%s' % (PLUGINS_PREFIX, p), OTHER_PLUGINS))
PLUGINS = KEYSTORE_PLUGINS + OTHER_PLUGINS
class PluginsImporter(object):
def find_module(self, name):
return self
def load_module(self, name):
if name in KEYSTORE_PLUGINS:
return getattr(__import__('%s.%s' % (PLUGINS_PREFIX, name)), name)
elif name in OTHER_PLUGINS:
return getattr(__import__(name), name.split('.')[-1])
elif name.endswith('.qt'):
split = name.split('.')
if split[0] != split[1]:
plugin_module = getattr(__import__(name), split[-2])
return getattr(plugin_module, 'qt')
else:
path = '.'.join(split[1:])
plugin_module = getattr(__import__(path), split[-2])
return getattr(plugin_module, 'qt')
else:
raise Exception('Can not import %s' % name)
_old_find_loader = pkgutil.find_loader
def _new_find_loader(fullname):
if fullname.startswith('%s.' % PLUGINS_PREFIX):
return PluginsImporter()
else:
return _old_find_loader(fullname)
pkgutil.find_loader = _new_find_loader
_old_iter_modules = pkgutil.iter_modules
def _new_iter_modules(path=None, prefix=''):
if path and len(path) == 1 and path[0].endswith(PLUGINS_PREFIX):
for p in PLUGINS:
yield PluginsImporter(), p, True
else:
for loader, name, ispkg in _old_iter_modules(path, prefix):
yield loader, name, ispkg
pkgutil.iter_modules = _new_iter_modules

View File

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
"""PyInstaller runtime hook for trezorctl"""
from sys import exit

View File

@ -12,3 +12,4 @@ qrcode==5.3
requests==2.18.4
six==1.11.0
urllib3==1.22
x11_hash==1.4

View File

@ -0,0 +1,119 @@
FROM ubuntu:16.04
LABEL maintainer "Andriy Khavryuchenko <akhavr@khavr.com>"
RUN dpkg --add-architecture i386 \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
language-pack-en build-essential ccache git \
libncurses5:i386 libstdc++6:i386 libgtk2.0-0:i386 \
libpangox-1.0-0:i386 libpangoxft-1.0-0:i386 libidn11:i386 \
openjdk-8-jdk unzip zlib1g-dev zlib1g:i386 \
python3-dev python3-kivy \
wget vim less autoconf automake libtool \
ffmpeg \
libsdl2-dev \
libsdl2-image-dev \
libsdl2-mixer-dev \
libsdl2-ttf-dev \
libportmidi-dev \
libswscale-dev \
libavformat-dev \
libavcodec-dev \
&& rm -rf /var/lib/apt/lists/*
RUN wget https://bootstrap.pypa.io/get-pip.py && python3 get-pip.py \
&& pip3 install --upgrade setuptools cython==0.21.2 Pillow
RUN git config --global user.email "buildozer@example.com" \
&& git config --global user.name "Buildozer"
RUN adduser --disabled-password --gecos '' buildozer && mkdir /home/buildozer/build
RUN cd /opt \
&& git clone https://github.com/kivy/python-for-android \
&& cd python-for-android \
&& git remote add agilewalker https://github.com/agilewalker/python-for-android \
&& git fetch --all \
&& git checkout 93759f36ba45c7bbe0456a4b3e6788622924cbac \
&& git merge -m 'merge1' a2fb5ecbc09c4847adbcfd03c6b1ca62b3d09b8d \
&& cd /opt \
&& git clone https://github.com/kivy/buildozer \
&& cd buildozer \
&& python3 setup.py install \
&& chown -R buildozer.buildozer /opt
RUN cd /opt \
&& wget http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.11-bin.tar.gz \
&& tar xzf apache-ant-1.9.11-bin.tar.gz \
&& rm apache-ant-1.9.11-bin.tar.gz \
&& chown -R buildozer.buildozer /opt
RUN cd /opt \
&& wget https://www.crystax.net/download/crystax-ndk-10.3.2-linux-x86_64.tar.xz \
&& tar xJf crystax-ndk-10.3.2-linux-x86_64.tar.xz \
&& rm crystax-ndk-10.3.2-linux-x86_64.tar.xz \
&& rm -rf \
crystax-ndk-10.3.2/platforms/android-*/arch-mips* \
crystax-ndk-10.3.2/platforms/android-*/arch-x86* \
crystax-ndk-10.3.2/sources/boost/1.59.0/libs/mips* \
crystax-ndk-10.3.2/sources/crystax/src/math/mips* \
crystax-ndk-10.3.2/sources/crystax/src/include/crystax/mips* \
crystax-ndk-10.3.2/sources/crystax/libs/mips* \
crystax-ndk-10.3.2/sources/crystax/include/crystax/mips* \
crystax-ndk-10.3.2/sources/libjpeg-turbo/1.4.2/libs/mips* \
crystax-ndk-10.3.2/sources/python/2.7/libs/mips* \
crystax-ndk-10.3.2/sources/python/3.5/libs/mips* \
crystax-ndk-10.3.2/sources/icu/56.1/libs/mips* \
crystax-ndk-10.3.2/sources/libjpeg/9a/libs/mips* \
crystax-ndk-10.3.2/sources/objc/gnustep-libobjc2/libs/mips* \
crystax-ndk-10.3.2/sources/objc/cocotron/0.1.0/frameworks/mips* \
crystax-ndk-10.3.2/sources/sqlite/3/libs/mips* \
crystax-ndk-10.3.2/sources/android/compiler-rt/libs/mips* \
crystax-ndk-10.3.2/sources/android/gccunwind/libs/mips* \
crystax-ndk-10.3.2/sources/libtiff/4.0.6/libs/mips* \
crystax-ndk-10.3.2/sources/libpng/1.6.19/libs/mips* \
crystax-ndk-10.3.2/sources/boost/1.59.0/libs/x86* \
crystax-ndk-10.3.2/sources/crystax/src/math/x86* \
crystax-ndk-10.3.2/sources/crystax/src/include/crystax/x86* \
crystax-ndk-10.3.2/sources/crystax/libs/x86* \
crystax-ndk-10.3.2/sources/crystax/include/crystax/x86* \
crystax-ndk-10.3.2/sources/libjpeg-turbo/1.4.2/libs/x86* \
crystax-ndk-10.3.2/sources/python/2.7/libs/x86* \
crystax-ndk-10.3.2/sources/python/3.5/libs/x86* \
crystax-ndk-10.3.2/sources/icu/56.1/libs/x86* \
crystax-ndk-10.3.2/sources/libjpeg/9a/libs/x86* \
crystax-ndk-10.3.2/sources/objc/gnustep-libobjc2/libs/x86* \
crystax-ndk-10.3.2/sources/objc/cocotron/0.1.0/frameworks/x86* \
crystax-ndk-10.3.2/sources/sqlite/3/libs/x86* \
crystax-ndk-10.3.2/sources/android/compiler-rt/libs/x86* \
crystax-ndk-10.3.2/sources/android/gccunwind/libs/x86* \
crystax-ndk-10.3.2/sources/libtiff/4.0.6/libs/x86* \
crystax-ndk-10.3.2/sources/libpng/1.6.19/libs/x86* \
crystax-ndk-10.3.2/sources/cxx-stl/llvm-libc++/3.6/libs/x86* \
crystax-ndk-10.3.2/sources/cxx-stl/llvm-libc++/3.6/libs/mips* \
crystax-ndk-10.3.2/sources/cxx-stl/llvm-libc++/3.7/libs/x86* \
crystax-ndk-10.3.2/sources/cxx-stl/llvm-libc++/3.7/libs/mips* \
crystax-ndk-10.3.2/sources/cxx-stl/gnu-libstdc++/4.9/libs/x86* \
crystax-ndk-10.3.2/sources/cxx-stl/gnu-libstdc++/4.9/libs/mips* \
crystax-ndk-10.3.2/sources/cxx-stl/gnu-libstdc++/5/libs/x86* \
crystax-ndk-10.3.2/sources/cxx-stl/gnu-libstdc++/5/libs/mips* \
&& chown -R buildozer.buildozer /opt/crystax-ndk-10.3.2
RUN cd /opt \
&& wget http://dl.google.com/android/android-sdk_r24-linux.tgz \
&& tar xzf android-sdk_r24-linux.tgz \
&& rm android-sdk_r24-linux.tgz \
&& (while sleep 3; do echo "y"; done) \
| android-sdk-linux/tools/android update sdk -u -a -t \
'tools, platform-tools-preview, build-tools-23.0.1' \
&& (while sleep 3; do echo "y"; done) \
| android-sdk-linux/tools/android update sdk -u -a -t \
'tools, platform-tools, build-tools-27.0.3' \
&& (while sleep 3; do echo "y"; done) \
| android-sdk-linux/tools/android update sdk -u -a -t \
'android-19,extra-android-m2repository' \
&& chown -R buildozer.buildozer /opt/android-sdk-linux
USER buildozer
WORKDIR /home/buildozer/build

View File

@ -0,0 +1,7 @@
FROM debian:stretch-slim
LABEL maintainer "Andriy Khavryuchenko <akhavr@khavr.com>"
RUN apt-get update -y \
&& apt-get install -y python3-pip pyqt5-dev-tools \
gettext python3-pycurl python3-requests \
&& rm -rf /var/lib/apt/lists/*

View File

@ -0,0 +1,87 @@
FROM debian:stretch-slim
LABEL maintainer "Andriy Khavryuchenko <akhavr@khavr.com>"
USER root
WORKDIR /root
RUN dpkg --add-architecture i386 \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
wine-development wine32-development wine64-development libwine-development libwine-development:i386 \
cabextract xauth xvfb wget ca-certificates zip unzip p7zip-full \
&& wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks \
&& chmod +x winetricks && mv winetricks /usr/local/bin \
&& rm -rf /var/lib/apt/lists/*
ENV WINEPATH c:/git/cmd
ENV WINEDEBUG -all
ENV WINEPREFIX /root/.wine-32
ENV WINEARCH win32
ENV PYHOME $WINEPREFIX/drive_c/Python34
RUN echo 'download and install 32-bit Python/mingwpy/pywin32/PyQt/git/NSIS/PyInstaller' \
&& wineboot -i \
&& xvfb-run -a winetricks -q vcrun2010 \
\
&& wget -nv -O python.msi https://www.python.org/ftp/python/3.4.4/python-3.4.4.msi \
&& msiexec /q /i python.msi && rm python.msi \
\
&& wget -nv -O libusb.7z https://prdownloads.sourceforge.net/project/libusb/libusb-1.0/libusb-1.0.22/libusb-1.0.22.7z?download \
&& 7z x -olibusb libusb.7z -aos && rm libusb.7z \
&& cp libusb/MS32/dll/libusb-1.0.dll $PYHOME/ \
\
&& wine pip install -i https://pypi.anaconda.org/carlkl/simple mingwpy \
&& /bin/echo -e '[build]\ncompiler=mingw32\n' > $PYHOME/Lib/distutils/distutils.cfg \
\
&& wget -nv -O pywin32.exe https://github.com/mhammond/pywin32/releases/download/b221/pywin32-221.win32-py3.4.exe \
&& unzip -qq -d pywin32 pywin32.exe; echo && rm pywin32.exe \
&& cp -r pywin32/PLATLIB/* $PYHOME/Lib/site-packages/ \
&& cp -r pywin32/SCRIPTS/* $PYHOME/Scripts/ && rm -rf pywin32 \
&& wine python $PYHOME/Scripts/pywin32_postinstall.py -install \
\
&& wget -nv -O PyQt.exe "https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-5.5.1/PyQt5-5.5.1-gpl-Py3.4-Qt5.5.1-x32.exe/download" \
&& wine PyQt.exe /S && rm PyQt.exe \
\
&& wget -nv -O git.zip https://github.com/git-for-windows/git/releases/download/v2.16.3.windows.1/MinGit-2.16.3-32-bit.zip \
&& unzip -qq -d git git.zip && rm git.zip && mv git $WINEPREFIX/drive_c/ \
\
&& wget -nv -O nsis.exe "https://sourceforge.net/projects/nsis/files/NSIS%202/2.51/nsis-2.51-setup.exe/download" \
&& wine nsis.exe /S && rm nsis.exe \
\
&& wine pip install PyInstaller==3.2.1 \
&& rm -rf /tmp/.wine-0
ENV WINEPREFIX /root/.wine-64
ENV WINEARCH win64
ENV PYHOME $WINEPREFIX/drive_c/Python34
RUN echo 'download and install 64-bit Python/mingwpy/pywin32/PyQt/git/NSIS/PyInstaller' \
&& wineboot -i \
&& xvfb-run -a winetricks -q vcrun2010 \
\
&& wget -nv -O python.msi https://www.python.org/ftp/python/3.4.4/python-3.4.4.amd64.msi \
&& msiexec /q /i python.msi && rm python.msi \
\
&& cp libusb/MS64/dll/libusb-1.0.dll $PYHOME/ && rm -rf libusb \
\
&& wine pip install -i https://pypi.anaconda.org/carlkl/simple mingwpy \
&& /bin/echo -e '[build]\ncompiler=mingw32\n' > $PYHOME/Lib/distutils/distutils.cfg \
\
&& wget -nv -O pywin32.exe https://github.com/mhammond/pywin32/releases/download/b221/pywin32-221.win-amd64-py3.4.exe \
&& unzip -qq -d pywin32 pywin32.exe; echo && rm pywin32.exe \
&& cp -r pywin32/PLATLIB/* $PYHOME/Lib/site-packages/ \
&& cp -r pywin32/SCRIPTS/* $PYHOME/Scripts/ && rm -rf pywin32 \
&& wine python $PYHOME/Scripts/pywin32_postinstall.py -install \
\
&& wget -nv -O PyQt.exe "https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-5.5.1/PyQt5-5.5.1-gpl-Py3.4-Qt5.5.1-x64.exe/download" \
&& wine PyQt.exe /S && rm PyQt.exe \
\
&& wget -nv -O git.zip https://github.com/git-for-windows/git/releases/download/v2.16.3.windows.1/MinGit-2.16.3-64-bit.zip \
&& unzip -qq -d git git.zip && rm git.zip && mv git $WINEPREFIX/drive_c/ \
\
&& wget -nv -O nsis.exe "https://sourceforge.net/projects/nsis/files/NSIS%202/2.51/nsis-2.51-setup.exe/download" \
&& wine nsis.exe /S && rm nsis.exe \
\
&& wine pip install PyInstaller==3.2.1 \
&& rm -rf /tmp/.wine-0

View File

@ -0,0 +1,10 @@
#!/bin/bash
set -ev
if [[ -z $TRAVIS_TAG ]]; then
echo TRAVIS_TAG unset, exiting
exit 1
fi
docker pull zebralucky/electrum-dash-winebuild:Linux
docker pull zebralucky/electrum-dash-winebuild:Kivy

View File

@ -0,0 +1,10 @@
#!/bin/bash
set -ev
if [[ -z $TRAVIS_TAG ]]; then
echo TRAVIS_TAG unset, exiting
exit 1
fi
docker pull zebralucky/electrum-dash-winebuild:Linux
docker pull zebralucky/electrum-dash-winebuild:Wine

View File

@ -0,0 +1,27 @@
#!/bin/bash
set -ev
if [[ -z $TRAVIS_TAG ]]; then
echo TRAVIS_TAG unset, exiting
exit 1
fi
cd build
brew update
brew install zebra-lucky/qt5/qt5
brew install gettext
curl -O https://www.python.org/ftp/python/3.6.5/python-3.6.5-macosx10.6.pkg
curl -O https://bootstrap.pypa.io/get-pip.py
sudo installer -pkg python-3.6.5-macosx10.6.pkg -target /
sudo python3 get-pip.py
mkdir libusb
curl https://homebrew.bintray.com/bottles/libusb-1.0.22.el_capitan.bottle.tar.gz | tar xz --directory libusb
cp libusb/libusb/1.0.22/lib/libusb-1.0.dylib .
sudo pip3 install SIP==4.19.8
sudo pip3 install PyQt5==5.7.1
sudo pip3 install Cython==0.28.1
sudo pip3 install PyInstaller==3.3.1

View File

@ -0,0 +1,7 @@
#!/bin/sh
pyrcc5 icons.qrc -o gui/qt/icons_rc.py
./contrib/make_locale
./contrib/make_packages
mv contrib/packages .
python3 setup.py sdist --format=zip,gztar

View File

@ -0,0 +1,49 @@
#!/bin/bash
source ./contrib/zcash/travis/electrum_zcash_version_env.sh;
echo wine build version is $ELECTRUM_ZCASH_VERSION
mv /opt/zbarw $WINEPREFIX/drive_c/
cd $WINEPREFIX/drive_c/electrum-zcash
rm -rf build
rm -rf dist/electrum-zcash
cp contrib/zcash/deterministic.spec .
cp contrib/zcash/pyi_runtimehook.py .
cp contrib/zcash/pyi_tctl_runtimehook.py .
wine pip install --upgrade pip
export PYINSTALLER_TAG=dev180610
wget https://github.com/zebra-lucky/pyinstaller/archive/$PYINSTALLER_TAG.tar.gz
wine pip install $PYINSTALLER_TAG.tar.gz
rm $PYINSTALLER_TAG.tar.gz
wine pip install eth-hash==0.1.2
wine pip install -r contrib/zcash/requirements.txt
wine pip install x11_hash
wine pip install cython
wine pip install hidapi
wine pip install pycryptodomex==3.6.0
wine pip install btchip-python==0.1.26
wine pip install keepkey==4.0.2
wine pip install trezor==0.9.1
mkdir $WINEPREFIX/drive_c/Qt
ln -s $PYHOME/Lib/site-packages/PyQt5/ $WINEPREFIX/drive_c/Qt/5.5.1
wine pyinstaller -y \
--name electrum-zcash-$ELECTRUM_ZCASH_VERSION.exe \
deterministic.spec
if [[ $WINEARCH == win32 ]]; then
NSIS_EXE="$WINEPREFIX/drive_c/Program Files/NSIS/makensis.exe"
else
NSIS_EXE="$WINEPREFIX/drive_c/Program Files (x86)/NSIS/makensis.exe"
fi
wine "$NSIS_EXE" /NOCD -V3 \
/DPRODUCT_VERSION=$ELECTRUM_ZCASH_VERSION \
/DWINEARCH=$WINEARCH \
contrib/zcash/electrum-zcash.nsi

View File

@ -0,0 +1,14 @@
#!/bin/bash
VERSION_STRING=(`grep ELECTRUM_VERSION lib/version.py`)
ELECTRUM_ZCASH_VERSION=${VERSION_STRING[2]}
ELECTRUM_ZCASH_VERSION=${ELECTRUM_ZCASH_VERSION#\'}
ELECTRUM_ZCASH_VERSION=${ELECTRUM_ZCASH_VERSION%\'}
DOTS=`echo $ELECTRUM_ZCASH_VERSION | grep -o "\." | wc -l`
if [[ $DOTS -lt 3 ]]; then
ELECTRUM_ZCASH_APK_VERSION=$ELECTRUM_ZCASH_VERSION.0
else
ELECTRUM_ZCASH_APK_VERSION=$ELECTRUM_ZCASH_VERSION
fi
export ELECTRUM_ZCASH_VERSION
export ELECTRUM_ZCASH_APK_VERSION

View File

@ -0,0 +1,28 @@
#!/bin/bash
set -ev
if [[ -z $TRAVIS_TAG ]]; then
echo TRAVIS_TAG unset, exiting
exit 1
fi
BUILD_REPO_URL=https://github.com/zebra-lucky/electrum-zcash
cd build
git clone --branch $TRAVIS_TAG $BUILD_REPO_URL electrum-zcash
docker run --rm \
-v $(pwd):/opt \
-w /opt/electrum-zcash \
-t zebralucky/electrum-dash-winebuild:Linux /opt/build_linux.sh
sudo find . -name '*.po' -delete
sudo find . -name '*.pot' -delete
sudo chown -R 1000 electrum-zcash
docker run --rm \
-v $(pwd)/electrum-zcash:/home/buildozer/build \
-t zebralucky/electrum-dash-winebuild:Kivy bash -c \
'rm -rf packages && ./contrib/make_packages && ./contrib/make_apk'

View File

@ -0,0 +1,53 @@
#!/bin/bash
set -ev
if [[ -z $TRAVIS_TAG ]]; then
echo TRAVIS_TAG unset, exiting
exit 1
fi
BUILD_REPO_URL=https://github.com/zebra-lucky/electrum-zcash
cd build
git clone --branch $TRAVIS_TAG $BUILD_REPO_URL electrum-zcash
docker run --rm \
-v $(pwd):/opt \
-w /opt/electrum-zcash \
-t zebralucky/electrum-dash-winebuild:Linux /opt/build_linux.sh
sudo find . -name '*.po' -delete
sudo find . -name '*.pot' -delete
export WINEARCH=win32
export WINEPREFIX=/root/.wine-32
export PYHOME=$WINEPREFIX/drive_c/Python34
wget https://github.com/zebra-lucky/zbarw/releases/download/20180620/zbarw-zbarcam-0.10-win32.zip
unzip zbarw-zbarcam-0.10-win32.zip && rm zbarw-zbarcam-0.10-win32.zip
docker run --rm \
-e WINEARCH=$WINEARCH \
-e WINEPREFIX=$WINEPREFIX \
-e PYHOME=$PYHOME \
-v $(pwd):/opt \
-v $(pwd)/electrum-zcash/:$WINEPREFIX/drive_c/electrum-zcash \
-w /opt/electrum-zcash \
-t zebralucky/electrum-dash-winebuild:Wine /opt/build_wine.sh
export WINEARCH=win64
export WINEPREFIX=/root/.wine-64
export PYHOME=$WINEPREFIX/drive_c/Python34
wget https://github.com/zebra-lucky/zbarw/releases/download/20180620/zbarw-zbarcam-0.10-win64.zip
unzip zbarw-zbarcam-0.10-win64.zip && rm zbarw-zbarcam-0.10-win64.zip
docker run --rm \
-e WINEARCH=$WINEARCH \
-e WINEPREFIX=$WINEPREFIX \
-e PYHOME=$PYHOME \
-v $(pwd):/opt \
-v $(pwd)/electrum-zcash/:$WINEPREFIX/drive_c/electrum-zcash \
-w /opt/electrum-zcash \
-t zebralucky/electrum-dash-winebuild:Wine /opt/build_wine.sh

View File

@ -0,0 +1,49 @@
#!/bin/bash
set -ev
if [[ -z $TRAVIS_TAG ]]; then
echo TRAVIS_TAG unset, exiting
exit 1
fi
BUILD_REPO_URL=https://github.com/zebra-lucky/electrum-zcash
cd build
git clone --branch $TRAVIS_TAG $BUILD_REPO_URL electrum-zcash
cd electrum-zcash
export PY36BINDIR=/Library/Frameworks/Python.framework/Versions/3.6/bin/
export PATH=$PATH:$PY36BINDIR
source ./contrib/zcash/travis/electrum_zcash_version_env.sh;
echo wine build version is $ELECTRUM_ZCASH_VERSION
sudo pip3 install --upgrade pip
sudo pip3 install -r contrib/deterministic-build/requirements.txt
sudo pip3 install \
x11_hash>=1.4 \
pycryptodomex==3.6.0 \
btchip-python==0.1.26 \
keepkey==4.0.2 \
trezor==0.9.1
pyrcc5 icons.qrc -o gui/qt/icons_rc.py
export PATH="/usr/local/opt/gettext/bin:$PATH"
./contrib/make_locale
find . -name '*.po' -delete
find . -name '*.pot' -delete
cp contrib/zcash/osx.spec .
cp contrib/zcash/pyi_runtimehook.py .
cp contrib/zcash/pyi_tctl_runtimehook.py .
pyinstaller \
-y \
--name electrum-zcash-$ELECTRUM_ZCASH_VERSION.bin \
osx.spec
sudo hdiutil create -fs HFS+ -volname "Electrum-Zcash" \
-srcfolder dist/Electrum-Zcash.app \
dist/electrum-zcash-$ELECTRUM_ZCASH_VERSION-macosx.dmg