Updated validator to recognise new features
[0publish.git] / validator.py
blob95ea7e2466bd2a2885357d2c49d034956c70d71c
1 import os
2 from zeroinstall.injector import model, namespaces
3 from zeroinstall.injector.reader import InvalidInterface, update
4 from xml.dom import minidom, Node, XMLNS_NAMESPACE
5 import tempfile
6 from logging import warn, info
8 group_impl_attribs = ['version', 'version-modifier', 'released', 'main', 'stability', 'arch', 'license', 'doc-dir', 'self-test', 'langs', 'local-path']
10 known_elements = {
11 'interface' : ['uri', 'min-injector-version', 'main'], # (main is deprecated)
12 'name' : [],
13 'summary' : [],
14 'description' : [],
15 'needs-terminal' : [],
16 'homepage' : [],
17 'category' : ['type'],
18 'icon' : ['type', 'href'],
19 'feed' : ['src', 'arch'],
20 'feed-for' : ['interface'],
22 'group' : group_impl_attribs,
23 'implementation' : ['id'] + group_impl_attribs,
24 'package-implementation' : ['package', 'main', 'distributions'],
25 'manifest-digest' : ['sha1new', 'sha256'],
26 'command' : ['name', 'path', 'shell-command'],
27 'arg' : [],
29 'archive' : ['href', 'size', 'extract', 'type', 'start-offset'],
30 'recipe' : [],
31 'requires' : ['interface', 'use'],
32 'runner' : ['interface', 'use', 'command'],
33 'version' : ['not-before', 'before'],
34 'environment' : ['name', 'insert', 'value', 'default', 'mode'],
35 'executable-in-var' : ['name', 'command'],
36 'executable-in-path' : ['name', 'command'],
37 #'overlay' : ['src', 'mount-point'],
40 def checkElement(elem):
41 if elem.namespaceURI != namespaces.XMLNS_IFACE:
42 info("Note: Skipping unknown (but namespaced) element <%s>", elem.localName)
43 return # Namespaces elements are OK
45 if elem.localName not in known_elements:
46 warn("Unknown Zero Install element <%s>.\nNon Zero-Install elements should be namespaced.", elem.localName)
47 return
49 known_attrs = known_elements[elem.localName]
51 for (uri, name), value in elem.attributes.itemsNS():
52 if uri == XMLNS_NAMESPACE:
53 continue # Namespace declarations are fine
55 if uri:
56 info("Note: Skipping unknown (but namespaced) attribute '%s'", name)
57 continue
59 if name not in known_attrs:
60 warn("Unknown Zero Install attribute '%s' on <%s>.\nNon Zero-Install attributes should be namespaced.",
61 name, elem.localName)
63 for child in elem.childNodes:
64 if child.nodeType == Node.ELEMENT_NODE:
65 checkElement(child)
67 def check(data, warnings = True):
68 fd, tmp_name = tempfile.mkstemp(prefix = '0publish-validate-')
69 os.close(fd)
70 tmp_iface = model.Interface(tmp_name)
71 try:
72 tmp_file = file(tmp_name, 'w')
73 tmp_file.write(data)
74 tmp_file.close()
75 try:
76 update(tmp_iface, tmp_name, local = True)
77 except InvalidInterface, ex:
78 raise
79 except Exception, ex:
80 warn("Internal error: %s", ex)
81 raise InvalidInterface(str(ex))
82 finally:
83 os.unlink(tmp_name)
85 if warnings:
86 doc = minidom.parseString(data)
87 checkElement(doc.documentElement)