mirror of
https://gitlab.com/fdroid/fdroidserver.git
synced 2024-11-18 20:50:10 +01:00
Merge branch 'antiFeatures-from-config' into 'master'
allow Anti-Features to include localized descriptions about why they were added Closes #683 See merge request fdroid/fdroidserver!1350
This commit is contained in:
commit
86343cbf18
@ -41,7 +41,7 @@ metadata_v0:
|
||||
image: registry.gitlab.com/fdroid/fdroidserver:buildserver
|
||||
variables:
|
||||
GIT_DEPTH: 1000
|
||||
RELEASE_COMMIT_ID: 0124b9dde99f9cab19c034cbc7d8cc6005a99b48 # 2.3a0
|
||||
RELEASE_COMMIT_ID: 1c2187a53bfb7a92cb9837435ae3717aacf5920d # 2.3a0
|
||||
script:
|
||||
- git fetch https://gitlab.com/fdroid/fdroidserver.git $RELEASE_COMMIT_ID
|
||||
- cd tests
|
||||
|
@ -597,7 +597,14 @@ include tests/main.TestCase
|
||||
include tests/metadata/apk/info.guardianproject.urzip.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/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/dump/app.with.special.build.params.yaml
|
||||
include tests/metadata/dump/com.politedroid.yaml
|
||||
include tests/metadata/dump/org.adaway.yaml
|
||||
include tests/metadata/dump/org.smssecure.smssecure.yaml
|
||||
|
@ -546,6 +546,13 @@ def package_metadata(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 = {}
|
||||
if "added" in version:
|
||||
ver["added"] = convert_datetime(version["added"])
|
||||
@ -555,7 +562,7 @@ def convert_version(version, app, repodir):
|
||||
ver["file"] = {
|
||||
"name": "/{}".format(version["apkName"]),
|
||||
version["hashType"]: version["hash"],
|
||||
"size": version["size"]
|
||||
"size": version["size"],
|
||||
}
|
||||
|
||||
ipfsCIDv1 = version.get("ipfsCIDv1")
|
||||
@ -619,24 +626,14 @@ def convert_version(version, app, repodir):
|
||||
else:
|
||||
manifest[en].append({"name": perm[0]})
|
||||
|
||||
antiFeatures = dict()
|
||||
if "AntiFeatures" in app and app["AntiFeatures"]:
|
||||
for antif in app["AntiFeatures"]:
|
||||
# TODO: get reasons from fdroiddata
|
||||
# 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()
|
||||
|
||||
# index-v2 has only per-version antifeatures, not per package.
|
||||
antiFeatures = app.get('AntiFeatures', {})
|
||||
for name, descdict in version.get('antiFeatures', dict()).items():
|
||||
antiFeatures[name] = descdict
|
||||
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 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()):
|
||||
lordered[lkey][ikey] = iname
|
||||
app_dict['localized'] = lordered
|
||||
antiFeatures = app_dict.get('antiFeatures', [])
|
||||
if apps[app_dict["packageName"]].get("NoSourceSince"):
|
||||
antiFeatures.append("NoSourceSince")
|
||||
# v1 uses a list of keys for Anti-Features
|
||||
antiFeatures = app_dict.get('antiFeatures', dict()).keys()
|
||||
if antiFeatures:
|
||||
app_dict['antiFeatures'] = sorted(set(antiFeatures))
|
||||
|
||||
@ -915,6 +911,9 @@ def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
|
||||
continue
|
||||
if k in ('icon', 'icons', 'icons_src', 'ipfsCIDv1', 'name'):
|
||||
continue
|
||||
if k == 'antiFeatures':
|
||||
d[k] = sorted(v.keys())
|
||||
continue
|
||||
d[k] = v
|
||||
|
||||
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)
|
||||
if 'antiFeatures' in apklist[0]:
|
||||
antiFeatures.extend(apklist[0]['antiFeatures'])
|
||||
if app.get("NoSourceSince"):
|
||||
antiFeatures.append("NoSourceSince")
|
||||
if antiFeatures:
|
||||
afout = sorted(set(antiFeatures))
|
||||
addElementNonEmpty('antifeatures', ','.join(afout), doc, apel)
|
||||
|
@ -624,6 +624,17 @@ def check_app_field_types(app):
|
||||
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):
|
||||
|
@ -114,7 +114,7 @@ class App(dict):
|
||||
super().__init__()
|
||||
|
||||
self.Disabled = None
|
||||
self.AntiFeatures = []
|
||||
self.AntiFeatures = dict()
|
||||
self.Provides = None
|
||||
self.Categories = []
|
||||
self.License = 'Unknown'
|
||||
@ -182,12 +182,14 @@ TYPE_SCRIPT = 5
|
||||
TYPE_MULTILINE = 6
|
||||
TYPE_BUILD = 7
|
||||
TYPE_INT = 8
|
||||
TYPE_STRINGMAP = 9
|
||||
|
||||
fieldtypes = {
|
||||
'Description': TYPE_MULTILINE,
|
||||
'MaintainerNotes': TYPE_MULTILINE,
|
||||
'Categories': TYPE_LIST,
|
||||
'AntiFeatures': TYPE_LIST,
|
||||
'AntiFeatures': TYPE_STRINGMAP,
|
||||
'RequiresRoot': TYPE_BOOL,
|
||||
'AllowedAPKSigningKeys': TYPE_LIST,
|
||||
'Builds': TYPE_BUILD,
|
||||
'VercodeOperation': TYPE_LIST,
|
||||
@ -277,7 +279,7 @@ class Build(dict):
|
||||
self.antcommands = []
|
||||
self.postbuild = ''
|
||||
self.novcheck = False
|
||||
self.antifeatures = []
|
||||
self.antifeatures = dict()
|
||||
if copydict:
|
||||
super().__init__(copydict)
|
||||
return
|
||||
@ -358,7 +360,7 @@ flagtypes = {
|
||||
'forceversion': TYPE_BOOL,
|
||||
'forcevercode': TYPE_BOOL,
|
||||
'novcheck': TYPE_BOOL,
|
||||
'antifeatures': TYPE_LIST,
|
||||
'antifeatures': TYPE_STRINGMAP,
|
||||
'timeout': TYPE_INT,
|
||||
}
|
||||
|
||||
@ -649,8 +651,6 @@ def parse_metadata(metadatapath):
|
||||
metadatapath = Path(metadatapath)
|
||||
app = App()
|
||||
app.metadatapath = metadatapath.as_posix()
|
||||
if metadatapath.stem != '.fdroid':
|
||||
app.id = metadatapath.stem
|
||||
if metadatapath.suffix == '.yml':
|
||||
with metadatapath.open('r', encoding='utf-8') as mf:
|
||||
app.update(parse_yaml_metadata(mf))
|
||||
@ -659,6 +659,10 @@ def parse_metadata(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:
|
||||
build_dir = common.get_build_dir(app)
|
||||
metadata_in_repo = build_dir / '.fdroid.yml'
|
||||
@ -770,6 +774,115 @@ def parse_yaml_metadata(mf):
|
||||
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()
|
||||
app['AntiFeatures'][f.stem][locale] = f.read_text()
|
||||
|
||||
|
||||
def _normalize_type_string(v):
|
||||
"""Normalize any data to TYPE_STRING.
|
||||
|
||||
@ -787,6 +900,61 @@ def _normalize_type_string(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):
|
||||
"""Convert human-readable metadata data structures into consistent data structures.
|
||||
|
||||
@ -808,6 +976,9 @@ def post_parse_yaml_metadata(yamldata):
|
||||
elif _fieldtype == TYPE_STRING:
|
||||
if v or v == 0:
|
||||
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:
|
||||
if type(v) in (float, int):
|
||||
yamldata[k] = str(v)
|
||||
@ -843,12 +1014,187 @@ def post_parse_yaml_metadata(yamldata):
|
||||
build_flag=k, value=v
|
||||
)
|
||||
)
|
||||
elif _flagtype == TYPE_STRINGMAP:
|
||||
if v or v == 0:
|
||||
build[k] = _normalize_type_stringmap(k, v)
|
||||
|
||||
builds.append(build)
|
||||
|
||||
if builds:
|
||||
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 _format_stringmap(appid, field, stringmap, versionCode=None):
|
||||
"""Format TYPE_STRINGMAP taking into account localized files in the metadata dir.
|
||||
|
||||
If there are any localized versions on the filesystem already,
|
||||
then move them all there. Otherwise, keep them in the .yml file.
|
||||
|
||||
The directory for the localized files that is named after the
|
||||
field is all lower case, following the convention set by Fastlane
|
||||
metadata, and used by fdroidserver.
|
||||
|
||||
"""
|
||||
app_dir = Path('metadata', appid)
|
||||
try:
|
||||
next(app_dir.glob('*/%s/*.txt' % field.lower()))
|
||||
files = []
|
||||
overwrites = []
|
||||
for name, descdict in stringmap.items():
|
||||
for locale, desc in descdict.items():
|
||||
outdir = app_dir / locale / field.lower()
|
||||
if versionCode:
|
||||
filename = '%d_%s.txt' % (versionCode, name)
|
||||
else:
|
||||
filename = '%s.txt' % name
|
||||
outfile = outdir / filename
|
||||
files.append(str(outfile))
|
||||
if outfile.exists():
|
||||
if desc != outfile.read_text():
|
||||
overwrites.append(str(outfile))
|
||||
else:
|
||||
if not outfile.parent.exists():
|
||||
outfile.parent.mkdir(parents=True)
|
||||
outfile.write_text(desc)
|
||||
if overwrites:
|
||||
_warn_or_exception(
|
||||
_(
|
||||
'Conflicting "{field}" definitions between .yml and localized files:'
|
||||
).format(field=field)
|
||||
+ '\n'
|
||||
+ '\n'.join(sorted(overwrites))
|
||||
)
|
||||
logging.warning(
|
||||
_('Moving Anti-Features declarations to localized files:')
|
||||
+ '\n'
|
||||
+ '\n'.join(sorted(files))
|
||||
)
|
||||
return
|
||||
except StopIteration:
|
||||
pass
|
||||
make_list = True
|
||||
outlist = []
|
||||
for name in sorted(stringmap):
|
||||
outlist.append(name)
|
||||
descdict = stringmap.get(name)
|
||||
if descdict and any(descdict.values()):
|
||||
make_list = False
|
||||
break
|
||||
if make_list:
|
||||
return outlist
|
||||
return stringmap
|
||||
|
||||
|
||||
def _del_duplicated_NoSourceSince(app):
|
||||
# noqa: D403 NoSourceSince is the word.
|
||||
"""NoSourceSince gets auto-added to AntiFeatures, but can also be manually added."""
|
||||
key = 'NoSourceSince'
|
||||
if key in app:
|
||||
no_source_since = app.get(key)
|
||||
af_no_source_since = app.get('AntiFeatures', dict()).get(key)
|
||||
if af_no_source_since == {common.DEFAULT_LOCALE: no_source_since}:
|
||||
del app['AntiFeatures'][key]
|
||||
|
||||
|
||||
def _field_to_yaml(typ, value):
|
||||
"""Convert data to YAML 1.2 format that keeps the right TYPE_*."""
|
||||
if typ == TYPE_STRING:
|
||||
return str(value)
|
||||
elif typ == TYPE_INT:
|
||||
return int(value)
|
||||
elif typ == TYPE_MULTILINE:
|
||||
if '\n' in value:
|
||||
return ruamel.yaml.scalarstring.preserve_literal(str(value))
|
||||
else:
|
||||
return str(value)
|
||||
elif typ == TYPE_SCRIPT:
|
||||
if type(value) == list:
|
||||
if len(value) == 1:
|
||||
return value[0]
|
||||
else:
|
||||
return value
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
def _builds_to_yaml(app):
|
||||
builds = ruamel.yaml.comments.CommentedSeq()
|
||||
for build in app.get('Builds', []):
|
||||
if not isinstance(build, Build):
|
||||
build = Build(build)
|
||||
b = ruamel.yaml.comments.CommentedMap()
|
||||
for field in build_flags:
|
||||
if hasattr(build, field):
|
||||
value = getattr(build, field)
|
||||
if field == 'gradle' and value == ['off']:
|
||||
value = [
|
||||
ruamel.yaml.scalarstring.SingleQuotedScalarString('off')
|
||||
]
|
||||
typ = flagtype(field)
|
||||
# don't check value == True for TYPE_INT as it could be 0
|
||||
if value and typ == TYPE_STRINGMAP:
|
||||
v = _format_stringmap(app['id'], field, value, build['versionCode'])
|
||||
if v:
|
||||
b[field] = v
|
||||
elif value is not None and (typ == TYPE_INT or value):
|
||||
b.update({field: _field_to_yaml(typ, value)})
|
||||
|
||||
builds.append(b)
|
||||
|
||||
# insert extra empty lines between build entries
|
||||
for i in range(1, len(builds)):
|
||||
builds.yaml_set_comment_before_after_key(i, 'bogus')
|
||||
builds.ca.items[i][1][-1].value = '\n'
|
||||
|
||||
return builds
|
||||
|
||||
|
||||
def _app_to_yaml(app):
|
||||
cm = ruamel.yaml.comments.CommentedMap()
|
||||
insert_newline = False
|
||||
for field in yaml_app_field_order:
|
||||
if field == '\n':
|
||||
# next iteration will need to insert a newline
|
||||
insert_newline = True
|
||||
else:
|
||||
value = app.get(field)
|
||||
if value or field == 'Builds':
|
||||
if field == 'Builds':
|
||||
if app.get('Builds'):
|
||||
cm.update({field: _builds_to_yaml(app)})
|
||||
elif field == 'CurrentVersionCode':
|
||||
cm[field] = _field_to_yaml(TYPE_INT, value)
|
||||
elif field == 'AntiFeatures':
|
||||
v = _format_stringmap(app['id'], field, value)
|
||||
if v:
|
||||
cm[field] = v
|
||||
elif field == 'AllowedAPKSigningKeys':
|
||||
value = [str(i).lower() for i in value]
|
||||
if len(value) == 1:
|
||||
cm[field] = _field_to_yaml(TYPE_STRING, value[0])
|
||||
else:
|
||||
cm[field] = _field_to_yaml(TYPE_LIST, value)
|
||||
else:
|
||||
cm[field] = _field_to_yaml(fieldtype(field), value)
|
||||
|
||||
if insert_newline:
|
||||
# we need to prepend a newline in front of this field
|
||||
insert_newline = False
|
||||
# inserting empty lines is not supported so we add a
|
||||
# bogus comment and over-write its value
|
||||
cm.yaml_set_comment_before_after_key(field, 'bogus')
|
||||
cm.ca.items[field][1][-1].value = '\n'
|
||||
return cm
|
||||
|
||||
|
||||
def write_yaml(mf, app):
|
||||
"""Write metadata in yaml format.
|
||||
@ -859,87 +1205,9 @@ def write_yaml(mf, app):
|
||||
active file discriptor for writing
|
||||
app
|
||||
app metadata to written to the yaml file
|
||||
|
||||
"""
|
||||
def _field_to_yaml(typ, value):
|
||||
"""Convert data to YAML 1.2 format that keeps the right TYPE_*."""
|
||||
if typ == TYPE_STRING:
|
||||
return str(value)
|
||||
elif typ == TYPE_INT:
|
||||
return int(value)
|
||||
elif typ == TYPE_MULTILINE:
|
||||
if '\n' in value:
|
||||
return ruamel.yaml.scalarstring.preserve_literal(str(value))
|
||||
else:
|
||||
return str(value)
|
||||
elif typ == TYPE_SCRIPT:
|
||||
if type(value) == list:
|
||||
if len(value) == 1:
|
||||
return value[0]
|
||||
else:
|
||||
return value
|
||||
else:
|
||||
return value
|
||||
|
||||
def _app_to_yaml(app):
|
||||
cm = ruamel.yaml.comments.CommentedMap()
|
||||
insert_newline = False
|
||||
for field in yaml_app_field_order:
|
||||
if field == '\n':
|
||||
# next iteration will need to insert a newline
|
||||
insert_newline = True
|
||||
else:
|
||||
if app.get(field) or field == 'Builds':
|
||||
if field == 'Builds':
|
||||
if app.get('Builds'):
|
||||
cm.update({field: _builds_to_yaml(app)})
|
||||
elif field == 'CurrentVersionCode':
|
||||
cm.update({field: _field_to_yaml(TYPE_INT, getattr(app, field))})
|
||||
elif field == 'AllowedAPKSigningKeys':
|
||||
value = getattr(app, field)
|
||||
if value:
|
||||
value = [str(i).lower() for i in value]
|
||||
if len(value) == 1:
|
||||
cm.update({field: _field_to_yaml(TYPE_STRING, value[0])})
|
||||
else:
|
||||
cm.update({field: _field_to_yaml(TYPE_LIST, value)})
|
||||
else:
|
||||
cm.update({field: _field_to_yaml(fieldtype(field), getattr(app, field))})
|
||||
|
||||
if insert_newline:
|
||||
# we need to prepend a newline in front of this field
|
||||
insert_newline = False
|
||||
# inserting empty lines is not supported so we add a
|
||||
# bogus comment and over-write its value
|
||||
cm.yaml_set_comment_before_after_key(field, 'bogus')
|
||||
cm.ca.items[field][1][-1].value = '\n'
|
||||
return cm
|
||||
|
||||
def _builds_to_yaml(app):
|
||||
builds = ruamel.yaml.comments.CommentedSeq()
|
||||
for build in app.get('Builds', []):
|
||||
if not isinstance(build, Build):
|
||||
build = Build(build)
|
||||
b = ruamel.yaml.comments.CommentedMap()
|
||||
for field in build_flags:
|
||||
if hasattr(build, field):
|
||||
value = getattr(build, field)
|
||||
if field == 'gradle' and value == ['off']:
|
||||
value = [
|
||||
ruamel.yaml.scalarstring.SingleQuotedScalarString('off')
|
||||
]
|
||||
typ = flagtype(field)
|
||||
# don't check value == True for TYPE_INT as it could be 0
|
||||
if value is not None and (typ == TYPE_INT or value):
|
||||
b.update({field: _field_to_yaml(typ, value)})
|
||||
builds.append(b)
|
||||
|
||||
# insert extra empty lines between build entries
|
||||
for i in range(1, len(builds)):
|
||||
builds.yaml_set_comment_before_after_key(i, 'bogus')
|
||||
builds.ca.items[i][1][-1].value = '\n'
|
||||
|
||||
return builds
|
||||
|
||||
_del_duplicated_NoSourceSince(app)
|
||||
yaml_app = _app_to_yaml(app)
|
||||
yaml = ruamel.yaml.YAML()
|
||||
yaml.indent(mapping=4, sequence=4, offset=2)
|
||||
|
@ -52,8 +52,9 @@ def remove_blank_flags_from_builds(builds):
|
||||
for build in builds:
|
||||
new = dict()
|
||||
for k in metadata.build_flags:
|
||||
v = build[k]
|
||||
if v is None or v is False or v == [] or v == '':
|
||||
v = build.get(k)
|
||||
# 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
|
||||
new[k] = v
|
||||
newbuilds.append(new)
|
||||
@ -98,6 +99,7 @@ def main():
|
||||
print(path)
|
||||
continue
|
||||
|
||||
# TODO these should be moved to metadata.write_yaml()
|
||||
builds = remove_blank_flags_from_builds(app.get('Builds'))
|
||||
if builds:
|
||||
app['Builds'] = builds
|
||||
|
@ -294,7 +294,7 @@ class ExodusSignatureDataController(SignatureDataController):
|
||||
"warn_code_signatures": [tracker["code_signature"]],
|
||||
# exodus also provides network signatures, unused atm.
|
||||
# "network_signatures": [tracker["network_signature"]],
|
||||
"AntiFeatures": ["Tracking"],
|
||||
"AntiFeatures": ["Tracking"], # TODO
|
||||
"license": "NonFree" # We assume all trackers in exodus
|
||||
# are non-free, although free
|
||||
# trackers like piwik, acra,
|
||||
|
@ -158,7 +158,7 @@ def status_update_json(apps, apks):
|
||||
|
||||
for appid in apps:
|
||||
app = apps[appid]
|
||||
for af in app.get('AntiFeatures', []):
|
||||
for af in app.get('AntiFeatures', dict()):
|
||||
antiFeatures = output['antiFeatures'] # JSON camelCase
|
||||
if af not in antiFeatures:
|
||||
antiFeatures[af] = dict()
|
||||
@ -351,7 +351,8 @@ def get_cache():
|
||||
if not isinstance(v, dict):
|
||||
continue
|
||||
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:
|
||||
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.
|
||||
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
|
||||
if not hasattr(has_known_vulnerability, "pattern"):
|
||||
@ -431,15 +432,23 @@ def has_known_vulnerability(filename):
|
||||
logging.debug(_('"{path}" contains recent {name} ({version})')
|
||||
.format(path=filename, name=name, version=version))
|
||||
else:
|
||||
logging.warning(_('"{path}" contains outdated {name} ({version})')
|
||||
.format(path=filename, name=name, version=version))
|
||||
found_vuln = True
|
||||
msg = '"{path}" contains outdated {name} ({version})'
|
||||
logging.warning(
|
||||
_(msg).format(path=filename, name=name, version=version)
|
||||
)
|
||||
found_vuln += msg.format(
|
||||
path=filename, name=name, version=version
|
||||
)
|
||||
found_vuln += '\n'
|
||||
break
|
||||
elif name == 'AndroidManifest.xml' or name == 'classes.dex' or name.endswith('.so'):
|
||||
if name in files_in_apk:
|
||||
logging.warning(_('{apkfilename} has multiple {name} files, looks like Master Key exploit!')
|
||||
.format(apkfilename=filename, name=name))
|
||||
found_vuln = True
|
||||
msg = '{apkfilename} has multiple {name} files, looks like Master Key exploit!'
|
||||
logging.warning(
|
||||
_(msg).format(apkfilename=filename, name=name)
|
||||
)
|
||||
found_vuln += msg.format(apkfilename=filename, name=name)
|
||||
found_vuln += '\n'
|
||||
files_in_apk.add(name)
|
||||
return found_vuln
|
||||
|
||||
@ -545,7 +554,7 @@ def translate_per_build_anti_features(apps, apks):
|
||||
if d:
|
||||
afl = d.get(apk['versionCode'])
|
||||
if afl:
|
||||
apk['antiFeatures'].update(afl)
|
||||
apk['antiFeatures'].update(afl) # TODO
|
||||
|
||||
|
||||
def _get_localized_dict(app, locale):
|
||||
@ -1228,7 +1237,7 @@ def scan_apk(apk_file, require_signature=True):
|
||||
'features': [],
|
||||
'icons_src': {},
|
||||
'icons': {},
|
||||
'antiFeatures': set(),
|
||||
'antiFeatures': {},
|
||||
}
|
||||
ipfsCIDv1 = common.calculate_IPFS_cid(apk_file)
|
||||
if ipfsCIDv1:
|
||||
@ -1263,8 +1272,9 @@ def scan_apk(apk_file, require_signature=True):
|
||||
apk['minSdkVersion'] = 3 # aapt defaults to 3 as the min
|
||||
|
||||
# Check for known vulnerabilities
|
||||
if has_known_vulnerability(apk_file):
|
||||
apk['antiFeatures'].add('KnownVuln')
|
||||
hkv = has_known_vulnerability(apk_file)
|
||||
if hkv:
|
||||
apk['antiFeatures']['KnownVuln'] = {DEFAULT_LOCALE: hkv}
|
||||
|
||||
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:
|
||||
try:
|
||||
common.verify_deprecated_jar_signature(apkfile)
|
||||
apk['antiFeatures'].update(['KnownVuln', 'DisabledAlgorithm'])
|
||||
apk['antiFeatures'].update(['KnownVuln', 'DisabledAlgorithm']) # TODO
|
||||
except VerificationException:
|
||||
skipapk = True
|
||||
else:
|
||||
@ -1885,7 +1895,7 @@ def archive_old_apks(apps, apks, archapks, repodir, archivedir, defaultkeepversi
|
||||
for apk in all_app_apks:
|
||||
if len(keep) == keepversions:
|
||||
break
|
||||
if 'antiFeatures' not in apk:
|
||||
if 'antiFeatures' not in apk: # TODO
|
||||
keep.append(apk)
|
||||
elif 'DisabledAlgorithm' not in apk['antiFeatures'] or disabled_algorithms_allowed():
|
||||
keep.append(apk)
|
||||
|
@ -77,6 +77,9 @@ Builds:
|
||||
maven: yes@..
|
||||
srclibs:
|
||||
- FacebookSDK@sdk-version-3.0.2
|
||||
antifeatures:
|
||||
Tracking:
|
||||
en-US: Uses the Facebook SDK.
|
||||
|
||||
- versionName: 2.1.1-c
|
||||
versionCode: 50
|
||||
|
@ -26,6 +26,7 @@ if localmodule not in sys.path:
|
||||
import fdroidserver
|
||||
from fdroidserver import metadata
|
||||
from fdroidserver.exception import MetaDataException
|
||||
from fdroidserver.common import DEFAULT_LOCALE
|
||||
|
||||
|
||||
def _get_mock_mf(s):
|
||||
@ -203,7 +204,8 @@ class MetadataTest(unittest.TestCase):
|
||||
)
|
||||
|
||||
@mock.patch('git.Repo')
|
||||
def test_read_metadata(self, git_repo):
|
||||
@mock.patch('logging.error')
|
||||
def test_read_metadata(self, logging_error, git_repo):
|
||||
"""Read specified metadata files included in tests/, compare to stored output"""
|
||||
|
||||
self.maxDiff = None
|
||||
@ -216,6 +218,7 @@ class MetadataTest(unittest.TestCase):
|
||||
yaml = ruamel.yaml.YAML(typ='safe')
|
||||
apps = fdroidserver.metadata.read_metadata()
|
||||
for appid in (
|
||||
'app.with.special.build.params',
|
||||
'org.smssecure.smssecure',
|
||||
'org.adaway',
|
||||
'org.videolan.vlc',
|
||||
@ -234,6 +237,10 @@ class MetadataTest(unittest.TestCase):
|
||||
# yaml.register_class(metadata.Build)
|
||||
# yaml.dump(frommeta, fp)
|
||||
|
||||
# errors are printed when .yml overrides localized
|
||||
logging_error.assert_called()
|
||||
self.assertEqual(3, len(logging_error.call_args_list))
|
||||
|
||||
@mock.patch('git.Repo')
|
||||
def test_metadata_overrides_dot_fdroid_yml(self, git_Repo):
|
||||
"""Fields in metadata files should override anything in .fdroid.yml."""
|
||||
@ -254,7 +261,8 @@ class MetadataTest(unittest.TestCase):
|
||||
metadata.parse_metadata(yml) # should not throw an exception
|
||||
|
||||
@mock.patch('git.Repo')
|
||||
def test_rewrite_yaml_fakeotaupdate(self, git_Repo):
|
||||
@mock.patch('logging.error')
|
||||
def test_rewrite_yaml_fakeotaupdate(self, logging_error, git_Repo):
|
||||
with tempfile.TemporaryDirectory() as testdir:
|
||||
testdir = Path(testdir)
|
||||
fdroidserver.common.config = {'accepted_formats': ['yml']}
|
||||
@ -276,6 +284,10 @@ class MetadataTest(unittest.TestCase):
|
||||
(Path('metadata-rewrite-yml') / file_name).read_text(encoding='utf-8'),
|
||||
)
|
||||
|
||||
# errors are printed when .yml overrides localized
|
||||
logging_error.assert_called()
|
||||
self.assertEqual(3, len(logging_error.call_args_list))
|
||||
|
||||
@mock.patch('git.Repo')
|
||||
def test_rewrite_yaml_fdroidclient(self, git_Repo):
|
||||
with tempfile.TemporaryDirectory() as testdir:
|
||||
@ -300,24 +312,24 @@ class MetadataTest(unittest.TestCase):
|
||||
|
||||
@mock.patch('git.Repo')
|
||||
def test_rewrite_yaml_special_build_params(self, git_Repo):
|
||||
with tempfile.TemporaryDirectory() as testdir:
|
||||
testdir = Path(testdir)
|
||||
"""Test rewriting a plain YAML metadata file without localized files."""
|
||||
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
|
||||
allapps = fdroidserver.metadata.read_metadata()
|
||||
for appid, app in allapps.items():
|
||||
if appid == 'app.with.special.build.params':
|
||||
fdroidserver.metadata.write_metadata(
|
||||
testdir / (appid + '.yml'), app
|
||||
)
|
||||
# rewrite metadata
|
||||
allapps = fdroidserver.metadata.read_metadata({appid: -1})
|
||||
for appid, app in allapps.items():
|
||||
metadata.write_metadata(file_name, app)
|
||||
|
||||
# assert rewrite result
|
||||
self.maxDiff = None
|
||||
file_name = 'app.with.special.build.params.yml'
|
||||
self.assertEqual(
|
||||
(testdir / file_name).read_text(encoding='utf-8'),
|
||||
(Path('metadata-rewrite-yml') / file_name).read_text(encoding='utf-8'),
|
||||
)
|
||||
# assert rewrite result
|
||||
self.maxDiff = None
|
||||
self.assertEqual(
|
||||
file_name.read_text(),
|
||||
(self.basedir / 'metadata-rewrite-yml' / file_name.name).read_text(),
|
||||
)
|
||||
|
||||
def test_normalize_type_string(self):
|
||||
"""TYPE_STRING currently has some quirky behavior."""
|
||||
@ -331,6 +343,18 @@ class MetadataTest(unittest.TestCase):
|
||||
self.assertEqual('false', metadata._normalize_type_string(False))
|
||||
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):
|
||||
yamldata = dict()
|
||||
metadata.post_parse_yaml_metadata(yamldata)
|
||||
@ -507,6 +531,96 @@ class MetadataTest(unittest.TestCase):
|
||||
_warning.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):
|
||||
with tempfile.TemporaryDirectory() as testdir:
|
||||
testdir = Path(testdir)
|
||||
@ -741,6 +855,257 @@ class MetadataTest(unittest.TestCase):
|
||||
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):
|
||||
mf = io.StringIO()
|
||||
app = fdroidserver.metadata.App()
|
||||
@ -931,6 +1296,87 @@ class MetadataTest(unittest.TestCase):
|
||||
),
|
||||
)
|
||||
|
||||
def test_write_yaml_build_antifeatures(self):
|
||||
mf = io.StringIO()
|
||||
app = metadata.App(
|
||||
{
|
||||
'License': 'Apache-2.0',
|
||||
'Builds': [
|
||||
metadata.Build(
|
||||
{
|
||||
'versionCode': 102030,
|
||||
'versionName': 'v1.2.3',
|
||||
'gradle': ['yes'],
|
||||
'antifeatures': {
|
||||
'a': {},
|
||||
'b': {'de': 'Probe', 'en-US': 'test'},
|
||||
},
|
||||
}
|
||||
),
|
||||
],
|
||||
'id': 'placeholder',
|
||||
}
|
||||
)
|
||||
metadata.write_yaml(mf, app)
|
||||
mf.seek(0)
|
||||
self.assertEqual(
|
||||
mf.read(),
|
||||
textwrap.dedent(
|
||||
"""\
|
||||
License: Apache-2.0
|
||||
|
||||
Builds:
|
||||
- versionName: v1.2.3
|
||||
versionCode: 102030
|
||||
gradle:
|
||||
- yes
|
||||
antifeatures:
|
||||
a: {}
|
||||
b:
|
||||
de: Probe
|
||||
en-US: test
|
||||
"""
|
||||
),
|
||||
)
|
||||
|
||||
def test_write_yaml_build_antifeatures_old_style(self):
|
||||
mf = io.StringIO()
|
||||
app = metadata.App(
|
||||
{
|
||||
'License': 'Apache-2.0',
|
||||
'Builds': [
|
||||
metadata.Build(
|
||||
{
|
||||
'versionCode': 102030,
|
||||
'versionName': 'v1.2.3',
|
||||
'gradle': ['yes'],
|
||||
'antifeatures': {'b': {}, 'a': {}},
|
||||
}
|
||||
),
|
||||
],
|
||||
'id': 'placeholder',
|
||||
}
|
||||
)
|
||||
metadata.write_yaml(mf, app)
|
||||
mf.seek(0)
|
||||
self.assertEqual(
|
||||
mf.read(),
|
||||
textwrap.dedent(
|
||||
"""\
|
||||
License: Apache-2.0
|
||||
|
||||
Builds:
|
||||
- versionName: v1.2.3
|
||||
versionCode: 102030
|
||||
gradle:
|
||||
- yes
|
||||
antifeatures:
|
||||
- a
|
||||
- b
|
||||
"""
|
||||
),
|
||||
)
|
||||
|
||||
def test_write_yaml_make_sure_provides_does_not_get_written(self):
|
||||
mf = io.StringIO()
|
||||
app = fdroidserver.metadata.App()
|
||||
@ -1248,6 +1694,219 @@ class MetadataTest(unittest.TestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
build.ndk_path()
|
||||
|
||||
def test_del_duplicated_NoSourceSince(self):
|
||||
app = {
|
||||
'AntiFeatures': {'Ads': {}, 'NoSourceSince': {DEFAULT_LOCALE: '1.0'}},
|
||||
'NoSourceSince': '1.0',
|
||||
}
|
||||
metadata._del_duplicated_NoSourceSince(app)
|
||||
self.assertEqual(app, {'AntiFeatures': {'Ads': {}}, 'NoSourceSince': '1.0'})
|
||||
|
||||
def test_check_manually_extended_NoSourceSince(self):
|
||||
app = {
|
||||
'AntiFeatures': {'NoSourceSince': {DEFAULT_LOCALE: '1.0', 'de': '1,0'}},
|
||||
'NoSourceSince': '1.0',
|
||||
}
|
||||
metadata._del_duplicated_NoSourceSince(app)
|
||||
self.assertEqual(
|
||||
app,
|
||||
{
|
||||
'AntiFeatures': {'NoSourceSince': {DEFAULT_LOCALE: '1.0', 'de': '1,0'}},
|
||||
'NoSourceSince': '1.0',
|
||||
},
|
||||
)
|
||||
|
||||
def test_make_sure_nosourcesince_does_not_get_written(self):
|
||||
appid = 'com.politedroid'
|
||||
app = metadata.read_metadata({appid: -1})[appid]
|
||||
builds = app['Builds']
|
||||
app['Builds'] = [copy.deepcopy(builds[0])]
|
||||
mf = io.StringIO()
|
||||
metadata.write_yaml(mf, app)
|
||||
mf.seek(0)
|
||||
self.maxDiff = None
|
||||
self.assertEqual(
|
||||
mf.read(),
|
||||
textwrap.dedent(
|
||||
"""\
|
||||
AntiFeatures:
|
||||
- NonFreeNet
|
||||
Categories:
|
||||
- Time
|
||||
License: GPL-3.0-only
|
||||
SourceCode: https://github.com/miguelvps/PoliteDroid
|
||||
IssueTracker: https://github.com/miguelvps/PoliteDroid/issues
|
||||
|
||||
AutoName: Polite Droid
|
||||
Summary: Calendar tool
|
||||
Description: Activates silent mode during calendar events.
|
||||
|
||||
RepoType: git
|
||||
Repo: https://github.com/miguelvps/PoliteDroid.git
|
||||
|
||||
Builds:
|
||||
- versionName: '1.2'
|
||||
versionCode: 3
|
||||
commit: 6a548e4b19
|
||||
target: android-10
|
||||
antifeatures:
|
||||
- KnownVuln
|
||||
- NonFreeAssets
|
||||
- UpstreamNonFree
|
||||
|
||||
ArchivePolicy: 4 versions
|
||||
AutoUpdateMode: Version v%v
|
||||
UpdateCheckMode: Tags
|
||||
CurrentVersion: '1.5'
|
||||
CurrentVersionCode: 6
|
||||
|
||||
NoSourceSince: '1.5'
|
||||
"""
|
||||
),
|
||||
)
|
||||
|
||||
def test_app_to_yaml_smokecheck(self):
|
||||
self.assertTrue(
|
||||
isinstance(metadata._app_to_yaml(dict()), ruamel.yaml.comments.CommentedMap)
|
||||
)
|
||||
|
||||
def test_app_to_yaml_build_list_empty(self):
|
||||
app = metadata.App({'Builds': [metadata.Build({'rm': []})]})
|
||||
self.assertEqual(dict(), metadata._app_to_yaml(app)['Builds'][0])
|
||||
|
||||
def test_app_to_yaml_build_list_string(self):
|
||||
app = metadata.App({'Builds': [metadata.Build({'rm': 'one'})]})
|
||||
self.assertEqual({'rm': 'one'}, metadata._app_to_yaml(app)['Builds'][0])
|
||||
|
||||
def test_app_to_yaml_build_list_one(self):
|
||||
app = metadata.App({'Builds': [metadata.Build({'rm': ['one']})]})
|
||||
self.assertEqual({'rm': ['one']}, metadata._app_to_yaml(app)['Builds'][0])
|
||||
|
||||
def test_app_to_yaml_build_list(self):
|
||||
app = metadata.App({'Builds': [metadata.Build({'rm': ['b2', 'NO1']})]})
|
||||
self.assertEqual({'rm': ['b2', 'NO1']}, metadata._app_to_yaml(app)['Builds'][0])
|
||||
|
||||
def test_app_to_yaml_AllowedAPKSigningKeys_two(self):
|
||||
cm = metadata._app_to_yaml(metadata.App({'AllowedAPKSigningKeys': ['b', 'A']}))
|
||||
self.assertEqual(['b', 'a'], cm['AllowedAPKSigningKeys'])
|
||||
|
||||
def test_app_to_yaml_AllowedAPKSigningKeys_one(self):
|
||||
cm = metadata._app_to_yaml(metadata.App({'AllowedAPKSigningKeys': ['One']}))
|
||||
self.assertEqual('one', cm['AllowedAPKSigningKeys'])
|
||||
|
||||
def test_app_to_yaml_int_hex(self):
|
||||
cm = metadata._app_to_yaml(metadata.App({'CurrentVersionCode': 0xFF}))
|
||||
self.assertEqual(255, cm['CurrentVersionCode'])
|
||||
|
||||
def test_app_to_yaml_int_underscore(self):
|
||||
cm = metadata._app_to_yaml(metadata.App({'CurrentVersionCode': 1_2_3}))
|
||||
self.assertEqual(123, cm['CurrentVersionCode'])
|
||||
|
||||
def test_app_to_yaml_int_0(self):
|
||||
"""Document that 0 values fail to make it through."""
|
||||
# TODO it should be possible to use `CurrentVersionCode: 0`
|
||||
cm = metadata._app_to_yaml(metadata.App({'CurrentVersionCode': 0}))
|
||||
self.assertFalse('CurrentVersionCode' in cm)
|
||||
|
||||
def test_format_stringmap_empty(self):
|
||||
self.assertEqual(
|
||||
metadata._format_stringmap('🔥', 'test', dict()),
|
||||
list(),
|
||||
)
|
||||
|
||||
def test_format_stringmap_one_list(self):
|
||||
self.assertEqual(
|
||||
metadata._format_stringmap('🔥', 'test', {'Tracking': {}, 'Ads': {}}),
|
||||
['Ads', 'Tracking'],
|
||||
)
|
||||
|
||||
def test_format_stringmap_one_list_empty_desc(self):
|
||||
self.assertEqual(
|
||||
metadata._format_stringmap('🔥', 'test', {'NonFree': {}, 'Ads': {'en': ''}}),
|
||||
['Ads', 'NonFree'],
|
||||
)
|
||||
|
||||
def test_format_stringmap_three_list(self):
|
||||
self.assertEqual(
|
||||
metadata._format_stringmap('🔥', 'test', {'B': {}, 'A': {}, 'C': {}}),
|
||||
['A', 'B', 'C'],
|
||||
)
|
||||
|
||||
def test_format_stringmap_two_dict(self):
|
||||
self.assertEqual(
|
||||
metadata._format_stringmap('🔥', 'test', {'1': {'uz': 'a'}, '2': {}}),
|
||||
{'1': {'uz': 'a'}, '2': {}},
|
||||
)
|
||||
|
||||
def test_format_stringmap_three_locales(self):
|
||||
self.assertEqual(
|
||||
metadata._format_stringmap(
|
||||
'🔥', 'test', {'AF': {'uz': 'a', 'ko': 'b', 'zh': 'c'}}
|
||||
),
|
||||
{'AF': {'ko': 'b', 'uz': 'a', 'zh': 'c'}},
|
||||
)
|
||||
|
||||
def test_format_stringmap_move_build_antifeatures_to_filesystem(self):
|
||||
os.chdir(self.testdir)
|
||||
appid = 'a'
|
||||
yml = Path('metadata/a.yml')
|
||||
yml.parent.mkdir()
|
||||
self.assertEqual(
|
||||
metadata._format_stringmap(
|
||||
appid, 'antifeatures', {'AF': {'uz': 'a', 'ko': 'b', 'zh': 'c'}}
|
||||
),
|
||||
{'AF': {'ko': 'b', 'uz': 'a', 'zh': 'c'}},
|
||||
)
|
||||
|
||||
def test_format_stringmap_app_antifeatures_conflict(self):
|
||||
"""Raise an error if a YAML Anti-Feature conflicts with a localized file."""
|
||||
os.chdir(self.testdir)
|
||||
appid = 'a'
|
||||
field = 'AntiFeatures'
|
||||
locale = 'ko'
|
||||
yml = Path('metadata/a.yml')
|
||||
antifeatures_ko = yml.parent / appid / locale / field.lower()
|
||||
antifeatures_ko.mkdir(parents=True)
|
||||
afname = 'Anti-🔥'
|
||||
(antifeatures_ko / (afname + '.txt')).write_text('SOMETHING ELSE')
|
||||
with self.assertRaises(MetaDataException):
|
||||
metadata._format_stringmap(
|
||||
appid, field, {afname: {'uz': 'a', locale: 'b', 'zh': 'c'}}
|
||||
)
|
||||
|
||||
def test_format_stringmap_app_antifeatures_conflict_same_contents(self):
|
||||
"""Raise an error if a YAML Anti-Feature conflicts with a localized file."""
|
||||
os.chdir(self.testdir)
|
||||
appid = 'a'
|
||||
field = 'AntiFeatures'
|
||||
locale = 'ko'
|
||||
yml = Path('metadata/a.yml')
|
||||
antifeatures_ko = yml.parent / appid / locale / field.lower()
|
||||
antifeatures_ko.mkdir(parents=True)
|
||||
afname = 'Anti-🔥'
|
||||
(antifeatures_ko / (afname + '.txt')).write_text('b')
|
||||
metadata._format_stringmap(
|
||||
appid, field, {afname: {'uz': 'a', locale: 'b', 'zh': 'c'}}
|
||||
)
|
||||
|
||||
def test_format_stringmap_build_antifeatures_conflict(self):
|
||||
"""Raise an error if a YAML Anti-Feature conflicts with a localized file."""
|
||||
os.chdir(self.testdir)
|
||||
appid = 'a'
|
||||
field = 'antifeatures'
|
||||
locale = 'ko'
|
||||
versionCode = 123
|
||||
yml = Path('metadata/a.yml')
|
||||
antifeatures_ko = yml.parent / appid / locale / field.lower()
|
||||
antifeatures_ko.mkdir(parents=True)
|
||||
afname = 'Anti-🔥'
|
||||
with (antifeatures_ko / ('%d_%s.txt' % (versionCode, afname))).open('w') as fp:
|
||||
fp.write('SOMETHING ELSE')
|
||||
with self.assertRaises(MetaDataException):
|
||||
metadata._format_stringmap(
|
||||
appid, field, {afname: {'uz': 'a', locale: 'b', 'zh': 'c'}}, versionCode
|
||||
)
|
||||
|
||||
|
||||
class PostMetadataParseTest(unittest.TestCase):
|
||||
"""Test the functions that post process the YAML input.
|
||||
@ -1263,9 +1922,9 @@ class PostMetadataParseTest(unittest.TestCase):
|
||||
fdroidserver.metadata.warnings_action = 'error'
|
||||
|
||||
def _post_metadata_parse_app_list(self, from_yaml, expected):
|
||||
app = {'AntiFeatures': from_yaml}
|
||||
app = {'AllowedAPKSigningKeys': from_yaml}
|
||||
metadata.post_parse_yaml_metadata(app)
|
||||
return {'AntiFeatures': expected}, app
|
||||
return {'AllowedAPKSigningKeys': expected}, app
|
||||
|
||||
def _post_metadata_parse_app_string(self, from_yaml, expected):
|
||||
app = {'Repo': from_yaml}
|
||||
|
@ -1,4 +1,4 @@
|
||||
antiFeatures: !!set {}
|
||||
antiFeatures: {}
|
||||
features: []
|
||||
hash: abfb3adb7496611749e7abfb014c5c789e3a02489e48a5c3665110d1b1acd931
|
||||
hashType: sha256
|
||||
|
@ -1,4 +1,4 @@
|
||||
antiFeatures: !!set {}
|
||||
antiFeatures: {}
|
||||
features: []
|
||||
hash: 897486e1f857c6c0ee32ccbad0e1b8cd82f6d0e65a44a23f13f852d2b63a18c8
|
||||
hashType: sha256
|
||||
|
@ -77,6 +77,8 @@ Builds:
|
||||
maven: yes@..
|
||||
srclibs:
|
||||
- FacebookSDK@sdk-version-3.0.2
|
||||
antifeatures:
|
||||
Tracking: Uses the Facebook SDK.
|
||||
|
||||
- versionName: 2.1.1-c
|
||||
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: []
|
||||
AntiFeatures:
|
||||
- NonFreeNet
|
||||
NoSourceSince:
|
||||
en-US: '1.5'
|
||||
NonFreeNet: {}
|
||||
ArchivePolicy: 4 versions
|
||||
AuthorEmail: null
|
||||
AuthorName: null
|
||||
@ -13,9 +15,9 @@ Builds:
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures:
|
||||
- KnownVuln
|
||||
- UpstreamNonFree
|
||||
- NonFreeAssets
|
||||
KnownVuln: {}
|
||||
NonFreeAssets: {}
|
||||
UpstreamNonFree: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -50,7 +52,7 @@ Builds:
|
||||
versionName: '1.2'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -85,7 +87,7 @@ Builds:
|
||||
versionName: '1.3'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -120,7 +122,7 @@ Builds:
|
||||
versionName: '1.4'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
|
@ -1,5 +1,5 @@
|
||||
AllowedAPKSigningKeys: []
|
||||
AntiFeatures: []
|
||||
AntiFeatures: {}
|
||||
ArchivePolicy: null
|
||||
AuthorEmail: null
|
||||
AuthorName: null
|
||||
@ -11,7 +11,7 @@ Bitcoin: null
|
||||
Builds:
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -47,7 +47,7 @@ Builds:
|
||||
versionName: '1.12'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -84,7 +84,7 @@ Builds:
|
||||
versionName: '1.15'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -121,7 +121,7 @@ Builds:
|
||||
versionName: '1.18'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -158,7 +158,7 @@ Builds:
|
||||
versionName: '1.19'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -195,7 +195,7 @@ Builds:
|
||||
versionName: '1.20'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -232,7 +232,7 @@ Builds:
|
||||
versionName: '1.21'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -267,7 +267,7 @@ Builds:
|
||||
versionName: '1.23'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -304,7 +304,7 @@ Builds:
|
||||
versionName: '1.24'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -341,7 +341,7 @@ Builds:
|
||||
versionName: '1.25'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -378,7 +378,7 @@ Builds:
|
||||
versionName: '1.26'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -415,7 +415,7 @@ Builds:
|
||||
versionName: '1.27'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -453,7 +453,7 @@ Builds:
|
||||
versionName: '1.29'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -491,7 +491,7 @@ Builds:
|
||||
versionName: '1.32'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -528,7 +528,7 @@ Builds:
|
||||
versionName: '1.33'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -566,7 +566,7 @@ Builds:
|
||||
versionName: '1.34'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -604,7 +604,7 @@ Builds:
|
||||
versionName: '1.35'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -642,7 +642,7 @@ Builds:
|
||||
versionName: '1.36'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -684,7 +684,7 @@ Builds:
|
||||
- android-libs/ActionBarSherlock
|
||||
- android-libs/HtmlSpanner/htmlspanner
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -734,7 +734,7 @@ Builds:
|
||||
- android-libs/ActionBarSherlock
|
||||
- android-libs/HtmlSpanner/htmlspanner
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -780,7 +780,7 @@ Builds:
|
||||
versionName: '2.3'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -818,7 +818,7 @@ Builds:
|
||||
versionName: '2.6'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -856,7 +856,7 @@ Builds:
|
||||
versionName: '2.7'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -894,7 +894,7 @@ Builds:
|
||||
versionName: '2.8'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -932,7 +932,7 @@ Builds:
|
||||
versionName: 2.8.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -970,7 +970,7 @@ Builds:
|
||||
versionName: '2.9'
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -1008,7 +1008,7 @@ Builds:
|
||||
versionName: 2.9.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
@ -1046,7 +1046,7 @@ Builds:
|
||||
versionName: 2.9.2
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni:
|
||||
|
@ -1,5 +1,5 @@
|
||||
AllowedAPKSigningKeys: []
|
||||
AntiFeatures: []
|
||||
AntiFeatures: {}
|
||||
ArchivePolicy: null
|
||||
AuthorEmail: null
|
||||
AuthorName: null
|
||||
@ -11,7 +11,7 @@ Bitcoin: null
|
||||
Builds:
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -72,7 +72,7 @@ Builds:
|
||||
versionName: 0.3.3
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -115,7 +115,7 @@ Builds:
|
||||
versionName: 0.3.3
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -156,7 +156,7 @@ Builds:
|
||||
versionName: 0.4.2
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -197,7 +197,7 @@ Builds:
|
||||
versionName: 0.5.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -237,7 +237,7 @@ Builds:
|
||||
versionName: 0.5.2
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -277,7 +277,7 @@ Builds:
|
||||
versionName: 0.5.3
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
@ -317,7 +317,7 @@ Builds:
|
||||
versionName: 0.5.4
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build: ''
|
||||
buildjni: []
|
||||
|
@ -1,5 +1,5 @@
|
||||
AllowedAPKSigningKeys: []
|
||||
AntiFeatures: []
|
||||
AntiFeatures: {}
|
||||
ArchivePolicy: 9 versions
|
||||
AuthorEmail: null
|
||||
AuthorName: null
|
||||
@ -14,7 +14,7 @@ Builds:
|
||||
- ../java-libs/SlidingMenu
|
||||
- ../java-libs/ActionBarSherlock
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
|
||||
@ -54,7 +54,7 @@ Builds:
|
||||
- ../java-libs/SlidingMenu
|
||||
- ../java-libs/ActionBarSherlock
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi ./compile.sh release
|
||||
@ -94,7 +94,7 @@ Builds:
|
||||
- ../java-libs/SlidingMenu
|
||||
- ../java-libs/ActionBarSherlock
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=x86 ./compile.sh release
|
||||
@ -134,7 +134,7 @@ Builds:
|
||||
- ../java-libs/SlidingMenu
|
||||
- ../java-libs/ActionBarSherlock
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=mips ./compile.sh release
|
||||
@ -171,7 +171,7 @@ Builds:
|
||||
versionName: 0.0.11-mips
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=mips ./compile.sh release
|
||||
@ -210,7 +210,7 @@ Builds:
|
||||
versionName: 0.1.3-MIPS
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=x86 ./compile.sh release
|
||||
@ -249,7 +249,7 @@ Builds:
|
||||
versionName: 0.1.3-x86
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi ./compile.sh release
|
||||
@ -288,7 +288,7 @@ Builds:
|
||||
versionName: 0.1.3-ARM
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
|
||||
@ -327,7 +327,7 @@ Builds:
|
||||
versionName: 0.1.3-ARMv7
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=x86 ./compile.sh release
|
||||
@ -365,7 +365,7 @@ Builds:
|
||||
versionName: 0.9.0
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
|
||||
@ -403,7 +403,7 @@ Builds:
|
||||
versionName: 0.9.0
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=x86 ./compile.sh release
|
||||
@ -441,7 +441,7 @@ Builds:
|
||||
versionName: 0.9.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
|
||||
@ -479,7 +479,7 @@ Builds:
|
||||
versionName: 0.9.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=x86 ./compile.sh release
|
||||
@ -517,7 +517,7 @@ Builds:
|
||||
versionName: 0.9.5
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
|
||||
@ -555,7 +555,7 @@ Builds:
|
||||
versionName: 0.9.5
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=x86 ./compile.sh release
|
||||
@ -593,7 +593,7 @@ Builds:
|
||||
versionName: 0.9.6
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
|
||||
@ -631,7 +631,7 @@ Builds:
|
||||
versionName: 0.9.6
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=x86 ./compile.sh release
|
||||
@ -669,7 +669,7 @@ Builds:
|
||||
versionName: 0.9.7
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
|
||||
@ -707,7 +707,7 @@ Builds:
|
||||
versionName: 0.9.7
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=mips ./compile.sh release
|
||||
@ -745,7 +745,7 @@ Builds:
|
||||
versionName: 0.9.7.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=x86 ./compile.sh release
|
||||
@ -783,7 +783,7 @@ Builds:
|
||||
versionName: 0.9.7.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
|
||||
@ -821,7 +821,7 @@ Builds:
|
||||
versionName: 0.9.7.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=x86 ./compile.sh release
|
||||
@ -859,7 +859,7 @@ Builds:
|
||||
versionName: 0.9.8
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi ./compile.sh release
|
||||
@ -897,7 +897,7 @@ Builds:
|
||||
versionName: 0.9.8
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
|
||||
@ -935,7 +935,7 @@ Builds:
|
||||
versionName: 0.9.8
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=x86 ./compile.sh release
|
||||
@ -973,7 +973,7 @@ Builds:
|
||||
versionName: 0.9.9
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi ./compile.sh release
|
||||
@ -1011,7 +1011,7 @@ Builds:
|
||||
versionName: 0.9.9
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
|
||||
@ -1049,7 +1049,7 @@ Builds:
|
||||
versionName: 0.9.9
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=x86 ./compile.sh release
|
||||
@ -1087,7 +1087,7 @@ Builds:
|
||||
versionName: 0.9.10
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi ./compile.sh release
|
||||
@ -1125,7 +1125,7 @@ Builds:
|
||||
versionName: 0.9.10
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
|
||||
@ -1163,7 +1163,7 @@ Builds:
|
||||
versionName: 0.9.10
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=x86 ./compile.sh release
|
||||
@ -1201,7 +1201,7 @@ Builds:
|
||||
versionName: 1.0.0
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi ./compile.sh release
|
||||
@ -1239,7 +1239,7 @@ Builds:
|
||||
versionName: 1.0.0
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
|
||||
@ -1277,7 +1277,7 @@ Builds:
|
||||
versionName: 1.0.0
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=x86 ./compile.sh release
|
||||
@ -1315,7 +1315,7 @@ Builds:
|
||||
versionName: 1.0.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi ./compile.sh release
|
||||
@ -1353,7 +1353,7 @@ Builds:
|
||||
versionName: 1.0.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release
|
||||
@ -1391,7 +1391,7 @@ Builds:
|
||||
versionName: 1.0.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi" --release
|
||||
@ -1431,7 +1431,7 @@ Builds:
|
||||
versionName: 1.1.3
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi-v7a" --release
|
||||
@ -1471,7 +1471,7 @@ Builds:
|
||||
versionName: 1.1.3
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "x86" --release
|
||||
@ -1511,7 +1511,7 @@ Builds:
|
||||
versionName: 1.1.3
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi" --release
|
||||
@ -1551,7 +1551,7 @@ Builds:
|
||||
versionName: 1.1.5
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi-v7a" --release
|
||||
@ -1591,7 +1591,7 @@ Builds:
|
||||
versionName: 1.1.5
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "x86" --release
|
||||
@ -1631,7 +1631,7 @@ Builds:
|
||||
versionName: 1.1.5
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi" --release
|
||||
@ -1671,7 +1671,7 @@ Builds:
|
||||
versionName: 1.1.6
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi-v7a" --release
|
||||
@ -1711,7 +1711,7 @@ Builds:
|
||||
versionName: 1.1.6
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "x86" --release
|
||||
@ -1751,7 +1751,7 @@ Builds:
|
||||
versionName: 1.1.6
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi" --release
|
||||
@ -1791,7 +1791,7 @@ Builds:
|
||||
versionName: 1.2.0
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi-v7a" --release
|
||||
@ -1831,7 +1831,7 @@ Builds:
|
||||
versionName: 1.2.0
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "x86" --release
|
||||
@ -1871,7 +1871,7 @@ Builds:
|
||||
versionName: 1.2.0
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi" --release
|
||||
@ -1911,7 +1911,7 @@ Builds:
|
||||
versionName: 1.2.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi-v7a" --release
|
||||
@ -1951,7 +1951,7 @@ Builds:
|
||||
versionName: 1.2.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "x86" --release
|
||||
@ -1991,7 +1991,7 @@ Builds:
|
||||
versionName: 1.2.1
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi" --release
|
||||
@ -2031,7 +2031,7 @@ Builds:
|
||||
versionName: 1.2.2
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi-v7a" --release
|
||||
@ -2071,7 +2071,7 @@ Builds:
|
||||
versionName: 1.2.2
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "x86" --release
|
||||
@ -2111,7 +2111,7 @@ Builds:
|
||||
versionName: 1.2.2
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi" --release
|
||||
@ -2151,7 +2151,7 @@ Builds:
|
||||
versionName: 1.2.3
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi-v7a" --release
|
||||
@ -2191,7 +2191,7 @@ Builds:
|
||||
versionName: 1.2.3
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "x86" --release
|
||||
@ -2231,7 +2231,7 @@ Builds:
|
||||
versionName: 1.2.3
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi" --release
|
||||
@ -2271,7 +2271,7 @@ Builds:
|
||||
versionName: 1.2.4
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi-v7a" --release
|
||||
@ -2311,7 +2311,7 @@ Builds:
|
||||
versionName: 1.2.4
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "x86" --release
|
||||
@ -2351,7 +2351,7 @@ Builds:
|
||||
versionName: 1.2.4
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi" --release
|
||||
@ -2391,7 +2391,7 @@ Builds:
|
||||
versionName: 1.2.5
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi-v7a" --release
|
||||
@ -2431,7 +2431,7 @@ Builds:
|
||||
versionName: 1.2.5
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "x86" --release
|
||||
@ -2471,7 +2471,7 @@ Builds:
|
||||
versionName: 1.2.5
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi" --release
|
||||
@ -2511,7 +2511,7 @@ Builds:
|
||||
versionName: 1.2.6
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "armeabi-v7a" --release
|
||||
@ -2551,7 +2551,7 @@ Builds:
|
||||
versionName: 1.2.6
|
||||
- androidupdate: []
|
||||
antcommands: []
|
||||
antifeatures: []
|
||||
antifeatures: {}
|
||||
binary: null
|
||||
build:
|
||||
- cd ../ && ./compile.sh -a "x86" --release
|
||||
|
@ -3,8 +3,8 @@
|
||||
"version": 20002,
|
||||
"index": {
|
||||
"name": "/index-v2.json",
|
||||
"sha256": "a3c7e88a522a7228937e5c3d760fc239e3578e292035d88478d32fec9ff5eb54",
|
||||
"size": 52314,
|
||||
"sha256": "f4979b9db840cb51a99e80c20da676ba42b13133dbaa4819673bc43ed2ffc3f3",
|
||||
"size": 52481,
|
||||
"numPackages": 10
|
||||
},
|
||||
"diffs": {}
|
||||
|
@ -568,7 +568,9 @@
|
||||
]
|
||||
},
|
||||
"antiFeatures": {
|
||||
"NoSourceSince": {},
|
||||
"NoSourceSince": {
|
||||
"en-US": "1.5"
|
||||
},
|
||||
"NonFreeNet": {}
|
||||
}
|
||||
},
|
||||
@ -602,7 +604,9 @@
|
||||
]
|
||||
},
|
||||
"antiFeatures": {
|
||||
"NoSourceSince": {},
|
||||
"NoSourceSince": {
|
||||
"en-US": "1.5"
|
||||
},
|
||||
"NonFreeNet": {}
|
||||
}
|
||||
},
|
||||
@ -645,7 +649,9 @@
|
||||
]
|
||||
},
|
||||
"antiFeatures": {
|
||||
"NoSourceSince": {},
|
||||
"NoSourceSince": {
|
||||
"en-US": "1.5"
|
||||
},
|
||||
"NonFreeNet": {}
|
||||
}
|
||||
},
|
||||
@ -689,7 +695,9 @@
|
||||
},
|
||||
"antiFeatures": {
|
||||
"KnownVuln": {},
|
||||
"NoSourceSince": {},
|
||||
"NoSourceSince": {
|
||||
"en-US": "1.5"
|
||||
},
|
||||
"NonFreeAssets": {},
|
||||
"NonFreeNet": {},
|
||||
"UpstreamNonFree": {}
|
||||
@ -1395,4 +1403,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -45,11 +45,11 @@ class RewriteMetaTest(unittest.TestCase):
|
||||
'versionCode': 3,
|
||||
'commit': '6a548e4b19',
|
||||
'target': 'android-10',
|
||||
'antifeatures': [
|
||||
'KnownVuln',
|
||||
'UpstreamNonFree',
|
||||
'NonFreeAssets',
|
||||
],
|
||||
'antifeatures': {
|
||||
'KnownVuln': {},
|
||||
'UpstreamNonFree': {},
|
||||
'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):
|
||||
"""Unset fields in Builds: entries should be removed."""
|
||||
self.assertEqual(
|
||||
@ -78,6 +96,43 @@ class RewriteMetaTest(unittest.TestCase):
|
||||
rewritemeta.remove_blank_flags_from_builds(dict()),
|
||||
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_remove_blank_flags_from_builds_values_to_purge(self):
|
||||
self.assertEqual(
|
||||
rewritemeta.remove_blank_flags_from_builds(
|
||||
[
|
||||
{
|
||||
'antifeatures': dict(),
|
||||
'forceversion': False,
|
||||
'init': None,
|
||||
'rm': '',
|
||||
'scandelete': list(),
|
||||
'versionCode': 0,
|
||||
},
|
||||
{'antifeatures': list(), 'versionCode': 1},
|
||||
{'antifeatures': '', 'versionCode': 2},
|
||||
]
|
||||
),
|
||||
[{'versionCode': 0}, {'versionCode': 1}, {'versionCode': 2}],
|
||||
)
|
||||
|
||||
def test_rewrite_no_builds(self):
|
||||
os.chdir(self.testdir)
|
||||
@ -144,6 +199,30 @@ class RewriteMetaTest(unittest.TestCase):
|
||||
},
|
||||
)
|
||||
|
||||
def test_remove_blank_flags_from_builds_app_with_special_build_params_af(self):
|
||||
"""Unset fields in Builds: entries should be removed."""
|
||||
appid = 'app.with.special.build.params'
|
||||
app = metadata.read_metadata({appid: -1})[appid]
|
||||
builds = rewritemeta.remove_blank_flags_from_builds(app.get('Builds'))
|
||||
self.assertEqual(
|
||||
builds[-2],
|
||||
{
|
||||
'antifeatures': {
|
||||
'Ads': {'en-US': 'includes ad lib\n', 'zh-CN': '包括广告图书馆\n'},
|
||||
'Tracking': {'en-US': 'standard suspects\n'},
|
||||
},
|
||||
'commit': '2.1.1',
|
||||
'maven': '2',
|
||||
'patch': [
|
||||
'manifest-ads.patch',
|
||||
'mobilecore.patch',
|
||||
],
|
||||
'srclibs': ['FacebookSDK@sdk-version-3.0.2'],
|
||||
'versionCode': 50,
|
||||
'versionName': '2.1.1-c',
|
||||
},
|
||||
)
|
||||
|
||||
def test_rewrite_scenario_trivial(self):
|
||||
sys.argv = ['rewritemeta', 'a', 'b']
|
||||
|
||||
|
@ -768,7 +768,7 @@ class UpdateTest(unittest.TestCase):
|
||||
'-1': 'res/drawable-mdpi-v4/icon_launcher.png'})
|
||||
self.assertEqual(apk_info['icons'], {})
|
||||
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['hash'],
|
||||
'897486e1f857c6c0ee32ccbad0e1b8cd82f6d0e65a44a23f13f852d2b63a18c8')
|
||||
@ -819,7 +819,7 @@ class UpdateTest(unittest.TestCase):
|
||||
'hashType': 'sha256',
|
||||
'packageName': 'no.min.target.sdk',
|
||||
'features': [],
|
||||
'antiFeatures': set(),
|
||||
'antiFeatures': dict(),
|
||||
'size': 14102,
|
||||
'sig': 'b4964fd759edaa54e65bb476d0276880',
|
||||
'versionName': '1.2-fake',
|
||||
@ -1433,7 +1433,7 @@ class UpdateTest(unittest.TestCase):
|
||||
'NoSourceSince': '',
|
||||
'Repo': '',
|
||||
'RepoType': '',
|
||||
'RequiresRoot': '',
|
||||
'RequiresRoot': None,
|
||||
'SourceCode': '',
|
||||
'Summary': 'rocks.janicerand',
|
||||
'Translation': '',
|
||||
|
Loading…
Reference in New Issue
Block a user