chiark / gitweb /
Open metadata files in only one place
[fdroidserver.git] / fdroidserver / metadata.py
index 6115fed6d3b4da01f35cea716b2f26c98ff879f5..163ebf01b1653427b8be1c974f1353333de5a5e7 100644 (file)
@@ -162,10 +162,11 @@ class App():
             if k == 'builds':
                 d['builds'] = []
                 for build in v:
-                    d['builds'].append(build.__dict__)
-            else:
-                k = App.attr_to_field(k)
-                d[k] = v
+                    b = {k: v for k, v in build.__dict__.iteritems() if not k.startswith('_')}
+                    d['builds'].append(b)
+            elif not k.startswith('_'):
+                f = App.attr_to_field(k)
+                d[f] = v
         return d
 
     # Gets the value associated to a field name, e.g. 'Auto Name'
@@ -277,7 +278,7 @@ class Build():
         self.submodules = False
         self.init = ''
         self.patch = []
-        self.gradle = False
+        self.gradle = []
         self.maven = False
         self.kivy = False
         self.output = None
@@ -289,7 +290,7 @@ class Build():
         self.rm = []
         self.extlibs = []
         self.prebuild = ''
-        self.update = None
+        self.update = []
         self.target = None
         self.scanignore = []
         self.scandelete = []
@@ -298,7 +299,7 @@ class Build():
         self.ndk = None
         self.preassemble = []
         self.gradleprops = []
-        self.antcommands = None
+        self.antcommands = []
         self.novcheck = False
 
         self._modified = set()
