mirror of
				https://github.com/f-droid/fdroidserver.git
				synced 2025-11-04 14:30:30 +03:00 
			
		
		
		
	define "string map" type for new Anti-Features explanations
closes #683
This commit is contained in:
		
							parent
							
								
									6e62ea3614
								
							
						
					
					
						commit
						061ca38afd
					
				
					 27 changed files with 1188 additions and 194 deletions
				
			
		| 
						 | 
					@ -597,7 +597,14 @@ include tests/main.TestCase
 | 
				
			||||||
include tests/metadata/apk/info.guardianproject.urzip.yaml
 | 
					include tests/metadata/apk/info.guardianproject.urzip.yaml
 | 
				
			||||||
include tests/metadata/apk/org.dyndns.fules.ck.yaml
 | 
					include tests/metadata/apk/org.dyndns.fules.ck.yaml
 | 
				
			||||||
include tests/metadata/app.with.special.build.params.yml
 | 
					include tests/metadata/app.with.special.build.params.yml
 | 
				
			||||||
 | 
					include tests/metadata/app.with.special.build.params/en-US/antifeatures/50_Ads.txt
 | 
				
			||||||
 | 
					include tests/metadata/app.with.special.build.params/en-US/antifeatures/50_Tracking.txt
 | 
				
			||||||
 | 
					include tests/metadata/app.with.special.build.params/en-US/antifeatures/Ads.txt
 | 
				
			||||||
 | 
					include tests/metadata/app.with.special.build.params/en-US/antifeatures/NoSourceSince.txt
 | 
				
			||||||
 | 
					include tests/metadata/app.with.special.build.params/zh-CN/antifeatures/49_Tracking.txt
 | 
				
			||||||
 | 
					include tests/metadata/app.with.special.build.params/zh-CN/antifeatures/50_Ads.txt
 | 
				
			||||||
include tests/metadata/com.politedroid.yml
 | 
					include tests/metadata/com.politedroid.yml
 | 
				
			||||||
 | 
					include tests/metadata/dump/app.with.special.build.params.yaml
 | 
				
			||||||
include tests/metadata/dump/com.politedroid.yaml
 | 
					include tests/metadata/dump/com.politedroid.yaml
 | 
				
			||||||
include tests/metadata/dump/org.adaway.yaml
 | 
					include tests/metadata/dump/org.adaway.yaml
 | 
				
			||||||
