chiark / gitweb /
use pyyaml for rewriting .yml metadata files
authorHans-Christoph Steiner <hans@eds.org>
Fri, 25 Nov 2016 14:20:19 +0000 (15:20 +0100)
committerHans-Christoph Steiner <hans@eds.org>
Tue, 2 May 2017 12:55:23 +0000 (14:55 +0200)
This replaces the broken, custom code with the standard YAML lib.

In rewritemeta, do not call app.metadatapath since it will be deleted when
the dict is cleaned up for outputing. metadatapath is only used internally
and should not be written out.

closes #169
refs #290

fdroidserver/metadata.py
fdroidserver/rewritemeta.py

index fe7e07f17bacac770cdf29bd6adab97bf00d50b9..360ffc8238d59cb412ac8b830b2a348ad8640b70 100644 (file)
@@ -239,8 +239,9 @@ build_flags_order = [
     'novcheck',
 ]
 
-
-build_flags = set(build_flags_order + ['versionName', 'versionCode'])
+# old .txt format has version name/code inline in the 'Build:' line
+# but YAML and JSON have a explicit key for them
+build_flags = ['versionName', 'versionCode'] + build_flags_order
 
 
 class Build(dict):
@@ -959,6 +960,25 @@ def parse_yaml_metadata(mf, app):
     return app
 
 
+def write_yaml(mf, app):
+
+    def _class_as_dict_representer(dumper, data):
+        '''Creates a YAML representation of a App/Build instance'''
+        return dumper.represent_dict(data)
+
+    empty_keys = [k for k, v in app.items() if not v]
+    for k in empty_keys:
+        del app[k]
+
+    for k in ['added', 'lastUpdated', 'id', 'metadatapath']:
+        if k in app:
+            del app[k]
+
+    yaml.add_representer(fdroidserver.metadata.App, _class_as_dict_representer)
+    yaml.add_representer(fdroidserver.metadata.Build, _class_as_dict_representer)
+    yaml.dump(app, mf, default_flow_style=False)
+
+
 build_line_sep = re.compile(r'(?<!\\),')
 build_cont = re.compile(r'^[ \t]')
 
@@ -1304,70 +1324,6 @@ def write_txt(mf, app):
     write_plaintext_metadata(mf, app, w_comment, w_field, w_build)
 
 
-def write_yaml(mf, app):
-
-    def w_comment(line):
-        mf.write("# %s\n" % line)
-
-    def escape(v):
-        if not v:
-            return ''
-        if any(c in v for c in [': ', '%', '@', '*']):
-            return "'" + v.replace("'", "''") + "'"
-        return v
-
-    def w_field(f, v, prefix='', t=None):
-        if t is None:
-            t = fieldtype(f)
-        v = ''
-        if t == TYPE_LIST:
-            v = '\n'
-            for e in v:
-                v += prefix + ' - ' + escape(e) + '\n'
-        elif t == TYPE_MULTILINE:
-            v = ' |\n'
-            for l in v.splitlines():
-                if l:
-                    v += prefix + '  ' + l + '\n'
-                else:
-                    v += '\n'
-        elif t == TYPE_BOOL:
-            v = ' yes\n'
-        elif t == TYPE_SCRIPT:
-            cmds = [s + '&& \\' for s in v.split('&& ')]
-            if len(cmds) > 0:
-                cmds[-1] = cmds[-1][:-len('&& \\')]
-            w_field(f, cmds, prefix, 'multiline')
-            return
-        else:
-            v = ' ' + escape(v) + '\n'
-
-        mf.write(prefix)
-        mf.write(f)
-        mf.write(":")
-        mf.write(v)
-
-    global first_build
-    first_build = True
-
-    def w_build(build):
-        global first_build
-        if first_build:
-            mf.write("builds:\n")
-            first_build = False
-
-        w_field('versionName', build.versionName, '  - ', TYPE_STRING)
-        w_field('versionCode', build.versionCode, '    ', TYPE_STRING)
-        for f in build_flags_order:
-            v = build.get(f)
-            if not v:
-                continue
-
-            w_field(f, v, '    ', flagtype(f))
-
-    write_plaintext_metadata(mf, app, w_comment, w_field, w_build)
-
-
 def write_metadata(metadatapath, app):
     _, ext = fdroidserver.common.get_extension(metadatapath)
     accepted = fdroidserver.common.config['accepted_formats']
index f6e2910f01c96da20e9b5a238c1b58da53b23a3a..2d2d18037fc9ebc83335d6dc35f14ba8d8112d96 100644 (file)
@@ -72,9 +72,10 @@ def main():
         parser.error("Unsupported metadata format, use: --to [" + ' '.join(supported) + "]")
 
     for appid, app in apps.items():
-        base, ext = common.get_extension(app.metadatapath)
+        path = app.metadatapath
+        base, ext = common.get_extension(path)
         if not options.to and ext not in supported:
-            logging.info("Ignoring %s file at '%s'" % (ext, app.metadatapath))
+            logging.info("Ignoring %s file at '%s'" % (ext, path))
             continue
 
         to_ext = ext
@@ -83,13 +84,24 @@ def main():
 
         if options.list:
             if not proper_format(app):
-                print(app.metadatapath)
+                print(path)
             continue
 
+        newbuilds = []
+        for build in app.builds:
+            new = metadata.Build()
+            for k in metadata.build_flags:
+                v = build[k]
+                if v is None or v is False or v == [] or v == '':
+                    continue
+                new[k] = v
+            newbuilds.append(new)
+        app.builds = newbuilds
+
         metadata.write_metadata(base + '.' + to_ext, app)
 
         if ext != to_ext:
-            os.remove(app.metadatapath)
+            os.remove(path)
 
     logging.debug("Finished.")