X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=fdroidserver%2Fcheckupdates.py;h=72c8b22b4fa3407542e9fc55404e3a0985ffe530;hb=70d9633555ba07b4bb83dfd7dcda9781cc80cf51;hp=0e68c97c9249c37e8761e04832d39b3a76eeadf6;hpb=d23ecf1b359017e2cdd284f8b17d84be15807e3d;p=fdroidserver.git diff --git a/fdroidserver/checkupdates.py b/fdroidserver/checkupdates.py index 0e68c97c..72c8b22b 100644 --- a/fdroidserver/checkupdates.py +++ b/fdroidserver/checkupdates.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- +#!/usr/bin/env python3 # # checkupdates.py - part of the FDroid server tools # Copyright (C) 2010-2015, Ciaran Gultnieks, ciaran@ciarang.com @@ -18,22 +17,25 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import sys import os import re -import urllib2 +import urllib.request +import urllib.error import time import subprocess +import sys from argparse import ArgumentParser import traceback -import HTMLParser +import html from distutils.version import LooseVersion import logging +import copy +import urllib.parse -import common -import metadata -from common import VCSException, FDroidException -from metadata import MetaDataException +from . import _ +from . import common +from . import metadata +from .exception import VCSException, NoSubmodulesException, FDroidException, MetaDataException # Check for a new version by looking at a document retrieved via HTTP. @@ -43,30 +45,37 @@ def check_http(app): try: - if 'Update Check Data' not in app: + if not app.UpdateCheckData: raise FDroidException('Missing Update Check Data') - urlcode, codeex, urlver, verex = app['Update Check Data'].split('|') + urlcode, codeex, urlver, verex = app.UpdateCheckData.split('|') + parsed = urllib.parse.urlparse(urlcode) + if not parsed.netloc or not parsed.scheme or parsed.scheme != 'https': + raise FDroidException(_('UpdateCheckData has invalid URL: {url}').format(url=urlcode)) + if urlver != '.': + parsed = urllib.parse.urlparse(urlver) + if not parsed.netloc or not parsed.scheme or parsed.scheme != 'https': + raise FDroidException(_('UpdateCheckData has invalid URL: {url}').format(url=urlcode)) vercode = "99999999" if len(urlcode) > 0: logging.debug("...requesting {0}".format(urlcode)) - req = urllib2.Request(urlcode, None) - resp = urllib2.urlopen(req, None, 20) - page = resp.read() + req = urllib.request.Request(urlcode, None) + resp = urllib.request.urlopen(req, None, 20) + page = resp.read().decode('utf-8') m = re.search(codeex, page) if not m: raise FDroidException("No RE match for version code") - vercode = m.group(1) + vercode = m.group(1).strip() version = "??" if len(urlver) > 0: if urlver != '.': logging.debug("...requesting {0}".format(urlver)) - req = urllib2.Request(urlver, None) - resp = urllib2.urlopen(req, None, 20) - page = resp.read() + req = urllib.request.Request(urlver, None) + resp = urllib.request.urlopen(req, None, 20) + page = resp.read().decode('utf-8') m = re.search(verex, page) if not m: @@ -76,19 +85,10 @@ def check_http(app): return (version, vercode) except FDroidException: - msg = "Could not complete http check for app {0} due to unknown error: {1}".format(app['id'], traceback.format_exc()) + msg = "Could not complete http check for app {0} due to unknown error: {1}".format(app.id, traceback.format_exc()) return (None, msg) -def app_matches_packagename(app, package): - if not package: - return False - appid = app['Update Check Name'] or app['id'] - if appid == "Ignore": - return True - return appid == package - - # Check for a new version by looking at the tags in the source repo. # Whether this can be used reliably or not depends on # the development procedures used by the project's developers. Use it with @@ -99,65 +99,72 @@ def check_tags(app, pattern): try: - if app['Repo Type'] == 'srclib': - build_dir = os.path.join('build', 'srclib', app['Repo']) - repotype = common.getsrclibvcs(app['Repo']) + if app.RepoType == 'srclib': + build_dir = os.path.join('build', 'srclib', app.Repo) + repotype = common.getsrclibvcs(app.Repo) else: - build_dir = os.path.join('build/', app['id']) - repotype = app['Repo Type'] + build_dir = os.path.join('build', app.id) + repotype = app.RepoType if repotype not in ('git', 'git-svn', 'hg', 'bzr'): return (None, 'Tags update mode only works for git, hg, bzr and git-svn repositories currently', None) - if repotype == 'git-svn' and ';' not in app['Repo']: + if repotype == 'git-svn' and ';' not in app.Repo: return (None, 'Tags update mode used in git-svn, but the repo was not set up with tags', None) # Set up vcs interface and make sure we have the latest code... - vcs = common.getvcs(app['Repo Type'], app['Repo'], build_dir) + vcs = common.getvcs(app.RepoType, app.Repo, build_dir) vcs.gotorevision(None) - flavours = [] - if len(app['builds']) > 0: - if app['builds'][-1]['subdir']: - build_dir = os.path.join(build_dir, app['builds'][-1]['subdir']) - if app['builds'][-1]['gradle']: - flavours = app['builds'][-1]['gradle'] + last_build = app.get_last_build() + + try_init_submodules(app, last_build, vcs) hpak = None htag = None hver = None hcode = "0" - tags = vcs.gettags() + tags = [] + if repotype == 'git': + tags = vcs.latesttags() + else: + tags = vcs.gettags() + if not tags: + return (None, "No tags found", None) + logging.debug("All tags: " + ','.join(tags)) if pattern: pat = re.compile(pattern) tags = [tag for tag in tags if pat.match(tag)] + if not tags: + return (None, "No matching tags found", None) logging.debug("Matching tags: " + ','.join(tags)) - if repotype in ('git',): - tags = vcs.latesttags(tags, 5) + if len(tags) > 5 and repotype == 'git': + tags = tags[:5] logging.debug("Latest tags: " + ','.join(tags)) for tag in tags: logging.debug("Check tag: '{0}'".format(tag)) vcs.gotorevision(tag) - # Only process tags where the manifest exists... - paths = common.manifest_paths(build_dir, flavours) - version, vercode, package = \ - common.parse_androidmanifests(paths, app['Update Check Ignore']) - if not app_matches_packagename(app, package) or not version or not vercode: - continue - - logging.debug("Manifest exists. Found version {0} ({1})" - .format(version, vercode)) - if int(vercode) > int(hcode): - hpak = package - htag = tag - hcode = str(int(vercode)) - hver = version + for subdir in possible_subdirs(app): + if subdir == '.': + root_dir = build_dir + else: + root_dir = os.path.join(build_dir, subdir) + paths = common.manifest_paths(root_dir, last_build.gradle) + version, vercode, package = common.parse_androidmanifests(paths, app) + if vercode: + logging.debug("Manifest exists in subdir '{0}'. Found version {1} ({2})" + .format(subdir, version, vercode)) + if int(vercode) > int(hcode): + hpak = package + htag = tag + hcode = str(int(vercode)) + hver = version if not hpak: return (None, "Couldn't find package ID", None) @@ -166,10 +173,10 @@ def check_tags(app, pattern): return (None, "Couldn't find any version information", None) except VCSException as vcse: - msg = "VCS error while scanning app {0}: {1}".format(app['id'], vcse) + msg = "VCS error while scanning app {0}: {1}".format(app.id, vcse) return (None, msg, None) except Exception: - msg = "Could not scan app {0} due to unknown error: {1}".format(app['id'], traceback.format_exc()) + msg = "Could not scan app {0} due to unknown error: {1}".format(app.id, traceback.format_exc()) return (None, msg, None) @@ -183,15 +190,15 @@ def check_repomanifest(app, branch=None): try: - if app['Repo Type'] == 'srclib': - build_dir = os.path.join('build', 'srclib', app['Repo']) - repotype = common.getsrclibvcs(app['Repo']) + if app.RepoType == 'srclib': + build_dir = os.path.join('build', 'srclib', app.Repo) + repotype = common.getsrclibvcs(app.Repo) else: - build_dir = os.path.join('build/', app['id']) - repotype = app['Repo Type'] + build_dir = os.path.join('build', app.id) + repotype = app.RepoType # Set up vcs interface and make sure we have the latest code... - vcs = common.getvcs(app['Repo Type'], app['Repo'], build_dir) + vcs = common.getvcs(app.RepoType, app.Repo, build_dir) if repotype == 'git': if branch: @@ -204,70 +211,69 @@ def check_repomanifest(app, branch=None): elif repotype == 'bzr': vcs.gotorevision(None) - flavours = [] - if len(app['builds']) > 0: - if app['builds'][-1]['subdir']: - build_dir = os.path.join(build_dir, app['builds'][-1]['subdir']) - if app['builds'][-1]['gradle']: - flavours = app['builds'][-1]['gradle'] + last_build = metadata.Build() + if len(app.builds) > 0: + last_build = app.builds[-1] - if not os.path.isdir(build_dir): - return (None, "Subdir '" + app['builds'][-1]['subdir'] + "'is not a valid directory") + try_init_submodules(app, last_build, vcs) - paths = common.manifest_paths(build_dir, flavours) + hpak = None + hver = None + hcode = "0" + for subdir in possible_subdirs(app): + if subdir == '.': + root_dir = build_dir + else: + root_dir = os.path.join(build_dir, subdir) + paths = common.manifest_paths(root_dir, last_build.gradle) + version, vercode, package = common.parse_androidmanifests(paths, app) + if vercode: + logging.debug("Manifest exists in subdir '{0}'. Found version {1} ({2})" + .format(subdir, version, vercode)) + if int(vercode) > int(hcode): + hpak = package + hcode = str(int(vercode)) + hver = version - version, vercode, package = \ - common.parse_androidmanifests(paths, app['Update Check Ignore']) - if not package: + if not hpak: return (None, "Couldn't find package ID") - if not app_matches_packagename(app, package): - return (None, "Package ID mismatch - got {0}".format(package)) - if not version: - return (None, "Couldn't find latest version name") - if not vercode: - if "Ignore" == version: - return (None, "Latest version is ignored") - return (None, "Couldn't find latest version code") - - vercode = str(int(vercode)) - - logging.debug("Manifest exists. Found version {0} ({1})".format(version, vercode)) - - return (version, vercode) + if hver: + return (hver, hcode) + return (None, "Couldn't find any version information") except VCSException as vcse: - msg = "VCS error while scanning app {0}: {1}".format(app['id'], vcse) + msg = "VCS error while scanning app {0}: {1}".format(app.id, vcse) return (None, msg) except Exception: - msg = "Could not scan app {0} due to unknown error: {1}".format(app['id'], traceback.format_exc()) + msg = "Could not scan app {0} due to unknown error: {1}".format(app.id, traceback.format_exc()) return (None, msg) -def check_repotrunk(app, branch=None): +def check_repotrunk(app): try: - if app['Repo Type'] == 'srclib': - build_dir = os.path.join('build', 'srclib', app['Repo']) - repotype = common.getsrclibvcs(app['Repo']) + if app.RepoType == 'srclib': + build_dir = os.path.join('build', 'srclib', app.Repo) + repotype = common.getsrclibvcs(app.Repo) else: - build_dir = os.path.join('build/', app['id']) - repotype = app['Repo Type'] + build_dir = os.path.join('build', app.id) + repotype = app.RepoType if repotype not in ('git-svn', ): return (None, 'RepoTrunk update mode only makes sense in git-svn repositories') # Set up vcs interface and make sure we have the latest code... - vcs = common.getvcs(app['Repo Type'], app['Repo'], build_dir) + vcs = common.getvcs(app.RepoType, app.Repo, build_dir) vcs.gotorevision(None) ref = vcs.getref() return (ref, ref) except VCSException as vcse: - msg = "VCS error while scanning app {0}: {1}".format(app['id'], vcse) + msg = "VCS error while scanning app {0}: {1}".format(app.id, vcse) return (None, msg) except Exception: - msg = "Could not scan app {0} due to unknown error: {1}".format(app['id'], traceback.format_exc()) + msg = "Could not scan app {0} due to unknown error: {1}".format(app.id, traceback.format_exc()) return (None, msg) @@ -276,23 +282,22 @@ def check_repotrunk(app, branch=None): # the details of the current version. def check_gplay(app): time.sleep(15) - url = 'https://play.google.com/store/apps/details?id=' + app['id'] + url = 'https://play.google.com/store/apps/details?id=' + app.id headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux i686; rv:18.0) Gecko/20100101 Firefox/18.0'} - req = urllib2.Request(url, None, headers) + req = urllib.request.Request(url, None, headers) try: - resp = urllib2.urlopen(req, None, 20) - page = resp.read() - except urllib2.HTTPError, e: + resp = urllib.request.urlopen(req, None, 20) + page = resp.read().decode() + except urllib.error.HTTPError as e: return (None, str(e.code)) - except Exception, e: + except Exception as e: return (None, 'Failed:' + str(e)) version = None m = re.search('itemprop="softwareVersion">[ ]*([^<]+)[ ]*', page) if m: - html_parser = HTMLParser.HTMLParser() - version = html_parser.unescape(m.group(1)) + version = html.unescape(m.group(1)) if version == 'Varies with device': return (None, 'Device-variable version, cannot use this method') @@ -302,72 +307,81 @@ def check_gplay(app): return (version.strip(), None) +def try_init_submodules(app, last_build, vcs): + """Try to init submodules if the last build entry used them. + They might have been removed from the app's repo in the meantime, + so if we can't find any submodules we continue with the updates check. + If there is any other error in initializing them then we stop the check. + """ + if last_build.submodules: + try: + vcs.initsubmodules() + except NoSubmodulesException: + logging.info("No submodules present for {}".format(app.Name)) + + # Return all directories under startdir that contain any of the manifest # files, and thus are probably an Android project. def dirs_with_manifest(startdir): - for r, d, f in os.walk(startdir): - if any(m in f for m in [ + for root, dirs, files in os.walk(startdir): + if any(m in files for m in [ 'AndroidManifest.xml', 'pom.xml', 'build.gradle']): - yield r + yield root # Tries to find a new subdir starting from the root build_dir. Returns said # subdir relative to the build dir if found, None otherwise. -def check_changed_subdir(app): +def possible_subdirs(app): - if app['Repo Type'] == 'srclib': - build_dir = os.path.join('build', 'srclib', app['Repo']) + if app.RepoType == 'srclib': + build_dir = os.path.join('build', 'srclib', app.Repo) else: - build_dir = os.path.join('build/', app['id']) - - if not os.path.isdir(build_dir): - return None + build_dir = os.path.join('build', app.id) - flavours = [] - if len(app['builds']) > 0 and app['builds'][-1]['gradle']: - flavours = app['builds'][-1]['gradle'] + last_build = app.get_last_build() for d in dirs_with_manifest(build_dir): - logging.debug("Trying possible dir %s." % d) - m_paths = common.manifest_paths(d, flavours) - package = common.parse_androidmanifests(m_paths, app['Update Check Ignore'])[2] - if app_matches_packagename(app, package): - logging.debug("Manifest exists in possible dir %s." % d) - return os.path.relpath(d, build_dir) - - return None + m_paths = common.manifest_paths(d, last_build.gradle) + package = common.parse_androidmanifests(m_paths, app)[2] + if package is not None: + subdir = os.path.relpath(d, build_dir) + logging.debug("Adding possible subdir %s" % subdir) + yield subdir def fetch_autoname(app, tag): - if not app["Repo Type"] or app['Update Check Mode'] in ('None', 'Static'): + if not app.RepoType or app.UpdateCheckMode in ('None', 'Static'): return None - if app['Repo Type'] == 'srclib': - app_dir = os.path.join('build', 'srclib', app['Repo']) + if app.RepoType == 'srclib': + build_dir = os.path.join('build', 'srclib', app.Repo) else: - app_dir = os.path.join('build/', app['id']) + build_dir = os.path.join('build', app.id) try: - vcs = common.getvcs(app["Repo Type"], app["Repo"], app_dir) + vcs = common.getvcs(app.RepoType, app.Repo, build_dir) vcs.gotorevision(tag) except VCSException: return None - flavours = [] - if len(app['builds']) > 0: - if app['builds'][-1]['subdir']: - app_dir = os.path.join(app_dir, app['builds'][-1]['subdir']) - if app['builds'][-1]['gradle']: - flavours = app['builds'][-1]['gradle'] + last_build = app.get_last_build() - logging.debug("...fetch auto name from " + app_dir) - new_name = common.fetch_real_name(app_dir, flavours) + logging.debug("...fetch auto name from " + build_dir) + new_name = None + for subdir in possible_subdirs(app): + if subdir == '.': + root_dir = build_dir + else: + root_dir = os.path.join(build_dir, subdir) + new_name = common.fetch_real_name(root_dir, last_build.gradle) + if new_name is not None: + break commitmsg = None if new_name: logging.debug("...got autoname '" + new_name + "'") - if new_name != app['Auto Name']: - app['Auto Name'] = new_name + if new_name != app.AutoName: + app.AutoName = new_name if not commitmsg: commitmsg = "Set autoname of {0}".format(common.getappname(app)) else: @@ -376,7 +390,7 @@ def fetch_autoname(app, tag): return commitmsg -def checkupdates_app(app, first=True): +def checkupdates_app(app): # If a change is made, commitmsg should be set to a description of it. # Only if this is set will changes be written back to the metadata. @@ -386,10 +400,12 @@ def checkupdates_app(app, first=True): msg = None vercode = None noverok = False - mode = app['Update Check Mode'] + mode = app.UpdateCheckMode if mode.startswith('Tags'): pattern = mode[5:] if len(mode) > 4 else None (version, vercode, tag) = check_tags(app, pattern) + if version == 'Unknown': + version = tag msg = vercode elif mode == 'RepoManifest': (version, vercode) = check_repomanifest(app) @@ -412,37 +428,35 @@ def checkupdates_app(app, first=True): version = None msg = 'Invalid update check method' - if first and version is None and vercode == "Couldn't find package ID": - logging.warn("Couldn't find any version information. Looking for a subdir change...") - new_subdir = check_changed_subdir(app) - if new_subdir is None: - logging.warn("Couldn't find any new subdir.") - else: - logging.warn("Trying a new subdir: %s" % new_subdir) - new_build = {} - metadata.fill_build_defaults(new_build) - new_build['version'] = "Ignore" - new_build['vercode'] = "-1" - new_build['subdir'] = new_subdir - app['builds'].append(new_build) - return checkupdates_app(app, first=False) - - if version and vercode and app['Vercode Operation']: - op = app['Vercode Operation'].replace("%c", str(int(vercode))) + if version and vercode and app.VercodeOperation: + if not common.VERCODE_OPERATION_RE.match(app.VercodeOperation): + raise MetaDataException(_('Invalid VercodeOperation: {field}') + .format(field=app.VercodeOperation)) + oldvercode = str(int(vercode)) + op = app.VercodeOperation.replace("%c", oldvercode) vercode = str(eval(op)) + logging.debug("Applied vercode operation: %s -> %s" % (oldvercode, vercode)) + + if version and any(version.startswith(s) for s in [ + '${', # Gradle variable names + '@string/', # Strings we could not resolve + ]): + version = "Unknown" updating = False if version is None: - logmsg = "...{0} : {1}".format(app['id'], msg) + logmsg = "...{0} : {1}".format(app.id, msg) if noverok: logging.info(logmsg) else: logging.warn(logmsg) - elif vercode == app['Current Version Code']: + elif vercode == app.CurrentVersionCode: logging.info("...up to date") else: - app['Current Version'] = version - app['Current Version Code'] = str(int(vercode)) + logging.debug("...updating - old vercode={0}, new vercode={1}".format( + app.CurrentVersionCode, vercode)) + app.CurrentVersion = version + app.CurrentVersionCode = str(int(vercode)) updating = True commitmsg = fetch_autoname(app, tag) @@ -454,8 +468,10 @@ def checkupdates_app(app, first=True): commitmsg = 'Update CV of %s to %s' % (name, ver) if options.auto: - mode = app['Auto Update Mode'] - if mode in ('None', 'Static'): + mode = app.AutoUpdateMode + if not app.CurrentVersionCode: + logging.warn("Can't auto-update app with no current version code: " + app.id) + elif mode in ('None', 'Static'): pass elif mode.startswith('Version '): pattern = mode[8:] @@ -468,32 +484,33 @@ def checkupdates_app(app, first=True): suffix = '' gotcur = False latest = None - for build in app['builds']: - if build['vercode'] == app['Current Version Code']: + for build in app.builds: + if int(build.versionCode) >= int(app.CurrentVersionCode): gotcur = True - if not latest or int(build['vercode']) > int(latest['vercode']): + if not latest or int(build.versionCode) > int(latest.versionCode): latest = build + if int(latest.versionCode) > int(app.CurrentVersionCode): + logging.info("Refusing to auto update, since the latest build is newer") + if not gotcur: - newbuild = latest.copy() - if 'origlines' in newbuild: - del newbuild['origlines'] - newbuild['disable'] = False - newbuild['vercode'] = app['Current Version Code'] - newbuild['version'] = app['Current Version'] + suffix - logging.info("...auto-generating build for " + newbuild['version']) - commit = pattern.replace('%v', newbuild['version']) - commit = commit.replace('%c', newbuild['vercode']) - newbuild['commit'] = commit - app['builds'].append(newbuild) + newbuild = copy.deepcopy(latest) + newbuild.disable = False + newbuild.versionCode = app.CurrentVersionCode + newbuild.versionName = app.CurrentVersion + suffix + logging.info("...auto-generating build for " + newbuild.versionName) + commit = pattern.replace('%v', newbuild.versionName) + commit = commit.replace('%c', newbuild.versionCode) + newbuild.commit = commit + app.builds.append(newbuild) name = common.getappname(app) ver = common.getcvname(app) commitmsg = "Update %s to %s" % (name, ver) else: - logging.warn('Invalid auto update mode "' + mode + '" on ' + app['id']) + logging.warn('Invalid auto update mode "' + mode + '" on ' + app.id) if commitmsg: - metadatapath = os.path.join('metadata', app['id'] + '.txt') + metadatapath = os.path.join('metadata', app.id + '.txt') metadata.write_metadata(metadatapath, app) if options.commit: logging.info("Commiting update for " + metadatapath) @@ -502,12 +519,44 @@ def checkupdates_app(app, first=True): gitcmd.extend(['--author', config['auto_author']]) gitcmd.extend(["--", metadatapath]) if subprocess.call(gitcmd) != 0: - logging.error("Git commit failed") - sys.exit(1) + raise FDroidException("Git commit failed") + + +def update_wiki(gplaylog, locallog): + if config.get('wiki_server') and config.get('wiki_path'): + try: + import mwclient + site = mwclient.Site((config['wiki_protocol'], config['wiki_server']), + path=config['wiki_path']) + site.login(config['wiki_user'], config['wiki_password']) + + # Write a page with the last build log for this version code + wiki_page_path = 'checkupdates_' + time.strftime('%s', start_timestamp) + newpage = site.Pages[wiki_page_path] + txt = '' + txt += "* command line: " + ' '.join(sys.argv) + "\n" + txt += common.get_git_describe_link() + txt += "* started at " + common.get_wiki_timestamp(start_timestamp) + '\n' + txt += "* completed at " + common.get_wiki_timestamp() + '\n' + txt += "\n\n" + txt += common.get_android_tools_version_log() + txt += "\n\n" + if gplaylog: + txt += '== --gplay check ==\n\n' + txt += gplaylog + if locallog: + txt += '== local source check ==\n\n' + txt += locallog + newpage.save(txt, summary='Run log') + newpage = site.Pages['checkupdates'] + newpage.save('#REDIRECT [[' + wiki_page_path + ']]', summary='Update redirect') + except Exception as e: + logging.error(_('Error while attempting to publish log: %s') % e) config = None options = None +start_timestamp = time.gmtime() def main(): @@ -516,30 +565,39 @@ def main(): # Parse command line... parser = ArgumentParser(usage="%(prog)s [options] [APPID [APPID ...]]") - parser.add_argument("appid", nargs='*', help="app-id to check for updates") - parser.add_argument("-v", "--verbose", action="store_true", default=False, - help="Spew out even more information than normal") - parser.add_argument("-q", "--quiet", action="store_true", default=False, - help="Restrict output to warnings and errors") + common.setup_global_opts(parser) + parser.add_argument("appid", nargs='*', help=_("applicationId to check for updates")) parser.add_argument("--auto", action="store_true", default=False, - help="Process auto-updates") + help=_("Process auto-updates")) parser.add_argument("--autoonly", action="store_true", default=False, - help="Only process apps with auto-updates") + help=_("Only process apps with auto-updates")) parser.add_argument("--commit", action="store_true", default=False, - help="Commit changes") + help=_("Commit changes")) + parser.add_argument("--allow-dirty", action="store_true", default=False, + help=_("Run on git repo that has uncommitted changes")) parser.add_argument("--gplay", action="store_true", default=False, - help="Only print differences with the Play Store") + help=_("Only print differences with the Play Store")) + metadata.add_metadata_arguments(parser) options = parser.parse_args() + metadata.warnings_action = options.W config = common.read_config(options) + if not options.allow_dirty: + status = subprocess.check_output(['git', 'status', '--porcelain']) + if status: + logging.error(_('Build metadata git repo has uncommited changes!')) + sys.exit(1) + # Get all apps... allapps = metadata.read_metadata() apps = common.read_app_args(options.appid, allapps, False) + gplaylog = '' if options.gplay: - for app in apps: + for appid, app in apps.items(): + gplaylog += '* ' + appid + '\n' version, reason = check_gplay(app) if version is None: if reason == '404': @@ -547,7 +605,7 @@ def main(): else: logging.info("{0} encountered a problem: {1}".format(common.getappname(app), reason)) if version is not None: - stored = app['Current Version'] + stored = app.CurrentVersion if not stored: logging.info("{0} has no Current Version but has version {1} on the Play Store" .format(common.getappname(app), version)) @@ -561,19 +619,31 @@ def main(): else: logging.info("{0} has the same version {1} on the Play Store" .format(common.getappname(app), version)) + update_wiki(gplaylog, None) return - for appid, app in apps.iteritems(): + locallog = '' + for appid, app in apps.items(): - if options.autoonly and app['Auto Update Mode'] in ('None', 'Static'): - logging.debug("Nothing to do for {0}...".format(appid)) + if options.autoonly and app.AutoUpdateMode in ('None', 'Static'): + logging.debug(_("Nothing to do for {appid}.").format(appid=appid)) continue - logging.info("Processing " + appid + '...') + msg = _("Processing {appid}").format(appid=appid) + logging.info(msg) + locallog += '* ' + msg + '\n' + + try: + checkupdates_app(app) + except Exception as e: + msg = _("...checkupdate failed for {appid} : {error}").format(appid=appid, error=e) + logging.error(msg) + locallog += msg + '\n' + + update_wiki(None, locallog) - checkupdates_app(app) + logging.info(_("Finished")) - logging.info("Finished.") if __name__ == "__main__": main()