def add_digest(impl, alg_name): alg = manifest.get_algorithm(alg_name) # Scan through the existing digests # - If we've already got the one we need, return # - Otherwise, find a cached implementation we can use existing_path = None for a, value in digests(impl): if a in ('sha1', 'sha1new', 'sha256'): digest = '%s=%s' % (a, value) else: digest = '%s_%s' % (a, value) if a == alg_name: return False # Already signed with this algorithm if not existing_path: try: existing_path = stores.lookup(digest) if existing_path: existing_digest = digest except NotStored: pass # OK if existing_path is None: print("No implementations of %s cached; can't calculate new digest" % get_version(impl)) return False info("Verifying %s", existing_path) manifest.verify(existing_path, existing_digest) print("Adding new digest to version %s" % get_version(impl)) new_digest = alg.new_digest() for line in alg.generate_manifest(existing_path): new_digest.update((line + '\n').encode()) for md in xmltools.children(impl, 'manifest-digest'): break else: md = xmltools.create_element(impl, 'manifest-digest') _, digest_value = manifest.splitID(alg.getID(new_digest)) md.setAttribute(alg_name, digest_value) return True
def add_digest(impl, alg_name): alg = manifest.get_algorithm(alg_name) # Scan through the existing digests # - If we've already got the one we need, return # - Otherwise, find a cached implementation we can use existing_path = None for a, value in digests(impl): digest = '%s=%s' % (a, value) if a == alg_name: return False # Already signed with this algorithm if not existing_path: try: existing_path = stores.lookup(digest) if existing_path: existing_digest = digest except NotStored: pass # OK if existing_path is None: print "No implementations of %s cached; can't calculate new digest" % get_version(impl) return False info("Verifying %s", existing_path) manifest.verify(existing_path, existing_digest) print "Adding new digest to version %s" % get_version(impl) new_digest = alg.new_digest() for line in alg.generate_manifest(existing_path): new_digest.update(line + '\n') for md in xmltools.children(impl, 'manifest-digest'): break else: md = xmltools.create_element(impl, 'manifest-digest') md.setAttribute(alg_name, new_digest.hexdigest()) return True
def merge(data, local): local_doc = minidom.parse(local) master_doc = minidom.parseString(data) known_ids = set() def check_unique(elem): impl_id = impl.getAttribute("id") if impl_id in known_ids: raise Exception("Duplicate ID " + impl_id) known_ids.add(impl_id) for impl in find_impls(master_doc.documentElement): check_unique(impl) # Merge each implementation in the local feed in turn (normally there will only be one) for impl in find_impls(local_doc.documentElement): check_unique(impl) # 1. Get the context of the implementation to add. This is: # - The set of its requirements # - The set of its commands # - Its attributes new_impl_context = Context(impl) # 2. For each <group> in the master feed, see if it provides a compatible context: # - A subset of the new implementation's requirements # - A subset of the new implementation's command names # - A subset of the new implementation's attributes (names, not values) # Choose the most compatible <group> (the root counts as a minimally compatible group) best_group = ((1, 0, 0), master_doc.documentElement) # (score, element) for group in find_groups(master_doc.documentElement): group_context = Context(group) score = score_subset(group_context, new_impl_context) if score > best_group[0]: best_group = (score, group) group = best_group[1] group_context = Context(group) if new_impl_context.has_main_and_run: # If the existing group doesn't have the same main value then we'll need a new group. Otherwise, # we're likely to override the command by having main on the implementation element. current_group_main = group_context.attribs.get((None, 'main'), None) need_new_group_for_main = current_group_main != new_impl_context.attribs[(None, 'main')] else: need_new_group_for_main = False new_commands = [] for name_expr, new_command in new_impl_context.commands.items(): if need_new_group_for_main and name_expr[0] == 'run': # If we're creating a new <group main='...'> then we can't inherit an existing <command name='run'/>, old_command = None else: old_command = group_context.commands.get(name_expr, None) if not (old_command and nodesEqual(old_command, new_command)): new_commands.append(xmltools.import_node(master_doc, new_command)) # If we have additional requirements or commands, we'll need to create a subgroup and add them if len(new_impl_context.requires) > len(group_context.requires) or new_commands or need_new_group_for_main: subgroup = xmltools.create_element(group, 'group') group = subgroup #group_context = Context(group) for x in new_impl_context.requires: for y in group_context.requires: if nodesEqual(x, y): break else: req = xmltools.import_node(master_doc, x) #print "Add", req xmltools.insert_element(req, group) for c in new_commands: xmltools.insert_element(c, group) if need_new_group_for_main: group.setAttribute('main', new_impl_context.attribs[(None, 'main')]) # We'll remove it from the <implementation> below, when cleaning up duplicates group_context = Context(group) new_impl = xmltools.import_node(master_doc, impl) # Attributes might have been set on a parent group; move to the impl for name in new_impl_context.attribs: #print "Set", name, value xmltools.add_attribute_ns(new_impl, name[0], name[1], new_impl_context.attribs[name]) for name, value in new_impl.attributes.itemsNS(): if name[0] == XMLNS_NAMESPACE or \ (name in group_context.attribs and group_context.attribs[name] == value): #print "Deleting duplicate attribute", name, value new_impl.removeAttributeNS(name[0], name[1]) xmltools.insert_element(new_impl, group) return master_doc.toxml('utf-8')
def merge(data, local): local_doc = minidom.parse(local) master_doc = minidom.parseString(data) # Merge each implementation in the local feed in turn (normally there will only be one) for impl in find_impls(local_doc.documentElement): # 1. Get the context of the implementation to add. This is: # - The set of its requirements # - The set of its commands # - Its attributes new_impl_context = Context(impl) # 2. For each <group> in the master feed, see if it provides a compatible context: # - A subset of the new implementation's requirements # - A subset of the new implementation's command names # - A subset of the new implementation's attributes (names, not values) # Choose the most compatible <group> (the root counts as a minimally compatible group) best_group = ((1, 0, 0), master_doc.documentElement) # (score, element) for group in find_groups(master_doc.documentElement): group_context = Context(group) score = score_subset(group_context, new_impl_context) if score > best_group[0]: best_group = (score, group) group = best_group[1] group_context = Context(group) new_commands = [] for name, new_command in new_impl_context.commands.iteritems(): old_command = group_context.commands.get(name, None) if not (old_command and nodesEqual(old_command, new_command)): new_commands.append(master_doc.importNode(new_command, True)) # If we have additional requirements, we'll need to create a subgroup and add them if len(new_impl_context.requires) > len(group_context.requires) or new_commands: subgroup = xmltools.create_element(group, 'group') group = subgroup #group_context = Context(group) for x in new_impl_context.requires: for y in group_context.requires: if nodesEqual(x, y): break else: req = master_doc.importNode(x, True) #print "Add", req xmltools.insert_element(req, group) for c in new_commands: xmltools.insert_element(c, group) new_impl = master_doc.importNode(impl, True) # Attributes might have been set on a parent group; move to the impl for name in new_impl_context.attribs: #print "Set", name, value xmltools.add_attribute_ns(new_impl, name[0], name[1], new_impl_context.attribs[name]) for name, value in new_impl.attributes.itemsNS(): if name[0] == XMLNS_NAMESPACE or \ (name in group_context.attribs and group_context.attribs[name] == value): #print "Deleting duplicate attribute", name, value new_impl.removeAttributeNS(name[0], name[1]) xmltools.insert_element(new_impl, group) return master_doc.toxml()