WIP: new build process using external daemon binary #37

Closed
lyoshenka wants to merge 2 commits from build into master
24 changed files with 320 additions and 707 deletions

18
.appveyor.yml Normal file
View file

@ -0,0 +1,18 @@
# Test against the latest version of this Node.js version
environment:
nodejs_version: "7"
GH_TOKEN:
secure: LiI5jyuHUw6XbH4kC3gP1HX4P/v4rwD/gCNtaFhQu2AvJz1/1wALkp5ECnIxRySN
skip_branch_with_pr: true
clone_folder: C:\projects\lbry-app
build_script:
- ps: build\build.ps1
test: off
artifacts:
- path: dist\*.exe
name: LBRY

6
.gitmodules vendored
View file

@ -1,6 +0,0 @@
[submodule "lbry"]
path = lbry
url = https://github.com/lbryio/lbry.git
[submodule "lbryum"]
path = lbryum
url = https://github.com/lbryio/lbryum.git

View file

@ -1,55 +0,0 @@
# Test against the latest version of this Node.js version
environment:
nodejs_version: "6"
GH_TOKEN:
secure: LiI5jyuHUw6XbH4kC3gP1HX4P/v4rwD/gCNtaFhQu2AvJz1/1wALkp5ECnIxRySN
skip_branch_with_pr: true
clone_folder: C:\projects\lbry-electron
# Install scripts. (runs after repo cloning)
install:
# needed to deal with submodules
- git submodule update --init --recursive
- python build\set_version.py
- python build\set_build.py
# Get the latest stable version of Node.js or io.js
- ps: Install-Product node $env:nodejs_version
# install modules
- npm install
- cd app
- npm install
- cd ..
# create daemon and cli executable
- cd daemon
- ps: .\build.ps1
- cd ..
# build ui
- cd ui
- npm install
- node_modules\.bin\node-sass --output dist\css --sourcemap=none scss\
- node_modules\.bin\webpack
- ps: Copy-Item dist ..\app\ -recurse
- cd ..
# copy executables into ui
- ps: Copy-Item daemon\dist\lbrynet-daemon.exe app\dist
- ps: Copy-Item daemon\dist\lbrynet-cli.exe app\dist
build_script:
# build electron app
- node_modules\.bin\build -p never
# for debugging, see what was built
- python build\zip_daemon.py
- dir dist
- pip install -r build\requirements.txt
- python build\release_on_tag.py
test: off
artifacts:
- path: dist\*.exe
name: LBRY
- path: dist\*.zip
name: lbrynet-daemon

1
build/DAEMON_URL Normal file
View file

@ -0,0 +1 @@
https://github.com/lbryio/lbry/releases/download/v0.9.2rc3/lbrynet-daemon-v0.9.2rc3-OSNAME.zip

34
build/build.ps1 Normal file
View file

@ -0,0 +1,34 @@
pip install -r build\requirements.txt
python build\set_version.py
# Get the latest stable version of Node.js or io.js
Install-Product node $env:nodejs_version
# install node modules
npm install
cd app
npm install
cd ..
# build ui
cd ui
npm install
node_modules\.bin\node-sass --output dist\css --sourcemap=none scss\
node_modules\.bin\webpack
Copy-Item dist ..\app\ -recurse
cd ..
# get daemon and cli executable
$daemon_url = (Get-Content build\DAEMON_URL -Raw).replace("OSNAME", "windows")
Invoke-WebRequest -Uri $daemon_url -OutFile daemon.zip
Expand-Archive daemon.zip -DestinationPath app\dist\
dir app\dist\ # verify that daemon binary is there
rm daemon.zip
# build electron app
node_modules\.bin\build -p never
$binary_name = Get-ChildItem -Path dist -Filter '*.exe' -Name
$new_name = $binary_name -replace '^LBRY Setup (.*)\.exe$', 'LBRY_$1.exe'
Rename-Item -Path "dist\$binary_name" -NewName $new_name
dir dist # verify that binary was built/named correctly
python build\release_on_tag.py

View file

