diff --git a/MANIFEST.in b/MANIFEST.in index fd5eb862..0a24f98b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -803,6 +803,7 @@ include tests/source-files/firebase-allowlisted/app/build.gradle include tests/source-files/firebase-allowlisted/build.gradle include tests/source-files/firebase-suspect/app/build.gradle include tests/source-files/firebase-suspect/build.gradle +include tests/source-files/flavor.test/build.gradle include tests/source-files/info.guardianproject.ripple/build.gradle include tests/source-files/lockfile.test/flutter/.dart_tool/flutter_gen/pubspec.yaml include tests/source-files/lockfile.test/flutter/pubspec.lock diff --git a/fdroidserver/build.py b/fdroidserver/build.py index 6593ff0c..8a59c771 100644 --- a/fdroidserver/build.py +++ b/fdroidserver/build.py @@ -541,13 +541,13 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext if build.preassemble: gradletasks += build.preassemble - flavours = build.gradle - if flavours == ['yes']: - flavours = [] + flavors = build.gradle + if flavors == ['yes']: + flavors = [] - flavours_cmd = ''.join([transform_first_char(flav, str.upper) for flav in flavours]) + flavors_cmd = ''.join([transform_first_char(flav, str.upper) for flav in flavors]) - gradletasks += ['assemble' + flavours_cmd + 'Release'] + gradletasks += ['assemble' + flavors_cmd + 'Release'] cmd = [config['gradle']] if build.gradleprops: @@ -763,11 +763,11 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext # really old path os.path.join(root_dir, 'build', 'apk'), ] - # If we build with gradle flavours with gradle plugin >= 3.0 the APK will be in - # a subdirectory corresponding to the flavour command used, but with different + # If we build with gradle flavors with gradle plugin >= 3.0 the APK will be in + # a subdirectory corresponding to the flavor command used, but with different # capitalization. - if flavours_cmd: - apk_dirs.append(os.path.join(root_dir, 'build', 'outputs', 'apk', transform_first_char(flavours_cmd, str.lower), 'release')) + if flavors_cmd: + apk_dirs.append(os.path.join(root_dir, 'build', 'outputs', 'apk', transform_first_char(flavors_cmd, str.lower), 'release')) for apks_dir in apk_dirs: for apkglob in ['*-release-unsigned.apk', '*-unsigned.apk', '*.apk']: apks = glob.glob(os.path.join(apks_dir, apkglob)) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 175c7f63..9b395ad6 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -58,6 +58,7 @@ from typing import List import git import glob import io +import itertools import os import sys import re @@ -1987,7 +1988,7 @@ def retrieve_string_singleline(app_dir, string, xmlfiles=None): return retrieve_string(app_dir, string, xmlfiles).replace('\n', ' ').strip() -def manifest_paths(app_dir, flavours): +def manifest_paths(app_dir, flavors): """Return list of existing files that will be used to find the highest vercode.""" possible_manifests = \ [Path(app_dir) / 'AndroidManifest.xml', @@ -1997,18 +1998,18 @@ def manifest_paths(app_dir, flavours): Path(app_dir) / 'build-extras.gradle', Path(app_dir) / 'build.gradle.kts'] - for flavour in flavours: - if flavour == 'yes': + for flavor in flavors: + if flavor == 'yes': continue possible_manifests.append( - Path(app_dir) / 'src' / flavour / 'AndroidManifest.xml') + Path(app_dir) / 'src' / flavor / 'AndroidManifest.xml') return [path for path in possible_manifests if path.is_file()] -def fetch_real_name(app_dir, flavours): +def fetch_real_name(app_dir, flavors): """Retrieve the package name. Returns the name, or None if not found.""" - for path in manifest_paths(app_dir, flavours): + for path in manifest_paths(app_dir, flavors): if not path.suffix == '.xml' or not path.is_file(): continue logging.debug("fetch_real_name: Checking manifest at %s" % path) @@ -2126,17 +2127,17 @@ def parse_androidmanifests(paths, app): vercode = None package = None - flavours = None + flavors = None temp_app_id = None temp_version_name = None if len(app.get('Builds', [])) > 0 and 'gradle' in app['Builds'][-1] and app['Builds'][-1].gradle: - flavours = app['Builds'][-1].gradle + flavors = app['Builds'][-1].gradle if path.suffix == '.gradle' or path.name.endswith('.gradle.kts'): with open(path, 'r', encoding='utf-8') as f: android_plugin_file = False - inside_flavour_group = 0 - inside_required_flavour = 0 + inside_flavor_group = 0 + inside_required_flavor = 0 for line in f: if gradle_comment.match(line): continue @@ -2151,8 +2152,8 @@ def parse_androidmanifests(paths, app): if matches: temp_version_name = matches - if inside_flavour_group > 0: - if inside_required_flavour > 1: + if inside_flavor_group > 0: + if inside_required_flavor > 1: matches = psearch_g(line) if matches: s = matches.group(2) @@ -2182,29 +2183,29 @@ def parse_androidmanifests(paths, app): if matches: vercode = version_code_string_to_int(matches.group(1)) - if inside_required_flavour > 0: + if inside_required_flavor > 0: if '{' in line: - inside_required_flavour += 1 + inside_required_flavor += 1 if '}' in line: - inside_required_flavour -= 1 - if inside_required_flavour == 1: - inside_required_flavour -= 1 - elif flavours: - for flavour in flavours: - if re.match(r'.*[\'"\s]{flavour}[\'"\s].*\{{.*'.format(flavour=flavour), line): - inside_required_flavour = 2 + inside_required_flavor -= 1 + if inside_required_flavor == 1: + inside_required_flavor -= 1 + elif flavors: + for flavor in flavors: + if re.match(r'.*[\'"\s]{flavor}[\'"\s].*\{{.*'.format(flavor=flavor), line): + inside_required_flavor = 2 break - if re.match(r'.*[\'"\s]{flavour}[\'"\s].*'.format(flavour=flavour), line): - inside_required_flavour = 1 + if re.match(r'.*[\'"\s]{flavor}[\'"\s].*'.format(flavor=flavor), line): + inside_required_flavor = 1 break if '{' in line: - inside_flavour_group += 1 + inside_flavor_group += 1 if '}' in line: - inside_flavour_group -= 1 + inside_flavor_group -= 1 else: if "productFlavors" in line: - inside_flavour_group = 1 + inside_flavor_group = 1 if not package: matches = psearch_g(line) if matches: @@ -2548,9 +2549,9 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver= with open(path, 'w', encoding='iso-8859-1') as f: f.write(props) - flavours = [] + flavors = [] if build.build_method() == 'gradle': - flavours = build.gradle + flavors = build.gradle if build.target: n = build.target.split('-')[1] @@ -2572,7 +2573,7 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver= # Insert version code and number into the manifest if necessary if build.forceversion: logging.info("Changing the version name") - for path in manifest_paths(root_dir, flavours): + for path in manifest_paths(root_dir, flavors): if not os.path.isfile(path): continue if path.suffix == '.xml': @@ -2586,7 +2587,7 @@ def prepare_source(vcs, app, build, build_dir, srclib_dir, extlib_dir, onserver= if build.forcevercode: logging.info("Changing the version code") - for path in manifest_paths(root_dir, flavours): + for path in manifest_paths(root_dir, flavors): if not path.is_file(): continue if path.suffix == '.xml': @@ -4823,6 +4824,20 @@ def calculate_archive_policy(app, default): return archive_policy +def calculate_gradle_flavor_combination(flavors): + """Calculate all combinations of gradle flavors.""" + combination_lists = itertools.product(*[[flavor, ''] for flavor in flavors]) + combinations = [ + re.sub( + r' +\w', + lambda pat: pat.group(0)[-1].upper(), + ' '.join(combination_list).strip(), + ) + for combination_list in combination_lists + ] + return combinations + + FDROIDORG_MIRRORS = [ { 'isPrimary': True, diff --git a/fdroidserver/looseversion.py b/fdroidserver/looseversion.py index 0c785d69..c2a32213 100644 --- a/fdroidserver/looseversion.py +++ b/fdroidserver/looseversion.py @@ -115,7 +115,7 @@ __license__ = "Python License 2.0" # been done in the StrictVersion class above. This works great as long # as everyone can go along with bondage and discipline. Hopefully a # (large) subset of Python module programmers will agree that the -# particular flavour of bondage and discipline provided by StrictVersion +# particular flavor of bondage and discipline provided by StrictVersion # provides enough benefit to be worth using, and will submit their # version numbering scheme to its domination. The free-thinking # anarchists in the lot will never give in, though, and something needs diff --git a/fdroidserver/scanner.py b/fdroidserver/scanner.py index c6cd57a0..3de65d33 100644 --- a/fdroidserver/scanner.py +++ b/fdroidserver/scanner.py @@ -270,9 +270,10 @@ def get_gradle_compile_commands(build): 'runtimeOnly', ] buildTypes = ['', 'release'] - flavors = [''] if build.gradle and build.gradle != ['yes']: - flavors += build.gradle + flavors = common.calculate_gradle_flavor_combination(build.gradle) + else: + flavors = [''] return [''.join(c) for c in itertools.product(flavors, buildTypes, compileCommands)] diff --git a/fdroidserver/update.py b/fdroidserver/update.py index 2fa0c532..e25a5209 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -1179,17 +1179,20 @@ def insert_localized_app_metadata(apps): locale = segments[-1] destdir = os.path.join('repo', packageName, locale) - # flavours specified in build receipt - build_flavours = "" + # flavors specified in build receipt + build_flavors = [] if ( apps[packageName] and len(apps[packageName].get('Builds', [])) > 0 and 'gradle' in apps[packageName]['Builds'][-1] + and apps[packageName]['Builds'][-1]['gradle'] != ['yes'] ): - build_flavours = apps[packageName]['Builds'][-1]['gradle'] + build_flavors = common.calculate_gradle_flavor_combination( + apps[packageName]['Builds'][-1]['gradle'] + ) - if len(segments) >= 5 and segments[4] == "fastlane" and segments[3] not in build_flavours: - logging.debug("ignoring due to wrong flavour") + if len(segments) >= 5 and segments[4] == "fastlane" and segments[3] not in build_flavors: + logging.debug("ignoring due to wrong flavor") continue for f in files: diff --git a/tests/source-files/flavor.test/build.gradle b/tests/source-files/flavor.test/build.gradle new file mode 100644 index 00000000..2c958bdc --- /dev/null +++ b/tests/source-files/flavor.test/build.gradle @@ -0,0 +1,15 @@ +dependenies { + /// dependencies for app building + fossImplementation 'com.android.support:multidex:1.0.2' + implementation 'com.github.nextcloud:android-library:1.0.33' + devImplementation 'com.github.nextcloud:android-library:master-SNAPSHOT' // use always latest master + implementation "com.android.support:support-v4:${supportLibraryVersion}" + prodImplementation "com.android.support:design:${supportLibraryVersion}" + gplayImplementation 'com.jakewharton:disklrucache:2.0.2' + implementation "com.android.support:appcompat-v7:${supportLibraryVersion}" + gplayProdImplementation "com.android.support:cardview-v7:${supportLibraryVersion}" + implementation "com.android.support:exifinterface:${supportLibraryVersion}" + fossDevImplementation 'com.github.tobiasKaminsky:android-floating-action-button:1.10.2' + gplayDevImplementation 'com.github.albfernandez:juniversalchardet:v2.0.0' + fossProdImplementation 'com.google.code.findbugs:annotations:2.0.1' +} diff --git a/tests/test_common.py b/tests/test_common.py index 521905aa..c8d10045 100755 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -3040,6 +3040,11 @@ class CommonTest(SetUpTearDownMixin, unittest.TestCase): p = fdroidserver.common.FDroidPopen(['printenv', 'SOURCE_DATE_EPOCH']) self.assertEqual(int(p.output), int(now.timestamp())) + def test_calculate_gradle_flavor_combination(self): + flavors = ['aa', 'BB', 'δδ'] + combinations = ['aaBBΔδ', 'aaBB', 'aaΔδ', 'aa', 'BBΔδ', 'BB', 'δδ', ''] + self.assertEqual(fdroidserver.common.calculate_gradle_flavor_combination(flavors), combinations) + APKS_WITH_JAR_SIGNATURES = ( ( diff --git a/tests/test_scanner.py b/tests/test_scanner.py index 82f48d35..3515e858 100755 --- a/tests/test_scanner.py +++ b/tests/test_scanner.py @@ -107,12 +107,16 @@ class ScannerTest(unittest.TestCase): ('source-files/eu.siacs.conversations/build.gradle', 'free', 21), ('source-files/org.mozilla.rocket/app/build.gradle', 'focus', 40), ('source-files/com.jens.automation2/app/build.gradle', 'fdroidFlavor', 5), + ('source-files/flavor.test/build.gradle', ['foss', 'prod'], 7), ] for f, flavor, count in test_files: i = 0 build = fdroidserver.metadata.Build() - build.gradle = [flavor] + if isinstance(flavor, list): + build.gradle = flavor + else: + build.gradle = [flavor] regexs = fdroidserver.scanner.get_gradle_compile_commands_without_catalog( build )