def add_objects(self, objects): """Add a set of objects to this object store. :param objects: Iterable over a list of objects. """ if len(objects) == 0: return f, commit = self.add_pack() write_pack_data(f, objects, len(objects)) commit()
def send_pack(self, path, determine_wants, generate_pack_contents): """Upload a pack to a remote repository. :param path: Repository path :param generate_pack_contents: Function that can return the shas of the objects to upload. """ refs, server_capabilities = self.read_refs() changed_refs = determine_wants(refs) if not changed_refs: self.proto.write_pkt_line(None) return {} want = [] have = [] sent_capabilities = False for changed_ref, new_sha1 in changed_refs.iteritems(): old_sha1 = refs.get(changed_ref, "0" * 40) if sent_capabilities: self.proto.write_pkt_line("%s %s %s" % (old_sha1, new_sha1, changed_ref)) else: self.proto.write_pkt_line("%s %s %s\0%s" % (old_sha1, new_sha1, changed_ref, self.capabilities())) sent_capabilities = True want.append(new_sha1) if old_sha1 != "0"*40: have.append(old_sha1) self.proto.write_pkt_line(None) objects = generate_pack_contents(want, have) (entries, sha) = write_pack_data(self.proto.write_file(), objects, len(objects)) self.proto.write(sha) # read the final confirmation sha client_sha = self.proto.read(20) # TODO : do something here that doesn't break #if not client_sha in (None, sha): # print "warning: local %s and server %s differ" % (sha_to_hex(sha), sha_to_hex(client_sha)) return changed_refs
def handle(self): def determine_wants(heads): keys = heads.keys() if keys: self.proto.write_pkt_line("%s %s\x00%s\n" % ( heads[keys[0]], keys[0], self.capabilities())) for k in keys[1:]: self.proto.write_pkt_line("%s %s\n" % (heads[k], k)) # i'm done.. self.proto.write("0000") # Now client will either send "0000", meaning that it doesnt want to pull. # or it will start sending want want want commands want = self.proto.read_pkt_line() if want == None: return [] want, self.client_capabilities = extract_capabilities(want) want_revs = [] while want and want[:4] == 'want': want_revs.append(want[5:45]) want = self.proto.read_pkt_line() return want_revs progress = lambda x: self.proto.write_sideband(2, x) write = lambda x: self.proto.write_sideband(1, x) class ProtocolGraphWalker(object): def __init__(self, proto): self.proto = proto self._last_sha = None def ack(self, have_ref): self.proto.write_pkt_line("ACK %s continue\n" % have_ref) def next(self): have = self.proto.read_pkt_line() if have[:4] == 'have': return have[5:45] #if have[:4] == 'done': # return None if self._last_sha: # Oddness: Git seems to resend the last ACK, without the "continue" statement self.proto.write_pkt_line("ACK %s\n" % self._last_sha) # The exchange finishes with a NAK self.proto.write_pkt_line("NAK\n") graph_walker = ProtocolGraphWalker(self.proto) num_objects, objects_iter = self.backend.fetch_objects(determine_wants, graph_walker, progress) # Do they want any objects? if num_objects == 0: return progress("dul-daemon says what\n") progress("counting objects: %d, done.\n" % num_objects) write_pack_data(ProtocolFile(None, write), objects_iter, num_objects) progress("how was that, then?\n") # we are done self.proto.write("0000")