diff --git a/.appveyor.yml b/.appveyor.yml index 54dd0cdcd..b8131bfb7 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,13 +1,36 @@ version: 1.0.{build} +environment: + GH_TOKEN: + secure: LiI5jyuHUw6XbH4kC3gP1HX4P/v4rwD/gCNtaFhQu2AvJz1/1wALkp5ECnIxRyS +# key_pass: +# secure: u6DydPcdrUJlxGL9uc7yQRYG8+5rY6aAEE9nfCSzFyNzZlX9NniOp8Uh5ZKQqX7bGEngLI6ipbLfiJvn0XFnhbn2iTkOuMqOXVJVOehvwlQ= +# pfx_key: +# secure: 1mwqyRy7hDqDjDK+TIAoaXyXzpNgwruFNA6TPkinUcVM7A+NLD33RQLnfnwVy+R5ovD2pUfhQ6+N0Fqebv6tZh436LIEsock+6IOdpgFwrg= -notifications: - - provider: Slack - incoming_webhook: - secure: LuxwG5OZnnA//gmSXzCKu8/FRqYjCgGfVFqajSsGHeQ1HQNp7rYNhQpsO8/3PK63xKJj3wzt86DJekf9q9Q5OcHa9AHXUQbEveX0psd7elw= +# +#notifications: +# - provider: Slack +# incoming_webhook: +# secure: LuxwG5OZnnA//gmSXzCKu8/FRqYjCgGfVFqajSsGHeQ1HQNp7rYNhQpsO8/3PK63xKJj3wzt86DJekf9q9Q5OcHa9AHXUQbEveX0psd7elw= clone_folder: c:\projects\lbry +test_script: +- cd C:\projects\lbry\ +- pip install cython +- pip install mock pylint unqlite +- pylint lbrynet +- python -m twisted.trial tests # avoids having to set PYTHONPATH=. (see https://twistedmatrix.com/trac/ticket/9035) +#- rvm use 2.3.1 && gem install danger --version '~> 4.0' && danger + + build_script: - - echo "Not currently building on appveyor" +- cd C:\projects\lbry\build\ +- ps: .\build.ps1 + + +artifacts: +- path: build\dist\*.zip + name: lbrynet-daemon diff --git a/.gitignore b/.gitignore index 74027cd71..e3d0a36f1 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,10 @@ *.prof .#* -/build -/dist +/build/build +/build/dist +/bulid/requirements_base.txt + /lbrynet.egg-info /docs_build /lbry-venv diff --git a/.pylintrc b/.pylintrc index 9af4993e0..fed2983f9 100644 --- a/.pylintrc +++ b/.pylintrc @@ -65,7 +65,60 @@ confidence= # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" -disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating +disable= + anomalous-backslash-in-string, + arguments-differ, + attribute-defined-outside-init, + bad-continuation, + bare-except, + broad-except, + cell-var-from-loop, + consider-iterating-dictionary, + cyclic-import, + dangerous-default-value, + duplicate-code, + exec-used, + fixme, + global-statement, + inherit-non-class, + invalid-name, + locally-disabled, + logging-not-lazy, + missing-docstring, + multiple-imports, + no-init, + no-member, + no-self-use, + pointless-string-statement, + protected-access, + redefined-builtin, + redefined-outer-name, + redefined-variable-type, + relative-import, + signature-differs, + singleton-comparison, + super-init-not-called, + too-few-public-methods, + too-many-arguments, + too-many-branches, + too-many-instance-attributes, + too-many-lines, + too-many-locals, + too-many-nested-blocks, + too-many-public-methods, + too-many-return-statements, + too-many-statements, + trailing-newlines, + undefined-loop-variable, + ungrouped-imports, + unidiomatic-typecheck, + unnecessary-lambda, + unused-argument, + unused-variable, + useless-else-on-loop, + wildcard-import, + wrong-import-order, + wrong-import-position [REPORTS] @@ -294,7 +347,8 @@ ignore-mixin-members=yes # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis. It # supports qualified module names, as well as Unix pattern matching. -ignored-modules=twisted.internet.reactor,leveldb +ignored-modules=twisted.internet.reactor,leveldb,distutils +# Ignoring distutils because: https://github.com/PyCQA/pylint/issues/73 # List of classes names for which member attributes should not be checked # (useful for classes with attributes dynamically set). This supports can work diff --git a/.travis.yml b/.travis.yml index 8dd7d86ef..b788bcd03 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,12 +33,11 @@ before_install: install: - pip install -U pip - pip install -r requirements.txt - - pip install git+https://github.com/lbryio/lbryum.git - pip install . script: - pip install cython - pip install mock pylint unqlite - - ./run_pylint.sh - - ./run_tests.sh + - pylint lbrynet + - PYTHONPATH=. trial tests - rvm use 2.3.1 && gem install danger --version '~> 4.0' && danger diff --git a/build/build.ps1 b/build/build.ps1 new file mode 100644 index 000000000..8ea59e29d --- /dev/null +++ b/build/build.ps1 @@ -0,0 +1,30 @@ +$env:Path += ";C:\MinGW\bin\" + +$env:Path += ";C:\Program Files (x86)\Windows Kits\10\bin\x86\" +gcc --version +mingw32-make --version + +# build/install miniupnpc manually +tar zxf miniupnpc-1.9.tar.gz +cd miniupnpc-1.9 +mingw32-make -f Makefile.mingw +python setupmingw32.py build --compiler=mingw32 +python setupmingw32.py install +cd ..\ +Remove-Item -Recurse -Force miniupnpc-1.9 + +# copy requirements from lbry, but remove gmpy and miniupnpc (installed manually) +Get-Content ..\requirements.txt | Select-String -Pattern 'gmpy|miniupnpc' -NotMatch | Out-File requirements_base.txt +# add in gmpy wheel +Add-Content requirements.txt "./gmpy-1.17-cp27-none-win32.whl" + +pip install -r requirements.txt + +python set_version.py +python set_build.py + +pyinstaller -y daemon.onefile.spec +pyinstaller -y cli.onefile.spec + +python zip_daemon.py +python release_on_tag.py \ No newline at end of file diff --git a/build/build.sh b/build/build.sh new file mode 100755 index 000000000..75247ae4d --- /dev/null +++ b/build/build.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +set -euo pipefail +set -x + +ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" +cd "$ROOT" +BUILD_DIR="$ROOT/build" + +FULL_BUILD="${FULL_BUILD:-false}" +if [ -n "${TEAMCITY_VERSION:-}" -o -n "${APPVEYOR:-}" ]; then + FULL_BUILD="true" +fi + +[ -d "$BUILD_DIR/bulid" ] && rm -rf "$BUILD_DIR/build" +[ -d "$BUILD_DIR/dist" ] && rm -rf "$BUILD_DIR/dist" + +if [ "$FULL_BUILD" == "true" ]; then + # install dependencies + $BUILD_DIR/prebuild.sh + + VENV="$BUILD_DIR/venv" + if [ -d "$VENV" ]; then + rm -rf "$VENV" + fi + virtualenv "$VENV" + set +u + source "$VENV/bin/activate" + set -u +fi + + +cp "$ROOT/requirements.txt" "$BUILD_DIR/requirements_base.txt" +( + cd "$BUILD_DIR" + pip install -r requirements.txt +) + +if [ "$FULL_BUILD" == "true" ]; then + python "$BUILD_DIR/set_version.py" + python "$BUILD_DIR/set_build.py" +fi + +( + cd "$BUILD_DIR" + pyinstaller -y daemon.onefile.spec + pyinstaller -y cli.onefile.spec +) + +python "$BUILD_DIR/zip_daemon.py" + +if [ "$FULL_BUILD" == "true" ]; then + # electron-build has a publish feature, but I had a hard time getting + # it to reliably work and it also seemed difficult to configure. Not proud of + # this, but it seemed better to write my own. + python "$BUILD_DIR/release_on_tag.py" + + deactivate +fi + +echo 'Build complete.' diff --git a/build/cli.onefile.spec b/build/cli.onefile.spec new file mode 100644 index 000000000..43ada14b7 --- /dev/null +++ b/build/cli.onefile.spec @@ -0,0 +1,59 @@ +# -*- mode: python -*- +import platform +import os + + +dir = 'build'; +cwd = os.getcwd() +if os.path.basename(cwd) != dir: + raise Exception('pyinstaller build needs to be run from the ' + dir + ' directory') +repo_base = os.path.abspath(os.path.join(cwd, '..')) + + +system = platform.system() +if system == 'Darwin': + icns = os.path.join(repo_base, 'build', 'icon.icns') +elif system == 'Linux': + icns = os.path.join(repo_base, 'build', 'icons', '256x256.png') +elif system == 'Windows': + icns = os.path.join(repo_base, 'build', 'icons', 'lbry256.ico') +else: + print 'Warning: System {} has no icons'.format(system) + icns = None + +block_cipher = None + + +a = Analysis( + ['cli.py'], + pathex=[cwd], + binaries=None, + datas=[], + hiddenimports=[], + hookspath=[], + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher +) + +pyz = PYZ( + a.pure, + a.zipped_data, + cipher=block_cipher +) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + name='lbrynet-cli', + debug=False, + strip=False, + upx=True, + console=True, + icon=icns +) diff --git a/build/cli.py b/build/cli.py new file mode 100644 index 000000000..075c13b7f --- /dev/null +++ b/build/cli.py @@ -0,0 +1,7 @@ +from lbrynet.lbrynet_daemon import DaemonCLI +import logging + +logging.basicConfig() + +if __name__ == '__main__': + DaemonCLI.main() diff --git a/build/daemon.onefile.spec b/build/daemon.onefile.spec new file mode 100644 index 000000000..80e9e7226 --- /dev/null +++ b/build/daemon.onefile.spec @@ -0,0 +1,78 @@ +# -*- mode: python -*- +import platform +import os + +import lbryum + + +dir = 'build'; +cwd = os.getcwd() +if os.path.basename(cwd) != dir: + raise Exception('pyinstaller build needs to be run from the ' + dir + ' directory') +repo_base = os.path.abspath(os.path.join(cwd, '..')) + + +system = platform.system() +if system == 'Darwin': + icns = os.path.join(repo_base, 'build', 'icon.icns') +elif system == 'Linux': + icns = os.path.join(repo_base, 'build', 'icons', '256x256.png') +elif system == 'Windows': + icns = os.path.join(repo_base, 'build', 'icons', 'lbry256.ico') +else: + print 'Warning: System {} has no icons'.format(system) + icns = None + + +block_cipher = None + + +languages = ( + 'chinese_simplified.txt', 'japanese.txt', 'spanish.txt', + 'english.txt', 'portuguese.txt' +) + + +datas = [ + ( + os.path.join(os.path.dirname(lbryum.__file__), 'wordlist', language), + 'lbryum/wordlist' + ) + for language in languages +] + + +a = Analysis( + ['daemon.py'], + pathex=[cwd], + binaries=None, + datas=datas, + hiddenimports=[], + hookspath=[], + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher +) + + +pyz = PYZ( + a.pure, a.zipped_data, + cipher=block_cipher +) + + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + name='lbrynet-daemon', + debug=False, + strip=False, + upx=True, + console=True, + icon=icns +) diff --git a/build/daemon.py b/build/daemon.py new file mode 100644 index 000000000..2ed0360ab --- /dev/null +++ b/build/daemon.py @@ -0,0 +1,4 @@ +from lbrynet.lbrynet_daemon import DaemonControl + +if __name__ == '__main__': + DaemonControl.start() diff --git a/packaging/windows/libs/gmpy-1.17-cp27-none-win32.whl b/build/gmpy-1.17-cp27-none-win32.whl similarity index 100% rename from packaging/windows/libs/gmpy-1.17-cp27-none-win32.whl rename to build/gmpy-1.17-cp27-none-win32.whl diff --git a/build/icons/128x128.png b/build/icons/128x128.png new file mode 100644 index 000000000..de083fcbc Binary files /dev/null and b/build/icons/128x128.png differ diff --git a/build/icons/256x256.png b/build/icons/256x256.png new file mode 100644 index 000000000..659957406 Binary files /dev/null and b/build/icons/256x256.png differ diff --git a/build/icons/32x32.png b/build/icons/32x32.png new file mode 100644 index 000000000..ece10998c Binary files /dev/null and b/build/icons/32x32.png differ diff --git a/build/icons/48x48.png b/build/icons/48x48.png new file mode 100644 index 000000000..bba3a8e9d Binary files /dev/null and b/build/icons/48x48.png differ diff --git a/build/icons/96x96.png b/build/icons/96x96.png new file mode 100644 index 000000000..195c31ea7 Binary files /dev/null and b/build/icons/96x96.png differ diff --git a/build/icons/lbry128.ico b/build/icons/lbry128.ico new file mode 100644 index 000000000..3cb6f992d Binary files /dev/null and b/build/icons/lbry128.ico differ diff --git a/build/icons/lbry16.ico b/build/icons/lbry16.ico new file mode 100644 index 000000000..40d849628 Binary files /dev/null and b/build/icons/lbry16.ico differ diff --git a/build/icons/lbry256.ico b/build/icons/lbry256.ico new file mode 100644 index 000000000..f8a33ff7c Binary files /dev/null and b/build/icons/lbry256.ico differ diff --git a/build/icons/lbry32.ico b/build/icons/lbry32.ico new file mode 100644 index 000000000..6a6219b50 Binary files /dev/null and b/build/icons/lbry32.ico differ diff --git a/build/icons/lbry48.ico b/build/icons/lbry48.ico new file mode 100644 index 000000000..95c0947fa Binary files /dev/null and b/build/icons/lbry48.ico differ diff --git a/build/icons/lbry96.ico b/build/icons/lbry96.ico new file mode 100644 index 000000000..25572bc9c Binary files /dev/null and b/build/icons/lbry96.ico differ diff --git a/build/miniupnpc-1.9.tar.gz b/build/miniupnpc-1.9.tar.gz new file mode 100644 index 000000000..85deda499 Binary files /dev/null and b/build/miniupnpc-1.9.tar.gz differ diff --git a/build/prebuild.sh b/build/prebuild.sh new file mode 100755 index 000000000..3f6e7a2b3 --- /dev/null +++ b/build/prebuild.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +set -euo pipefail +set -x + + +LINUX=false +OSX=false + +if [ "$(uname)" == "Darwin" ]; then + OSX=true +elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then + LINUX=true +else + echo "Platform detection failed" + exit 1 +fi + + +SUDO='' +if $LINUX && (( $EUID != 0 )); then + SUDO='sudo' +fi + +cmd_exists() { + command -v "$1" >/dev/null 2>&1 + return $? +} + +set +eu +GITUSERNAME=$(git config --global --get user.name) +if [ -z "$GITUSERNAME" ]; then + git config --global user.name "$(whoami)" +fi +GITEMAIL=$(git config --global --get user.email) +if [ -z "$GITEMAIL" ]; then + git config --global user.email "$(whoami)@lbry.io" +fi +set -eu + + +if $LINUX; then + INSTALL="$SUDO apt-get install --no-install-recommends -y" + $INSTALL build-essential libssl-dev libffi-dev libgmp3-dev python2.7-dev +elif $OSX && ! cmd_exists brew ; then + /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +fi + + +if ! cmd_exists python; then + if $LINUX; then + $INSTALL python2.7 + elif $OSX; then + brew install python + fi +fi + +PYTHON_VERSION=$(python -c 'import sys; print(".".join(map(str, sys.version_info[:2])))') +if [ "$PYTHON_VERSION" != "2.7" ]; then + echo "Python 2.7 required" + exit 1 +fi + +if ! cmd_exists pip; then + if $LINUX; then + $INSTALL python-pip + $SUDO pip install --upgrade pip + else + echo "Pip required" + exit 1 + fi +fi + +if $LINUX && [ "$(pip list --format=columns | grep setuptools | wc -l)" -ge 1 ]; then + #$INSTALL python-setuptools + $SUDO pip install setuptools +fi + +if ! cmd_exists virtualenv; then + $SUDO pip install virtualenv +fi diff --git a/build/release_on_tag.py b/build/release_on_tag.py new file mode 100644 index 000000000..d1585c2d6 --- /dev/null +++ b/build/release_on_tag.py @@ -0,0 +1,128 @@ +import glob +import json +import os +import subprocess +import sys + +import github +import requests +import uritemplate + + +def main(): + this_dir = os.path.dirname(os.path.realpath(__file__)) + try: + current_tag = subprocess.check_output( + ['git', 'describe', '--exact-match', 'HEAD']).strip() + except subprocess.CalledProcessError: + print 'Stopping as we are not currently on a tag' + return + + if 'GH_TOKEN' not in os.environ: + print 'Must set GH_TOKEN in order to publish assets to a release' + return + + gh_token = os.environ['GH_TOKEN'] + auth = github.Github(gh_token) + repo = auth.get_repo('lbryio/lbry') + + if not check_repo_has_tag(repo, current_tag): + print 'Tag {} is not in repo {}'.format(current_tag, repo) + # TODO: maybe this should be an error + return + + daemon_zip = glob.glob(this_dir + '/dist/*.zip')[0] + release = get_release(repo, current_tag) + upload_asset(release, daemon_zip, gh_token) + + +def check_repo_has_tag(repo, target_tag): + tags = repo.get_tags().get_page(0) + for tag in tags: + if tag.name == target_tag: + return True + return False + + +def get_release(current_repo, current_tag): + for release in current_repo.get_releases(): + if release.tag_name == current_tag: + return release + raise Exception('No release for {} was found'.format(current_tag)) + + +def upload_asset(release, asset_to_upload, token): + basename = os.path.basename(asset_to_upload) + if is_asset_already_uploaded(release, basename): + return + count = 0 + while count < 10: + try: + return _upload_asset(release, asset_to_upload, token, _curl_uploader) + except Exception: + print 'Failed uploading on attempt {}'.format(count + 1) + count += 1 + + +def _upload_asset(release, asset_to_upload, token, uploader): + basename = os.path.basename(asset_to_upload) + upload_uri = uritemplate.expand(release.upload_url, {'name': basename}) + output = uploader(upload_uri, asset_to_upload, token) + if 'errors' in output: + raise Exception(output) + else: + print 'Successfully uploaded to {}'.format(output['browser_download_url']) + + +# requests doesn't work on windows / linux / osx. +def _requests_uploader(upload_uri, asset_to_upload, token): + print 'Using requests to upload {} to {}'.format(asset_to_upload, upload_uri) + with open(asset_to_upload, 'rb') as f: + response = requests.post(upload_uri, data=f, auth=('', token)) + return response.json() + + +# curl -H "Content-Type: application/json" -X POST -d '{"username":"xyz","password":"xyz"}' http://localhost:3000/api/login + + +def _curl_uploader(upload_uri, asset_to_upload, token): + # using requests.post fails miserably with SSL EPIPE errors. I spent + # half a day trying to debug before deciding to switch to curl. + # + # TODO: actually set the content type + print 'Using curl to upload {} to {}'.format(asset_to_upload, upload_uri) + cmd = [ + 'curl', + '-sS', + '-X', 'POST', + '-u', ':{}'.format(os.environ['GH_TOKEN']), + '--header', 'Content-Type: application/octet-stream', + '--data-binary', '@-', + upload_uri + ] + # '-d', '{"some_key": "some_value"}', + print 'Calling curl:' + print cmd + print + with open(asset_to_upload, 'rb') as fp: + p = subprocess.Popen(cmd, stdin=fp, stderr=subprocess.PIPE, stdout=subprocess.PIPE) + stdout, stderr = p.communicate() + print 'curl return code:', p.returncode + if stderr: + print 'stderr output from curl:' + print stderr + print 'stdout from curl:' + print stdout + return json.loads(stdout) + + +def is_asset_already_uploaded(release, basename): + for asset in release.raw_data['assets']: + if asset['name'] == basename: + print 'File {} has already been uploaded to {}'.format(basename, release.tag_name) + return True + return False + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/build/requirements.txt b/build/requirements.txt new file mode 100644 index 000000000..43275963b --- /dev/null +++ b/build/requirements.txt @@ -0,0 +1,13 @@ +# install daemon requirements (copied from root, with possible modifications. see build.sh, build.ps1) +-r requirements_base.txt + +# install daemon itself. make sure you run `pip install` from this dir. this is how you do relative file paths with pip +file:../. + +# install other build requirements +PyInstaller==3.2.1 +requests[security]==2.13.0 +GitPython==2.1.1 +PyGithub==1.32 +uritemplate==3.0.0 +git+https://github.com/lbryio/bumpversion.git diff --git a/build/requirements_base.txt b/build/requirements_base.txt new file mode 100644 index 000000000..c942e551b --- /dev/null +++ b/build/requirements_base.txt @@ -0,0 +1 @@ +THIS FILE GETS FILLED IN BY BUILD SCRIPT AND INCLUDED IN requirements.txt diff --git a/build/set_build.py b/build/set_build.py new file mode 100644 index 000000000..39fe12d09 --- /dev/null +++ b/build/set_build.py @@ -0,0 +1,29 @@ +"""Set the build version to be 'dev', 'qa', 'rc', 'release'""" + +import os.path +import re +import subprocess +import sys + + +def main(): + build = get_build() + root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + with open(os.path.join(root_dir, 'lbrynet', 'build_type.py'), 'w') as f: + f.write("BUILD = '{}'\n".format(build)) + + +def get_build(): + try: + tag = subprocess.check_output(['git', 'describe', '--exact-match']).strip() + if re.match('v\d+\.\d+\.\d+rc\d+', tag): + return 'rc' + else: + return 'release' + except subprocess.CalledProcessError: + # if the build doesn't have a tag + return 'qa' + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/build/set_version.py b/build/set_version.py new file mode 100644 index 000000000..a2b69fb9a --- /dev/null +++ b/build/set_version.py @@ -0,0 +1,52 @@ +"""Set the package version to the output of `git describe`""" + +import argparse +import os.path +import re +import subprocess +import sys + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--version', help="defaults to the output of `git describe`") + args = parser.parse_args() + if args.version: + version = args.version + else: + tag = subprocess.check_output(['git', 'describe']).strip() + try: + version = get_version_from_tag(tag) + except InvalidVersionTag: + # this should be an error but its easier to handle here + # than in the calling scripts. + print 'Tag cannot be converted to a version. Exiting.' + return + set_version(version) + + +class InvalidVersionTag(Exception): + pass + + +def get_version_from_tag(tag): + match = re.match('v([\d.]+)', tag) + if match: + return match.group(1) + else: + raise InvalidVersionTag('Failed to parse version from tag {}'.format(tag)) + + +def set_version(version): + root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + with open(os.path.join(root_dir, 'lbrynet', '__init__.py'), 'w') as fp: + fp.write(LBRYNET_TEMPLATE.format(version=version)) + + +LBRYNET_TEMPLATE = """ +__version__ = "{version}" +version = tuple(__version__.split('.')) +""" + +if __name__ == '__main__': + sys.exit(main()) diff --git a/build/zip_daemon.py b/build/zip_daemon.py new file mode 100644 index 000000000..ef3f5e222 --- /dev/null +++ b/build/zip_daemon.py @@ -0,0 +1,29 @@ +import os +import platform +import subprocess +import sys +import zipfile + + +def main(): + this_dir = os.path.dirname(os.path.realpath(__file__)) + tag = subprocess.check_output(['git', 'describe']).strip() + zipfilename = 'lbrynet-daemon-{}-{}.zip'.format(tag, get_system_label()) + full_filename = os.path.join(this_dir, 'dist', zipfilename) + executables = ['lbrynet-daemon', 'lbrynet-cli'] + ext = '.exe' if platform.system() == 'Windows' else '' + with zipfile.ZipFile(full_filename, 'w') as myzip: + for executable in executables: + myzip.write(os.path.join(this_dir, 'dist', executable + ext), executable + ext) + + +def get_system_label(): + system = platform.system() + if system == 'Darwin': + return 'macos' + else: + return system.lower() + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/lbrynet/core/client/BlobRequester.py b/lbrynet/core/client/BlobRequester.py index 14a707fc3..5d392240b 100644 --- a/lbrynet/core/client/BlobRequester.py +++ b/lbrynet/core/client/BlobRequester.py @@ -239,9 +239,9 @@ class RequestHelper(object): def _handle_incoming_blob(response_dict, peer, request): - if not request.response_identifier in response_dict: + if request.response_identifier not in response_dict: return InvalidResponseError("response identifier not in response") - if not type(response_dict[request.response_identifier]) == dict: + if type(response_dict[request.response_identifier]) != dict: return InvalidResponseError("response not a dict. got %s" % type(response_dict[request.response_identifier])) response = response_dict[request.response_identifier] @@ -255,14 +255,14 @@ def _handle_incoming_blob(response_dict, peer, request): return InvalidResponseError("Got an unknown error from the peer: %s" % (response['error'],)) else: - if not 'blob_hash' in response: + if 'blob_hash' not in response: return InvalidResponseError("Missing the required field 'blob_hash'") if not response['blob_hash'] == request.request_dict['requested_blob']: return InvalidResponseError( "Incoming blob does not match expected. Incoming: %s. Expected: %s" % (response['blob_hash'], request.request_dict['requested_blob']) ) - if not 'length' in response: + if 'length' not in response: return InvalidResponseError("Missing the required field 'length'") if not request.blob.set_length(response['length']): return InvalidResponseError("Could not set the length of the blob") @@ -358,7 +358,7 @@ class AvailabilityRequest(RequestHelper): class PriceRequest(RequestHelper): """Ask a peer if a certain price is acceptable""" def can_make_request(self): - if len(self.available_blobs) and not self.protocol in self.protocol_prices: + if len(self.available_blobs) and self.protocol not in self.protocol_prices: return self.get_rate() is not None return False diff --git a/lbrynet/core/client/DHTPeerFinder.py b/lbrynet/core/client/DHTPeerFinder.py index 19b3ac39a..b7202368b 100644 --- a/lbrynet/core/client/DHTPeerFinder.py +++ b/lbrynet/core/client/DHTPeerFinder.py @@ -21,9 +21,6 @@ class DHTPeerFinder(object): self.next_manage_call = None def run_manage_loop(self): - - from twisted.internet import reactor - self._manage_peers() self.next_manage_call = reactor.callLater(60, self.run_manage_loop) diff --git a/lbrynet/lbrynet_daemon/Daemon.py b/lbrynet/lbrynet_daemon/Daemon.py index d858c95ba..90f449a6f 100644 --- a/lbrynet/lbrynet_daemon/Daemon.py +++ b/lbrynet/lbrynet_daemon/Daemon.py @@ -106,7 +106,7 @@ class IterableContainer(object): return False -class Checker: +class Checker(object): """The looping calls the daemon runs""" INTERNET_CONNECTION = 'internet_connection_checker' VERSION = 'version_checker' diff --git a/lbrynet/lbrynet_daemon/auth/server.py b/lbrynet/lbrynet_daemon/auth/server.py index 267791da1..684b1224c 100644 --- a/lbrynet/lbrynet_daemon/auth/server.py +++ b/lbrynet/lbrynet_daemon/auth/server.py @@ -414,9 +414,6 @@ class AuthJSONRPCServer(AuthorizedBase): return True allowed_server, allowed_port = self.get_server_port(allowed_origin) return (allowed_server, allowed_port) == (server, port) - return ( - server == conf.settings['api_host'] and - port == conf.settings['api_port']) def get_server_port(self, origin): parsed = urlparse.urlparse(origin) diff --git a/lbrynet/winhelpers/knownpaths.py b/lbrynet/winhelpers/knownpaths.py index 04deb4288..3a1e8ddc9 100644 --- a/lbrynet/winhelpers/knownpaths.py +++ b/lbrynet/winhelpers/knownpaths.py @@ -20,7 +20,7 @@ class GUID(ctypes.Structure): # http://msdn.microsoft.com/en-us/library/windows/desktop/dd378457.aspx -class FOLDERID: +class FOLDERID(object): # pylint: disable=bad-whitespace AccountPictures = UUID('{008ca0b1-55b4-4c56-b8a8-4de4b299d3be}') AdminTools = UUID('{724EF170-A42D-4FEF-9F26-B60E846FBA4F}') @@ -119,7 +119,7 @@ class FOLDERID: # http://msdn.microsoft.com/en-us/library/windows/desktop/bb762188.aspx -class UserHandle: +class UserHandle(object): current = wintypes.HANDLE(0) common = wintypes.HANDLE(-1) diff --git a/run_pylint.sh b/run_pylint.sh deleted file mode 100755 index c54cf0a44..000000000 --- a/run_pylint.sh +++ /dev/null @@ -1,15 +0,0 @@ -#! /bin/bash - -set -eu - -# Ignoring distutils because: https://github.com/PyCQA/pylint/issues/73 -# TODO: as code quality improves, make pylint be more strict -pylint -E --disable=inherit-non-class --disable=no-member \ - --ignored-modules=distutils \ - --enable=unused-import \ - --enable=bad-whitespace \ - --enable=line-too-long \ - --enable=trailing-whitespace \ - --enable=missing-final-newline \ - --enable=mixed-indentation \ - lbrynet $@ diff --git a/run_tests.sh b/run_tests.sh deleted file mode 100755 index c98eae7b2..000000000 --- a/run_tests.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -set -o xtrace - -if [ -z "$@" ]; then - TESTS=tests -else - TESTS="$@" -fi - -find -iname "*.pyc" -delete -PYTHONPATH=. trial $TESTS diff --git a/setup.py b/setup.py index c16604770..921c5e6e3 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,9 @@ from setuptools import setup, find_packages # dependencies of the lbrynet library. requirements.txt includes # dependencies of dependencies and specific versions that we know # all work together. -# See https://packaging.python.org/requirements/ for more details. +# +# See https://packaging.python.org/requirements/ and +# https://caremad.io/posts/2013/07/setup-vs-requirement/ for more details. requires = [ 'Twisted', 'appdirs',