@ -7,7 +7,18 @@ ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
cd "$ROOT"
BUILD_DIR="$ROOT/build"
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
if $OSX; then
ICON="$BUILD_DIR/icon.icns"
else
ICON="$BUILD_DIR/icons/lbry48.png"
@ -32,7 +43,6 @@ if [ "$FULL_BUILD" == "true" ]; then
set -u
pip install -r "$BUILD_DIR/requirements.txt"
python "$BUILD_DIR/set_version.py"
python "$BUILD_DIR/set_build.py"
fi
[ -d "$ROOT/dist" ] && rm -rf "$ROOT/dist"
@ -62,24 +72,17 @@ npm install
# daemon and cli #
####################
(
cd "$ROOT/daemon"
# copy requirements from lbry, but remove lbryum (we'll add it back in below)
grep -v lbryum "$ROOT/lbry/requirements.txt" > requirements.txt
# for electron, we install lbryum and lbry using submodules
echo "../lbryum" >> requirements.txt
echo "../lbry" >> requirements.txt
# also add pyinstaller
echo "PyInstaller==3.2.1" >> requirements.txt
pip install -r requirements.txt
pyinstaller -y daemon.onefile.spec
pyinstaller -y cli.onefile.spec
mv dist/lbrynet-daemon dist/lbrynet-cli "$ROOT/app/dist/"
)
python "$BUILD_DIR/zip_daemon.py"
if [ "$FULL_BUILD" == "true" ]; then
if $OSX; then
OSNAME="macos"
else
OSNAME="linux"
fi
DAEMON_URL="$(cat "$BUILD_DIR/DAEMON_URL" | sed "s/OSNAME/${OSNAME}/")"
wget --quiet "$DAEMON_URL" -O "$BUILD_DIR/daemon.zip"
unzip "$BUILD_DIR/daemon.zip" -d "$ROOT/app/dist/"
rm "$BUILD_DIR/daemon.zip"
fi
###################
# Build the app #
@ -91,12 +94,18 @@ python "$BUILD_DIR/zip_daemon.py"
)
if [ "$FULL_BUILD" == "true" ]; then
if [ "$(uname)" == "Darwin" ]; then
if $OSX; then
security unlock-keychain -p ${KEYCHAIN_PASSWORD} osx-build.keychain
fi
node_modules/.bin/build -p never
if $OSX; then
binary_name=$(find "$ROOT/dist" -iname "*dmg")
new_name=$(basename "$binary_name" | sed 's/-/_/')
mv "$binary_name" "$(dirname "$binary_name")/$new_name"
fi
# 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.

View file

