1
0
mirror of https://gitlab.com/fdroid/fdroidserver.git synced 2024-11-09 00:40:11 +01:00

Factor code for scanning a single APK out into its own method.

This allows projects using fdroidserver to scan individual APKs without
needing to re-scan all APKs present in a repository.
This commit is contained in:
Torsten Grote 2017-03-15 14:43:22 -03:00
parent 60f166b2c6
commit 04db6870d1
No known key found for this signature in database
GPG Key ID: 3E5F77D92CF891FF

View File

@ -52,6 +52,17 @@ from .metadata import MetaDataException
METADATA_VERSION = 18
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_SDK_VERSION_PAT = re.compile(".*'([0-9]*)'.*")
APK_PERMISSION_PAT = \
re.compile(".*(name='(?P<name>.*?)')(.*maxSdkVersion='(?P<maxSdkVersion>.*?)')?.*")
APK_FEATURE_PAT = re.compile(".*name='([^']*)'.*")
screen_densities = ['640', '480', '320', '240', '160', '120']
all_screen_densities = ['0'] + screen_densities
@ -716,49 +727,29 @@ def scan_repo_files(apkcache, repodir, knownapks, use_date_from_file=False):
return repo_files, cachechanged
def scan_apks(apkcache, repodir, knownapks, use_date_from_apk=False):
"""Scan the apks in the given repo directory.
def scan_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk):
"""Scan the apk with the given filename in the given repo directory.
This also extracts the icons.
:param apkcache: current apk cache information
:param apkfilename: the filename of the apk to scan
:param repodir: repo directory to scan
:param knownapks: known apks info
:param use_date_from_apk: use date from APK (instead of current date)
for newly added APKs
:returns: (apks, cachechanged) where apks is a list of apk information,
and cachechanged is True if the apkcache got changed.
:returns: (skip, apk, cachechanged) where skip is a boolean indicating whether to skip this apk,
apk is the scanned apk information, and cachechanged is True if the apkcache got changed.
"""
cachechanged = False
for icon_dir in get_all_icon_dirs(repodir):
if os.path.exists(icon_dir):
if options.clean:
shutil.rmtree(icon_dir)
os.makedirs(icon_dir)
else:
os.makedirs(icon_dir)
apks = []
name_pat = re.compile(".*name='([a-zA-Z0-9._]*)'.*")
vercode_pat = re.compile(".*versionCode='([0-9]*)'.*")
vername_pat = re.compile(".*versionName='([^']*)'.*")
label_pat = re.compile(".*label='(.*?)'(\n| [a-z]*?=).*")
icon_pat = re.compile(".*application-icon-([0-9]+):'([^']+?)'.*")
icon_pat_nodpi = re.compile(".*icon='([^']+?)'.*")
sdkversion_pat = re.compile(".*'([0-9]*)'.*")
permission_pat = re.compile(".*(name='(?P<name>.*?)')(.*maxSdkVersion='(?P<maxSdkVersion>.*?)')?.*")
feature_pat = re.compile(".*name='([^']*)'.*")
for apkfile in glob.glob(os.path.join(repodir, '*.apk')):
apkfilename = apkfile[len(repodir) + 1:]
if ' ' in apkfilename:
logging.critical("Spaces in filenames are not allowed.")
sys.exit(1)
apkfile = os.path.join(repodir, apkfilename)
shasum = sha256sum(apkfile)
cachechanged = False
usecache = False
if apkfilename in apkcache:
apk = apkcache[apkfilename]
@ -796,39 +787,39 @@ def scan_apks(apkcache, repodir, knownapks, use_date_from_apk=False):
logging.error("Could not find {0} to remove it".format(apkfile))
else:
logging.error("Failed to get apk information, skipping " + apkfile)
continue
return True
for line in p.output.splitlines():
if line.startswith("package:"):
try:
apk['packageName'] = re.match(name_pat, line).group(1)
apk['versionCode'] = int(re.match(vercode_pat, line).group(1))
apk['versionName'] = re.match(vername_pat, line).group(1)
apk['packageName'] = re.match(APK_NAME_PAT, line).group(1)
apk['versionCode'] = int(re.match(APK_VERCODE_PAT, line).group(1))
apk['versionName'] = re.match(APK_VERNAME_PAT, line).group(1)
except Exception as e:
logging.error("Package matching failed: " + str(e))
logging.info("Line was: " + line)
sys.exit(1)
elif line.startswith("application:"):
apk['name'] = re.match(label_pat, line).group(1)
apk['name'] = re.match(APK_LABEL_PAT, line).group(1)
# Keep path to non-dpi icon in case we need it
match = re.match(icon_pat_nodpi, line)
match = re.match(APK_ICON_PAT_NODPI, line)
if match:
apk['icons_src']['-1'] = match.group(1)
elif line.startswith("launchable-activity:"):
# Only use launchable-activity as fallback to application
if not apk['name']:
apk['name'] = re.match(label_pat, line).group(1)
apk['name'] = re.match(APK_LABEL_PAT, line).group(1)
if '-1' not in apk['icons_src']:
match = re.match(icon_pat_nodpi, line)
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(icon_pat, line)
match = re.match(APK_ICON_PAT, line)
if match:
density = match.group(1)
path = match.group(2)
apk['icons_src'][density] = path
elif line.startswith("sdkVersion:"):
m = re.match(sdkversion_pat, line)
m = re.match(APK_SDK_VERSION_PAT, line)
if m is None:
logging.error(line.replace('sdkVersion:', '')
+ ' is not a valid minSdkVersion!')
@ -838,20 +829,20 @@ def scan_apks(apkcache, repodir, knownapks, use_date_from_apk=False):
if 'targetSdkVersion' not in apk:
apk['targetSdkVersion'] = m.group(1)
elif line.startswith("targetSdkVersion:"):
m = re.match(sdkversion_pat, line)
m = re.match(APK_SDK_VERSION_PAT, line)
if m is None:
logging.error(line.replace('targetSdkVersion:', '')
+ ' is not a valid targetSdkVersion!')
else:
apk['targetSdkVersion'] = m.group(1)
elif line.startswith("maxSdkVersion:"):
apk['maxSdkVersion'] = re.match(sdkversion_pat, line).group(1)
apk['maxSdkVersion'] = re.match(APK_SDK_VERSION_PAT, line).group(1)
elif line.startswith("native-code:"):
apk['nativecode'] = []
for arch in line[13:].split(' '):
apk['nativecode'].append(arch[1:-1])
elif line.startswith('uses-permission:'):
perm_match = re.match(permission_pat, line).groupdict()
perm_match = re.match(APK_PERMISSION_PAT, line).groupdict()
if perm_match['maxSdkVersion']:
perm_match['maxSdkVersion'] = int(perm_match['maxSdkVersion'])
permission = UsesPermission(
@ -861,7 +852,7 @@ def scan_apks(apkcache, repodir, knownapks, use_date_from_apk=False):
apk['uses-permission'].add(permission)
elif line.startswith('uses-permission-sdk-23:'):
perm_match = re.match(permission_pat, line).groupdict()
perm_match = re.match(APK_PERMISSION_PAT, line).groupdict()
if perm_match['maxSdkVersion']:
perm_match['maxSdkVersion'] = int(perm_match['maxSdkVersion'])
permission_sdk_23 = UsesPermissionSdk23(
@ -872,7 +863,7 @@ def scan_apks(apkcache, repodir, knownapks, use_date_from_apk=False):
apk['uses-permission-sdk-23'].add(permission_sdk_23)
elif line.startswith('uses-feature:'):
feature = re.match(feature_pat, line).group(1)
feature = re.match(APK_FEATURE_PAT, line).group(1)
# Filter out this, it's only added with the latest SDK tools and
# causes problems for lots of apps.
if feature != "android.hardware.screen.portrait" \
@ -1032,13 +1023,47 @@ def scan_apks(apkcache, repodir, knownapks, use_date_from_apk=False):
default_date_param = None
# Record in known apks, getting the added date at the same time..
added = knownapks.recordapk(apk['apkName'], apk['packageName'], default_date=default_date_param)
added = knownapks.recordapk(apk['apkName'], apk['packageName'],
default_date=default_date_param)
if added:
apk['added'] = added
apkcache[apkfilename] = apk
cachechanged = True
return False, apk, cachechanged
def scan_apks(apkcache, repodir, knownapks, use_date_from_apk=False):
"""Scan the apks in the given repo directory.
This also extracts the icons.
:param apkcache: current apk cache information
:param repodir: repo directory to scan
:param knownapks: known apks info
:param use_date_from_apk: use date from APK (instead of current date)
for newly added APKs
:returns: (apks, cachechanged) where apks is a list of apk information,
and cachechanged is True if the apkcache got changed.
"""
cachechanged = False
for icon_dir in get_all_icon_dirs(repodir):
if os.path.exists(icon_dir):
if options.clean:
shutil.rmtree(icon_dir)
os.makedirs(icon_dir)
else:
os.makedirs(icon_dir)
apks = []
for apkfile in glob.glob(os.path.join(repodir, '*.apk')):
apkfilename = apkfile[len(repodir) + 1:]
(skip, apk, cachechanged) = scan_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk)
if skip:
continue
apks.append(apk)
return apks, cachechanged