chiark / gitweb /
build/checkupdates/update: log current fdroiddata commit to wiki
[fdroidserver.git] / fdroidserver / update.py
index fc945670ae1f07fe72cc0682fd9a0144359bc190..c22ac0f32b70d6add7f64a2367a24ef0e6091761 100644 (file)
@@ -53,9 +53,7 @@ UNSET_VERSION_CODE = -0x100000000
 APK_NAME_PAT = re.compile(".*name='([a-zA-Z0-9._]*)'.*")
 APK_VERCODE_PAT = re.compile(".*versionCode='([0-9]*)'.*")
 APK_VERNAME_PAT = re.compile(".*versionName='([^']*)'.*")
-APK_LABEL_PAT = re.compile(".*label='(.*?)'(\n| [a-z]*?=).*")
-APK_ICON_PAT = re.compile(".*application-icon-([0-9]+):'([^']+?)'.*")
-APK_ICON_PAT_NODPI = re.compile(".*icon='([^']+?)'.*")
+APK_LABEL_ICON_PAT = re.compile(".*\s+label='(.*)'\s+icon='(.*)'")
 APK_SDK_VERSION_PAT = re.compile(".*'([0-9]*)'.*")
 APK_PERMISSION_PAT = \
     re.compile(".*(name='(?P<name>.*?)')(.*maxSdkVersion='(?P<maxSdkVersion>.*?)')?.*")
@@ -331,6 +329,7 @@ def update_wiki(apps, sortedids, apks):
     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 += common.get_git_describe_link()
     txt += "\n\n"
     txt += common.get_android_tools_version_log()
     newpage.save(txt, summary='Run log')
@@ -1049,11 +1048,9 @@ def scan_apk(apk_file):
         'antiFeatures': set(),
     }
 
-    try:
-        import androguard
-        androguard  # silence pyflakes
+    if common.use_androguard():
         scan_apk_androguard(apk, apk_file)
-    except ImportError:
+    else:
         scan_apk_aapt(apk, apk_file)
 
     # Get the signature, or rather the signing key fingerprints
@@ -1082,6 +1079,27 @@ def scan_apk(apk_file):
     return apk
 
 
+def _get_apk_icons_src(apkfile, icon_name):
+    """Extract the paths to the app icon in all available densities
+
+    """
+    icons_src = dict()
+    density_re = re.compile('^res/(.*)/' + icon_name + '\.(png|xml)$')
+    with zipfile.ZipFile(apkfile) as zf:
+        for filename in zf.namelist():
+            m = density_re.match(filename)
+            if m:
+                folder = m.group(1).split('-')
+                if len(folder) > 1:
+                    density = screen_resolutions[folder[1]]
+                else:
+                    density = '160'
+                icons_src[density] = m.group(0)
+    if icons_src.get('-1') is None:
+        icons_src['-1'] = icons_src['160']
+    return icons_src
+
+
 def scan_apk_aapt(apk, apkfile):
     p = SdkToolsPopen(['aapt', 'dump', 'badging', apkfile], output=False)
     if p.returncode != 0:
@@ -1094,6 +1112,7 @@ def scan_apk_aapt(apk, apkfile):
         else:
             logging.error(_("Failed to get apk information, skipping {path}").format(path=apkfile))
         raise BuildException(_("Invalid APK"))
+    icon_name = None
     for line in p.output.splitlines():
         if line.startswith("package:"):
             try:
@@ -1103,25 +1122,13 @@ def scan_apk_aapt(apk, apkfile):
             except Exception as e:
                 raise FDroidException("Package matching failed: " + str(e) + "\nLine was: " + line)
         elif line.startswith("application:"):
-            apk['name'] = re.match(APK_LABEL_PAT, line).group(1)
-            # Keep path to non-dpi icon in case we need it
-            match = re.match(APK_ICON_PAT_NODPI, line)
-            if match:
-                apk['icons_src']['-1'] = match.group(1)
-        elif line.startswith("launchable-activity:"):
+            m = re.match(APK_LABEL_ICON_PAT, line)
+            if m:
+                apk['name'] = m.group(1)
+                icon_name = os.path.splitext(os.path.basename(m.group(2)))[0]
+        elif not apk.get('name') and line.startswith("launchable-activity:"):
             # Only use launchable-activity as fallback to application