@ -1,8 +1,5 @@
import argparse
import datetime
import re
import sys
CHANGELOG_START_RE = re.compile(r'^\#\# \[Unreleased\]')
CHANGELOG_END_RE = re.compile(r'^\#\# \[.*\] - \d{4}-\d{2}-\d{2}')
@ -14,118 +11,110 @@ EMPTY_RE = re.compile(r'^\w*\*\w*$')
ENTRY_RE = re.compile(r'\* (.*)')
VALID_SECTIONS = ['Added', 'Changed', 'Deprecated', 'Removed', 'Fixed', 'Security']
# allocate some entries to cut-down on merge conflicts
TEMPLATE = """### Added
*
*
*
### Changed
*
*
*
### Fixed
*
*
*
"""
def main():
print "i am broken"
return 1
parser = argparse.ArgumentParser()
parser.add_argument('changelog')
parser.add_argument('version')
args = parser.parse_args()
bump(changelog, version)
class Changelog(object):
def __init__(self, path):
self.path = path
self.start = []
self.unreleased = []
self.rest = []
self._parse()
def _parse(self):
with open(self.path) as fp:
lines = fp.readlines()
def bump(changelog, version):
with open(changelog) as fp:
lines = fp.readlines()
unreleased_start_found = False
unreleased_end_found = False
start = []
unreleased = []
rest = []
unreleased_start_found = False
unreleased_end_found = False
for line in lines:
if not unreleased_start_found:
start.append(line)
if CHANGELOG_START_RE.search(line):
unreleased_start_found = True
continue
if unreleased_end_found:
rest.append(line)
continue
if CHANGELOG_END_RE.search(line):
rest.append(line)
unreleased_end_found = True
continue
if CHANGELOG_ERROR_RE.search(line):
raise Exception(
'Failed to parse {}: {}'.format(changelog, 'unexpected section header found'))
unreleased.append(line)
for line in lines:
if not unreleased_start_found:
self.start.append(line)
if CHANGELOG_START_RE.search(line):
unreleased_start_found = True
continue
if unreleased_end_found:
self.rest.append(line)
continue
if CHANGELOG_END_RE.search(line):
self.rest.append(line)
unreleased_end_found = True
continue
if CHANGELOG_ERROR_RE.search(line):
raise Exception(
'Failed to parse {}: {}'.format(self.path, 'unexpected section header found'))
self.unreleased.append(line)
today = datetime.datetime.today()
header = '## [{}] - {}\n'.format(version, today.strftime('%Y-%m-%d'))
released = normalize(unreleased)
if not released:
# If we don't have anything in the Unreleased section, then leave the
# changelog as it is and return None
return
self.unreleased = self._normalize_section(self.unreleased)
changelog_data = (
''.join(start) +
TEMPLATE +
header +
'\n'.join(released) + '\n\n'
+ ''.join(rest)
)
with open(changelog, 'w') as fp:
fp.write(changelog_data)
return '\n'.join(released) + '\n\n'
@staticmethod
def _normalize_section(lines):
"""Parse a changelog entry and output a normalized form"""
sections = {}
current_section_name = None
current_section_contents = []
for line in lines:
line = line.strip()
if not line or EMPTY_RE.match(line):
continue
match = SECTION_RE.match(line)
if match:
if current_section_contents:
sections[current_section_name] = current_section_contents
current_section_contents = []
current_section_name = match.group(1)
if current_section_name not in VALID_SECTIONS:
raise ValueError("Section '{}' is not valid".format(current_section_name))
continue
match = ENTRY_RE.match(line)
if match:
current_section_contents.append(match.group(1))
continue
raise Exception('Something is wrong with line: {}'.format(line))
if current_section_contents:
sections[current_section_name] = current_section_contents
output = []
for section in VALID_SECTIONS:
if section not in sections:
continue
output.append('### {}'.format(section))
for entry in sections[section]:
output.append(' * {}'.format(entry))
return output
def normalize(lines):
"""Parse a changelog entry and output a normalized form"""
sections = {}
current_section_name = None
current_section_contents = []
for line in lines:
line = line.strip()
if not line or EMPTY_RE.match(line):
continue
match = SECTION_RE.match(line)
if match:
if current_section_contents:
sections[current_section_name] = current_section_contents
current_section_contents = []
current_section_name = match.group(1)
if current_section_name not in VALID_SECTIONS:
raise ValueError("Section '{}' is not valid".format(current_section_name))
continue
match = ENTRY_RE.match(line)
if match:
current_section_contents.append(match.group(1))
continue
raise Exception('Something is wrong with line: {}'.format(line))
if current_section_contents:
sections[current_section_name] = current_section_contents
def get_unreleased(self):
return '\n'.join(self.unreleased) if self.unreleased else None
output = []
for section in VALID_SECTIONS:
if section not in sections:
continue
output.append('### {}'.format(section))
for entry in sections[section]:
output.append(' * {}'.format(entry))
return output
def bump(self, version):
if not self.unreleased:
return
today = datetime.datetime.today()
header = '## [{}] - {}\n'.format(version, today.strftime('%Y-%m-%d'))
if __name__ == '__main__':
sys.exit(main())
changelog_data = (
''.join(self.start) +
TEMPLATE +
header +
'\n'.join(self.unreleased) + '\n\n'
+ ''.join(self.rest)
)
with open(self.path, 'w') as fp:
fp.write(changelog_data)

View file

@ -1,13 +0,0 @@
#!/bin/bash
# https://github.com/lbryio/lbry-app/commit/4386102ba3bf8c731a075797756111d73c31a47a
# https://github.com/lbryio/lbry-app/commit/a3a376922298b94615f7514ca59988b73a522f7f
# Appveyor and Teamcity struggle with SSH urls in submodules, so we use HTTPS
# But locally, SSH urls are way better since they dont require a password
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "DIR"
git config submodule.lbry.url git@github.com:lbryio/lbry.git
git config submodule.lbryum.url git@github.com:lbryio/lbryum.git

View file

