-# -*- coding: utf-8 -*-
+#!/usr/bin/env python3
#
# metadata.py - part of the FDroid server tools
# Copyright (C) 2013, Ciaran Gultnieks, ciaran@ciarang.com
import re
import glob
import cgi
+import logging
import textwrap
import io
self.state = self.stNONE
whole_para = ' '.join(self.para_lines)
self.addtext(whole_para)
- wrapped = textwrap.fill(whole_para.decode('utf-8'), 80,
+ wrapped = textwrap.fill(whole_para, 80,
break_long_words=False,
break_on_hyphens=False)
- self.text.write(wrapped.encode('utf-8'))
+ self.text.write(wrapped)
self.html.write('</p>')
del self.para_lines[:]
if not os.path.exists(metadatapath):
return thisinfo
- metafile = open(metadatapath, "r")
+ metafile = open(metadatapath, "r", encoding='utf-8')
n = 0
for line in metafile:
for metadatapath in sorted(glob.glob(os.path.join('metadata', '*.txt'))
+ glob.glob(os.path.join('metadata', '*.json'))
+ glob.glob(os.path.join('metadata', '*.xml'))
- + glob.glob(os.path.join('metadata', '*.yaml'))):
+ + glob.glob(os.path.join('metadata', '*.yml'))
+ + glob.glob('.fdroid.json')
+ + glob.glob('.fdroid.xml')
+ + glob.glob('.fdroid.yml')):
+ packageName, _ = fdroidserver.common.get_extension(os.path.basename(metadatapath))
+ if packageName in apps:
+ raise MetaDataException("Found multiple metadata files for " + packageName)
app = parse_metadata(metadatapath)
- if app.id in apps:
- raise MetaDataException("Found multiple metadata files for " + app.id)
check_metadata(app)
apps[app.id] = app
else:
appid, _ = fdroidserver.common.get_extension(os.path.basename(metadatapath))
+ if appid == '.fdroid': # we have local metadata in the app's source
+ if os.path.exists('AndroidManifest.xml'):
+ manifestroot = fdroidserver.common.parse_xml('AndroidManifest.xml')
+ else:
+ pattern = re.compile(""".*manifest\.srcFile\s+'AndroidManifest\.xml'.*""")
+ for root, dirs, files in os.walk(os.getcwd()):
+ if 'build.gradle' in files:
+ p = os.path.join(root, 'build.gradle')
+ with open(p, 'rb') as f:
+ data = f.read()
+ m = pattern.search(data)
+ if m:
+ logging.debug('Using: ' + os.path.join(root, 'AndroidManifest.xml'))
+ manifestroot = fdroidserver.common.parse_xml(os.path.join(root, 'AndroidManifest.xml'))
+ break
+ if manifestroot is None:
+ raise MetaDataException("Cannot find a packageName for {0}!".format(metadatapath))
+ appid = manifestroot.attrib['package']
+
app = App()
app.metadatapath = metadatapath
if appid is not None:
# This function uses __dict__ to be faster
def post_metadata_parse(app):
- for k, v in app.__dict__.items():
- if k not in app._modified:
- continue
+ for k in app._modified:
+ v = app.__dict__[k]
if type(v) in (float, int):
app.__dict__[k] = str(v)
for build in app.builds:
- for k, v in build.__dict__.items():
-
- if k not in build._modified:
- continue
+ for k in build._modified:
+ v = build.__dict__[k]
if type(v) in (float, int):
build.__dict__[k] = str(v)
continue
#
-def _decode_list(data):
- '''convert items in a list from unicode to str'''
- rv = []
- for item in data:
- if isinstance(item, unicode):
- item = item.encode('utf-8')
- elif isinstance(item, list):
- item = _decode_list(item)
- elif isinstance(item, dict):
- item = _decode_dict(item)
- rv.append(item)
- return rv
-
-
-def _decode_dict(data):
- '''convert items in a dict from unicode to str'''
- rv = {}
- for k, v in data.items():
- if isinstance(k, unicode):
- k = k.encode('utf-8')
- if isinstance(v, unicode):
- v = v.encode('utf-8')
- elif isinstance(v, list):
- v = _decode_list(v)
- elif isinstance(v, dict):
- v = _decode_dict(v)
- rv[k] = v
- return rv
-
-
bool_true = re.compile(r'([Yy]es|[Tt]rue)')
bool_false = re.compile(r'([Nn]o|[Ff]alse)')
app.metadatapath = metadatapath
app.id, _ = fdroidserver.common.get_extension(os.path.basename(metadatapath))
- with open(metadatapath, 'r') as mf:
+ with open(metadatapath, 'r', encoding='utf-8') as mf:
if ext == 'txt':
parse_txt_metadata(mf, app)
elif ext == 'json':
parse_json_metadata(mf, app)
elif ext == 'xml':
parse_xml_metadata(mf, app)
- elif ext == 'yaml':
+ elif ext == 'yml':
parse_yaml_metadata(mf, app)
else:
raise MetaDataException('Unknown metadata format: %s' % metadatapath)
def parse_json_metadata(mf, app):
- # fdroid metadata is only strings and booleans, no floats or ints. And
- # json returns unicode, and fdroidserver still uses plain python strings
+ # fdroid metadata is only strings and booleans, no floats or ints.
# TODO create schema using https://pypi.python.org/pypi/jsonschema
- jsoninfo = json.load(mf, object_hook=_decode_dict,
- parse_int=lambda s: s,
+ jsoninfo = json.load(mf, parse_int=lambda s: s,
parse_float=lambda s: s)
app.update_fields(jsoninfo)
for f in ['Description', 'Maintainer Notes']:
w_field_always('Binaries')
mf.write('\n')
- for build in sorted_builds(app.builds):
+ for build in app.builds:
if build.version == "Ignore":
continue
#
# 'mf' - Writer interface (file, StringIO, ...)
# 'app' - The app data
-def write_txt_metadata(mf, app):
+def write_txt(mf, app):
def w_comment(line):
mf.write("# %s\n" % line)
write_plaintext_metadata(mf, app, w_comment, w_field, w_build)
-def write_yaml_metadata(mf, app):
+def write_yaml(mf, app):
def w_comment(line):
mf.write("# %s\n" % line)
write_plaintext_metadata(mf, app, w_comment, w_field, w_build)
-def write_metadata(fmt, mf, app):
- if fmt == 'txt':
- return write_txt_metadata(mf, app)
- if fmt == 'yaml':
- return write_yaml_metadata(mf, app)
- raise MetaDataException("Unknown metadata format given")
+def write_metadata(metadatapath, app):
+ _, ext = fdroidserver.common.get_extension(metadatapath)
+ accepted = fdroidserver.common.config['accepted_formats']
+ if ext not in accepted:
+ raise MetaDataException('Cannot write "%s", not an accepted format, use: %s' % (
+ metadatapath, ', '.join(accepted)))
+
+ with open(metadatapath, 'w', encoding='utf8') as mf:
+ if ext == 'txt':
+ return write_txt(mf, app)
+ elif ext == 'yml':
+ return write_yaml(mf, app)
+ raise MetaDataException('Unknown metadata format: %s' % metadatapath)