mirror of
https://gitlab.com/fdroid/fdroidserver.git
synced 2024-11-14 02:50:12 +01:00
build: reuse common methods for getting metadata from APKs
This splits out the code that gets the list of native ABIs supported, then uses the standard methods for the rest.
This commit is contained in:
parent
487c4d02f3
commit
807bf3d26b
@ -42,7 +42,7 @@ from . import net
|
||||
from . import metadata
|
||||
from . import scanner
|
||||
from . import vmtools
|
||||
from .common import FDroidPopen, SdkToolsPopen
|
||||
from .common import FDroidPopen
|
||||
from .exception import FDroidException, BuildException, VCSException
|
||||
|
||||
try:
|
||||
@ -323,92 +323,28 @@ def transform_first_char(string, method):
|
||||
return method(string[0]) + string[1:]
|
||||
|
||||
|
||||
def has_native_code(apkobj):
|
||||
"""aapt checks if there are architecture folders under the lib/ folder
|
||||
so we are simulating the same behaviour"""
|
||||
arch_re = re.compile("^lib/(.*)/.*$")
|
||||
arch = [file for file in apkobj.get_files() if arch_re.match(file)]
|
||||
return False if not arch else True
|
||||
|
||||
|
||||
def get_apk_metadata_aapt(apkfile):
|
||||
"""aapt function to extract versionCode, versionName, packageName and nativecode"""
|
||||
vercode = None
|
||||
version = None
|
||||
foundid = None
|
||||
nativecode = None
|
||||
|
||||
p = SdkToolsPopen(['aapt', 'dump', 'badging', apkfile], output=False)
|
||||
|
||||
for line in p.output.splitlines():
|
||||
if line.startswith("package:"):
|
||||
pat = re.compile(".*name='([a-zA-Z0-9._]*)'.*")
|
||||
m = pat.match(line)
|
||||
if m:
|
||||
foundid = m.group(1)
|
||||
pat = re.compile(".*versionCode='([0-9]*)'.*")
|
||||
m = pat.match(line)
|
||||
if m:
|
||||
vercode = m.group(1)
|
||||
pat = re.compile(".*versionName='([^']*)'.*")
|
||||
m = pat.match(line)
|
||||
if m:
|
||||
version = m.group(1)
|
||||
elif line.startswith("native-code:"):
|
||||
nativecode = line[12:]
|
||||
|
||||
return vercode, version, foundid, nativecode
|
||||
|
||||
|
||||
def get_apk_metadata_androguard(apkfile):
|
||||
"""androguard function to extract versionCode, versionName, packageName and nativecode"""
|
||||
try:
|
||||
from androguard.core.bytecodes.apk import APK
|
||||
apkobject = APK(apkfile)
|
||||
except ImportError:
|
||||
raise BuildException("androguard library is not installed and aapt binary not found")
|
||||
except FileNotFoundError:
|
||||
raise BuildException("Could not open apk file for metadata analysis")
|
||||
|
||||
if not apkobject.is_valid_APK():
|
||||
raise BuildException("Invalid APK provided")
|
||||
|
||||
foundid = apkobject.get_package()
|
||||
vercode = apkobject.get_androidversion_code()
|
||||
version = apkobject.get_androidversion_name()
|
||||
nativecode = has_native_code(apkobject)
|
||||
|
||||
return vercode, version, foundid, nativecode
|
||||
|
||||
|
||||
def get_metadata_from_apk(app, build, apkfile):
|
||||
"""get the required metadata from the built APK"""
|
||||
"""get the required metadata from the built APK
|
||||
|
||||
if common.SdkToolsPopen(['aapt', 'version'], output=False):
|
||||
vercode, version, foundid, nativecode = get_apk_metadata_aapt(apkfile)
|
||||
else:
|
||||
vercode, version, foundid, nativecode = get_apk_metadata_androguard(apkfile)
|
||||
versionName is allowed to be a blank string, i.e. ''
|
||||
"""
|
||||
|
||||
# Ignore empty strings or any kind of space/newline chars that we don't
|
||||
# care about
|
||||
if nativecode is not None:
|
||||
nativecode = nativecode.strip()
|
||||
nativecode = None if not nativecode else nativecode
|
||||
appid, versionCode, versionName = common.get_apk_id(apkfile)
|
||||
native_code = common.get_native_code(apkfile)
|
||||
|
||||
if build.buildjni and build.buildjni != ['no']:
|
||||
if nativecode is None:
|
||||
raise BuildException("Native code should have been built but none was packaged")
|
||||
if build.buildjni and build.buildjni != ['no'] and not native_code:
|
||||
raise BuildException("Native code should have been built but none was packaged")
|
||||
if build.novcheck:
|
||||
vercode = build.versionCode
|
||||
version = build.versionName
|
||||
if not version or not vercode:
|
||||
versionCode = build.versionCode
|
||||
versionName = build.versionName
|
||||
if not versionCode or versionName is None:
|
||||
raise BuildException("Could not find version information in build in output")
|
||||
if not foundid:
|
||||
if not appid:
|
||||
raise BuildException("Could not find package ID in output")
|
||||
if foundid != app.id:
|
||||
raise BuildException("Wrong package ID - build " + foundid + " but expected " + app.id)
|
||||
if appid != app.id:
|
||||
raise BuildException("Wrong package ID - build " + appid + " but expected " + app.id)
|
||||
|
||||
return vercode, version
|
||||
return versionCode, versionName
|
||||
|
||||
|
||||
def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, extlib_dir, tmp_dir, force, onserver, refresh):
|
||||
|
@ -2128,6 +2128,19 @@ def get_apk_id_aapt(apkfile):
|
||||
.format(apkfilename=apkfile))
|
||||
|
||||
|
||||
def get_native_code(apkfile):
|
||||
"""aapt checks if there are architecture folders under the lib/ folder
|
||||
so we are simulating the same behaviour"""
|
||||
arch_re = re.compile("^lib/(.*)/.*$")
|
||||
archset = set()
|
||||
with ZipFile(apkfile) as apk:
|
||||
for filename in apk.namelist():
|
||||
m = arch_re.match(filename)
|
||||
if m:
|
||||
archset.add(m.group(1))
|
||||
return sorted(list(archset))
|
||||
|
||||
|
||||
def get_minSdkVersion_aapt(apkfile):
|
||||
"""Extract the minimum supported Android SDK from an APK using aapt
|
||||
|
||||
|
@ -20,6 +20,7 @@ if localmodule not in sys.path:
|
||||
|
||||
import fdroidserver.build
|
||||
import fdroidserver.common
|
||||
import fdroidserver.metadata
|
||||
|
||||
|
||||
class BuildTest(unittest.TestCase):
|
||||
@ -71,6 +72,55 @@ class BuildTest(unittest.TestCase):
|
||||
filedata = f.read()
|
||||
self.assertIsNotNone(pattern.search(filedata))
|
||||
|
||||
def test_get_apk_metadata(self):
|
||||
config = dict()
|
||||
fdroidserver.common.fill_config_defaults(config)
|
||||
fdroidserver.common.config = config
|
||||
fdroidserver.build.config = config
|
||||
self._set_build_tools()
|
||||
try:
|
||||
config['aapt'] = fdroidserver.common.find_sdk_tools_cmd('aapt')
|
||||
except fdroidserver.exception.FDroidException:
|
||||
pass # aapt is not required if androguard is present
|
||||
|
||||
testcases = [
|
||||
('repo/obb.main.twoversions_1101613.apk', 'obb.main.twoversions', '1101613', '0.1', None),
|
||||
('org.bitbucket.tickytacky.mirrormirror_1.apk', 'org.bitbucket.tickytacky.mirrormirror', '1', '1.0', None),
|
||||
('org.bitbucket.tickytacky.mirrormirror_2.apk', 'org.bitbucket.tickytacky.mirrormirror', '2', '1.0.1', None),
|
||||
('org.bitbucket.tickytacky.mirrormirror_3.apk', 'org.bitbucket.tickytacky.mirrormirror', '3', '1.0.2', None),
|
||||
('org.bitbucket.tickytacky.mirrormirror_4.apk', 'org.bitbucket.tickytacky.mirrormirror', '4', '1.0.3', None),
|
||||
('org.dyndns.fules.ck_20.apk', 'org.dyndns.fules.ck', '20', 'v1.6pre2',
|
||||
['arm64-v8a', 'armeabi', 'armeabi-v7a', 'mips', 'mips64', 'x86', 'x86_64']),
|
||||
('urzip.apk', 'info.guardianproject.urzip', '100', '0.1', None),
|
||||
('urzip-badcert.apk', 'info.guardianproject.urzip', '100', '0.1', None),
|
||||
('urzip-badsig.apk', 'info.guardianproject.urzip', '100', '0.1', None),
|
||||
('urzip-release.apk', 'info.guardianproject.urzip', '100', '0.1', None),
|
||||
('urzip-release-unsigned.apk', 'info.guardianproject.urzip', '100', '0.1', None),
|
||||
('repo/com.politedroid_3.apk', 'com.politedroid', '3', '1.2', None),
|
||||
('repo/com.politedroid_4.apk', 'com.politedroid', '4', '1.3', None),
|
||||
('repo/com.politedroid_5.apk', 'com.politedroid', '5', '1.4', None),
|
||||
('repo/com.politedroid_6.apk', 'com.politedroid', '6', '1.5', None),
|
||||
('repo/duplicate.permisssions_9999999.apk', 'duplicate.permisssions', '9999999', '', None),
|
||||
('repo/info.zwanenburg.caffeinetile_4.apk', 'info.zwanenburg.caffeinetile', '4', '1.3', None),
|
||||
('repo/obb.main.oldversion_1444412523.apk', 'obb.main.oldversion', '1444412523', '0.1', None),
|
||||
('repo/obb.mainpatch.current_1619_another-release-key.apk', 'obb.mainpatch.current', '1619', '0.1', None),
|
||||
('repo/obb.mainpatch.current_1619.apk', 'obb.mainpatch.current', '1619', '0.1', None),
|
||||
('repo/obb.main.twoversions_1101613.apk', 'obb.main.twoversions', '1101613', '0.1', None),
|
||||
('repo/obb.main.twoversions_1101615.apk', 'obb.main.twoversions', '1101615', '0.1', None),
|
||||
('repo/obb.main.twoversions_1101617.apk', 'obb.main.twoversions', '1101617', '0.1', None),
|
||||
('repo/urzip-; Рахма́, [rɐxˈmanʲɪnəf] سيرجي_رخمانينوف 谢·.apk', 'info.guardianproject.urzip', '100', '0.1', None),
|
||||
]
|
||||
for apkfilename, appid, versionCode, versionName, nativecode in testcases:
|
||||
app = fdroidserver.metadata.App()
|
||||
app.id = appid
|
||||
build = fdroidserver.metadata.Build()
|
||||
build.buildjni = ['yes'] if nativecode else build.buildjni
|
||||
build.versionCode = versionCode
|
||||
build.versionName = versionName
|
||||
vc, vn = fdroidserver.build.get_metadata_from_apk(app, build, apkfilename)
|
||||
self.assertEqual(versionCode, vc)
|
||||
self.assertEqual(versionName, vn)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.chdir(os.path.dirname(__file__))
|
||||
|
@ -636,6 +636,37 @@ class CommonTest(unittest.TestCase):
|
||||
else:
|
||||
self.fail('could not parse aapt output: {}'.format(f))
|
||||
|
||||
def test_get_native_code(self):
|
||||
testcases = [
|
||||
('repo/obb.main.twoversions_1101613.apk', []),
|
||||
('org.bitbucket.tickytacky.mirrormirror_1.apk', []),
|
||||
('org.bitbucket.tickytacky.mirrormirror_2.apk', []),
|
||||
('org.bitbucket.tickytacky.mirrormirror_3.apk', []),
|
||||
('org.bitbucket.tickytacky.mirrormirror_4.apk', []),
|
||||
('org.dyndns.fules.ck_20.apk', ['arm64-v8a', 'armeabi', 'armeabi-v7a', 'mips', 'mips64', 'x86', 'x86_64']),
|
||||
('urzip.apk', []),
|
||||
('urzip-badcert.apk', []),
|
||||
('urzip-badsig.apk', []),
|
||||
('urzip-release.apk', []),
|
||||
('urzip-release-unsigned.apk', []),
|
||||
('repo/com.politedroid_3.apk', []),
|
||||
('repo/com.politedroid_4.apk', []),
|
||||
('repo/com.politedroid_5.apk', []),
|
||||
('repo/com.politedroid_6.apk', []),
|
||||
('repo/duplicate.permisssions_9999999.apk', []),
|
||||
('repo/info.zwanenburg.caffeinetile_4.apk', []),
|
||||
('repo/obb.main.oldversion_1444412523.apk', []),
|
||||
('repo/obb.mainpatch.current_1619_another-release-key.apk', []),
|
||||
('repo/obb.mainpatch.current_1619.apk', []),
|
||||
('repo/obb.main.twoversions_1101613.apk', []),
|
||||
('repo/obb.main.twoversions_1101615.apk', []),
|
||||
('repo/obb.main.twoversions_1101617.apk', []),
|
||||
('repo/urzip-; Рахма́, [rɐxˈmanʲɪnəf] سيرجي_رخمانينوف 谢·.apk', []),
|
||||
]
|
||||
for apkfilename, native_code in testcases:
|
||||
nc = fdroidserver.common.get_native_code(apkfilename)
|
||||
self.assertEqual(native_code, nc)
|
||||
|
||||
def test_get_minSdkVersion_aapt(self):
|
||||
config = dict()
|
||||
fdroidserver.common.fill_config_defaults(config)
|
||||
|
Loading…
Reference in New Issue
Block a user