'Upload a pack to a remote repository.
:param path: Repository path (as bytestring)
:param update_refs: Function to determine changes to remote refs.
Receive dict with existing remote refs, returns dict with
changed refs (name -> sha, where sha=ZERO_SHA for deletions)
:param generate_pack_contents: Function that can return a sequence of
the shas of the objects to upload.
:param progress: Optional callback called with progress updates
:param write_pack: Function called with (file, iterable of objects) to
write the objects returned by generate_pack_contents to the server.
:raises SendPackError: if server rejects the pack data
:raises UpdateRefsError: if the server supports report-status
and rejects ref updates
:return: new_refs dictionary containing the changes that were made
{refname: new_ref}, including deleted refs.'

def send_pack(self, path, update_refs, generate_pack_contents, progress=None, write_pack=write_pack_objects):

    (proto, unused_can_read) = self._connect('receive-pack', path)
    with proto:
        (old_refs, server_capabilities) = read_pkt_refs(proto)
        negotiated_capabilities = self._negotiate_receive_pack_capabilities(server_capabilities)
        if (CAPABILITY_REPORT_STATUS in negotiated_capabilities):
            self._report_status_parser = ReportStatusParser()
        report_status_parser = self._report_status_parser
        try:
            new_refs = orig_new_refs = update_refs(dict(old_refs))
        except:
            proto.write_pkt_line(None)
            raise
        if (CAPABILITY_DELETE_REFS not in server_capabilities):
            new_refs = dict(orig_new_refs)
            for (ref, sha) in orig_new_refs.items():
                if (sha == ZERO_SHA):
                    if (CAPABILITY_REPORT_STATUS in negotiated_capabilities):
                        report_status_parser._ref_statuses.append((('ng    ' + sha) + '    remote    does    not    support    deleting    refs'))
                        report_status_parser._ref_status_ok = False
                    del new_refs[ref]
        if (new_refs is None):
            proto.write_pkt_line(None)
            return old_refs
        if ((len(new_refs) == 0) and len(orig_new_refs)):
            proto.write_pkt_line(None)
            if (report_status_parser is not None):
                report_status_parser.check()
            return old_refs
        (have, want) = self._handle_receive_pack_head(proto, negotiated_capabilities, old_refs, new_refs)
        if ((not want) and set(new_refs.items()).issubset(set(old_refs.items()))):
            return new_refs
        objects = generate_pack_contents(have, want)
        dowrite = (len(objects) > 0)
        dowrite = (dowrite or any(((old_refs.get(ref) != sha) for (ref, sha) in new_refs.items() if (sha != ZERO_SHA))))
        if dowrite:
            write_pack(proto.write_file(), objects)
        self._handle_receive_pack_tail(proto, negotiated_capabilities, progress)
        return new_refs