@@ -437,7 +438,7 @@ valuetypes = {
 
     FieldValidator("HTTP link",
                    r'^http[s]?://', None,
-                   ["Web Site", "Source Code", "Issue Tracker", "Changelog", "Donate"], []),
+                   ["WebSite", "SourceCode", "IssueTracker", "Changelog", "Donate"], []),
 
     FieldValidator("Bitcoin address",
                    r'^[a-zA-Z0-9]{27,34}$', None,
@@ -451,7 +452,7 @@ valuetypes = {
 
     FieldValidator("Repo Type",
                    ['git', 'git-svn', 'svn', 'hg', 'bzr', 'srclib'], None,
-                   ["Repo Type"],
+                   ["RepoType"],
                    []),
 
     FieldValidator("Binaries",
@@ -461,7 +462,7 @@ valuetypes = {
 
     FieldValidator("Archive Policy",
                    r'^[0-9]+ versions$', None,
-                   ["Archive Policy"],
+                   ["ArchivePolicy"],
                    []),
 
     FieldValidator("Anti-Feature",
@@ -471,12 +472,12 @@ valuetypes = {
 
     FieldValidator("Auto Update Mode",
                    r"^(Version .+|None)$", None,
-                   ["Auto Update Mode"],
+                   ["AutoUpdateMode"],
                    []),
 
     FieldValidator("Update Check Mode",
                    r"^(Tags|Tags .+|RepoManifest|RepoManifest/.+|RepoTrunk|HTTP|Static|None)$", None,
-                   ["Update Check Mode"],
+                   ["UpdateCheckMode"],
                    [])
 }
 
@@ -484,11 +485,15 @@ valuetypes = {
 # Check an app's metadata information for integrity errors
 def check_metadata(app):
     for v in valuetypes:
-        for f in v.fields:
-            v.check(app.get_field(f), app.id)
+        for k in v.fields:
+            if k not in app._modified:
+                continue
+            v.check(app.__dict__[k], app.id)
         for build in app.builds:
-            for f in v.flags:
-                v.check(build.get_flag(f), app.id)
+            for k in v.flags:
+                if k not in build._modified:
+                    continue
+                v.check(build.__dict__[k], app.id)
 
 
 # Formatter for descriptions. Create an instance, and call parseline() with
@@ -947,34 +952,34 @@ def parse_metadata(metadatapath):
         raise MetaDataException('"%s" is not an accepted format, convert to: %s' % (
             metadatapath, ', '.join(accepted)))
 
-    app = None
-    if ext == 'txt':
-        app = parse_txt_metadata(metadatapath)
-    elif ext == 'json':
-        app = parse_json_metadata(metadatapath)
-    elif ext == 'xml':
-        app = parse_xml_metadata(metadatapath)
-    elif ext == 'yaml':
-        app = parse_yaml_metadata(metadatapath)
-    else:
-        raise MetaDataException('Unknown metadata format: %s' % metadatapath)
+    app = App()
+    app.metadatapath = metadatapath
+    app.id, _ = common.get_extension(os.path.basename(metadatapath))
+
+    with open(metadatapath, 'r') 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':
+            parse_yaml_metadata(mf, app)
+        else:
+            raise MetaDataException('Unknown metadata format: %s' % metadatapath)
 
     post_metadata_parse(app)
     return app
 
 
-def parse_json_metadata(metadatapath):
-
-    app = get_default_app_info(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
     # TODO create schema using https://pypi.python.org/pypi/jsonschema
-    jsoninfo = None
-    with open(metadatapath, 'r') as f:
-        jsoninfo = json.load(f, object_hook=_decode_dict,
-                             parse_int=lambda s: s,
-                             parse_float=lambda s: s)
+    jsoninfo = json.load(mf, object_hook=_decode_dict,
+                         parse_int=lambda s: s,
+                         parse_float=lambda s: s)
     app.update_fields(jsoninfo)
     for f in ['Description', 'Maintainer Notes']:
         v = app.get_field(f)
@@ -982,11 +987,9 @@ def parse_json_metadata(metadatapath):
     return app
 
 
-def parse_xml_metadata(metadatapath):
+def parse_xml_metadata(mf, app):
 
-    app = get_default_app_info(metadatapath)
-
-    tree = ElementTree.ElementTree(file=metadatapath)
+    tree = ElementTree.ElementTree(file=mf)
     root = tree.getroot()
 
     if root.tag != 'resources':
@@ -1016,13 +1019,9 @@ def parse_xml_metadata(metadatapath):
     return app
 
 
-def parse_yaml_metadata(metadatapath):
-
-    app = get_default_app_info(metadatapath)
+def parse_yaml_metadata(mf, app):
 
-    yamlinfo = None
-    with open(metadatapath, 'r') as f:
-        yamlinfo = yaml.load(f, Loader=YamlLoader)
+    yamlinfo = yaml.load(mf, Loader=YamlLoader)
     app.update_fields(yamlinfo)
     return app
 
@@ -1031,7 +1030,7 @@ build_line_sep = re.compile(r'(?<!\\),')
 build_cont = re.compile(r'^[ \t]')
 
 
-def parse_txt_metadata(metadatapath):
+def parse_txt_metadata(mf, app):
 
     linedesc = None
 
@@ -1061,7 +1060,6 @@ def parse_txt_metadata(metadatapath):
         if len(parts) < 3:
             raise MetaDataException("Invalid build format: " + v + " in " + metafile.name)
         build = Build()
-        build.origlines = lines
         build.version = parts[0]
         build.vercode = parts[1]
         if parts[2].startswith('!'):
@@ -1088,9 +1086,6 @@ def parse_txt_metadata(metadatapath):
         app.comments[key] = list(curcomments)
         del curcomments[:]
 
-    app = get_default_app_info(metadatapath)
-    metafile = open(metadatapath, "r")
-
     mode = 0
     buildlines = []
     multiline_lines = []
@@ -1099,9 +1094,9 @@ def parse_txt_metadata(metadatapath):
     vc_seen = set()
 
     c = 0
-    for line in metafile:
+    for line in mf:
         c += 1
-        linedesc = "%s:%d" % (metafile.name, c)
+        linedesc = "%s:%d" % (mf.name, c)
         line = line.rstrip('\r\n')
         if mode == 3:
             if build_cont.match(line):
@@ -1193,11 +1188,10 @@ def parse_txt_metadata(metadatapath):
                 add_comments('build:' + app.builds[-1].vercode)
                 mode = 0
     add_comments(None)
-    metafile.close()
 
     # Mode at end of file should always be 0
     if mode == 1:
-        raise MetaDataException(f + " not terminated in " + metafile.name)
+        raise MetaDataException(f + " not terminated in " + mf.name)
     if mode == 2:
         raise MetaDataException("Unterminated continuation in " + metafile.name)
     if mode == 3: