Also merge <restricts> elements
[0publish.git] / digest.py
blobc0054a3b5ccbfbf8df261005735e553d31fbdfa5
1 from xml.dom import minidom
2 from zeroinstall.injector import namespaces
3 from zeroinstall.zerostore import manifest, Stores, NotStored
4 import xmltools
5 from logging import info
7 stores = Stores()
9 def digests(impl):
10 id = impl.getAttribute('id')
11 if '=' in id:
12 yield id.split('=', 1)
13 for x in xmltools.children(impl, 'manifest-digest'):
14 for name, value in x.attributes.itemsNS():
15 if name[0] is None:
16 yield name[1], value
18 def get_version(impl):
19 while impl:
20 v = impl.getAttribute('version')
21 if v: return v
22 impl = impl.parentNode
24 def add_digest(impl, alg_name):
25 alg = manifest.get_algorithm(alg_name)
27 # Scan through the existing digests
28 # - If we've already got the one we need, return
29 # - Otherwise, find a cached implementation we can use
30 existing_path = None
31 for a, value in digests(impl):
32 digest = '%s=%s' % (a, value)
33 if a == alg_name:
34 return False # Already signed with this algorithm
35 if not existing_path:
36 try:
37 existing_path = stores.lookup(digest)
38 if existing_path:
39 existing_digest = digest
40 except NotStored:
41 pass # OK
43 if existing_path is None:
44 print "No implementations of %s cached; can't calculate new digest" % get_version(impl)
45 return False
47 info("Verifying %s", existing_path)
48 manifest.verify(existing_path, existing_digest)
50 print "Adding new digest to version %s" % get_version(impl)
52 new_digest = alg.new_digest()
53 for line in alg.generate_manifest(existing_path):
54 new_digest.update(line + '\n')
56 for md in xmltools.children(impl, 'manifest-digest'):
57 break
58 else:
59 md = xmltools.create_element(impl, 'manifest-digest')
60 md.setAttribute(alg_name, new_digest.hexdigest())
62 return True
64 def add_digests(data, alg = None):
65 doc = minidom.parseString(data)
67 if alg is None:
68 alg = 'sha1new'
70 changed = False
71 for impl in doc.documentElement.getElementsByTagNameNS(namespaces.XMLNS_IFACE, 'implementation'):
72 if impl.getAttribute('id') in "./":
73 continue # Local implementation
75 if add_digest(impl, alg):
76 changed = True
78 if changed:
79 return doc.toxml('utf-8')
80 else:
81 return data