import urllib.error
import time
import subprocess
+import sys
from argparse import ArgumentParser
import traceback
-from html.parser import HTMLParser
+import html
from distutils.version import LooseVersion
import logging
import copy
+import urllib.parse
+from . import _
from . import common
from . import metadata
-from .exception import VCSException, FDroidException, MetaDataException
+from .exception import VCSException, NoSubmodulesException, FDroidException, MetaDataException
# Check for a new version by looking at a document retrieved via HTTP.
raise FDroidException('Missing Update Check Data')
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:
last_build = app.get_last_build()
- if last_build.submodules:
- vcs.initsubmodules()
+ try_init_submodules(app, last_build, vcs)
hpak = None
htag = None
if len(app.builds) > 0:
last_build = app.builds[-1]
- if last_build.submodules:
- vcs.initsubmodules()
+ try_init_submodules(app, last_build, vcs)
hpak = None
hver = None
m = re.search('itemprop="softwareVersion">[ ]*([^<]+)[ ]*</div>', page)
if m:
- html_parser = 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')
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
msg = 'Invalid update check method'
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))
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: <code>" + ' '.join(sys.argv) + "</code>\n"
+ 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():
# Parse command line...
parser = ArgumentParser(usage="%(prog)s [options] [APPID [APPID ...]]")
common.setup_global_opts(parser)
- parser.add_argument("appid", nargs='*', help="app-id to check for updates")
+ 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 appid, app in apps.items():
+ gplaylog += '* ' + appid + '\n'
version, reason = check_gplay(app)
if version is None:
if reason == '404':
else:
logging.info("{0} has the same version {1} on the Play Store"
.format(common.getappname(app), version))
+ update_wiki(gplaylog, None)
return
+ locallog = ''
for appid, app in apps.items():
if options.autoonly and app.AutoUpdateMode in ('None', 'Static'):
- logging.debug("Nothing to do for {0}...".format(appid))
+ 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:
- logging.error("...checkupdate failed for {0} : {1}".format(appid, e))
+ msg = _("...checkupdate failed for {appid} : {error}").format(appid=appid, error=e)
+ logging.error(msg)
+ locallog += msg + '\n'
+
+ update_wiki(None, locallog)
- logging.info("Finished.")
+ logging.info(_("Finished"))
if __name__ == "__main__":