-            if not apk['name']:
-                apk['name'] = re.match(APK_LABEL_PAT, line).group(1)
-            if '-1' not in apk['icons_src']:
-                match = re.match(APK_ICON_PAT_NODPI, line)
-                if match:
-                    apk['icons_src']['-1'] = match.group(1)
-        elif line.startswith("application-icon-"):
-            match = re.match(APK_ICON_PAT, line)
-            if match:
-                density = match.group(1)
-                path = match.group(2)
-                apk['icons_src'][density] = path
+            apk['name'] = re.match(APK_LABEL_ICON_PAT, line).group(1)
         elif line.startswith("sdkVersion:"):
             m = re.match(APK_SDK_VERSION_PAT, line)
             if m is None:
@@ -1172,6 +1179,7 @@ def scan_apk_aapt(apk, apkfile):
                 if feature.startswith("android.feature."):
                     feature = feature[16:]
                 apk['features'].add(feature)
+    apk['icons_src'] = _get_apk_icons_src(apkfile, icon_name)
 
 
 def scan_apk_androguard(apk, apkfile):
@@ -1217,22 +1225,7 @@ def scan_apk_androguard(apk, apkfile):
 
     icon_id = int(apkobject.get_element("application", "icon").replace("@", "0x"), 16)
     icon_name = arsc.get_id(apk['packageName'], icon_id)[1]
-
-    density_re = re.compile("^res/(.*)/" + icon_name + ".*$")
-
-    for file in apkobject.get_files():
-        d_re = density_re.match(file)
-        if d_re:
-            folder = d_re.group(1).split('-')
-            if len(folder) > 1:
-                resolution = folder[1]
-            else:
-                resolution = 'mdpi'
-            density = screen_resolutions[resolution]
-            apk['icons_src'][density] = d_re.group(0)
-
-    if apk['icons_src'].get('-1') is None:
-        apk['icons_src']['-1'] = apk['icons_src']['160']
+    apk['icons_src'] = _get_apk_icons_src(apkfile, icon_name)
 
     arch_re = re.compile("^lib/(.*)/.*$")
     arch = set([arch_re.match(file).group(1) for file in apkobject.get_files() if arch_re.match(file)])
@@ -1251,6 +1244,12 @@ def scan_apk_androguard(apk, apkfile):
             maxSdkVersion
         )
         apk['uses-permission'].append(permission)
+    for name, maxSdkVersion in apkobject.get_uses_implied_permission_list():
+        permission = UsesPermission(
+            name,
+            maxSdkVersion
+        )
+        apk['uses-permission'].append(permission)
 
     for item in xml.findall('uses-permission-sdk-23'):
         name = str(item.attrib['{' + xml.nsmap['android'] + '}name'])
@@ -1268,7 +1267,9 @@ def scan_apk_androguard(apk, apkfile):
                 and feature != "android.hardware.screen.landscape":
             if feature.startswith("android.feature."):
                 feature = feature[16:]
-        apk['features'].append(feature)
+        required = item.attrib.get('{' + xml.nsmap['android'] + '}required')
+        if required is None or required == 'true':
+            apk['features'].append(feature)
 
 
 def process_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk=False,
@@ -1316,7 +1317,7 @@ def process_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk=Fal
             return True, None, False
 
         # Check for debuggable apks...
-        if common.isApkAndDebuggable(apkfile):
+        if common.is_apk_and_debuggable(apkfile):
             logging.warning('{0} is set to android:debuggable="true"'.format(apkfile))
 
         if options.rename_apks:
@@ -1516,9 +1517,9 @@ def extract_apk_icons(icon_filename, apk, apkzip, repo_dir):
                     if density in apk['icons']:
                         break
                     if density == screen_densities[-1] or dpi >= int(density):
-                        apk['icons'][density] = icon_filename
+                        apk['icons'][density] = icon_filename + icon_type
                         shutil.move(icon_path,
-                                    os.path.join(get_icon_dir(repo_dir, density), icon_filename))
+                                    os.path.join(get_icon_dir(repo_dir, density), icon_filename + icon_type))
                         empty_densities.remove(density)
                         break
             except Exception as e: