diff --git a/bazarr/check_update.py b/bazarr/check_update.py index 64a2ef3f2..d8be1087c 100644 --- a/bazarr/check_update.py +++ b/bazarr/check_update.py @@ -11,14 +11,9 @@ import json from get_args import args from config import settings -bazarr_version = '7.2.0' -LATEST_VERSION = None -INSTALL_TYPE = None -UPDATE_AVAILABLE = None -COMMITS_BEHIND = None -LATEST_RELEASE = None -PREV_RELEASE = bazarr_version +# from main import bazarr_version + class FakeLock(object): @@ -63,243 +58,249 @@ def check_releases(): json.dump(releases, f) -def runGit(args): - git_locations = ['git'] - - if platform.system().lower() == 'darwin': - git_locations.append('/usr/local/git/bin/git') - - output = err = None - - for cur_git in git_locations: - cmd = cur_git + ' ' + args +class Updater(object): + def __init__(self): + self.bazarr_version = '7.2.0' - try: - logging.debug('Trying to execute: "' + cmd + '"') - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) - output, err = p.communicate() - output = output.strip() - - logging.debug('Git output: ' + output) - except OSError: - logging.debug('Command failed: %s', cmd) - continue - - if 'not found' in output or "not recognized as an internal or external command" in output: - logging.debug('Unable to find git with command ' + cmd) - output = None - elif 'fatal:' in output or err: - logging.error('Git returned bad info. Are you sure this is a git installation?') - output = None - elif output: - break + self.LATEST_VERSION = '' + self.INSTALL_TYPE = '' + self.UPDATE_AVAILABLE = '' + self.COMMITS_BEHIND = '' + self.LATEST_RELEASE = '' + self.CURRENT_VERSION = '' + self.PREV_RELEASE = self.bazarr_version + self.CURRENT_VERSION, self.GIT_REMOTE, self.GIT_BRANCH = self.getVersion() - return (output, err) - - -def getVersion(): - if os.path.isdir(os.path.join(os.path.dirname(__file__), '..', '.git')): - - INSTALL_TYPE = 'git' - output, err = runGit('rev-parse HEAD') - - if not output: - logging.error('Could not find latest installed version.') - cur_commit_hash = None + def runGit(self, args): + git_locations = ['git'] - cur_commit_hash = str(output) + if platform.system().lower() == 'darwin': + git_locations.append('/usr/local/git/bin/git') - if not re.match('^[a-z0-9]+$', cur_commit_hash): - logging.error('Output does not look like a hash, not using it.') - cur_commit_hash = None + output = err = None - if settings.general.branch: - branch_name = settings.general.branch - - else: - remote_branch, err = runGit('rev-parse --abbrev-ref --symbolic-full-name @{u}') - remote_branch = remote_branch.rsplit('/', 1) if remote_branch else [] - if len(remote_branch) == 2: - remote_name, branch_name = remote_branch - else: - remote_name = branch_name = None + for cur_git in git_locations: + cmd = cur_git + ' ' + args - if not remote_name and settings.general.branch: - logging.error('Could not retrieve remote name from git. Defaulting to origin.') - branch_name = settings.general.branch + try: + logging.debug('Trying to execute: "' + cmd + '"') + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) + output, err = p.communicate() + output = output.strip() + + logging.debug('Git output: ' + output) + except OSError: + logging.debug('Command failed: %s', cmd) + continue - if not branch_name: - logging.error('Could not retrieve branch name from git. Defaulting to master.') - branch_name = 'master' + if 'not found' in output or "not recognized as an internal or external command" in output: + logging.debug('Unable to find git with command ' + cmd) + output = None + elif 'fatal:' in output or err: + logging.error('Git returned bad info. Are you sure this is a git installation?') + output = None + elif output: + break - return cur_commit_hash, 'origin', branch_name + return (output, err) - else: - INSTALL_TYPE = 'source' + def getVersion(self): + if os.path.isdir(os.path.join(os.path.dirname(__file__), '..', '.git')) and not args.release_update: + + self.INSTALL_TYPE = 'git' + output, err = self.runGit('rev-parse HEAD') + + if not output: + logging.error('Could not find latest installed version.') + cur_commit_hash = None + + cur_commit_hash = str(output) + + if not re.match('^[a-z0-9]+$', cur_commit_hash): + logging.error('Output does not look like a hash, not using it.') + cur_commit_hash = None + + if settings.general.branch: + branch_name = settings.general.branch + + else: + remote_branch, err = self.runGit('rev-parse --abbrev-ref --symbolic-full-name @{u}') + remote_branch = remote_branch.rsplit('/', 1) if remote_branch else [] + if len(remote_branch) == 2: + remote_name, branch_name = remote_branch + else: + remote_name = branch_name = None + + if not remote_name and settings.general.branch: + logging.error('Could not retrieve remote name from git. Defaulting to origin.') + branch_name = settings.general.branch + + if not branch_name: + logging.error('Could not retrieve branch name from git. Defaulting to master.') + branch_name = 'master' + + return cur_commit_hash, 'origin', branch_name - if CURRENT_VERSION: - return CURRENT_VERSION, 'origin', settings.general.branch else: - return None, 'origin', settings.general.branch - - -CURRENT_VERSION, GIT_REMOTE, GIT_BRANCH = getVersion() - - -def check_updates(): - check_github() - if not CURRENT_VERSION: - UPDATE_AVAILABLE = None - elif COMMITS_BEHIND > 0 and settings.general.branch in ('master') and \ - ('V' + bazarr_version) != LATEST_RELEASE: - UPDATE_AVAILABLE = 'release' - elif COMMITS_BEHIND > 0 and CURRENT_VERSION != LATEST_VERSION: - UPDATE_AVAILABLE = 'commit' - else: - UPDATE_AVAILABLE = False - - -def check_github(): - COMMITS_BEHIND = 0 - - # Get the latest version available from github - logging.info('Retrieving latest version information from GitHub') - url = 'https://api.github.com/repos/morpheus65535/bazarr/commits/%s' % settings.general.branch - version = request_json(url, timeout=20, validator=lambda x: type(x) == dict) - - if version is None: - logging.warn('Could not get the latest version from GitHub. Are you running a local development version?') - return CURRENT_VERSION - - LATEST_VERSION = version['sha'] - logging.debug("Latest version is %s", LATEST_VERSION) - - # See how many commits behind we are - if not CURRENT_VERSION: - logging.info('You are running an unknown version of Bazarr. Run the updater to identify your version') - return LATEST_VERSION - - if LATEST_VERSION == CURRENT_VERSION: - logging.info('Bazarr is up to date') - return LATEST_VERSION - - logging.info('Comparing currently installed version with latest GitHub version') - url = 'https://api.github.com/repos/morpheus65535/bazarr/compare/%s...%s' % (LATEST_VERSION, - CURRENT_VERSION) - commits = request_json(url, timeout=20, whitelist_status_code=404, validator=lambda x: type(x) == dict) - - if commits is None: - logging.warn('Could not get commits behind from GitHub.') - return LATEST_VERSION - - try: - COMMITS_BEHIND = int(commits['behind_by']) - logging.debug("In total, %d commits behind", COMMITS_BEHIND) - except KeyError: - logging.info('Cannot compare versions. Are you running a local development version?') - COMMITS_BEHIND = 0 + self.INSTALL_TYPE = 'source' + + if self.CURRENT_VERSION: + return self.CURRENT_VERSION, 'origin', settings.general.branch + else: + return None, 'origin', settings.general.branch - if COMMITS_BEHIND > 0: - logging.info('New version is available. You are %s commits behind' % COMMITS_BEHIND) - - url = 'https://api.github.com/repos/morpheus65535/bazarr/releases' - releases = request_json(url, timeout=20, whitelist_status_code=404, validator=lambda x: type(x) == list) - - if releases is None: - logging.warn('Could not get releases from GitHub.') - return LATEST_VERSION - - if settings.general.branch == 'master': - release = next((r for r in releases if not r['prerelease']), releases[0]) + def check_updates(self): + self.check_github() + if not self.CURRENT_VERSION: + self.UPDATE_AVAILABLE = None + elif self.COMMITS_BEHIND > 0 and settings.general.branch in ('master') and \ + ('v' + self.bazarr_version) != self.LATEST_RELEASE: + self.UPDATE_AVAILABLE = 'release' + elif self.COMMITS_BEHIND > 0 and self.CURRENT_VERSION != self.LATEST_VERSION: + self.UPDATE_AVAILABLE = 'commit' else: - release = releases[0] - LATEST_RELEASE = release['tag_name'] + self.UPDATE_AVAILABLE = False + print self.UPDATE_AVAILABLE - elif COMMITS_BEHIND == 0: - logging.info('Bazarr is up to date') - - return LATEST_VERSION - - -def update(): - if INSTALL_TYPE == 'git': - output, err = runGit('pull ' + 'origin' + ' ' + settings.general.branch) - - if not output: - logging.error('Unable to download latest version') - return + def check_github(self): + self.COMMITS_BEHIND = 0 - for line in output.split('\n'): - - if 'Already up-to-date.' in line: - logging.info('No update available, not updating') - logging.info('Output: ' + str(output)) - elif line.endswith(('Aborting', 'Aborting.')): - logging.error('Unable to update from git: ' + line) - logging.info('Output: ' + str(output)) - - else: - tar_download_url = 'https://github.com/morpheus65535/bazarr/tarball/{}'.format(settings.general.branch) - update_dir = os.path.join(os.path.dirname(__file__), '..', 'update') + # Get the latest version available from github + logging.info('Retrieving latest version information from GitHub') + url = 'https://api.github.com/repos/morpheus65535/bazarr/commits/%s' % settings.general.branch + version = request_json(url, timeout=20, validator=lambda x: type(x) == dict) - logging.info('Downloading update from: ' + tar_download_url) - data = request_content(tar_download_url) + if version is None: + logging.warn('Could not get the latest version from GitHub. Are you running a local development version?') + return self.CURRENT_VERSION - if not data: - logging.error("Unable to retrieve new version from '%s', can't update", tar_download_url) - return + self.LATEST_VERSION = version['sha'] + logging.debug("Latest version is %s", self.LATEST_VERSION) - download_name = settings.general.branch + '-github' - tar_download_path = os.path.join(os.path.dirname(__file__), '..', download_name) + # See how many commits behind we are + if not self.CURRENT_VERSION: + logging.info('You are running an unknown version of Bazarr. Run the updater to identify your version') + return self.LATEST_VERSION - # Save tar to disk - with open(tar_download_path, 'wb') as f: - f.write(data) + if self.LATEST_VERSION == self.CURRENT_VERSION: + logging.info('Bazarr is up to date') + return self.LATEST_VERSION - # Extract the tar to update folder - logging.info('Extracting file: ' + tar_download_path) - tar = tarfile.open(tar_download_path) - tar.extractall(update_dir) - tar.close() + logging.info('Comparing currently installed version with latest GitHub version') + url = 'https://api.github.com/repos/morpheus65535/bazarr/compare/%s...%s' % (self.LATEST_VERSION, + self.CURRENT_VERSION) + commits = request_json(url, timeout=20, whitelist_status_code=404, validator=lambda x: type(x) == dict) - # Delete the tar.gz - logging.info('Deleting file: ' + tar_download_path) - os.remove(tar_download_path) + if commits is None: + logging.warn('Could not get commits behind from GitHub.') + return self.LATEST_VERSION - # Find update dir name - update_dir_contents = [x for x in os.listdir(update_dir) if os.path.isdir(os.path.join(update_dir, x))] - if len(update_dir_contents) != 1: - logging.error("Invalid update data, update failed: " + str(update_dir_contents)) - return - content_dir = os.path.join(update_dir, update_dir_contents[0]) + try: + self.COMMITS_BEHIND = int(commits['behind_by']) + logging.debug("In total, %d commits behind", self.COMMITS_BEHIND) + except KeyError: + logging.info('Cannot compare versions. Are you running a local development version?') + self.COMMITS_BEHIND = 0 - # walk temp folder and move files to main folder - for dirname, dirnames, filenames in os.walk(content_dir): - dirname = dirname[len(content_dir) + 1:] - for curfile in filenames: - old_path = os.path.join(content_dir, dirname, curfile) - new_path = os.path.join(os.path.dirname(__file__), '..', dirname, curfile) - - if os.path.isfile(new_path): - os.remove(new_path) - os.renames(old_path, new_path) - - -def checkout_git_branch(): - if INSTALL_TYPE == 'git': - output, err = runGit('fetch origin') - output, err = runGit('checkout %s' % settings.general.branch) + if self.COMMITS_BEHIND > 0: + logging.info('New version is available. You are %s commits behind' % self.COMMITS_BEHIND) + + url = 'https://api.github.com/repos/morpheus65535/bazarr/releases' + releases = request_json(url, timeout=20, whitelist_status_code=404, validator=lambda x: type(x) == list) + + if releases is None: + logging.warn('Could not get releases from GitHub.') + return self.LATEST_VERSION + + if settings.general.branch == 'master': + release = next((r for r in releases if not r['prerelease']), releases[0]) + else: + release = releases[0] + self.LATEST_RELEASE = release['tag_name'] - if not output: - logging.error('Unable to change git branch.') - return + elif self.COMMITS_BEHIND == 0: + logging.info('Bazarr is up to date') - for line in output.split('\n'): - if line.endswith(('Aborting', 'Aborting.')): - logging.error('Unable to checkout from git: ' + line) - logging.info('Output: ' + str(output)) + return self.LATEST_VERSION + + def update(self): + if self.INSTALL_TYPE == 'git' and not args.release_update: + output, err = self.runGit('pull ' + 'origin' + ' ' + settings.general.branch) + + if not output: + logging.error('Unable to download latest version') + return + + for line in output.split('\n'): + + if 'Already up-to-date.' in line: + logging.info('No update available, not updating') + logging.info('Output: ' + str(output)) + elif line.endswith(('Aborting', 'Aborting.')): + logging.error('Unable to update from git: ' + line) + logging.info('Output: ' + str(output)) - output, err = runGit('pull origin %s' % settings.general.branch) + else: + tar_download_url = 'https://github.com/morpheus65535/bazarr/tarball/{}'.format(settings.general.branch) + update_dir = os.path.join(os.path.dirname(__file__), '..', 'update') + + logging.info('Downloading update from: ' + tar_download_url) + data = request_content(tar_download_url) + + if not data: + logging.error("Unable to retrieve new version from '%s', can't update", tar_download_url) + return + + download_name = settings.general.branch + '-github' + tar_download_path = os.path.join(os.path.dirname(__file__), '..', download_name) + + # Save tar to disk + with open(tar_download_path, 'wb') as f: + f.write(data) + + # Extract the tar to update folder + logging.info('Extracting file: ' + tar_download_path) + tar = tarfile.open(tar_download_path) + tar.extractall(update_dir) + tar.close() + + # Delete the tar.gz + logging.info('Deleting file: ' + tar_download_path) + os.remove(tar_download_path) + + # Find update dir name + update_dir_contents = [x for x in os.listdir(update_dir) if os.path.isdir(os.path.join(update_dir, x))] + if len(update_dir_contents) != 1: + logging.error("Invalid update data, update failed: " + str(update_dir_contents)) + return + content_dir = os.path.join(update_dir, update_dir_contents[0]) + + # walk temp folder and move files to main folder + for dirname, dirnames, filenames in os.walk(content_dir): + dirname = dirname[len(content_dir) + 1:] + for curfile in filenames: + old_path = os.path.join(content_dir, dirname, curfile) + new_path = os.path.join(os.path.dirname(__file__), '..', dirname, curfile) + + if os.path.isfile(new_path): + os.remove(new_path) + os.renames(old_path, new_path) + + def checkout_git_branch(self): + if self.INSTALL_TYPE == 'git' and not args.release_update: + output, err = self.runGit('fetch origin') + output, err = self.runGit('checkout %s' % settings.general.branch) + + if not output: + logging.error('Unable to change git branch.') + return + + for line in output.split('\n'): + if line.endswith(('Aborting', 'Aborting.')): + logging.error('Unable to checkout from git: ' + line) + logging.info('Output: ' + str(output)) + + output, err = self.runGit('pull origin %s' % settings.general.branch) def request_content(url, **kwargs): diff --git a/bazarr/get_args.py b/bazarr/get_args.py index b55a2cf49..2f4bec9fe 100644 --- a/bazarr/get_args.py +++ b/bazarr/get_args.py @@ -19,6 +19,8 @@ def get_args(): help="Disable update functionality (default: False)") parser.add_argument('--debug', default=False, type=bool, const=True, metavar="BOOL", nargs="?", help="Enable console debugging (default: False)") + parser.add_argument('--release-update', default=False, type=bool, const=True, metavar="BOOL", nargs="?", + help="Enable file based updater (default: False)") return parser.parse_args() diff --git a/bazarr/main.py b/bazarr/main.py index 2b0d65a91..2efa50f6b 100644 --- a/bazarr/main.py +++ b/bazarr/main.py @@ -58,7 +58,7 @@ from get_series import * from get_episodes import * if not args.no_update: - from check_update import check_updates + from check_update import Updater from list_subtitles import store_subtitles, store_subtitles_movie, series_scan_subtitles, movies_scan_subtitles, \ list_missing_subtitles, list_missing_subtitles_movies from get_subtitle import download_subtitle, series_download_subtitles, movies_download_subtitles, \ diff --git a/bazarr/scheduler.py b/bazarr/scheduler.py index ccbf20d07..c07bbbe42 100644 --- a/bazarr/scheduler.py +++ b/bazarr/scheduler.py @@ -8,7 +8,7 @@ from get_subtitle import wanted_search_missing_subtitles, upgrade_subtitles from get_args import args if not args.no_update: - from check_update import check_updates, check_releases + from check_update import Updater, check_releases else: from check_update import check_releases from apscheduler.schedulers.background import BackgroundScheduler @@ -84,10 +84,10 @@ scheduler.add_listener(task_listener, EVENT_JOB_SUBMITTED | EVENT_JOB_EXECUTED) if not args.no_update: if settings.general.getboolean('auto_update'): - scheduler.add_job(check_updates, IntervalTrigger(hours=6), max_instances=1, coalesce=True, - misfire_grace_time=15, id='update_bazarr', name='Update bazarr from source on Github') + scheduler.add_job(Updater().check_updates, IntervalTrigger(hours=6), max_instances=1, coalesce=True, + misfire_grace_time=15, id='update_bazarr', name='Update bazarr from source on Github') else: - scheduler.add_job(check_updates, CronTrigger(year='2100'), hour=4, id='update_bazarr', + scheduler.add_job(Updater().check_updates, CronTrigger(year='2100'), hour=4, id='update_bazarr', name='Update bazarr from source on Github') scheduler.add_job(check_releases, IntervalTrigger(hours=6), max_instances=1, coalesce=True, misfire_grace_time=15, id='update_release', name='Update release info') diff --git a/views/menu.tpl b/views/menu.tpl index 4dfdc9f1b..02cfe3176 100644 --- a/views/menu.tpl +++ b/views/menu.tpl @@ -148,7 +148,44 @@ % elif restart_required[0] == '1':