@ -72,7 +72,6 @@ if ! cmd_exists pip; then
fi
if $LINUX && [ "$(pip list --format=columns | grep setuptools | wc -l)" -ge 1 ]; then
#$INSTALL python-setuptools
$SUDO pip install setuptools
fi
@ -88,3 +87,14 @@ if ! cmd_exists node; then
brew install node
fi
fi
if ! cmd_exists unzip; then
if $LINUX; then
$INSTALL unzip
elif $OSX; then
echo "unzip required"
exit 1
# not sure this works, but OSX should come with unzip
# brew install unzip
fi
fi

View file

@ -1,13 +1,11 @@
"""Trigger a release.
"""Bump version and create Github release
This script is to be run locally (not on a build server).
This script should be run locally, not on a build server.
"""
import argparse
import contextlib
import logging
import os
import re
import string
import subprocess
import sys
@ -16,122 +14,131 @@ import github
import changelog
# TODO: ask bumpversion for these
LBRY_PARTS = ('major', 'minor', 'patch', 'release', 'candidate')
LBRYUM_PARTS = ('major', 'minor', 'patch')
ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"lbry_part", help="part of lbry version to bump",
choices=LBRY_PARTS
)
parser.add_argument(
"--skip-lbryum", help="skip bumping lbryum, even if there are changes",
action="store_true",
)
parser.add_argument(
"--lbryum-part", help="part of lbryum version to bump",
choices=LBRYUM_PARTS
)
parser.add_argument(
"--last-release",
help=("manually set the last release version. The default is to query and parse the"
" value from the release page.")
)
parser.add_argument(
"--skip-sanity-checks", action="store_true")
parser.add_argument(
"--require-changelog", action="store_true",
help=("Set this flag to raise an exception if a submodules has changes without a"
" corresponding changelog entry. The default is to log a warning")
)
parser.add_argument(
"--skip-push", action="store_true",
help="Set to not push changes to remote repo"
)
bumpversion_parts = get_bumpversion_parts()
parser = argparse.ArgumentParser()
parser.add_argument("part", choices=bumpversion_parts, help="part of version to bump")
parser.add_argument("--skip-sanity-checks", action="store_true")
parser.add_argument("--skip-push", action="store_true")
parser.add_argument("--dry-run", action="store_true")
parser.add_argument("--confirm", action="store_true")
args = parser.parse_args()
base = git.Repo(os.getcwd())
if args.dry_run:
print "DRY RUN. Nothing will be committed/pushed."
repo = Repo('lbry-app', args.part, ROOT)
branch = 'master'
print 'Current version: {}'.format(repo.current_version)
print 'New version: {}'.format(repo.new_version)
if not args.confirm and not confirm():
print "Aborting"
return 1
if not args.skip_sanity_checks:
run_sanity_checks(base, branch)
run_sanity_checks(repo, branch)
repo.assert_new_tag_is_absent()
base_repo = Repo('lbry-app', args.lbry_part, os.getcwd())
base_repo.assert_new_tag_is_absent()
is_rc = re.search('\drc\d+$', repo.new_version) is not None
# only have a release message for real releases, not for RCs
release_msg = '' if is_rc else repo.get_unreleased_changelog()
last_release = args.last_release or base_repo.get_last_tag()
logging.info('Last release: %s', last_release)
if args.dry_run:
print "rc: " + ("yes" if is_rc else "no")
print "release message: \n" + (release_msg or " NO MESSAGE FOR RCs")
return
gh_token = get_gh_token()
auth = github.Github(gh_token)
github_repo = auth.get_repo('lbryio/lbry-app')
names = ['lbryum', 'lbry']
repos = {name: Repo(name, get_part(args, name)) for name in names}
if not is_rc:
repo.bump_changelog()
repo.bumpversion()
changelogs = {}
new_tag = repo.get_new_tag()
github_repo.create_git_release(new_tag, new_tag, release_msg, draft=True, prerelease=is_rc)
for repo in repos.values():
logging.info('Processing repo: %s', repo.name)
repo.checkout(branch)
last_submodule_hash = base_repo.get_submodule_hash(last_release, repo.name)
if repo.has_changes_from_revision(last_submodule_hash):
if repo.name == 'lbryum':
if args.skip_lbryum:
continue
if not repo.part:
repo.part = get_lbryum_part()
entry = repo.get_changelog_entry()
if entry:
changelogs[repo.name] = entry.strip()
repo.add_changelog()
else:
msg = 'Changelog entry is missing for {}'.format(repo.name)
if args.require_changelog:
raise Exception(msg)
else:
logging.warning(msg)
else:
logging.warning('Submodule %s has no changes.', repo.name)
if repo.name == 'lbryum':
# The other repos have their version track each other so need to bump
# them even if there aren't any changes, but lbryum should only be
# bumped if it has changes
continue
# bumpversion will fail if there is already the tag we want in the repo
repo.assert_new_tag_is_absent()
repo.bumpversion()
release_msg = get_release_msg(changelogs, names)
for name in names:
base.git.add(name)
base_repo.bumpversion()
current_tag = base.git.describe()
is_rc = re.match('\drc\d+$', current_tag) is not None
github_repo.create_git_release(current_tag, current_tag, release_msg, draft=True,
prerelease=is_rc)
no_change_msg = ('No change since the last release. This release is simply a placeholder'
' so that LBRY and LBRY App track the same version')
lbrynet_daemon_release_msg = changelogs.get('lbry', no_change_msg)
auth.get_repo('lbryio/lbry').create_git_release(
current_tag, current_tag, lbrynet_daemon_release_msg, draft=True)
if not args.skip_push:
for repo in repos.values():
repo.git.push(follow_tags=True)
base.git.push(follow_tags=True, recurse_submodules='check')
if args.skip_push:
print (
'Skipping push; you will have to reset and delete tags if '
'you want to run this script again.'
)
else:
logging.info('Skipping push; you will have to reset and delete tags if '
'you want to run this script again. Take a look at reset.sh; '
'it probably does what you want.')
repo.git_repo.git.push(follow_tags=True, recurse_submodules='check')
class Repo(object):
def __init__(self, name, part, directory):
self.name = name
self.part = part
if not self.part:
raise Exception('Part required')
self.directory = directory
self.git_repo = git.Repo(self.directory)
self._bumped = False
self.current_version = self._get_current_version()
self.new_version = self._get_new_version()
self._changelog = changelog.Changelog(os.path.join(self.directory, 'CHANGELOG.md'))
def get_new_tag(self):
return 'v' + self.new_version
def get_unreleased_changelog(self):
return self._changelog.get_unreleased()
def bump_changelog(self):
self._changelog.bump(self.new_version)
with pushd(self.directory):
self.git_repo.git.add(os.path.basename(self._changelog.path))
def _get_current_version(self):
with pushd(self.directory):
output = subprocess.check_output(
['bumpversion', '--dry-run', '--list', '--allow-dirty', self.part])
return re.search('^current_version=(.*)$', output, re.M).group(1)
def _get_new_version(self):
with pushd(self.directory):
output = subprocess.check_output(
['bumpversion', '--dry-run', '--list', '--allow-dirty', self.part])
return re.search('^new_version=(.*)$', output, re.M).group(1)
def bumpversion(self):
if self._bumped:
raise Exception('Cowardly refusing to bump a repo twice')
with pushd(self.directory):
subprocess.check_call(['bumpversion', '--allow-dirty', self.part])
self._bumped = True
def assert_new_tag_is_absent(self):
new_tag = self.get_new_tag()
tags = self.git_repo.git.tag()
if new_tag in tags.split('\n'):
raise Exception('Tag {} is already present in repo {}.'.format(new_tag, self.name))
def is_behind(self, branch):
self.git_repo.remotes.origin.fetch()
rev_list = '{branch}...origin/{branch}'.format(branch=branch)
commits_behind = self.git_repo.git.rev_list(rev_list, right_only=True, count=True)
commits_behind = int(commits_behind)
return commits_behind > 0
def get_bumpversion_parts():
with pushd(ROOT):
output = subprocess.check_output([
'bumpversion', '--dry-run', '--list', '--allow-dirty', 'fake-part',
])
parse_line = re.search('^parse=(.*)$', output, re.M).group(1)
return tuple(re.findall('<([^>]+)>', parse_line))
def get_gh_token():
@ -148,131 +155,36 @@ in the future"""
return raw_input('token: ').strip()
def get_lbryum_part():
print """The lbryum repo has changes but you didn't specify how to bump the
version. Please enter one of: {}""".format(', '.join(LBRYUM_PARTS))
while True:
part = raw_input('part: ').strip()
if part in LBRYUM_PARTS:
return part
print 'Invalid part. Enter one of: {}'.format(', '.join(LBRYUM_PARTS))
def confirm():
return raw_input('Is this what you want? [y/N] ').strip().lower() == 'y'
def get_release_msg(changelogs, names):
lines = []
for name in names:
entry = changelogs.get(name)
if not entry:
continue
lines.append('## {}\n'.format(name))
lines.append('{}\n'.format(entry))
return '\n'.join(lines)
def run_sanity_checks(base, branch):
if base.is_dirty():
def run_sanity_checks(repo, branch):
if repo.git_repo.is_dirty():
print 'Cowardly refusing to release a dirty repo'
sys.exit(1)
if base.active_branch.name != branch:
if repo.git_repo.active_branch.name != branch:
print 'Cowardly refusing to release when not on the {} branch'.format(branch)
sys.exit(1)
if is_behind(base, branch):
if repo.is_behind(branch):
print 'Cowardly refusing to release when behind origin'
sys.exit(1)
check_bumpversion()
def is_behind(base, branch):
base.remotes.origin.fetch()
rev_list = '{branch}...origin/{branch}'.format(branch=branch)
commits_behind = base.git.rev_list(rev_list, right_only=True, count=True)
commits_behind = int(commits_behind)
return commits_behind > 0
def check_bumpversion():
def require_new_version():
print 'Install bumpversion: pip install -U git+https://github.com/lbryio/bumpversion.git'
if not is_custom_bumpversion_version():
print (
'Install LBRY\'s fork of bumpversion: '
'pip install -U git+https://github.com/lbryio/bumpversion.git'
)
sys.exit(1)
def is_custom_bumpversion_version():
try:
output = subprocess.check_output(['bumpversion', '-v'], stderr=subprocess.STDOUT)
output = output.strip()
if output != 'bumpversion 0.5.4-lbry':
require_new_version()
except (subprocess.CalledProcessError, OSError) as err:
require_new_version()
def get_part(args, name):
return getattr(args, name + '_part') or args.lbry_part
class Repo(object):
def __init__(self, name, part, directory=None):
self.name = name
self.part = part
self.directory = directory or os.path.join(os.getcwd(), name)
self.git_repo = git.Repo(self.directory)
self.saved_commit = None
self._bumped = False
def get_last_tag(self):
return string.split(self.git_repo.git.describe(tags=True), '-')[0]
def get_submodule_hash(self, revision, submodule_path):
line = getattr(self.git_repo.git, 'ls-tree')(revision, submodule_path)
return string.split(line)[2] if line else None
def has_changes_from_revision(self, revision):
commit = str(self.git_repo.commit())
logging.info('%s =? %s', commit, revision)
return commit != revision
def save_commit(self):
self.saved_commit = self.git_repo.commit()
logging.info('Saved ', self.git_repo.commit(), self.saved_commit)
def checkout(self, branch):
self.git_repo.git.checkout(branch)
self.git_repo.git.pull(rebase=True)
def get_changelog_entry(self):
filename = os.path.join(self.directory, 'CHANGELOG.md')
return changelog.bump(filename, self.new_version())
def add_changelog(self):
with pushd(self.directory):
self.git_repo.git.add('CHANGELOG.md')
def new_version(self):
if self._bumped:
raise Exception('Cannot calculate a new version on an already bumped repo')
if not self.part:
raise Exception('Cannot calculate a new version without a part')
with pushd(self.directory):
output = subprocess.check_output(
['bumpversion', '--dry-run', '--list', '--allow-dirty', self.part])
return re.search('^new_version=(.*)$', output, re.M).group(1)
def bumpversion(self):
if self._bumped:
raise Exception('Cowardly refusing to bump a repo twice')
if not self.part:
raise Exception('Cannot bump version for {}: no part specified'.format(repo.name))
with pushd(self.directory):
subprocess.check_call(['bumpversion', '--allow-dirty', self.part])
self._bumped = True
def assert_new_tag_is_absent(self):
new_tag = 'v' + self.new_version()
tags = self.git_repo.git.tag()
if new_tag in tags.split('\n'):
raise Exception('Tag {} is already present in repo {}.'.format(new_tag, self.name))
@property
def git(self):
return self.git_repo.git
output = subprocess.check_output(['bumpversion', '-v'], stderr=subprocess.STDOUT).strip()
if output == 'bumpversion 0.5.4-lbry':
return True
except (subprocess.CalledProcessError, OSError):
pass
return False
@contextlib.contextmanager
@ -284,10 +196,4 @@ def pushd(new_dir):
if __name__ == '__main__':
logging.basicConfig(
format="%(asctime)s %(levelname)-8s %(name)s:%(lineno)d: %(message)s",
level='INFO'
)
sys.exit(main())
else:
log = logging.getLogger('__name__')