include tests/metadata/dump/org.smssecure.smssecure.yaml
 | 
					include tests/metadata/dump/org.smssecure.smssecure.yaml
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -546,6 +546,13 @@ def package_metadata(app, repodir):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def convert_version(version, app, repodir):
 | 
					def convert_version(version, app, repodir):
 | 
				
			||||||
 | 
					    """Convert the internal representation of Builds: into index-v2 versions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    The diff algorithm of index-v2 uses null/None to mean a field to
 | 
				
			||||||
 | 
					    be removed, so this function handles any Nones that are in the
 | 
				
			||||||
 | 
					    metadata file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
    ver = {}
 | 
					    ver = {}
 | 
				
			||||||
    if "added" in version:
 | 
					    if "added" in version:
 | 
				
			||||||
        ver["added"] = convert_datetime(version["added"])
 | 
					        ver["added"] = convert_datetime(version["added"])
 | 
				
			||||||
| 
						 | 
					@ -555,7 +562,7 @@ def convert_version(version, app, repodir):
 | 
				
			||||||
    ver["file"] = {
 | 
					    ver["file"] = {
 | 
				
			||||||
        "name": "/{}".format(version["apkName"]),
 | 
					        "name": "/{}".format(version["apkName"]),
 | 
				
			||||||
        version["hashType"]: version["hash"],
 | 
					        version["hashType"]: version["hash"],
 | 
				
			||||||
        "size": version["size"]
 | 
					        "size": version["size"],
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ipfsCIDv1 = version.get("ipfsCIDv1")
 | 
					    ipfsCIDv1 = version.get("ipfsCIDv1")
 | 
				
			||||||
| 
						 | 
					@ -619,24 +626,14 @@ def convert_version(version, app, repodir):
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    manifest[en].append({"name": perm[0]})
 | 
					                    manifest[en].append({"name": perm[0]})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    antiFeatures = dict()
 | 
					    # index-v2 has only per-version antifeatures, not per package.
 | 
				
			||||||
    if "AntiFeatures" in app and app["AntiFeatures"]:
 | 
					    antiFeatures = app.get('AntiFeatures', {})
 | 
				
			||||||
        for antif in app["AntiFeatures"]:
 | 
					    for name, descdict in version.get('antiFeatures', dict()).items():
 | 
				
			||||||
            # TODO: get reasons from fdroiddata
 | 
					        antiFeatures[name] = descdict
 | 
				
			||||||
            # ver["antiFeatures"][antif] = {"en-US": "reason"}
 | 
					 | 
				
			||||||
            antiFeatures[antif] = dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if "antiFeatures" in version and version["antiFeatures"]:
 | 
					 | 
				
			||||||
        for antif in version["antiFeatures"]:
 | 
					 | 
				
			||||||
            # TODO: get reasons from fdroiddata
 | 
					 | 
				
			||||||
            # ver["antiFeatures"][antif] = {"en-US": "reason"}
 | 
					 | 
				
			||||||
            antiFeatures[antif] = dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if app.get("NoSourceSince"):
 | 
					 | 
				
			||||||
        antiFeatures["NoSourceSince"] = dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if antiFeatures:
 | 
					    if antiFeatures:
 | 
				
			||||||
        ver["antiFeatures"] = dict(sorted(antiFeatures.items()))
 | 
					        ver['antiFeatures'] = {
 | 
				
			||||||
 | 
					            k: dict(sorted(antiFeatures[k].items())) for k in sorted(antiFeatures)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if "versionCode" in version:
 | 
					    if "versionCode" in version:
 | 
				
			||||||
        if version["versionCode"] > app["CurrentVersionCode"]:
 | 
					        if version["versionCode"] > app["CurrentVersionCode"]:
 | 
				
			||||||
| 
						 | 
					@ -881,9 +878,8 @@ def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
 | 
				
			||||||
                for ikey, iname in sorted(lvalue.items()):
 | 
					                for ikey, iname in sorted(lvalue.items()):
 | 
				
			||||||
                    lordered[lkey][ikey] = iname
 | 
					                    lordered[lkey][ikey] = iname
 | 
				
			||||||
            app_dict['localized'] = lordered
 | 
					            app_dict['localized'] = lordered
 | 
				
			||||||
        antiFeatures = app_dict.get('antiFeatures', [])
 | 
					        # v1 uses a list of keys for Anti-Features
 | 
				
			||||||
        if apps[app_dict["packageName"]].get("NoSourceSince"):
 | 
					        antiFeatures = app_dict.get('antiFeatures', dict()).keys()
 | 
				
			||||||
            antiFeatures.append("NoSourceSince")
 | 
					 | 
				
			||||||
        if antiFeatures:
 | 
					        if antiFeatures:
 | 
				
			||||||
            app_dict['antiFeatures'] = sorted(set(antiFeatures))
 | 
					            app_dict['antiFeatures'] = sorted(set(antiFeatures))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -915,6 +911,9 @@ def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            if k in ('icon', 'icons', 'icons_src', 'ipfsCIDv1', 'name'):
 | 
					            if k in ('icon', 'icons', 'icons_src', 'ipfsCIDv1', 'name'):
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
 | 
					            if k == 'antiFeatures':
 | 
				
			||||||
 | 
					                d[k] = sorted(v.keys())
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
            d[k] = v
 | 
					            d[k] = v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    json_name = 'index-v1.json'
 | 
					    json_name = 'index-v1.json'
 | 
				
			||||||
| 
						 | 
					@ -1160,8 +1159,6 @@ def make_v0(apps, apks, repodir, repodict, requestsdict, fdroid_signing_key_fing
 | 
				
			||||||
        antiFeatures = list(app.AntiFeatures)
 | 
					        antiFeatures = list(app.AntiFeatures)
 | 
				
			||||||
        if 'antiFeatures' in apklist[0]:
 | 
					        if 'antiFeatures' in apklist[0]:
 | 
				
			||||||
            antiFeatures.extend(apklist[0]['antiFeatures'])
 | 
					            antiFeatures.extend(apklist[0]['antiFeatures'])
 | 
				
			||||||
        if app.get("NoSourceSince"):
 | 
					 | 
				
			||||||
            antiFeatures.append("NoSourceSince")
 | 
					 | 
				
			||||||
        if antiFeatures:
 | 
					        if antiFeatures:
 | 
				
			||||||
            afout = sorted(set(antiFeatures))
 | 
					            afout = sorted(set(antiFeatures))
 | 
				
			||||||
            addElementNonEmpty('antifeatures', ','.join(afout), doc, apel)
 | 
					            addElementNonEmpty('antifeatures', ','.join(afout), doc, apel)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -624,6 +624,17 @@ def check_app_field_types(app):
 | 
				
			||||||
                    fieldtype=v.__class__.__name__,
 | 
					                    fieldtype=v.__class__.__name__,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					        elif t == metadata.TYPE_STRINGMAP and not isinstance(v, dict):
 | 
				
			||||||
 | 
					            yield (
 | 
				
			||||||
 | 
					                _(
 | 
				
			||||||
 | 
					                    "{appid}: {field} must be a '{type}', but it is a '{fieldtype}'!"
 | 
				
			||||||
 | 
					                ).format(
 | 
				
			||||||
 | 
					                    appid=app.id,
 | 
				
			||||||
 | 
					                    field=field,
 | 
				
			||||||
 | 
					                    type='dict',
 | 
				
			||||||
 | 
					                    fieldtype=v.__class__.__name__,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def check_antiFeatures(app):
 | 
					def check_antiFeatures(app):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -114,7 +114,7 @@ class App(dict):
 | 
				
			||||||
        super().__init__()
 | 
					        super().__init__()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.Disabled = None
 | 
					        self.Disabled = None
 | 
				
			||||||
        self.AntiFeatures = []
 | 
					        self.AntiFeatures = dict()
 | 
				
			||||||
        self.Provides = None
 | 
					        self.Provides = None
 | 
				
			||||||
        self.Categories = []
 | 
					        self.Categories = []
 | 
				
			||||||
        self.License = 'Unknown'
 | 
					        self.License = 'Unknown'
 | 
				
			||||||
| 
						 | 
					@ -182,12 +182,13 @@ TYPE_SCRIPT = 5
 | 
				
			||||||
TYPE_MULTILINE = 6
 | 
					TYPE_MULTILINE = 6
 | 
				
			||||||
TYPE_BUILD = 7
 | 
					TYPE_BUILD = 7
 | 
				
			||||||
TYPE_INT = 8
 | 
					TYPE_INT = 8
 | 
				
			||||||
 | 
					TYPE_STRINGMAP = 9
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fieldtypes = {
 | 
					fieldtypes = {
 | 
				
			||||||
    'Description': TYPE_MULTILINE,
 | 
					    'Description': TYPE_MULTILINE,
 | 
				
			||||||
    'MaintainerNotes': TYPE_MULTILINE,
 | 
					    'MaintainerNotes': TYPE_MULTILINE,
 | 
				
			||||||
    'Categories': TYPE_LIST,
 | 
					    'Categories': TYPE_LIST,
 | 
				
			||||||
    'AntiFeatures': TYPE_LIST,
 | 
					    'AntiFeatures': TYPE_STRINGMAP,
 | 
				
			||||||
    'AllowedAPKSigningKeys': TYPE_LIST,
 | 
					    'AllowedAPKSigningKeys': TYPE_LIST,
 | 
				
			||||||
    'Builds': TYPE_BUILD,
 | 
					    'Builds': TYPE_BUILD,
 | 
				
			||||||
    'VercodeOperation': TYPE_LIST,
 | 
					    'VercodeOperation': TYPE_LIST,
 | 
				
			||||||
| 
						 | 
					@ -277,7 +278,7 @@ class Build(dict):
 | 
				
			||||||
        self.antcommands = []
 | 
					        self.antcommands = []
 | 
				
			||||||
        self.postbuild = ''
 | 
					        self.postbuild = ''
 | 
				
			||||||
        self.novcheck = False
 | 
					        self.novcheck = False
 | 
				
			||||||
        self.antifeatures = []
 | 
					        self.antifeatures = dict()
 | 
				
			||||||
        if copydict:
 | 
					        if copydict:
 | 
				
			||||||
            super().__init__(copydict)
 | 
					            super().__init__(copydict)
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
| 
						 | 
					@ -358,7 +359,7 @@ flagtypes = {
 | 
				
			||||||
    'forceversion': TYPE_BOOL,
 | 
					    'forceversion': TYPE_BOOL,
 | 
				
			||||||
    'forcevercode': TYPE_BOOL,
 | 
					    'forcevercode': TYPE_BOOL,
 | 
				
			||||||
    'novcheck': TYPE_BOOL,
 | 
					    'novcheck': TYPE_BOOL,
 | 
				
			||||||
    'antifeatures': TYPE_LIST,
 | 
					    'antifeatures': TYPE_STRINGMAP,
 | 
				
			||||||
    'timeout': TYPE_INT,
 | 
					    'timeout': TYPE_INT,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -649,8 +650,6 @@ def parse_metadata(metadatapath):
 | 
				
			||||||
    metadatapath = Path(metadatapath)
 | 
					    metadatapath = Path(metadatapath)
 | 
				
			||||||
    app = App()
 | 
					    app = App()
 | 
				
			||||||
    app.metadatapath = metadatapath.as_posix()
 | 
					    app.metadatapath = metadatapath.as_posix()
 | 
				
			||||||
    if metadatapath.stem != '.fdroid':
 | 
					 | 
				
			||||||
        app.id = metadatapath.stem
 | 
					 | 
				
			||||||
    if metadatapath.suffix == '.yml':
 | 
					    if metadatapath.suffix == '.yml':
 | 
				
			||||||
        with metadatapath.open('r', encoding='utf-8') as mf:
 | 
					        with metadatapath.open('r', encoding='utf-8') as mf:
 | 
				
			||||||
            app.update(parse_yaml_metadata(mf))
 | 
					            app.update(parse_yaml_metadata(mf))
 | 
				
			||||||
| 
						 | 
					@ -659,6 +658,10 @@ def parse_metadata(metadatapath):
 | 
				
			||||||
            _('Unknown metadata format: {path} (use: *.yml)').format(path=metadatapath)
 | 
					            _('Unknown metadata format: {path} (use: *.yml)').format(path=metadatapath)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if metadatapath.stem != '.fdroid':
 | 
				
			||||||
 | 
					        app.id = metadatapath.stem
 | 
				
			||||||
 | 
					        parse_localized_antifeatures(app)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if metadatapath.name != '.fdroid.yml' and app.Repo:
 | 
					    if metadatapath.name != '.fdroid.yml' and app.Repo:
 | 
				
			||||||
        build_dir = common.get_build_dir(app)
 | 
					        build_dir = common.get_build_dir(app)
 | 
				
			||||||
        metadata_in_repo = build_dir / '.fdroid.yml'
 | 
					        metadata_in_repo = build_dir / '.fdroid.yml'
 | 
				
			||||||
| 
						 | 
					@ -770,6 +773,116 @@ def parse_yaml_metadata(mf):
 | 
				
			||||||
    return yamldata
 | 
					    return yamldata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def parse_localized_antifeatures(app):
 | 
				
			||||||
 | 
					    """Read in localized Anti-Features files from the filesystem.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    To support easy integration with Weblate and other translation
 | 
				
			||||||
 | 
					    systems, there is a special type of metadata that can be
 | 
				
			||||||
 | 
					    maintained in a Fastlane-style directory layout, where each field
 | 
				
			||||||
 | 
					    is represented by a text file on directories that specified which
 | 
				
			||||||
 | 
					    app it belongs to, which locale, etc.  This function reads those
 | 
				
			||||||
 | 
					    in and puts them into the internal dict, to be merged with any
 | 
				
			||||||
 | 
					    related data that came from the metadata.yml file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This needs to be run after parse_yaml_metadata() since that
 | 
				
			||||||
 | 
					    normalizes the data structure.  Also, these values are lower
 | 
				
			||||||
 | 
					    priority than what comes from the metadata file. So this should
 | 
				
			||||||
 | 
					    not overwrite anything parse_yaml_metadata() puts into the App
 | 
				
			||||||
 | 
					    instance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    metadata/<Application ID>/<locale>/antifeatures/<Version Code>_<Anti-Feature>.txt
 | 
				
			||||||
 | 
					    metadata/<Application ID>/<locale>/antifeatures/<Anti-Feature>.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    └── metadata/
 | 
				
			||||||
 | 
					        └── <Application ID>/
 | 
				
			||||||
 | 
					            ├── en-US/
 | 
				
			||||||
 | 
					            │   └── antifeatures/
 | 
				
			||||||
 | 
					            │       ├── 123_Ads.txt       -> "includes ad lib"
 | 
				
			||||||
 | 
					            │       ├── 123_Tracking.txt  -> "standard suspects"
 | 
				
			||||||
 | 
					            │       └── NoSourceSince.txt -> "it vanished"
 | 
				
			||||||
 | 
					            │
 | 
				
			||||||
 | 
					            └── zh-CN/
 | 
				
			||||||
 | 
					                └── antifeatures/
 | 
				
			||||||
 | 
					                    └── 123_Ads.txt       -> "包括广告图书馆"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Gets parsed into the metadata data structure:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    AntiFeatures:
 | 
				
			||||||
 | 
					      NoSourceSince:
 | 
				
			||||||
 | 
					        en-US: it vanished
 | 
				
			||||||
 | 
					    Builds:
 | 
				
			||||||
 | 
					      - versionCode: 123
 | 
				
			||||||
 | 
					        antifeatures:
 | 
				
			||||||
 | 
					          Ads:
 | 
				
			||||||
 | 
					            en-US: includes ad lib
 | 
				
			||||||
 | 
					            zh-CN: 包括广告图书馆
 | 
				
			||||||
 | 
					          Tracking:
 | 
				
			||||||
 | 
					            en-US: standard suspects
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    app_dir = Path('metadata', app['id'])
 | 
				
			||||||
 | 
					    if not app_dir.is_dir():
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					    af_dup_msg = _('Duplicate Anti-Feature declaration at {path} was ignored!')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if app.get('AntiFeatures'):
 | 
				
			||||||
 | 
					        app_has_AntiFeatures = True
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        app_has_AntiFeatures = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    has_versionCode = re.compile(r'^-?[0-9]+_.*')
 | 
				
			||||||
 | 
					    has_antifeatures_from_app = set()
 | 
				
			||||||
 | 
					    for build in app.get('Builds', []):
 | 
				
			||||||
 | 
					        antifeatures = build.get('antifeatures')
 | 
				
			||||||
 | 
					        if antifeatures:
 | 
				
			||||||
 | 
					            has_antifeatures_from_app.add(build['versionCode'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for f in sorted(app_dir.glob('*/antifeatures/*.txt')):
 | 
				
			||||||
 | 
					        path = f.as_posix()
 | 
				
			||||||
 | 
					        left = path.index('/', 9)  # 9 is length of "metadata/"
 | 
				
			||||||
 | 
					        right = path.index('/', left + 1)
 | 
				
			||||||
 | 
					        locale = path[left + 1 : right]
 | 
				
			||||||
 | 
					        description = f.read_text()
 | 
				
			||||||
 | 
					        if has_versionCode.match(f.stem):
 | 
				
			||||||
 | 
					            i = f.stem.index('_')
 | 
				
			||||||
 | 
					            versionCode = int(f.stem[:i])
 | 
				
			||||||
 | 
					            antifeature = f.stem[i + 1 :]
 | 
				
			||||||
 | 
					            if versionCode in has_antifeatures_from_app:
 | 
				
			||||||
 | 
					                logging.error(af_dup_msg.format(path=f))
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            if 'Builds' not in app:
 | 
				
			||||||
 | 
					                app['Builds'] = []
 | 
				
			||||||
 | 
					            found = False
 | 
				
			||||||
 | 
					            for build in app['Builds']:
 | 
				
			||||||
 | 
					                # loop though builds again, there might be duplicate versionCodes
 | 
				
			||||||
 | 
					                if versionCode == build['versionCode']:
 | 
				
			||||||
 | 
					                    found = True
 | 
				
			||||||
 | 
					                    if 'antifeatures' not in build:
 | 
				
			||||||
 | 
					                        build['antifeatures'] = dict()
 | 
				
			||||||
 | 
					                    if antifeature not in build['antifeatures']:
 | 
				
			||||||
 | 
					                        build['antifeatures'][antifeature] = dict()
 | 
				
			||||||
 | 
					                    build['antifeatures'][antifeature][locale] = description
 | 
				
			||||||
 | 
					            if not found:
 | 
				
			||||||
 | 
					                app['Builds'].append(
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        'versionCode': versionCode,
 | 
				
			||||||
 | 
					                        'antifeatures': {
 | 
				
			||||||
 | 
					                            antifeature: {locale: description},
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					        elif app_has_AntiFeatures:
 | 
				
			||||||
 | 
					            logging.error(af_dup_msg.format(path=f))
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if 'AntiFeatures' not in app:
 | 
				
			||||||
 | 
					                app['AntiFeatures'] = dict()
 | 
				
			||||||
 | 
					            if f.stem not in app['AntiFeatures']:
 | 
				
			||||||
 | 
					                app['AntiFeatures'][f.stem] = dict()
 | 
				
			||||||
 | 
					            with f.open() as fp:
 | 
				
			||||||
 | 
					                app['AntiFeatures'][f.stem][locale] = fp.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _normalize_type_string(v):
 | 
					def _normalize_type_string(v):
 | 
				
			||||||
    """Normalize any data to TYPE_STRING.
 | 
					    """Normalize any data to TYPE_STRING.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -787,6 +900,61 @@ def _normalize_type_string(v):
 | 
				
			||||||
    return str(v)
 | 
					    return str(v)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _normalize_type_stringmap(k, v):
 | 
				
			||||||
 | 
					    """Normalize any data to TYPE_STRINGMAP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    The internal representation of this format is a dict of dicts,
 | 
				
			||||||
 | 
					    where the outer dict's keys are things like tag names of
 | 
				
			||||||
 | 
					    Anti-Features, the inner dict's keys are locales, and the ultimate
 | 
				
			||||||
 | 
					    values are human readable text.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Metadata entries like AntiFeatures: can be written in many
 | 
				
			||||||
 | 
					    forms, including a simple one-entry string, a list of strings,
 | 
				
			||||||
 | 
					    a dict with keys and descriptions as values, or a dict with
 | 
				
			||||||
 | 
					    localization.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Returns
 | 
				
			||||||
 | 
					    -------
 | 
				
			||||||
 | 
					    A dictionary with string keys, where each value is either a string
 | 
				
			||||||
 | 
					    message or a dict with locale keys and string message values.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    if v is None:
 | 
				
			||||||
 | 
					        return dict()
 | 
				
			||||||
 | 
					    if isinstance(v, str) or isinstance(v, int) or isinstance(v, float):
 | 
				
			||||||
 | 
					        return {_normalize_type_string(v): dict()}
 | 
				
			||||||
 | 
					    if isinstance(v, list) or isinstance(v, tuple) or isinstance(v, set):
 | 
				
			||||||
 | 
					        retdict = dict()
 | 
				
			||||||
 | 
					        for i in v:
 | 
				
			||||||
 | 
					            if isinstance(i, dict):
 | 
				
			||||||
 | 
					                # transitional format
 | 
				
			||||||
 | 
					                if len(i) != 1:
 | 
				
			||||||
 | 
					                    _warn_or_exception(
 | 
				
			||||||
 | 
					                        _(
 | 
				
			||||||
 | 
					                            "'{value}' is not a valid {field}, should be {pattern}"
 | 
				
			||||||
 | 
					                        ).format(field=k, value=v, pattern='key: value')
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                afname = _normalize_type_string(next(iter(i)))
 | 
				
			||||||
 | 
					                desc = _normalize_type_string(next(iter(i.values())))
 | 
				
			||||||
 | 
					                retdict[afname] = {common.DEFAULT_LOCALE: desc}
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                retdict[_normalize_type_string(i)] = {}
 | 
				
			||||||
 | 
					        return retdict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    retdict = dict()
 | 
				
			||||||
 | 
					    for af, afdict in v.items():
 | 
				
			||||||
 | 
					        key = _normalize_type_string(af)
 | 
				
			||||||
 | 
					        if afdict:
 | 
				
			||||||
 | 
					            if isinstance(afdict, dict):
 | 
				
			||||||
 | 
					                retdict[key] = afdict
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                retdict[key] = {common.DEFAULT_LOCALE: _normalize_type_string(afdict)}
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            retdict[key] = dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return retdict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def post_parse_yaml_metadata(yamldata):
 | 
					def post_parse_yaml_metadata(yamldata):
 | 
				
			||||||
    """Convert human-readable metadata data structures into consistent data structures.
 | 
					    """Convert human-readable metadata data structures into consistent data structures.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -808,6 +976,9 @@ def post_parse_yaml_metadata(yamldata):
 | 
				
			||||||
        elif _fieldtype == TYPE_STRING:
 | 
					        elif _fieldtype == TYPE_STRING:
 | 
				
			||||||
            if v or v == 0:
 | 
					            if v or v == 0:
 | 
				
			||||||
                yamldata[k] = _normalize_type_string(v)
 | 
					                yamldata[k] = _normalize_type_string(v)
 | 
				
			||||||
 | 
					        elif _fieldtype == TYPE_STRINGMAP:
 | 
				
			||||||
 | 
					            if v or v == 0:  # TODO probably want just `if v:`
 | 
				
			||||||
 | 
					                yamldata[k] = _normalize_type_stringmap(k, v)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            if type(v) in (float, int):
 | 
					            if type(v) in (float, int):
 | 
				
			||||||
                yamldata[k] = str(v)
 | 
					                yamldata[k] = str(v)
 | 
				
			||||||
| 
						 | 
					@ -843,12 +1014,24 @@ def post_parse_yaml_metadata(yamldata):
 | 
				
			||||||
                            build_flag=k, value=v
 | 
					                            build_flag=k, value=v
 | 
				
			||||||
                        )
 | 
					                        )
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
 | 
					            elif _flagtype == TYPE_STRINGMAP:
 | 
				
			||||||
 | 
					                if v or v == 0:
 | 
				
			||||||
 | 
					                    build[k] = _normalize_type_stringmap(k, v)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        builds.append(build)
 | 
					        builds.append(build)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if builds:
 | 
					    if builds:
 | 
				
			||||||
        yamldata['Builds'] = sorted(builds, key=lambda build: build['versionCode'])
 | 
					        yamldata['Builds'] = sorted(builds, key=lambda build: build['versionCode'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    no_source_since = yamldata.get("NoSourceSince")
 | 
				
			||||||
 | 
					    # do not overwrite the description if it is there
 | 
				
			||||||
 | 
					    if no_source_since and not yamldata.get('AntiFeatures', {}).get('NoSourceSince'):
 | 
				
			||||||
 | 
					        if 'AntiFeatures' not in yamldata:
 | 
				
			||||||
 | 
					            yamldata['AntiFeatures'] = dict()
 | 
				
			||||||
 | 
					        yamldata['AntiFeatures']['NoSourceSince'] = {
 | 
				
			||||||
 | 
					            common.DEFAULT_LOCALE: no_source_since
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def write_yaml(mf, app):
 | 
					def write_yaml(mf, app):
 | 
				
			||||||
    """Write metadata in yaml format.
 | 
					    """Write metadata in yaml format.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,8 +52,9 @@ def remove_blank_flags_from_builds(builds):
 | 
				
			||||||
    for build in builds:
 | 
					    for build in builds:
 | 
				
			||||||
        new = dict()
 | 
					        new = dict()
 | 
				
			||||||
        for k in metadata.build_flags:
 | 
					        for k in metadata.build_flags:
 | 
				
			||||||
            v = build[k]
 | 
					            v = build.get(k)
 | 
				
			||||||
            if v is None or v is False or v == [] or v == '':
 | 
					            # 0 is valid value, it should not be stripped
 | 
				
			||||||
 | 
					            if v is None or v is False or v == '' or v == dict() or v == list():
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            new[k] = v
 | 
					            new[k] = v
 | 
				
			||||||
        newbuilds.append(new)
 | 
					        newbuilds.append(new)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -294,7 +294,7 @@ class ExodusSignatureDataController(SignatureDataController):
 | 
				
			||||||
                        "warn_code_signatures": [tracker["code_signature"]],
 | 
					                        "warn_code_signatures": [tracker["code_signature"]],
 | 
				
			||||||
                        # exodus also provides network signatures, unused atm.
 | 
					                        # exodus also provides network signatures, unused atm.
 | 
				
			||||||
                        # "network_signatures": [tracker["network_signature"]],
 | 
					                        # "network_signatures": [tracker["network_signature"]],
 | 
				
			||||||
                        "AntiFeatures": ["Tracking"],
 | 
					                        "AntiFeatures": ["Tracking"],  # TODO
 | 
				
			||||||
                        "license": "NonFree"  # We assume all trackers in exodus
 | 
					                        "license": "NonFree"  # We assume all trackers in exodus
 | 
				
			||||||
                                              # are non-free, although free
 | 
					                                              # are non-free, although free
 | 
				
			||||||
                                              # trackers like piwik, acra,
 | 
					                                              # trackers like piwik, acra,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -158,7 +158,7 @@ def status_update_json(apps, apks):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for appid in apps:
 | 
					    for appid in apps:
 | 
				
			||||||
        app = apps[appid]
 | 
					        app = apps[appid]
 | 
				
			||||||
        for af in app.get('AntiFeatures', []):
 | 
					        for af in app.get('AntiFeatures', dict()):
 | 
				
			||||||
            antiFeatures = output['antiFeatures']  # JSON camelCase
 | 
					            antiFeatures = output['antiFeatures']  # JSON camelCase
 | 
				
			||||||
            if af not in antiFeatures:
 | 
					            if af not in antiFeatures:
 | 
				
			||||||
                antiFeatures[af] = dict()
 | 
					                antiFeatures[af] = dict()
 | 
				
			||||||
| 
						 | 
					@ -351,7 +351,8 @@ def get_cache():
 | 
				
			||||||
        if not isinstance(v, dict):
 | 
					        if not isinstance(v, dict):
 | 
				
			||||||
            continue
 | 
					            continue
 | 
				
			||||||
        if 'antiFeatures' in v:
 | 
					        if 'antiFeatures' in v:
 | 
				
			||||||
            v['antiFeatures'] = set(v['antiFeatures'])
 | 
					            if not isinstance(v['antiFeatures'], dict):
 | 
				
			||||||
 | 
					                v['antiFeatures'] = {k: {} for k in sorted(v['antiFeatures'])}
 | 
				
			||||||
        if 'added' in v:
 | 
					        if 'added' in v:
 | 
				
			||||||
            v['added'] = datetime.fromtimestamp(v['added'])
 | 
					            v['added'] = datetime.fromtimestamp(v['added'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -400,7 +401,7 @@ def has_known_vulnerability(filename):
 | 
				
			||||||
    Janus is similar to Master Key but is perhaps easier to scan for.
 | 
					    Janus is similar to Master Key but is perhaps easier to scan for.
 | 
				
			||||||
    https://www.guardsquare.com/en/blog/new-android-vulnerability-allows-attackers-modify-apps-without-affecting-their-signatures
 | 
					    https://www.guardsquare.com/en/blog/new-android-vulnerability-allows-attackers-modify-apps-without-affecting-their-signatures
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    found_vuln = False
 | 
					    found_vuln = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # statically load this pattern
 | 
					    # statically load this pattern
 | 
				
			||||||
    if not hasattr(has_known_vulnerability, "pattern"):
 | 
					    if not hasattr(has_known_vulnerability, "pattern"):
 | 
				
			||||||
| 
						 | 
					@ -431,15 +432,23 @@ def has_known_vulnerability(filename):
 | 
				
			||||||
                            logging.debug(_('"{path}" contains recent {name} ({version})')
 | 
					                            logging.debug(_('"{path}" contains recent {name} ({version})')
 | 
				
			||||||
                                          .format(path=filename, name=name, version=version))
 | 
					                                          .format(path=filename, name=name, version=version))
 | 
				
			||||||
                        else:
 | 
					                        else:
 | 
				
			||||||
                            logging.warning(_('"{path}" contains outdated {name} ({version})')
 | 
					                            msg = '"{path}" contains outdated {name} ({version})'
 | 
				
			||||||
                                            .format(path=filename, name=name, version=version))
 | 
					                            logging.warning(
 | 
				
			||||||
                            found_vuln = True
 | 
					                                _(msg).format(path=filename, name=name, version=version)
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                            found_vuln += msg.format(
 | 
				
			||||||
 | 
					                                path=filename, name=name, version=version
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                            found_vuln += '\n'
 | 
				
			||||||
                        break
 | 
					                        break
 | 
				
			||||||
            elif name == 'AndroidManifest.xml' or name == 'classes.dex' or name.endswith('.so'):
 | 
					            elif name == 'AndroidManifest.xml' or name == 'classes.dex' or name.endswith('.so'):
 | 
				
			||||||
                if name in files_in_apk:
 | 
					                if name in files_in_apk:
 | 
				
			||||||
                    logging.warning(_('{apkfilename} has multiple {name} files, looks like Master Key exploit!')
 | 
					                    msg = '{apkfilename} has multiple {name} files, looks like Master Key exploit!'
 | 
				
			||||||
                                    .format(apkfilename=filename, name=name))
 | 
					                    logging.warning(
 | 
				
			||||||
                    found_vuln = True
 | 
					                        _(msg).format(apkfilename=filename, name=name)
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                    found_vuln += msg.format(apkfilename=filename, name=name)
 | 
				
			||||||
 | 
					                    found_vuln += '\n'
 | 
				
			||||||
                files_in_apk.add(name)
 | 
					                files_in_apk.add(name)
 | 
				
			||||||
    return found_vuln
 | 
					    return found_vuln
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -545,7 +554,7 @@ def translate_per_build_anti_features(apps, apks):
 | 
				
			||||||
        if d:
 | 
					        if d:
 | 
				
			||||||
            afl = d.get(apk['versionCode'])
 | 
					            afl = d.get(apk['versionCode'])
 | 
				
			||||||
            if afl:
 | 
					            if afl:
 | 
				
			||||||
                apk['antiFeatures'].update(afl)
 | 
					                apk['antiFeatures'].update(afl)  # TODO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _get_localized_dict(app, locale):
 | 
					def _get_localized_dict(app, locale):
 | 
				
			||||||
| 
						 | 
					@ -1228,7 +1237,7 @@ def scan_apk(apk_file, require_signature=True):
 | 
				
			||||||
        'features': [],
 | 
					        'features': [],
 | 
				
			||||||
        'icons_src': {},
 | 
					        'icons_src': {},
 | 
				
			||||||
        'icons': {},
 | 
					        'icons': {},
 | 
				
			||||||
        'antiFeatures': set(),
 | 
					        'antiFeatures': {},
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    ipfsCIDv1 = common.calculate_IPFS_cid(apk_file)
 | 
					    ipfsCIDv1 = common.calculate_IPFS_cid(apk_file)
 | 
				
			||||||
    if ipfsCIDv1:
 | 
					    if ipfsCIDv1:
 | 
				
			||||||
| 
						 | 
					@ -1263,8 +1272,9 @@ def scan_apk(apk_file, require_signature=True):
 | 
				
			||||||
        apk['minSdkVersion'] = 3  # aapt defaults to 3 as the min
 | 
					        apk['minSdkVersion'] = 3  # aapt defaults to 3 as the min
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Check for known vulnerabilities
 | 
					    # Check for known vulnerabilities
 | 
				
			||||||
    if has_known_vulnerability(apk_file):
 | 
					    hkv = has_known_vulnerability(apk_file)
 | 
				
			||||||
        apk['antiFeatures'].add('KnownVuln')
 | 
					    if hkv:
 | 
				
			||||||
 | 
					        apk['antiFeatures']['KnownVuln'] = {DEFAULT_LOCALE: hkv}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return apk
 | 
					    return apk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1545,7 +1555,7 @@ def process_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk=Fal
 | 
				
			||||||
            if repodir == 'archive' or allow_disabled_algorithms:
 | 
					            if repodir == 'archive' or allow_disabled_algorithms:
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    common.verify_deprecated_jar_signature(apkfile)
 | 
					                    common.verify_deprecated_jar_signature(apkfile)
 | 
				
			||||||
                    apk['antiFeatures'].update(['KnownVuln', 'DisabledAlgorithm'])
 | 
					                    apk['antiFeatures'].update(['KnownVuln', 'DisabledAlgorithm'])  # TODO
 | 
				
			||||||
                except VerificationException:
 | 
					                except VerificationException:
 | 
				
			||||||
                    skipapk = True
 | 
					                    skipapk = True
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
| 
						 | 
					@ -1885,7 +1895,7 @@ def archive_old_apks(apps, apks, archapks, repodir, archivedir, defaultkeepversi
 | 
				
			||||||
        for apk in all_app_apks:
 | 
					        for apk in all_app_apks:
 | 
				
			||||||
            if len(keep) == keepversions:
 | 
					            if len(keep) == keepversions:
 | 
				
			||||||
                break
 | 
					                break
 | 
				
			||||||
            if 'antiFeatures' not in apk:
 | 
					            if 'antiFeatures' not in apk:  # TODO
 | 
				
			||||||
                keep.append(apk)
 | 
					                keep.append(apk)
 | 
				
			||||||
            elif 'DisabledAlgorithm' not in apk['antiFeatures'] or disabled_algorithms_allowed():
 | 
					            elif 'DisabledAlgorithm' not in apk['antiFeatures'] or disabled_algorithms_allowed():
 | 
				
			||||||
                keep.append(apk)
 | 
					                keep.append(apk)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
AntiFeatures:
 | 
					AntiFeatures:
 | 
				
			||||||
  - UpstreamNonFree
 | 
					    UpstreamNonFree: {}
 | 
				
			||||||
Categories:
 | 
					Categories:
 | 
				
			||||||
  - System
 | 
					  - System
 | 
				
			||||||
License: GPL-3.0-only
 | 
					License: GPL-3.0-only
 | 
				
			||||||
| 
						 | 
					@ -77,6 +77,9 @@ Builds:
 | 
				
			||||||
    maven: yes@..
 | 
					    maven: yes@..
 | 
				
			||||||
    srclibs:
 | 
					    srclibs:
 | 
				
			||||||
      - FacebookSDK@sdk-version-3.0.2
 | 
					      - FacebookSDK@sdk-version-3.0.2
 | 
				
			||||||
 | 
					    antifeatures:
 | 
				
			||||||
 | 
					        Tracking:
 | 
				
			||||||
 | 
					            en-US: Uses the Facebook SDK.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - versionName: 2.1.1-c
 | 
					  - versionName: 2.1.1-c
 | 
				
			||||||
    versionCode: 50
 | 
					    versionCode: 50
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@ if localmodule not in sys.path:
 | 
				
			||||||
import fdroidserver
 | 
					import fdroidserver
 | 
				
			||||||
from fdroidserver import metadata
 | 
					from fdroidserver import metadata
 | 
				
			||||||
from fdroidserver.exception import MetaDataException
 | 
					from fdroidserver.exception import MetaDataException
 | 
				
			||||||
 | 
					from fdroidserver.common import DEFAULT_LOCALE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _get_mock_mf(s):
 | 
					def _get_mock_mf(s):
 | 
				
			||||||
| 
						 | 
					@ -216,6 +217,7 @@ class MetadataTest(unittest.TestCase):
 | 
				
			||||||
        yaml = ruamel.yaml.YAML(typ='safe')
 | 
					        yaml = ruamel.yaml.YAML(typ='safe')
 | 
				
			||||||
        apps = fdroidserver.metadata.read_metadata()
 | 
					        apps = fdroidserver.metadata.read_metadata()
 | 
				
			||||||
        for appid in (
 | 
					        for appid in (
 | 
				
			||||||
 | 
					            'app.with.special.build.params',
 | 
				
			||||||
            'org.smssecure.smssecure',
 | 
					            'org.smssecure.smssecure',
 | 
				
			||||||
            'org.adaway',
 | 
					            'org.adaway',
 | 
				
			||||||
            'org.videolan.vlc',
 | 
					            'org.videolan.vlc',
 | 
				
			||||||
| 
						 | 
					@ -300,24 +302,24 @@ class MetadataTest(unittest.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @mock.patch('git.Repo')
 | 
					    @mock.patch('git.Repo')
 | 
				
			||||||
    def test_rewrite_yaml_special_build_params(self, git_Repo):
 | 
					    def test_rewrite_yaml_special_build_params(self, git_Repo):
 | 
				
			||||||
        with tempfile.TemporaryDirectory() as testdir:
 | 
					        """Test rewriting a plain YAML metadata file without localized files."""
 | 
				
			||||||
            testdir = Path(testdir)
 | 
					        os.chdir(self.testdir)
 | 
				
			||||||
 | 
					        os.mkdir('metadata')
 | 
				
			||||||
 | 
					        appid = 'app.with.special.build.params'
 | 
				
			||||||
 | 
					        file_name = Path('metadata/%s.yml' % appid)
 | 
				
			||||||
 | 
					        shutil.copy(self.basedir / file_name, file_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # rewrite metadata
 | 
					        # rewrite metadata
 | 
				
			||||||
            allapps = fdroidserver.metadata.read_metadata()
 | 
					        allapps = fdroidserver.metadata.read_metadata({appid: -1})
 | 
				
			||||||
            for appid, app in allapps.items():
 | 
					        for appid, app in allapps.items():
 | 
				
			||||||
                if appid == 'app.with.special.build.params':
 | 
					            metadata.write_metadata(file_name, app)
 | 
				
			||||||
                    fdroidserver.metadata.write_metadata(
 | 
					 | 
				
			||||||
                        testdir / (appid + '.yml'), app
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # assert rewrite result
 | 
					        # assert rewrite result
 | 
				
			||||||
            self.maxDiff = None
 | 
					        self.maxDiff = None
 | 
				
			||||||
            file_name = 'app.with.special.build.params.yml'
 | 
					        self.assertEqual(
 | 
				
			||||||
            self.assertEqual(
 | 
					            file_name.read_text(),
 | 
				
			||||||
                (testdir / file_name).read_text(encoding='utf-8'),
 | 
					            (self.basedir / 'metadata-rewrite-yml' / file_name.name).read_text(),
 | 
				
			||||||
                (Path('metadata-rewrite-yml') / file_name).read_text(encoding='utf-8'),
 | 
					        )
 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_normalize_type_string(self):
 | 
					    def test_normalize_type_string(self):
 | 
				
			||||||
        """TYPE_STRING currently has some quirky behavior."""
 | 
					        """TYPE_STRING currently has some quirky behavior."""
 | 
				
			||||||
| 
						 | 
					@ -331,6 +333,18 @@ class MetadataTest(unittest.TestCase):
 | 
				
			||||||
        self.assertEqual('false', metadata._normalize_type_string(False))
 | 
					        self.assertEqual('false', metadata._normalize_type_string(False))
 | 
				
			||||||
        self.assertEqual('true', metadata._normalize_type_string(True))
 | 
					        self.assertEqual('true', metadata._normalize_type_string(True))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_normalize_type_stringmap_none(self):
 | 
				
			||||||
 | 
					        self.assertEqual(dict(), metadata._normalize_type_stringmap('key', None))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_normalize_type_stringmap_empty_list(self):
 | 
				
			||||||
 | 
					        self.assertEqual(dict(), metadata._normalize_type_stringmap('AntiFeatures', []))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_normalize_type_stringmap_simple_list_format(self):
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            {'Ads': {}, 'Tracking': {}},
 | 
				
			||||||
 | 
					            metadata._normalize_type_stringmap('AntiFeatures', ['Ads', 'Tracking']),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_post_parse_yaml_metadata(self):
 | 
					    def test_post_parse_yaml_metadata(self):
 | 
				
			||||||
        yamldata = dict()
 | 
					        yamldata = dict()
 | 
				
			||||||
        metadata.post_parse_yaml_metadata(yamldata)
 | 
					        metadata.post_parse_yaml_metadata(yamldata)
 | 
				
			||||||
| 
						 | 
					@ -507,6 +521,96 @@ class MetadataTest(unittest.TestCase):
 | 
				
			||||||
        _warning.assert_called_once()
 | 
					        _warning.assert_called_once()
 | 
				
			||||||
        _error.assert_called_once()
 | 
					        _error.assert_called_once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_localized_antifeatures(self):
 | 
				
			||||||
 | 
					        """Unit test based on reading files included in the test repo."""
 | 
				
			||||||
 | 
					        app = dict()
 | 
				
			||||||
 | 
					        app['id'] = 'app.with.special.build.params'
 | 
				
			||||||
 | 
					        metadata.parse_localized_antifeatures(app)
 | 
				
			||||||
 | 
					        self.maxDiff = None
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            app,
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                'AntiFeatures': {
 | 
				
			||||||
 | 
					                    'Ads': {'en-US': 'please no'},
 | 
				
			||||||
 | 
					                    'NoSourceSince': {'en-US': 'no activity\n'},
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                'Builds': [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        'versionCode': 50,
 | 
				
			||||||
 | 
					                        'antifeatures': {
 | 
				
			||||||
 | 
					                            'Ads': {
 | 
				
			||||||
 | 
					                                'en-US': 'includes ad lib\n',
 | 
				
			||||||
 | 
					                                'zh-CN': '包括广告图书馆\n',
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            'Tracking': {'en-US': 'standard suspects\n'},
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        'versionCode': 49,
 | 
				
			||||||
 | 
					                        'antifeatures': {
 | 
				
			||||||
 | 
					                            'Tracking': {'zh-CN': 'Text from zh-CN/49_Tracking.txt'},
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                'id': app['id'],
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_localized_antifeatures_passthrough(self):
 | 
				
			||||||
 | 
					        """Test app values are cleanly passed through if no localized files."""
 | 
				
			||||||
 | 
					        before = {
 | 
				
			||||||
 | 
					            'id': 'placeholder',
 | 
				
			||||||
 | 
					            'AntiFeatures': {'NonFreeDep': {}},
 | 
				
			||||||
 | 
					            'Builds': [{'versionCode': 999, 'antifeatures': {'zero': {}, 'one': {}}}],
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        after = copy.deepcopy(before)
 | 
				
			||||||
 | 
					        with tempfile.TemporaryDirectory() as testdir:
 | 
				
			||||||
 | 
					            os.chdir(testdir)
 | 
				
			||||||
 | 
					            os.mkdir('metadata')
 | 
				
			||||||
 | 
					            os.mkdir(os.path.join('metadata', after['id']))
 | 
				
			||||||
 | 
					            metadata.parse_localized_antifeatures(after)
 | 
				
			||||||
 | 
					        self.assertEqual(before, after)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_metadata_antifeatures_NoSourceSince(self):
 | 
				
			||||||
 | 
					        """Test that NoSourceSince gets added as an Anti-Feature."""
 | 
				
			||||||
 | 
					        os.chdir(self.testdir)
 | 
				
			||||||
 | 
					        yml = Path('metadata/test.yml')
 | 
				
			||||||
 | 
					        yml.parent.mkdir()
 | 
				
			||||||
 | 
					        with yml.open('w') as fp:
 | 
				
			||||||
 | 
					            fp.write('AntiFeatures: Ads\nNoSourceSince: gone\n')
 | 
				
			||||||
 | 
					        app = metadata.parse_metadata(yml)
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            app['AntiFeatures'], {'Ads': {}, 'NoSourceSince': {DEFAULT_LOCALE: 'gone'}}
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @mock.patch('logging.error')
 | 
				
			||||||
 | 
					    def test_yml_overrides_localized_antifeatures(self, logging_error):
 | 
				
			||||||
 | 
					        """Definitions in .yml files should override the localized versions."""
 | 
				
			||||||
 | 
					        app = metadata.parse_metadata('metadata/app.with.special.build.params.yml')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(app['AntiFeatures'], {'UpstreamNonFree': {}})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(49, app['Builds'][-3]['versionCode'])
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            app['Builds'][-3]['antifeatures'],
 | 
				
			||||||
 | 
					            {'Tracking': {DEFAULT_LOCALE: 'Uses the Facebook SDK.'}},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(50, app['Builds'][-2]['versionCode'])
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            app['Builds'][-2]['antifeatures'],
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                'Ads': {
 | 
				
			||||||
 | 
					                    'en-US': 'includes ad lib\n',
 | 
				
			||||||
 | 
					                    'zh-CN': '包括广告图书馆\n',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                'Tracking': {'en-US': 'standard suspects\n'},
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        # errors are printed when .yml overrides localized
 | 
				
			||||||
 | 
					        logging_error.assert_called()
 | 
				
			||||||
 | 
					        self.assertEqual(3, len(logging_error.call_args_list))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_parse_yaml_srclib_corrupt_file(self):
 | 
					    def test_parse_yaml_srclib_corrupt_file(self):
 | 
				
			||||||
        with tempfile.TemporaryDirectory() as testdir:
 | 
					        with tempfile.TemporaryDirectory() as testdir:
 | 
				
			||||||
            testdir = Path(testdir)
 | 
					            testdir = Path(testdir)
 | 
				
			||||||
| 
						 | 
					@ -741,6 +845,257 @@ class MetadataTest(unittest.TestCase):
 | 
				
			||||||
        self.assertNotIn('Provides', result)
 | 
					        self.assertNotIn('Provides', result)
 | 
				
			||||||
        self.assertNotIn('provides', result)
 | 
					        self.assertNotIn('provides', result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_app_antifeatures_dict(self):
 | 
				
			||||||
 | 
					        nonfreenet = 'free it!'
 | 
				
			||||||
 | 
					        tracking = 'so many'
 | 
				
			||||||
 | 
					        mf = io.StringIO(
 | 
				
			||||||
 | 
					            textwrap.dedent(
 | 
				
			||||||
 | 
					                f"""
 | 
				
			||||||
 | 
					                AntiFeatures:
 | 
				
			||||||
 | 
					                  Tracking: {tracking}
 | 
				
			||||||
 | 
					                  NonFreeNet: {nonfreenet}
 | 
				
			||||||
 | 
					                """
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(mf),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                'AntiFeatures': {
 | 
				
			||||||
 | 
					                    'NonFreeNet': {DEFAULT_LOCALE: nonfreenet},
 | 
				
			||||||
 | 
					                    'Tracking': {DEFAULT_LOCALE: tracking},
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_metadata_build_antifeatures_old_style(self):
 | 
				
			||||||
 | 
					        mf = _get_mock_mf(
 | 
				
			||||||
 | 
					            textwrap.dedent(
 | 
				
			||||||
 | 
					                """
 | 
				
			||||||
 | 
					                AntiFeatures:
 | 
				
			||||||
 | 
					                  - Ads
 | 
				
			||||||
 | 
					                Builds:
 | 
				
			||||||
 | 
					                  - versionCode: 123
 | 
				
			||||||
 | 
					                    antifeatures:
 | 
				
			||||||
 | 
					                      - KnownVuln
 | 
				
			||||||
 | 
					                      - UpstreamNonFree
 | 
				
			||||||
 | 
					                      - NonFreeAssets
 | 
				
			||||||
 | 
					                """
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(mf),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                'AntiFeatures': {'Ads': {}},
 | 
				
			||||||
 | 
					                'Builds': [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        'antifeatures': {
 | 
				
			||||||
 | 
					                            'KnownVuln': {},
 | 
				
			||||||
 | 
					                            'NonFreeAssets': {},
 | 
				
			||||||
 | 
					                            'UpstreamNonFree': {},
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        'versionCode': 123,
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_metadata_antifeatures_sort(self):
 | 
				
			||||||
 | 
					        """All data should end up sorted, to minimize diffs in the index files."""
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(
 | 
				
			||||||
 | 
					                _get_mock_mf(
 | 
				
			||||||
 | 
					                    textwrap.dedent(
 | 
				
			||||||
 | 
					                        """
 | 
				
			||||||
 | 
					                Builds:
 | 
				
			||||||
 | 
					                  - versionCode: 123
 | 
				
			||||||
 | 
					                    antifeatures:
 | 
				
			||||||
 | 
					                      KnownVuln:
 | 
				
			||||||
 | 
					                        es: 2nd
 | 
				
			||||||
 | 
					                        az: zero
 | 
				
			||||||
 | 
					                        en-US: first
 | 
				
			||||||
 | 
					                      UpstreamNonFree:
 | 
				
			||||||
 | 
					                      NonFreeAssets:
 | 
				
			||||||
 | 
					                AntiFeatures:
 | 
				
			||||||
 | 
					                  NonFreeDep:
 | 
				
			||||||
 | 
					                  Ads:
 | 
				
			||||||
 | 
					                    sw: 2nd
 | 
				
			||||||
 | 
					                    zh-CN: 3rd
 | 
				
			||||||
 | 
					                    de: 1st
 | 
				
			||||||
 | 
					                """
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                'AntiFeatures': {
 | 
				
			||||||
 | 
					                    'Ads': {'de': '1st', 'sw': '2nd', 'zh-CN': '3rd'},
 | 
				
			||||||
 | 
					                    'NonFreeDep': {},
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                'Builds': [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        'antifeatures': {
 | 
				
			||||||
 | 
					                            'KnownVuln': {'az': 'zero', 'en-US': 'first', 'es': '2nd'},
 | 
				
			||||||
 | 
					                            'NonFreeAssets': {},
 | 
				
			||||||
 | 
					                            'UpstreamNonFree': {},
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        'versionCode': 123,
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_app_antifeatures_str(self):
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(io.StringIO('AntiFeatures: Tracking')),
 | 
				
			||||||
 | 
					            {'AntiFeatures': {'Tracking': {}}},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_app_antifeatures_bool(self):
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(io.StringIO('AntiFeatures: true')),
 | 
				
			||||||
 | 
					            {'AntiFeatures': {'true': {}}},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_app_antifeatures_int(self):
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(io.StringIO('AntiFeatures: 1')),
 | 
				
			||||||
 | 
					            {'AntiFeatures': {'1': {}}},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_app_antifeatures_float(self):
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(io.StringIO('AntiFeatures: 1.0')),
 | 
				
			||||||
 | 
					            {'AntiFeatures': {'1.0': {}}},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_app_antifeatures_list_float(self):
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(io.StringIO('AntiFeatures:\n  - 1.0\n')),
 | 
				
			||||||
 | 
					            {'AntiFeatures': {'1.0': {}}},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_app_antifeatures_dict_float(self):
 | 
				
			||||||
 | 
					        mf = io.StringIO('AntiFeatures:\n  0.0: too early\n')
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(mf),
 | 
				
			||||||
 | 
					            {'AntiFeatures': {'0.0': {'en-US': 'too early'}}},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_app_antifeatures_dict_float_fail_value(self):
 | 
				
			||||||
 | 
					        mf = io.StringIO('AntiFeatures:\n  NoSourceSince: 1.0\n')
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(mf),
 | 
				
			||||||
 | 
					            {'AntiFeatures': {'NoSourceSince': {'en-US': '1.0'}}},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_metadata_type_stringmap_old_list(self):
 | 
				
			||||||
 | 
					        mf = _get_mock_mf(
 | 
				
			||||||
 | 
					            textwrap.dedent(
 | 
				
			||||||
 | 
					                """
 | 
				
			||||||
 | 
					                    AntiFeatures:
 | 
				
			||||||
 | 
					                      - Ads
 | 
				
			||||||
 | 
					                      - Tracking
 | 
				
			||||||
 | 
					                """
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            {'AntiFeatures': {'Ads': {}, 'Tracking': {}}},
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(mf),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_app_antifeatures_dict_no_value(self):
 | 
				
			||||||
 | 
					        mf = io.StringIO(
 | 
				
			||||||
 | 
					            textwrap.dedent(
 | 
				
			||||||
 | 
					                """\
 | 
				
			||||||
 | 
					                AntiFeatures:
 | 
				
			||||||
 | 
					                  Tracking:
 | 
				
			||||||
 | 
					                  NonFreeNet:
 | 
				
			||||||
 | 
					                """
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(mf),
 | 
				
			||||||
 | 
					            {'AntiFeatures': {'NonFreeNet': {}, 'Tracking': {}}},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_metadata_type_stringmap_transitional(self):
 | 
				
			||||||
 | 
					        """Support a transitional format, where users just append a text"""
 | 
				
			||||||
 | 
					        ads = 'Has ad lib in it.'
 | 
				
			||||||
 | 
					        tracking = 'opt-out reports with ACRA'
 | 
				
			||||||
 | 
					        mf = _get_mock_mf(
 | 
				
			||||||
 | 
					            textwrap.dedent(
 | 
				
			||||||
 | 
					                f"""
 | 
				
			||||||
 | 
					                    AntiFeatures:
 | 
				
			||||||
 | 
					                      - Ads: {ads}
 | 
				
			||||||
 | 
					                      - Tracking: {tracking}
 | 
				
			||||||
 | 
					                """
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(mf),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                'AntiFeatures': {
 | 
				
			||||||
 | 
					                    'Ads': {DEFAULT_LOCALE: ads},
 | 
				
			||||||
 | 
					                    'Tracking': {DEFAULT_LOCALE: tracking},
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_app_antifeatures_dict_mixed_values(self):
 | 
				
			||||||
 | 
					        ads = 'true'
 | 
				
			||||||
 | 
					        tracking = 'many'
 | 
				
			||||||
 | 
					        nonfreenet = '1'
 | 
				
			||||||
 | 
					        mf = io.StringIO(
 | 
				
			||||||
 | 
					            textwrap.dedent(
 | 
				
			||||||
 | 
					                f"""
 | 
				
			||||||
 | 
					                AntiFeatures:
 | 
				
			||||||
 | 
					                  Ads: {ads}
 | 
				
			||||||
 | 
					                  Tracking: {tracking}
 | 
				
			||||||
 | 
					                  NonFreeNet: {nonfreenet}
 | 
				
			||||||
 | 
					                """
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(mf),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                'AntiFeatures': {
 | 
				
			||||||
 | 
					                    'Ads': {DEFAULT_LOCALE: ads},
 | 
				
			||||||
 | 
					                    'NonFreeNet': {DEFAULT_LOCALE: nonfreenet},
 | 
				
			||||||
 | 
					                    'Tracking': {DEFAULT_LOCALE: tracking},
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_parse_yaml_app_antifeatures_stringmap_full(self):
 | 
				
			||||||
 | 
					        ads = 'watching'
 | 
				
			||||||
 | 
					        tracking = 'many'
 | 
				
			||||||
 | 
					        nonfreenet = 'pipes'
 | 
				
			||||||
 | 
					        nonfreenet_zh = '非免费网络'
 | 
				
			||||||
 | 
					        self.maxDiff = None
 | 
				
			||||||
 | 
					        mf = io.StringIO(
 | 
				
			||||||
 | 
					            textwrap.dedent(
 | 
				
			||||||
 | 
					                f"""
 | 
				
			||||||
 | 
					                AntiFeatures:
 | 
				
			||||||
 | 
					                  Ads:
 | 
				
			||||||
 | 
					                    {DEFAULT_LOCALE}: {ads}
 | 
				
			||||||
 | 
					                  Tracking:
 | 
				
			||||||
 | 
					                    {DEFAULT_LOCALE}: {tracking}
 | 
				
			||||||
 | 
					                  NonFreeNet:
 | 
				
			||||||
 | 
					                    {DEFAULT_LOCALE}: {nonfreenet}
 | 
				
			||||||
 | 
					                    zh-CN: {nonfreenet_zh}
 | 
				
			||||||
 | 
					                """
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            metadata.parse_yaml_metadata(mf),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                'AntiFeatures': {
 | 
				
			||||||
 | 
					                    'Ads': {DEFAULT_LOCALE: ads},
 | 
				
			||||||
 | 
					                    'NonFreeNet': {DEFAULT_LOCALE: nonfreenet, 'zh-CN': nonfreenet_zh},
 | 
				
			||||||
 | 
					                    'Tracking': {DEFAULT_LOCALE: tracking},
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_write_yaml_1_line_scripts_as_string(self):
 | 
					    def test_write_yaml_1_line_scripts_as_string(self):
 | 
				
			||||||
        mf = io.StringIO()
 | 
					        mf = io.StringIO()
 | 
				
			||||||
        app = fdroidserver.metadata.App()
 | 
					        app = fdroidserver.metadata.App()
 | 
				
			||||||
| 
						 | 
					@ -1263,9 +1618,9 @@ class PostMetadataParseTest(unittest.TestCase):
 | 
				
			||||||
        fdroidserver.metadata.warnings_action = 'error'
 | 
					        fdroidserver.metadata.warnings_action = 'error'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _post_metadata_parse_app_list(self, from_yaml, expected):
 | 
					    def _post_metadata_parse_app_list(self, from_yaml, expected):
 | 
				
			||||||
        app = {'AntiFeatures': from_yaml}
 | 
					        app = {'AllowedAPKSigningKeys': from_yaml}
 | 
				
			||||||
        metadata.post_parse_yaml_metadata(app)
 | 
					        metadata.post_parse_yaml_metadata(app)
 | 
				
			||||||
        return {'AntiFeatures': expected}, app
 | 
					        return {'AllowedAPKSigningKeys': expected}, app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _post_metadata_parse_app_string(self, from_yaml, expected):
 | 
					    def _post_metadata_parse_app_string(self, from_yaml, expected):
 | 
				
			||||||
        app = {'Repo': from_yaml}
 | 
					        app = {'Repo': from_yaml}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
antiFeatures: !!set {}
 | 
					antiFeatures: {}
 | 
				
			||||||
features: []
 | 
					features: []
 | 
				
			||||||
hash: abfb3adb7496611749e7abfb014c5c789e3a02489e48a5c3665110d1b1acd931
 | 
					hash: abfb3adb7496611749e7abfb014c5c789e3a02489e48a5c3665110d1b1acd931
 | 
				
			||||||
hashType: sha256
 | 
					hashType: sha256
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
antiFeatures: !!set {}
 | 
					antiFeatures: {}
 | 
				
			||||||
features: []
 | 
					features: []
 | 
				
			||||||
hash: 897486e1f857c6c0ee32ccbad0e1b8cd82f6d0e65a44a23f13f852d2b63a18c8
 | 
					hash: 897486e1f857c6c0ee32ccbad0e1b8cd82f6d0e65a44a23f13f852d2b63a18c8
 | 
				
			||||||
hashType: sha256
 | 
					hashType: sha256
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,6 +77,8 @@ Builds:
 | 
				
			||||||
    maven: yes@..
 | 
					    maven: yes@..
 | 
				
			||||||
    srclibs:
 | 
					    srclibs:
 | 
				
			||||||
      - FacebookSDK@sdk-version-3.0.2
 | 
					      - FacebookSDK@sdk-version-3.0.2
 | 
				
			||||||
 | 
					    antifeatures:
 | 
				
			||||||
 | 
					      Tracking: Uses the Facebook SDK.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - versionName: 2.1.1-c
 | 
					  - versionName: 2.1.1-c
 | 
				
			||||||
    versionCode: 50
 | 
					    versionCode: 50
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					includes ad lib
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					standard suspects
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					please no
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					no activity
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					Text from zh-CN/49_Tracking.txt
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					包括广告图书馆
 | 
				
			||||||
							
								
								
									
										373
									
								
								tests/metadata/dump/app.with.special.build.params.yaml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								tests/metadata/dump/app.with.special.build.params.yaml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,373 @@
 | 
				
			||||||
 | 
					AllowedAPKSigningKeys: []
 | 
				
			||||||
 | 
					AntiFeatures:
 | 
				
			||||||
 | 
					  UpstreamNonFree: {}
 | 
				
			||||||
 | 
					ArchivePolicy: 0 versions
 | 
				
			||||||
 | 
					AuthorEmail: null
 | 
				
			||||||
 | 
					AuthorName: null
 | 
				
			||||||
 | 
					AuthorWebSite: null
 | 
				
			||||||
 | 
					AutoName: UberSync for Facebook
 | 
				
			||||||
 | 
					AutoUpdateMode: None
 | 
				
			||||||
 | 
					Binaries: null
 | 
				
			||||||
 | 
					Bitcoin: null
 | 
				
			||||||
 | 
					Builds:
 | 
				
			||||||
 | 
					- androidupdate: []
 | 
				
			||||||
 | 
					  antcommands: []
 | 
				
			||||||
 | 
					  antifeatures: {}
 | 
				
			||||||
 | 
					  binary: null
 | 
				
			||||||
 | 
					  build: ''
 | 
				
			||||||
 | 
					  buildjni: []
 | 
				
			||||||
 | 
					  commit: b3879c973e7cac3a3319
 | 
				
			||||||
 | 
					  disable: ''
 | 
				
			||||||
 | 
					  encoding: null
 | 
				
			||||||
 | 
					  extlibs: []
 | 
				
			||||||
 | 
					  forcevercode: false
 | 
				
			||||||
 | 
					  forceversion: false
 | 
				
			||||||
 | 
					  gradle: []
 | 
				
			||||||
 | 
					  gradleprops: []
 | 
				
			||||||
 | 
					  init: ''
 | 
				
			||||||
 | 
					  maven: null
 | 
				
			||||||
 | 
					  ndk: null
 | 
				
			||||||
 | 
					  novcheck: false
 | 
				
			||||||
 | 
					  oldsdkloc: false
 | 
				
			||||||
 | 
					  output: null
 | 
				
			||||||
 | 
					  patch: []
 | 
				
			||||||
 | 
					  postbuild: ''
 | 
				
			||||||
 | 
					  preassemble: []
 | 
				
			||||||
 | 
					  prebuild: ''
 | 
				
			||||||
 | 
					  rm: []
 | 
				
			||||||
 | 
					  scandelete: []
 | 
				
			||||||
 | 
					  scanignore: []
 | 
				
			||||||
 | 
					  srclibs: []
 | 
				
			||||||
 | 
					  subdir: null
 | 
				
			||||||
 | 
					  submodules: false
 | 
				
			||||||
 | 
					  sudo: ''
 | 
				
			||||||
 | 
					  target: null
 | 
				
			||||||
 | 
					  timeout: null
 | 
				
			||||||
 | 
					  versionCode: 32
 | 
				
			||||||
 | 
					  versionName: 1.0.0
 | 
				
			||||||
 | 
					- androidupdate: []
 | 
				
			||||||
 | 
					  antcommands: []
 | 
				
			||||||
 | 
					  antifeatures: {}
 | 
				
			||||||
 | 
					  binary: null
 | 
				
			||||||
 | 
					  build: ''
 | 
				
			||||||
 | 
					  buildjni: []
 | 
				
			||||||
 | 
					  commit: 252c8dd4c9
 | 
				
			||||||
 | 
					  disable: ''
 | 
				
			||||||
 | 
					  encoding: null
 | 
				
			||||||
 | 
					  extlibs: []
 | 
				
			||||||
 | 
					  forcevercode: false
 | 
				
			||||||
 | 
					  forceversion: false
 | 
				
			||||||
 | 
					  gradle: []
 | 
				
			||||||
 | 
					  gradleprops: []
 | 
				
			||||||
 | 
					  init: ''
 | 
				
			||||||
 | 
					  maven: null
 | 
				
			||||||
 | 
					  ndk: null
 | 
				
			||||||
 | 
					  novcheck: false
 | 
				
			||||||
 | 
					  oldsdkloc: false
 | 
				
			||||||
 | 
					  output: null
 | 
				
			||||||
 | 
					  patch: []
 | 
				
			||||||
 | 
					  postbuild: ''
 | 
				
			||||||
 | 
					  preassemble: []
 | 
				
			||||||
 | 
					  prebuild: ''
 | 
				
			||||||
 | 
					  rm: []
 | 
				
			||||||
 | 
					  scandelete: []
 | 
				
			||||||
 | 
					  scanignore: []
 | 
				
			||||||
 | 
					  srclibs: []
 | 
				
			||||||
 | 
					  subdir: null
 | 
				
			||||||
 | 
					  submodules: false
 | 
				
			||||||
 | 
					  sudo: ''
 | 
				
			||||||
 | 
					  target: null
 | 
				
			||||||
 | 
					  timeout: null
 | 
				
			||||||
 | 
					  versionCode: 33
 | 
				
			||||||
 | 
					  versionName: 1.0.1
 | 
				
			||||||
 | 
					- androidupdate: []
 | 
				
			||||||
 | 
					  antcommands: []
 | 
				
			||||||
 | 
					  antifeatures: {}
 | 
				
			||||||
 | 
					  binary: null
 | 
				
			||||||
 | 
					  build: ''
 | 
				
			||||||
 | 
					  buildjni: []
 | 
				
			||||||
 | 
					  commit: v1.2.0
 | 
				
			||||||
 | 
					  disable: ''
 | 
				
			||||||
 | 
					  encoding: null
 | 
				
			||||||
 | 
					  extlibs: []
 | 
				
			||||||
 | 
					  forcevercode: false
 | 
				
			||||||
 | 
					  forceversion: false
 | 
				
			||||||
 | 
					  gradle: []
 | 
				
			||||||
 | 
					  gradleprops: []
 | 
				
			||||||
 | 
					  init: ''
 | 
				
			||||||
 | 
					  maven: null
 | 
				
			||||||
 | 
					  ndk: null
 | 
				
			||||||
 | 
					  novcheck: false
 | 
				
			||||||
 | 
					  oldsdkloc: false
 | 
				
			||||||
 | 
					  output: null
 | 
				
			||||||
 | 
					  patch:
 | 
				
			||||||
 | 
					  - appbrain.patch
 | 
				
			||||||
 | 
					  postbuild: ''
 | 
				
			||||||
 | 
					  preassemble: []
 | 
				
			||||||
 | 
					  prebuild:
 | 
				
			||||||
 | 
					  - sed -i 's@\(reference.1=\).*@\1$$FacebookSDK$$@' project.properties
 | 
				
			||||||
 | 
					  - sed -i 's/Class\[\]/Class\<?\>\[\]/g' $$FacebookSDK$$/src/com/facebook/model/GraphObject.java
 | 
				
			||||||
 | 
					  rm:
 | 
				
			||||||
 | 
					  - libs/appbrain-sdk-android.jar
 | 
				
			||||||
 | 
					  scandelete: []
 | 
				
			||||||
 | 
					  scanignore: []
 | 
				
			||||||
 | 
					  srclibs:
 | 
				
			||||||
 | 
					  - FacebookSDK@sdk-version-3.0.1
 | 
				
			||||||
 | 
					  subdir: null
 | 
				
			||||||
 | 
					  submodules: false
 | 
				
			||||||
 | 
					  sudo: ''
 | 
				
			||||||
 | 
					  target: null
 | 
				
			||||||
 | 
					  timeout: null
 | 
				
			||||||
 | 
					  versionCode: 39
 | 
				
			||||||
 | 
					  versionName: 1.2.0
 | 
				
			||||||
 | 
					- androidupdate: []
 | 
				
			||||||
 | 
					  antcommands: []
 | 
				
			||||||
 | 
					  antifeatures: {}
 | 
				
			||||||
 | 
					  binary: null
 | 
				
			||||||
 | 
					  build: ''
 | 
				
			||||||
 | 
					  buildjni: []
 | 
				
			||||||
 | 
					  commit: v1.2.2
 | 
				
			||||||
 | 
					  disable: ''
 | 
				
			||||||
 | 
					  encoding: null
 | 
				
			||||||
 | 
					  extlibs:
 | 
				
			||||||
 | 
					  - android/android-support-v4.jar
 | 
				
			||||||
 | 
					  forcevercode: false
 | 
				
			||||||
 | 
					  forceversion: false
 | 
				
			||||||
 | 
					  gradle: []
 | 
				
			||||||
 | 
					  gradleprops: []
 | 
				
			||||||
 | 
					  init: ''
 | 
				
			||||||
 | 
					  maven: null
 | 
				
			||||||
 | 
					  ndk: null
 | 
				
			||||||
 | 
					  novcheck: false
 | 
				
			||||||
 | 
					  oldsdkloc: false
 | 
				
			||||||
 | 
					  output: null
 | 
				
			||||||
 | 
					  patch:
 | 
				
			||||||
 | 
					  - appbrain.patch
 | 
				
			||||||
 | 
					  postbuild: ''
 | 
				
			||||||
 | 
					  preassemble: []
 | 
				
			||||||
 | 
					  prebuild:
 | 
				
			||||||
 | 
					  - mv libs/android-support-v4.jar $$FacebookSDK$$/libs/
 | 
				
			||||||
 | 
					  - sed -i 's@\(reference.1=\).*@\1$$FacebookSDK$$@' project.properties
 | 
				
			||||||
 | 
					  - sed -i 's/Class\[\]/Class\<?\>\[\]/g'          $$FacebookSDK$$/src/com/facebook/model/GraphObject.java
 | 
				
			||||||
 | 
					  rm:
 | 
				
			||||||
 | 
					  - libs/appbrain-sdk-android.jar
 | 
				
			||||||
 | 
					  scandelete: []
 | 
				
			||||||
 | 
					  scanignore: []
 | 
				
			||||||
 | 
					  srclibs:
 | 
				
			||||||
 | 
					  - FacebookSDK@sdk-version-3.0.2
 | 
				
			||||||
 | 
					  subdir: null
 | 
				
			||||||
 | 
					  submodules: false
 | 
				
			||||||
 | 
					  sudo: ''
 | 
				
			||||||
 | 
					  target: null
 | 
				
			||||||
 | 
					  timeout: null
 | 
				
			||||||
 | 
					  versionCode: 42
 | 
				
			||||||
 | 
					  versionName: 1.2.2
 | 
				
			||||||
 | 
					- androidupdate: []
 | 
				
			||||||
 | 
					  antcommands: []
 | 
				
			||||||
 | 
					  antifeatures: {}
 | 
				
			||||||
 | 
					  binary: null
 | 
				
			||||||
 | 
					  build: ''
 | 
				
			||||||
 | 
					  buildjni: []
 | 
				
			||||||
 | 
					  commit: 2.1.1
 | 
				
			||||||
 | 
					  disable: ''
 | 
				
			||||||
 | 
					  encoding: null
 | 
				
			||||||
 | 
					  extlibs: []
 | 
				
			||||||
 | 
					  forcevercode: false
 | 
				
			||||||
 | 
					  forceversion: false
 | 
				
			||||||
 | 
					  gradle: []
 | 
				
			||||||
 | 
					  gradleprops: []
 | 
				
			||||||
 | 
					  init: ''
 | 
				
			||||||
 | 
					  maven: yes
 | 
				
			||||||
 | 
					  ndk: null
 | 
				
			||||||
 | 
					  novcheck: false
 | 
				
			||||||
 | 
					  oldsdkloc: false
 | 
				
			||||||
 | 
					  output: null
 | 
				
			||||||
 | 
					  patch:
 | 
				
			||||||
 | 
					  - manifest-ads.patch
 | 
				
			||||||
 | 
					  - mobilecore.patch
 | 
				
			||||||
 | 
					  postbuild: ''
 | 
				
			||||||
 | 
					  preassemble: []
 | 
				
			||||||
 | 
					  prebuild: ''
 | 
				
			||||||
 | 
					  rm: []
 | 
				
			||||||
 | 
					  scandelete: []
 | 
				
			||||||
 | 
					  scanignore: []
 | 
				
			||||||
 | 
					  srclibs:
 | 
				
			||||||
 | 
					  - FacebookSDK@sdk-version-3.0.2
 | 
				
			||||||
 | 
					  subdir: null
 | 
				
			||||||
 | 
					  submodules: false
 | 
				
			||||||
 | 
					  sudo: ''
 | 
				
			||||||
 | 
					  target: null
 | 
				
			||||||
 | 
					  timeout: null
 | 
				
			||||||
 | 
					  versionCode: 48
 | 
				
			||||||
 | 
					  versionName: 2.1.1
 | 
				
			||||||
 | 
					- androidupdate: []
 | 
				
			||||||
 | 
					  antcommands: []
 | 
				
			||||||
 | 
					  antifeatures:
 | 
				
			||||||
 | 
					    Tracking:
 | 
				
			||||||
 | 
					      en-US: Uses the Facebook SDK.
 | 
				
			||||||
 | 
					  binary: null
 | 
				
			||||||
 | 
					  build: ''
 | 
				
			||||||
 | 
					  buildjni: []
 | 
				
			||||||
 | 
					  commit: 2.1.1
 | 
				
			||||||
 | 
					  disable: ''
 | 
				
			||||||
 | 
					  encoding: null
 | 
				
			||||||
 | 
					  extlibs: []
 | 
				
			||||||
 | 
					  forcevercode: false
 | 
				
			||||||
 | 
					  forceversion: false
 | 
				
			||||||
 | 
					  gradle: []
 | 
				
			||||||
 | 
					  gradleprops: []
 | 
				
			||||||
 | 
					  init: ''
 | 
				
			||||||
 | 
					  maven: yes@..
 | 
				
			||||||
 | 
					  ndk: null
 | 
				
			||||||
 | 
					  novcheck: false
 | 
				
			||||||
 | 
					  oldsdkloc: false
 | 
				
			||||||
 | 
					  output: null
 | 
				
			||||||
 | 
					  patch:
 | 
				
			||||||
 | 
					  - manifest-ads.patch
 | 
				
			||||||
 | 
					  - mobilecore.patch
 | 
				
			||||||
 | 
					  postbuild: ''
 | 
				
			||||||
 | 
					  preassemble: []
 | 
				
			||||||
 | 
					  prebuild: ''
 | 
				
			||||||
 | 
					  rm: []
 | 
				
			||||||
 | 
					  scandelete: []
 | 
				
			||||||
 | 
					  scanignore: []
 | 
				
			||||||
 | 
					  srclibs:
 | 
				
			||||||
 | 
					  - FacebookSDK@sdk-version-3.0.2
 | 
				
			||||||
 | 
					  subdir: null
 | 
				
			||||||
 | 
					  submodules: false
 | 
				
			||||||
 | 
					  sudo: ''
 | 
				
			||||||
 | 
					  target: null
 | 
				
			||||||
 | 
					  timeout: null
 | 
				
			||||||
 | 
					  versionCode: 49
 | 
				
			||||||
 | 
					  versionName: 2.1.1-b
 | 
				
			||||||
 | 
					- androidupdate: []
 | 
				
			||||||
 | 
					  antcommands: []
 | 
				
			||||||
 | 
					  antifeatures:
 | 
				
			||||||
 | 
					    Ads:
 | 
				
			||||||
 | 
					      en-US: 'includes ad lib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        '
 | 
				
			||||||
 | 
					      zh-CN: '包括广告图书馆
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        '
 | 
				
			||||||
 | 
					    Tracking:
 | 
				
			||||||
 | 
					      en-US: 'standard suspects
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        '
 | 
				
			||||||
 | 
					  binary: null
 | 
				
			||||||
 | 
					  build: ''
 | 
				
			||||||
 | 
					  buildjni: []
 | 
				
			||||||
 | 
					  commit: 2.1.1
 | 
				
			||||||
 | 
					  disable: ''
 | 
				
			||||||
 | 
					  encoding: null
 | 
				
			||||||
 | 
					  extlibs: []
 | 
				
			||||||
 | 
					  forcevercode: false
 | 
				
			||||||
 | 
					  forceversion: false
 | 
				
			||||||
 | 
					  gradle: []
 | 
				
			||||||
 | 
					  gradleprops: []
 | 
				
			||||||
 | 
					  init: ''
 | 
				
			||||||
 | 
					  maven: '2'
 | 
				
			||||||
 | 
					  ndk: null
 | 
				
			||||||
 | 
					  novcheck: false
 | 
				
			||||||
 | 
					  oldsdkloc: false
 | 
				
			||||||
 | 
					  output: null
 | 
				
			||||||
 | 
					  patch:
 | 
				
			||||||
 | 
					  - manifest-ads.patch
 | 
				
			||||||
 | 
					  - mobilecore.patch
 | 
				
			||||||
 | 
					  postbuild: ''
 | 
				
			||||||
 | 
					  preassemble: []
 | 
				
			||||||
 | 
					  prebuild: ''
 | 
				
			||||||
 | 
					  rm: []
 | 
				
			||||||
 | 
					  scandelete: []
 | 
				
			||||||
 | 
					  scanignore: []
 | 
				
			||||||
 | 
					  srclibs:
 | 
				
			||||||
 | 
					  - FacebookSDK@sdk-version-3.0.2
 | 
				
			||||||
 | 
					  subdir: null
 | 
				
			||||||
 | 
					  submodules: false
 | 
				
			||||||
 | 
					  sudo: ''
 | 
				
			||||||
 | 
					  target: null
 | 
				
			||||||
 | 
					  timeout: null
 | 
				
			||||||
 | 
					  versionCode: 50
 | 
				
			||||||
 | 
					  versionName: 2.1.1-c
 | 
				
			||||||
 | 
					- androidupdate: []
 | 
				
			||||||
 | 
					  antcommands: []
 | 
				
			||||||
 | 
					  antifeatures: {}
 | 
				
			||||||
 | 
					  binary: null
 | 
				
			||||||
 | 
					  build: ''
 | 
				
			||||||
 | 
					  buildjni: []
 | 
				
			||||||
 | 
					  commit: null
 | 
				
			||||||
 | 
					  disable: Labelled as pre-release, so skipped
 | 
				
			||||||
 | 
					  encoding: null
 | 
				
			||||||
 | 
					  extlibs: []
 | 
				
			||||||
 | 
					  forcevercode: false
 | 
				
			||||||
 | 
					  forceversion: false
 | 
				
			||||||
 | 
					  gradle: []
 | 
				
			||||||
 | 
					  gradleprops: []
 | 
				
			||||||
 | 
					  init: ''
 | 
				
			||||||
 | 
					  maven: null
 | 
				
			||||||
 | 
					  ndk: null
 | 
				
			||||||
 | 
					  novcheck: false
 | 
				
			||||||
 | 
					  oldsdkloc: false
 | 
				
			||||||
 | 
					  output: null
 | 
				
			||||||
 | 
					  patch: []
 | 
				
			||||||
 | 
					  postbuild: ''
 | 
				
			||||||
 | 
					  preassemble: []
 | 
				
			||||||
 | 
					  prebuild: ''
 | 
				
			||||||
 | 
					  rm: []
 | 
				
			||||||
 | 
					  scandelete: []
 | 
				
			||||||
 | 
					  scanignore: []
 | 
				
			||||||
 | 
					  srclibs: []
 | 
				
			||||||
 | 
					  subdir: null
 | 
				
			||||||
 | 
					  submodules: false
 | 
				
			||||||
 | 
					  sudo: ''
 | 
				
			||||||
 | 
					  target: null
 | 
				
			||||||
 | 
					  timeout: null
 | 
				
			||||||
 | 
					  versionCode: 51
 | 
				
			||||||
 | 
					  versionName: 2.1.2
 | 
				
			||||||
 | 
					Categories:
 | 
				
			||||||
 | 
					- System
 | 
				
			||||||
 | 
					Changelog: ''
 | 
				
			||||||
 | 
					CurrentVersion: 2.1.2
 | 
				
			||||||
 | 
					CurrentVersionCode: 49
 | 
				
			||||||
 | 
					Description: 'To configure, go to "Settings => Accounts & Sync => Add Account". Depending
 | 
				
			||||||
 | 
					  on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  how many friends you have, the first import might take a while, so be patient.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  * Facebook does not allow to export phone numbers or emails: only names, pictures
 | 
				
			||||||
 | 
					  and statuses are synced.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  * Facebook users have the option to block one or all apps: if they opt for that,
 | 
				
			||||||
 | 
					  they will be EXCLUDED from your friends list.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Appbrain SDK was removed before building.'
 | 
				
			||||||
 | 
					Disabled: null
 | 
				
			||||||
 | 
					Donate: null
 | 
				
			||||||
 | 
					FlattrID: null
 | 
				
			||||||
 | 
					IssueTracker: https://github.com/loadrunner/Facebook-Contact-Sync/issues
 | 
				
			||||||
 | 
					Liberapay: null
 | 
				
			||||||
 | 
					License: GPL-3.0-only
 | 
				
			||||||
 | 
					Litecoin: null
 | 
				
			||||||
 | 
					MaintainerNotes: ''
 | 
				
			||||||
 | 
					Name: null
 | 
				
			||||||
 | 
					NoSourceSince: ''
 | 
				
			||||||
 | 
					OpenCollective: null
 | 
				
			||||||
 | 
					Provides: null
 | 
				
			||||||
 | 
					Repo: https://github.com/loadrunner/Facebook-Contact-Sync.git
 | 
				
			||||||
 | 
					RepoType: git
 | 
				
			||||||
 | 
					RequiresRoot: false
 | 
				
			||||||
 | 
					SourceCode: https://github.com/loadrunner/Facebook-Contact-Sync
 | 
				
			||||||
 | 
					Summary: Sync your Facebook Contacts
 | 
				
			||||||
 | 
					Translation: ''
 | 
				
			||||||
 | 
					UpdateCheckData: null
 | 
				
			||||||
 | 
					UpdateCheckIgnore: null
 | 
				
			||||||
 | 
					UpdateCheckMode: None
 | 
				
			||||||
 | 
					UpdateCheckName: null
 | 
				
			||||||
 | 
					VercodeOperation: []
 | 
				
			||||||
 | 
					WebSite: ''
 | 
				
			||||||
 | 
					added: null
 | 
				
			||||||
 | 
					id: app.with.special.build.params
 | 
				
			||||||
 | 
					lastUpdated: null
 | 
				
			||||||
 | 
					metadatapath: metadata/app.with.special.build.params.yml
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
AllowedAPKSigningKeys: []
 | 
					AllowedAPKSigningKeys: []
 | 
				
			||||||
AntiFeatures:
 | 
					AntiFeatures:
 | 
				
			||||||
- NonFreeNet
 | 
					  NoSourceSince:
 | 
				
			||||||
 | 
					    en-US: '1.5'
 | 
				
			||||||
 | 
					  NonFreeNet: {}
 | 
				
			||||||
ArchivePolicy: 4 versions
 | 
					ArchivePolicy: 4 versions
 | 
				
			||||||
AuthorEmail: null
 | 
					AuthorEmail: null
 | 
				
			||||||
AuthorName: null
 | 
					AuthorName: null
 | 
				
			||||||
| 
						 | 
					@ -13,9 +15,9 @@ Builds:
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures:
 | 
					  antifeatures:
 | 
				
			||||||
  - KnownVuln
 | 
					    KnownVuln: {}
 | 
				
			||||||
  - UpstreamNonFree
 | 
					    NonFreeAssets: {}
 | 
				
			||||||
  - NonFreeAssets
 | 
					    UpstreamNonFree: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -50,7 +52,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.2'
 | 
					  versionName: '1.2'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -85,7 +87,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.3'
 | 
					  versionName: '1.3'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -120,7 +122,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.4'
 | 
					  versionName: '1.4'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
AllowedAPKSigningKeys: []
 | 
					AllowedAPKSigningKeys: []
 | 
				
			||||||
AntiFeatures: []
 | 
					AntiFeatures: {}
 | 
				
			||||||
ArchivePolicy: null
 | 
					ArchivePolicy: null
 | 
				
			||||||
AuthorEmail: null
 | 
					AuthorEmail: null
 | 
				
			||||||
AuthorName: null
 | 
					AuthorName: null
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@ Bitcoin: null
 | 
				
			||||||
Builds:
 | 
					Builds:
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -47,7 +47,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.12'
 | 
					  versionName: '1.12'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -84,7 +84,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.15'
 | 
					  versionName: '1.15'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -121,7 +121,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.18'
 | 
					  versionName: '1.18'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -158,7 +158,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.19'
 | 
					  versionName: '1.19'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -195,7 +195,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.20'
 | 
					  versionName: '1.20'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -232,7 +232,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.21'
 | 
					  versionName: '1.21'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -267,7 +267,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.23'
 | 
					  versionName: '1.23'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -304,7 +304,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.24'
 | 
					  versionName: '1.24'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -341,7 +341,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.25'
 | 
					  versionName: '1.25'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -378,7 +378,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.26'
 | 
					  versionName: '1.26'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -415,7 +415,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.27'
 | 
					  versionName: '1.27'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -453,7 +453,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.29'
 | 
					  versionName: '1.29'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -491,7 +491,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.32'
 | 
					  versionName: '1.32'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -528,7 +528,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.33'
 | 
					  versionName: '1.33'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -566,7 +566,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.34'
 | 
					  versionName: '1.34'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -604,7 +604,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.35'
 | 
					  versionName: '1.35'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -642,7 +642,7 @@ Builds:
 | 
				
			||||||
  versionName: '1.36'
 | 
					  versionName: '1.36'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -684,7 +684,7 @@ Builds:
 | 
				
			||||||
  - android-libs/ActionBarSherlock
 | 
					  - android-libs/ActionBarSherlock
 | 
				
			||||||
  - android-libs/HtmlSpanner/htmlspanner
 | 
					  - android-libs/HtmlSpanner/htmlspanner
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -734,7 +734,7 @@ Builds:
 | 
				
			||||||
  - android-libs/ActionBarSherlock
 | 
					  - android-libs/ActionBarSherlock
 | 
				
			||||||
  - android-libs/HtmlSpanner/htmlspanner
 | 
					  - android-libs/HtmlSpanner/htmlspanner
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -780,7 +780,7 @@ Builds:
 | 
				
			||||||
  versionName: '2.3'
 | 
					  versionName: '2.3'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -818,7 +818,7 @@ Builds:
 | 
				
			||||||
  versionName: '2.6'
 | 
					  versionName: '2.6'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -856,7 +856,7 @@ Builds:
 | 
				
			||||||
  versionName: '2.7'
 | 
					  versionName: '2.7'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -894,7 +894,7 @@ Builds:
 | 
				
			||||||
  versionName: '2.8'
 | 
					  versionName: '2.8'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -932,7 +932,7 @@ Builds:
 | 
				
			||||||
  versionName: 2.8.1
 | 
					  versionName: 2.8.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -970,7 +970,7 @@ Builds:
 | 
				
			||||||
  versionName: '2.9'
 | 
					  versionName: '2.9'
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -1008,7 +1008,7 @@ Builds:
 | 
				
			||||||
  versionName: 2.9.1
 | 
					  versionName: 2.9.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					@ -1046,7 +1046,7 @@ Builds:
 | 
				
			||||||
  versionName: 2.9.2
 | 
					  versionName: 2.9.2
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni:
 | 
					  buildjni:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
AllowedAPKSigningKeys: []
 | 
					AllowedAPKSigningKeys: []
 | 
				
			||||||
AntiFeatures: []
 | 
					AntiFeatures: {}
 | 
				
			||||||
ArchivePolicy: null
 | 
					ArchivePolicy: null
 | 
				
			||||||
AuthorEmail: null
 | 
					AuthorEmail: null
 | 
				
			||||||
AuthorName: null
 | 
					AuthorName: null
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@ Bitcoin: null
 | 
				
			||||||
Builds:
 | 
					Builds:
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -72,7 +72,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.3.3
 | 
					  versionName: 0.3.3
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -115,7 +115,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.3.3
 | 
					  versionName: 0.3.3
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -156,7 +156,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.4.2
 | 
					  versionName: 0.4.2
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -197,7 +197,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.5.1
 | 
					  versionName: 0.5.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -237,7 +237,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.5.2
 | 
					  versionName: 0.5.2
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -277,7 +277,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.5.3
 | 
					  versionName: 0.5.3
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					@ -317,7 +317,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.5.4
 | 
					  versionName: 0.5.4
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build: ''
 | 
					  build: ''
 | 
				
			||||||
  buildjni: []
 | 
					  buildjni: []
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
AllowedAPKSigningKeys: []
 | 
					AllowedAPKSigningKeys: []
 | 
				
			||||||
AntiFeatures: []
 | 
					AntiFeatures: {}
 | 
				
			||||||
ArchivePolicy: 9 versions
 | 
					ArchivePolicy: 9 versions
 | 
				
			||||||
AuthorEmail: null
 | 
					AuthorEmail: null
 | 
				
			||||||
AuthorName: null
 | 
					AuthorName: null
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@ Builds:
 | 
				
			||||||
  - ../java-libs/SlidingMenu
 | 
					  - ../java-libs/SlidingMenu
 | 
				
			||||||
  - ../java-libs/ActionBarSherlock
 | 
					  - ../java-libs/ActionBarSherlock
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -54,7 +54,7 @@ Builds:
 | 
				
			||||||
  - ../java-libs/SlidingMenu
 | 
					  - ../java-libs/SlidingMenu
 | 
				
			||||||
  - ../java-libs/ActionBarSherlock
 | 
					  - ../java-libs/ActionBarSherlock
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -94,7 +94,7 @@ Builds:
 | 
				
			||||||
  - ../java-libs/SlidingMenu
 | 
					  - ../java-libs/SlidingMenu
 | 
				
			||||||
  - ../java-libs/ActionBarSherlock
 | 
					  - ../java-libs/ActionBarSherlock
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -134,7 +134,7 @@ Builds:
 | 
				
			||||||
  - ../java-libs/SlidingMenu
 | 
					  - ../java-libs/SlidingMenu
 | 
				
			||||||
  - ../java-libs/ActionBarSherlock
 | 
					  - ../java-libs/ActionBarSherlock
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=mips ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=mips ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -171,7 +171,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.0.11-mips
 | 
					  versionName: 0.0.11-mips
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=mips ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=mips ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -210,7 +210,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.1.3-MIPS
 | 
					  versionName: 0.1.3-MIPS
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -249,7 +249,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.1.3-x86
 | 
					  versionName: 0.1.3-x86
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -288,7 +288,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.1.3-ARM
 | 
					  versionName: 0.1.3-ARM
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -327,7 +327,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.1.3-ARMv7
 | 
					  versionName: 0.1.3-ARMv7
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -365,7 +365,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.0
 | 
					  versionName: 0.9.0
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -403,7 +403,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.0
 | 
					  versionName: 0.9.0
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -441,7 +441,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.1
 | 
					  versionName: 0.9.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -479,7 +479,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.1
 | 
					  versionName: 0.9.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -517,7 +517,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.5
 | 
					  versionName: 0.9.5
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -555,7 +555,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.5
 | 
					  versionName: 0.9.5
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -593,7 +593,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.6
 | 
					  versionName: 0.9.6
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -631,7 +631,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.6
 | 
					  versionName: 0.9.6
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -669,7 +669,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.7
 | 
					  versionName: 0.9.7
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -707,7 +707,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.7
 | 
					  versionName: 0.9.7
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=mips ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=mips ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -745,7 +745,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.7.1
 | 
					  versionName: 0.9.7.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -783,7 +783,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.7.1
 | 
					  versionName: 0.9.7.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -821,7 +821,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.7.1
 | 
					  versionName: 0.9.7.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -859,7 +859,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.8
 | 
					  versionName: 0.9.8
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -897,7 +897,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.8
 | 
					  versionName: 0.9.8
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -935,7 +935,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.8
 | 
					  versionName: 0.9.8
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -973,7 +973,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.9
 | 
					  versionName: 0.9.9
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -1011,7 +1011,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.9
 | 
					  versionName: 0.9.9
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -1049,7 +1049,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.9
 | 
					  versionName: 0.9.9
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -1087,7 +1087,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.10
 | 
					  versionName: 0.9.10
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -1125,7 +1125,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.10
 | 
					  versionName: 0.9.10
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -1163,7 +1163,7 @@ Builds:
 | 
				
			||||||
  versionName: 0.9.10
 | 
					  versionName: 0.9.10
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -1201,7 +1201,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.0.0
 | 
					  versionName: 1.0.0
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -1239,7 +1239,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.0.0
 | 
					  versionName: 1.0.0
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -1277,7 +1277,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.0.0
 | 
					  versionName: 1.0.0
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=x86 ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -1315,7 +1315,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.0.1
 | 
					  versionName: 1.0.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -1353,7 +1353,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.0.1
 | 
					  versionName: 1.0.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
					  - cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
 | 
				
			||||||
| 
						 | 
					@ -1391,7 +1391,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.0.1
 | 
					  versionName: 1.0.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
				
			||||||
| 
						 | 
					@ -1431,7 +1431,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.1.3
 | 
					  versionName: 1.1.3
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
				
			||||||
| 
						 | 
					@ -1471,7 +1471,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.1.3
 | 
					  versionName: 1.1.3
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "x86" --release
 | 
					  - cd ../ && ./compile.sh -a "x86" --release
 | 
				
			||||||
| 
						 | 
					@ -1511,7 +1511,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.1.3
 | 
					  versionName: 1.1.3
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
				
			||||||
| 
						 | 
					@ -1551,7 +1551,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.1.5
 | 
					  versionName: 1.1.5
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
				
			||||||
| 
						 | 
					@ -1591,7 +1591,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.1.5
 | 
					  versionName: 1.1.5
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "x86" --release
 | 
					  - cd ../ && ./compile.sh -a "x86" --release
 | 
				
			||||||
| 
						 | 
					@ -1631,7 +1631,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.1.5
 | 
					  versionName: 1.1.5
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
				
			||||||
| 
						 | 
					@ -1671,7 +1671,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.1.6
 | 
					  versionName: 1.1.6
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
				
			||||||
| 
						 | 
					@ -1711,7 +1711,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.1.6
 | 
					  versionName: 1.1.6
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "x86" --release
 | 
					  - cd ../ && ./compile.sh -a "x86" --release
 | 
				
			||||||
| 
						 | 
					@ -1751,7 +1751,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.1.6
 | 
					  versionName: 1.1.6
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
				
			||||||
| 
						 | 
					@ -1791,7 +1791,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.0
 | 
					  versionName: 1.2.0
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
				
			||||||
| 
						 | 
					@ -1831,7 +1831,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.0
 | 
					  versionName: 1.2.0
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "x86" --release
 | 
					  - cd ../ && ./compile.sh -a "x86" --release
 | 
				
			||||||
| 
						 | 
					@ -1871,7 +1871,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.0
 | 
					  versionName: 1.2.0
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
				
			||||||
| 
						 | 
					@ -1911,7 +1911,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.1
 | 
					  versionName: 1.2.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
				
			||||||
| 
						 | 
					@ -1951,7 +1951,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.1
 | 
					  versionName: 1.2.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "x86" --release
 | 
					  - cd ../ && ./compile.sh -a "x86" --release
 | 
				
			||||||
| 
						 | 
					@ -1991,7 +1991,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.1
 | 
					  versionName: 1.2.1
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
				
			||||||
| 
						 | 
					@ -2031,7 +2031,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.2
 | 
					  versionName: 1.2.2
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
				
			||||||
| 
						 | 
					@ -2071,7 +2071,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.2
 | 
					  versionName: 1.2.2
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "x86" --release
 | 
					  - cd ../ && ./compile.sh -a "x86" --release
 | 
				
			||||||
| 
						 | 
					@ -2111,7 +2111,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.2
 | 
					  versionName: 1.2.2
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
				
			||||||
| 
						 | 
					@ -2151,7 +2151,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.3
 | 
					  versionName: 1.2.3
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
				
			||||||
| 
						 | 
					@ -2191,7 +2191,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.3
 | 
					  versionName: 1.2.3
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "x86" --release
 | 
					  - cd ../ && ./compile.sh -a "x86" --release
 | 
				
			||||||
| 
						 | 
					@ -2231,7 +2231,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.3
 | 
					  versionName: 1.2.3
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
				
			||||||
| 
						 | 
					@ -2271,7 +2271,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.4
 | 
					  versionName: 1.2.4
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
				
			||||||
| 
						 | 
					@ -2311,7 +2311,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.4
 | 
					  versionName: 1.2.4
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "x86" --release
 | 
					  - cd ../ && ./compile.sh -a "x86" --release
 | 
				
			||||||
| 
						 | 
					@ -2351,7 +2351,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.4
 | 
					  versionName: 1.2.4
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
				
			||||||
| 
						 | 
					@ -2391,7 +2391,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.5
 | 
					  versionName: 1.2.5
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
				
			||||||
| 
						 | 
					@ -2431,7 +2431,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.5
 | 
					  versionName: 1.2.5
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "x86" --release
 | 
					  - cd ../ && ./compile.sh -a "x86" --release
 | 
				
			||||||
| 
						 | 
					@ -2471,7 +2471,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.5
 | 
					  versionName: 1.2.5
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi" --release
 | 
				
			||||||
| 
						 | 
					@ -2511,7 +2511,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.6
 | 
					  versionName: 1.2.6
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
					  - cd ../ && ./compile.sh -a "armeabi-v7a" --release
 | 
				
			||||||
| 
						 | 
					@ -2551,7 +2551,7 @@ Builds:
 | 
				
			||||||
  versionName: 1.2.6
 | 
					  versionName: 1.2.6
 | 
				
			||||||
- androidupdate: []
 | 
					- androidupdate: []
 | 
				
			||||||
  antcommands: []
 | 
					  antcommands: []
 | 
				
			||||||
  antifeatures: []
 | 
					  antifeatures: {}
 | 
				
			||||||
  binary: null
 | 
					  binary: null
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
  - cd ../ && ./compile.sh -a "x86" --release
 | 
					  - cd ../ && ./compile.sh -a "x86" --release
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,8 +3,8 @@
 | 
				
			||||||
  "version": 20002,
 | 
					  "version": 20002,
 | 
				
			||||||
  "index": {
 | 
					  "index": {
 | 
				
			||||||
    "name": "/index-v2.json",
 | 
					    "name": "/index-v2.json",
 | 
				
			||||||
    "sha256": "a3c7e88a522a7228937e5c3d760fc239e3578e292035d88478d32fec9ff5eb54",
 | 
					    "sha256": "f4979b9db840cb51a99e80c20da676ba42b13133dbaa4819673bc43ed2ffc3f3",
 | 
				
			||||||
    "size": 52314,
 | 
					    "size": 52481,
 | 
				
			||||||
    "numPackages": 10
 | 
					    "numPackages": 10
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "diffs": {}
 | 
					  "diffs": {}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -568,7 +568,9 @@
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "antiFeatures": {
 | 
					          "antiFeatures": {
 | 
				
			||||||
            "NoSourceSince": {},
 | 
					            "NoSourceSince": {
 | 
				
			||||||
 | 
					              "en-US": "1.5"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            "NonFreeNet": {}
 | 
					            "NonFreeNet": {}
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
| 
						 | 
					@ -602,7 +604,9 @@
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "antiFeatures": {
 | 
					          "antiFeatures": {
 | 
				
			||||||
            "NoSourceSince": {},
 | 
					            "NoSourceSince": {
 | 
				
			||||||
 | 
					              "en-US": "1.5"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            "NonFreeNet": {}
 | 
					            "NonFreeNet": {}
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
| 
						 | 
					@ -645,7 +649,9 @@
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "antiFeatures": {
 | 
					          "antiFeatures": {
 | 
				
			||||||
            "NoSourceSince": {},
 | 
					            "NoSourceSince": {
 | 
				
			||||||
 | 
					              "en-US": "1.5"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            "NonFreeNet": {}
 | 
					            "NonFreeNet": {}
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
| 
						 | 
					@ -689,7 +695,9 @@
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "antiFeatures": {
 | 
					          "antiFeatures": {
 | 
				
			||||||
            "KnownVuln": {},
 | 
					            "KnownVuln": {},
 | 
				
			||||||
            "NoSourceSince": {},
 | 
					            "NoSourceSince": {
 | 
				
			||||||
 | 
					              "en-US": "1.5"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            "NonFreeAssets": {},
 | 
					            "NonFreeAssets": {},
 | 
				
			||||||
            "NonFreeNet": {},
 | 
					            "NonFreeNet": {},
 | 
				
			||||||
            "UpstreamNonFree": {}
 | 
					            "UpstreamNonFree": {}
 | 
				
			||||||
| 
						 | 
					@ -1395,4 +1403,4 @@
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -45,11 +45,11 @@ class RewriteMetaTest(unittest.TestCase):
 | 
				
			||||||
                'versionCode': 3,
 | 
					                'versionCode': 3,
 | 
				
			||||||
                'commit': '6a548e4b19',
 | 
					                'commit': '6a548e4b19',
 | 
				
			||||||
                'target': 'android-10',
 | 
					                'target': 'android-10',
 | 
				
			||||||
                'antifeatures': [
 | 
					                'antifeatures': {
 | 
				
			||||||
                    'KnownVuln',
 | 
					                    'KnownVuln': {},
 | 
				
			||||||
                    'UpstreamNonFree',
 | 
					                    'UpstreamNonFree': {},
 | 
				
			||||||
                    'NonFreeAssets',
 | 
					                    'NonFreeAssets': {},
 | 
				
			||||||
                ],
 | 
					                },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,6 +68,24 @@ class RewriteMetaTest(unittest.TestCase):
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_remove_blank_flags_from_builds_org_adaway_52(self):
 | 
				
			||||||
 | 
					        """Unset fields in Builds: entries should be removed."""
 | 
				
			||||||
 | 
					        appid = 'org.adaway'
 | 
				
			||||||
 | 
					        app = metadata.read_metadata({appid: -1})[appid]
 | 
				
			||||||
 | 
					        builds = rewritemeta.remove_blank_flags_from_builds(app.get('Builds'))
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            builds[-1],
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                'buildjni': ['yes'],
 | 
				
			||||||
 | 
					                'commit': 'v3.0',
 | 
				
			||||||
 | 
					                'gradle': ['yes'],
 | 
				
			||||||
 | 
					                'preassemble': ['renameExecutables'],
 | 
				
			||||||
 | 
					                'subdir': 'AdAway',
 | 
				
			||||||
 | 
					                'versionCode': 52,
 | 
				
			||||||
 | 
					                'versionName': '3.0',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_remove_blank_flags_from_builds_no_builds(self):
 | 
					    def test_remove_blank_flags_from_builds_no_builds(self):
 | 
				
			||||||
        """Unset fields in Builds: entries should be removed."""
 | 
					        """Unset fields in Builds: entries should be removed."""
 | 
				
			||||||
        self.assertEqual(
 | 
					        self.assertEqual(
 | 
				
			||||||
| 
						 | 
					@ -78,6 +96,24 @@ class RewriteMetaTest(unittest.TestCase):
 | 
				
			||||||
            rewritemeta.remove_blank_flags_from_builds(dict()),
 | 
					            rewritemeta.remove_blank_flags_from_builds(dict()),
 | 
				
			||||||
            list(),
 | 
					            list(),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            rewritemeta.remove_blank_flags_from_builds(list()),
 | 
				
			||||||
 | 
					            list(),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            rewritemeta.remove_blank_flags_from_builds(set()),
 | 
				
			||||||
 | 
					            list(),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            rewritemeta.remove_blank_flags_from_builds(tuple()),
 | 
				
			||||||
 | 
					            list(),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_remove_blank_flags_from_builds_0_is_a_value(self):
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            rewritemeta.remove_blank_flags_from_builds([{'versionCode': 0}]),
 | 
				
			||||||
 | 
					            [{'versionCode': 0}],
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_rewrite_no_builds(self):
 | 
					    def test_rewrite_no_builds(self):
 | 
				
			||||||
        os.chdir(self.testdir)
 | 
					        os.chdir(self.testdir)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -768,7 +768,7 @@ class UpdateTest(unittest.TestCase):
 | 
				
			||||||
                                                 '-1': 'res/drawable-mdpi-v4/icon_launcher.png'})
 | 
					                                                 '-1': 'res/drawable-mdpi-v4/icon_launcher.png'})
 | 
				
			||||||
        self.assertEqual(apk_info['icons'], {})
 | 
					        self.assertEqual(apk_info['icons'], {})
 | 
				
			||||||
        self.assertEqual(apk_info['features'], [])
 | 
					        self.assertEqual(apk_info['features'], [])
 | 
				
			||||||
        self.assertEqual(apk_info['antiFeatures'], set())
 | 
					        self.assertEqual(apk_info['antiFeatures'], dict())
 | 
				
			||||||
        self.assertEqual(apk_info['versionName'], 'v1.6pre2')
 | 
					        self.assertEqual(apk_info['versionName'], 'v1.6pre2')
 | 
				
			||||||
        self.assertEqual(apk_info['hash'],
 | 
					        self.assertEqual(apk_info['hash'],
 | 
				
			||||||
                         '897486e1f857c6c0ee32ccbad0e1b8cd82f6d0e65a44a23f13f852d2b63a18c8')
 | 
					                         '897486e1f857c6c0ee32ccbad0e1b8cd82f6d0e65a44a23f13f852d2b63a18c8')
 | 
				
			||||||
| 
						 | 
					@ -819,7 +819,7 @@ class UpdateTest(unittest.TestCase):
 | 
				
			||||||
            'hashType': 'sha256',
 | 
					            'hashType': 'sha256',
 | 
				
			||||||
            'packageName': 'no.min.target.sdk',
 | 
					            'packageName': 'no.min.target.sdk',
 | 
				
			||||||
            'features': [],
 | 
					            'features': [],
 | 
				
			||||||
            'antiFeatures': set(),
 | 
					            'antiFeatures': dict(),
 | 
				
			||||||
            'size': 14102,
 | 
					            'size': 14102,
 | 
				
			||||||
            'sig': 'b4964fd759edaa54e65bb476d0276880',
 | 
					            'sig': 'b4964fd759edaa54e65bb476d0276880',
 | 
				
			||||||
            'versionName': '1.2-fake',
 | 
					            'versionName': '1.2-fake',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue