chiark / gitweb /
checkupdates: use html.unescape instead of HTMLParser.unescape
[fdroidserver.git] / fdroidserver / checkupdates.py
index b617ea9aa12d7e13a1a44851dfc75e560ca82526..217139d19a956fb052d5ac5f5365e89615ba5f49 100644 (file)
@@ -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
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-import sys
 import os
 import re
-import urllib2
+import urllib.request
+import urllib.error
 import time
 import subprocess
 from argparse import ArgumentParser
 import traceback
-import HTMLParser
+import html
 from distutils.version import LooseVersion
 import logging
 import copy
 
-import common
-import metadata
-from common import VCSException, FDroidException
-from metadata import MetaDataException
+from . import common
+from . import metadata
+from .exception import VCSException, FDroidException, MetaDataException
 
 
 # Check for a new version by looking at a document retrieved via HTTP.
@@ -52,22 +50,22 @@ def check_http(app):
         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:
@@ -109,9 +107,7 @@ def check_tags(app, pattern):
 
         vcs.gotorevision(None)
 
-        last_build = metadata.Build()
-        if len(app.builds) > 0:
-            last_build = app.builds[-1]
+        last_build = app.get_last_build()
 
         if last_build.submodules:
             vcs.initsubmodules()
@@ -121,7 +117,11 @@ def check_tags(app, pattern):
         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)
 
@@ -133,8 +133,8 @@ def check_tags(app, pattern):
                 return (None, "No matching tags found", None)
             logging.debug("Matching tags: " + ','.join(tags))
 
-        if len(tags) > 5 and 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:
@@ -241,7 +241,7 @@ def check_repomanifest(app, branch=None):
         return (None, msg)
 
 
-def check_repotrunk(app, branch=None):
+def check_repotrunk(app):
 
     try:
         if app.RepoType == 'srclib':
@@ -276,11 +276,11 @@ def check_gplay(app):
     time.sleep(15)
     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 as 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 as e:
         return (None, 'Failed:' + str(e))
@@ -289,8 +289,7 @@ def check_gplay(app):
 
     m = re.search('itemprop="softwareVersion">[ ]*([^<]+)[ ]*</div>', 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')
@@ -318,9 +317,7 @@ def possible_subdirs(app):
     else:
         build_dir = os.path.join('build', app.id)
 
-    last_build = metadata.Build()
-    if len(app.builds) > 0:
-        last_build = app.builds[-1]
+    last_build = app.get_last_build()
 
     for d in dirs_with_manifest(build_dir):
         m_paths = common.manifest_paths(d, last_build.gradle)
@@ -347,9 +344,7 @@ def fetch_autoname(app, tag):
     except VCSException:
         return None
 
-    last_build = metadata.Build()
-    if len(app.builds) > 0:
-        last_build = app.builds[-1]
+    last_build = app.get_last_build()
 
     logging.debug("...fetch auto name from " + build_dir)
     new_name = None
@@ -374,7 +369,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.
@@ -434,6 +429,8 @@ def checkupdates_app(app, first=True):
     elif vercode == app.CurrentVersionCode:
         logging.info("...up to date")
     else:
+        logging.debug("...updating - old vercode={0}, new vercode={1}".format(
+            app.CurrentVersionCode, vercode))
         app.CurrentVersion = version
         app.CurrentVersionCode = str(int(vercode))
         updating = True
@@ -448,7 +445,9 @@ def checkupdates_app(app, first=True):
 
     if options.auto:
         mode = app.AutoUpdateMode
-        if mode in ('None', 'Static'):
+        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:]
@@ -462,22 +461,22 @@ def checkupdates_app(app, first=True):
             gotcur = False
             latest = None
             for build in app.builds:
-                if int(build.vercode) >= int(app.CurrentVersionCode):
+                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.vercode) > int(app.CurrentVersionCode):
+            if int(latest.versionCode) > int(app.CurrentVersionCode):
                 logging.info("Refusing to auto update, since the latest build is newer")
 
             if not gotcur:
                 newbuild = copy.deepcopy(latest)
                 newbuild.disable = False
-                newbuild.vercode = app.CurrentVersionCode
-                newbuild.version = app.CurrentVersion + suffix
-                logging.info("...auto-generating build for " + newbuild.version)
-                commit = pattern.replace('%v', newbuild.version)
-                commit = commit.replace('%c', newbuild.vercode)
+                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)
@@ -488,8 +487,7 @@ def checkupdates_app(app, first=True):
 
     if commitmsg:
         metadatapath = os.path.join('metadata', app.id + '.txt')
-        with open(metadatapath, 'w') as f:
-            metadata.write_metadata('txt', f, app)
+        metadata.write_metadata(metadatapath, app)
         if options.commit:
             logging.info("Commiting update for " + metadatapath)
             gitcmd = ["git", "commit", "-m", commitmsg]
@@ -497,8 +495,7 @@ 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")
 
 
 config = None
@@ -521,7 +518,9 @@ def main():
                         help="Commit changes")
     parser.add_argument("--gplay", action="store_true", default=False,
                         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)
 
@@ -531,7 +530,7 @@ def main():
     apps = common.read_app_args(options.appid, allapps, False)
 
     if options.gplay:
-        for app in apps:
+        for appid, app in apps.items():
             version, reason = check_gplay(app)
             if version is None:
                 if reason == '404':
@@ -555,7 +554,7 @@ def main():
                                      .format(common.getappname(app), version))
         return
 
-    for appid, app in apps.iteritems():
+    for appid, app in apps.items():
 
         if options.autoonly and app.AutoUpdateMode in ('None', 'Static'):
             logging.debug("Nothing to do for {0}...".format(appid))
@@ -563,9 +562,13 @@ def main():
 
         logging.info("Processing " + appid + '...')
 
-        checkupdates_app(app)
+        try:
+            checkupdates_app(app)
+        except Exception as e:
+            logging.error("...checkupdate failed for {0} : {1}".format(appid, e))
 
     logging.info("Finished.")
 
+
 if __name__ == "__main__":
     main()