View file

@ -1,6 +1,5 @@
import glob
import json
import logging
import os
import platform
import subprocess
@ -10,15 +9,13 @@ import github
import requests
import uritemplate
from lbrynet.core import log_support
def main():
try:
current_tag = subprocess.check_output(
['git', 'describe', '--exact-match', 'HEAD']).strip()
except subprocess.CalledProcessError:
log.info('Stopping as we are not currently on a tag')
print 'Stopping as we are not currently on a tag'
return
if 'GH_TOKEN' not in os.environ:
@ -27,20 +24,15 @@ def main():
gh_token = os.environ['GH_TOKEN']
auth = github.Github(gh_token)
app_repo = auth.get_repo('lbryio/lbry-app')
daemon_repo = auth.get_repo('lbryio/lbry')
repo = auth.get_repo('lbryio/lbry-app')
if not check_repo_has_tag(app_repo, current_tag):
log.info('Tag %s is not in repo %s', current_tag, app_repo)
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 = get_daemon_artifact()
# release = get_release(daemon_repo, current_tag)
# upload_asset(release, daemon, gh_token)
app = get_app_artifact()
release = get_release(app_repo, current_tag)
release = get_release(repo, current_tag)
upload_asset(release, app, gh_token)
@ -60,21 +52,18 @@ def get_release(current_repo, current_tag):
def get_app_artifact():
this_dir = os.path.dirname(os.path.realpath(__file__))
system = platform.system()
if system == 'Darwin':
return glob.glob('dist/mac/LBRY*.dmg')[0]
return glob.glob(this_dir + '/../dist/mac/LBRY*.dmg')[0]
elif system == 'Linux':
return glob.glob('dist/LBRY*.deb')[0]
return glob.glob(this_dir + '/../dist/LBRY*.deb')[0]
elif system == 'Windows':
return glob.glob('dist/LBRY*.exe')[0]
return glob.glob(this_dir + '/../dist/LBRY*.exe')[0]
else:
raise Exception("I don't know about any artifact on {}".format(system))
def get_daemon_artifact():
return glob.glob('dist/*.zip')[0]
def upload_asset(release, asset_to_upload, token):
basename = os.path.basename(asset_to_upload)
if is_asset_already_uploaded(release, basename):
@ -84,30 +73,26 @@ def upload_asset(release, asset_to_upload, token):
try:
return _upload_asset(release, asset_to_upload, token, _curl_uploader)
except Exception:
log.exception('Failed to upload')
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}
)
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:
log.info('Successfully uploaded to %s', output['browser_download_url'])
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):
log.info('Using requests to upload %s to %s', asset_to_upload, upload_uri)
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))
output = response.json()
return output
return response.json()
# curl -H "Content-Type: application/json" -X POST -d '{"username":"xyz","password":"xyz"}' http://localhost:3000/api/login
@ -118,7 +103,7 @@ def _curl_uploader(upload_uri, asset_to_upload, token):
# half a day trying to debug before deciding to switch to curl.
#
# TODO: actually set the content type
log.info('Using curl to upload %s to %s', asset_to_upload, upload_uri)
print 'Using curl to upload {} to {}'.format(asset_to_upload, upload_uri)
cmd = [
'curl',
'-sS',
@ -141,21 +126,16 @@ def _curl_uploader(upload_uri, asset_to_upload, token):
print stderr
print 'stdout from curl:'
print stdout
output = json.loads(stdout)
return output
return json.loads(stdout)
def is_asset_already_uploaded(release, basename):
for asset in release.raw_data['assets']:
if asset['name'] == basename:
log.info('File %s has already been uploaded to %s', basename, release.tag_name)
print 'File {} has already been uploaded to {}'.format(basename, release.tag_name)
return True
return False
if __name__ == '__main__':
log = logging.getLogger('release-on-tag')
log_support.configure_console(level='INFO')
sys.exit(main())
else:
log = logging.getLogger(__name__)

View file

@ -1,21 +0,0 @@
#!/bin/bash
set -euxo pipefail
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
cd "$ROOT"
(
cd lbry
git tag -d $(git describe)
git reset --hard origin/master
)
(
cd lbryum
git tag -d $(git describe)
git reset --hard origin/master
)
git tag -d $(git describe)
git reset --hard HEAD~1

View file

@ -1,28 +0,0 @@
"""Set the build version to be 'dev', 'qa', 'rc', 'release'"""
import os.path
import re
import subprocess
import sys
def main():
build = get_build()
with open(os.path.join('lbry', 'lbrynet', 'build_type.py'), 'w') as f:
f.write('BUILD = "{}"'.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())

View file

@ -39,20 +39,13 @@ def get_version_from_tag(tag):
def set_version(version):
package_file = os.path.join('app', 'package.json')
root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
package_file = os.path.join(root_dir, 'app', 'package.json')
with open(package_file) as fp:
package_data = json.load(fp)
package_data['version'] = version
with open(package_file, 'w') as fp:
json.dump(package_data, fp, indent=2, separators=(',', ': '))
with open(os.path.join('lbry', 'lbrynet', '__init__.py'), 'w') as fp:
fp.write(LBRYNET_TEMPLATE.format(version=version))
LBRYNET_TEMPLATE = """
__version__ = "{version}"
version = tuple(__version__.split('.'))
"""
if __name__ == '__main__':

View file

@ -1,28 +0,0 @@
import os
import platform
import subprocess
import sys
import zipfile
def main():
tag = subprocess.check_output(['git', 'describe']).strip()
zipfilename = 'lbrynet-daemon-{}-{}.zip'.format(tag, get_system_label())
full_filename = os.path.join('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('app', '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())

View file

@ -1,28 +0,0 @@
$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.exe -f Makefile.mingw
python.exe setupmingw32.py build --compiler=mingw32
python.exe setupmingw32.py install
cd ..\
Remove-Item -Recurse -Force miniupnpc-1.9
# copy requirements from lbry, but remove lbryum (we'll add it back in below) and gmpy and miniupnpc (installed manually)
Get-Content ..\lbry\requirements.txt | Select-String -Pattern 'lbryum|gmpy|miniupnpc' -NotMatch | Out-File requirements.txt
# add in gmpy wheel
Add-Content requirements.txt "./gmpy-1.17-cp27-none-win32.whl"
# for electron, we install lbryum and lbry using submodules
Add-Content requirements.txt "../lbryum"
Add-Content requirements.txt "../lbry"
pip.exe install pyinstaller
pip.exe install -r requirements.txt
pyinstaller -y daemon.onefile.spec
pyinstaller -y cli.onefile.spec

View file

@ -1,58 +0,0 @@
# -*- mode: python -*-
import platform
import os
cwd = os.getcwd()
if os.path.basename(cwd) != 'daemon':
raise Exception('The build needs to be run from the same directory as the spec file')
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
)

View file

@ -1,7 +0,0 @@
from lbrynet.lbrynet_daemon import DaemonCLI
import logging
logging.basicConfig()
if __name__ == '__main__':
DaemonCLI.main()

View file

@ -1,77 +0,0 @@
# -*- mode: python -*-
import platform
import os
import lbryum
cwd = os.getcwd()
if os.path.basename(cwd) != 'daemon':
raise Exception('The build needs to be run from the same directory as the spec file')
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
)

View file

@ -1,4 +0,0 @@
from lbrynet.lbrynet_daemon import DaemonControl
if __name__ == '__main__':
DaemonControl.start()

Binary file not shown.

Binary file not shown.

1
lbry

@ -1 +0,0 @@
Subproject commit 043e2d0ab96030468d53d02e311fd848f35c2dc1

1
lbryum

@ -1 +0,0 @@
Subproject commit 121bda3963ee94f0c9c027813c55b71b38219739