Beispiel #1
0
    def fetch_pack(self,
                   path,
                   determine_wants,
                   graph_walker,
                   pack_data,
                   progress=None):
        """Retrieve a pack from a git smart server.

        :param determine_wants: Callback that returns list of commits to fetch
        :param graph_walker: Object with next() and ack().
        :param pack_data: Callback called for each bit of data in the pack
        :param progress: Callback for progress reports (strings)
        :return: Dictionary with the refs of the remote repository
        """
        url = self._get_url(path)
        refs, server_capabilities = self._discover_references(
            "git-upload-pack", url)
        negotiated_capabilities = server_capabilities
        wants = determine_wants(refs)
        if wants is not None:
            wants = [cid for cid in wants if cid != ZERO_SHA]
        if not wants:
            return refs
        if self.dumb:
            raise NotImplementedError(self.send_pack)
        req_data = StringIO()
        req_proto = Protocol(None, req_data.write)
        self._handle_upload_pack_head(req_proto, negotiated_capabilities,
                                      graph_walker, wants, lambda: False)
        resp = self._smart_request("git-upload-pack",
                                   url,
                                   data=req_data.getvalue())
        resp_proto = Protocol(resp.read, None)
        self._handle_upload_pack_tail(resp_proto, negotiated_capabilities,
                                      graph_walker, pack_data, progress)
        return refs
Beispiel #2
0
 def _connect(self, service, path):
     import subprocess
     if self.git_command is None:
         git_command = find_git_command()
     argv = git_command + [service, path]
     argv = ['git', service.decode('ascii'), path]
     p = SubprocessWrapper(
         subprocess.Popen(argv,
                          bufsize=0,
                          stdin=subprocess.PIPE,
                          stdout=subprocess.PIPE,
                          stderr=self._stderr))
     return Protocol(p.read,
                     p.write,
                     p.close,
                     report_activity=self._report_activity), p.can_read
Beispiel #3
0
 def _connect(self, cmd, path):
     if type(cmd) is not bytes:
         raise TypeError(path)
     if type(path) is not bytes:
         raise TypeError(path)
     if path.startswith(b"/~"):
         path = path[1:]
     argv = self._get_cmd_path(cmd) + b" '" + path + b"'"
     con = self.ssh_vendor.run_command(self.host,
                                       argv,
                                       port=self.port,
                                       username=self.username)
     return (Protocol(con.read,
                      con.write,
                      con.close,
                      report_activity=self._report_activity), con.can_read)
Beispiel #4
0
def receive_pack(path=".", inf=sys.stdin, outf=sys.stdout):
    """Receive a pack file after negotiating its contents using smart protocol.

    :param path: Path to the repository
    :param inf: Input stream to communicate with client
    :param outf: Output stream to communicate with client
    """
    backend = FileSystemBackend()
    def send_fn(data):
        outf.write(data)
        outf.flush()
    proto = Protocol(inf.read, send_fn)
    handler = ReceivePackHandler(backend, [path], proto)
    # FIXME: Catch exceptions and write a single-line summary to outf.
    handler.handle()
    return 0
Beispiel #5
0
 def _discover_references(self, service, url):
     assert url[-1] == "/"
     url = urlparse.urljoin(url, "info/refs")
     headers = {}
     if self.dumb != False:
         url += "?service=%s" % service
         headers["Content-Type"] = "application/x-%s-request" % service
     resp = self._http_request(url, headers)
     self.dumb = (not resp.info().gettype().startswith("application/x-git-"))
     proto = Protocol(resp.read, None)
     if not self.dumb:
         # The first line should mention the service
         pkts = list(proto.read_pkt_seq())
         if pkts != [('# service=%s\n' % service)]:
             raise GitProtocolError(
                 "unexpected first line %r from smart server" % pkts)
     return self._read_refs(proto)
Beispiel #6
0
    def handle(self):
        try:
            proto = Protocol(self.rfile.read, self.wfile.write)
            command, args = proto.read_cmd()

            # switch case to handle the specific git command
            if command == 'git-upload-pack':
                cls = UploadPackHandler
            elif command == 'git-receive-pack':
                cls = ReceivePackHandler
            else:
                return

            h = cls(self.server.backend, self.rfile.read, self.wfile.write,
                    args)
            h.handle()
        except:
            pass
Beispiel #7
0
def upload_pack(path=".", inf=None, outf=None):
    """Upload a pack file after negotiating its contents using smart protocol.

    :param path: Path to the repository
    :param inf: Input stream to communicate with client
    :param outf: Output stream to communicate with client
    """
    if outf is None:
        outf = getattr(sys.stdout, 'buffer', sys.stdout)
    if inf is None:
        inf = getattr(sys.stdin, 'buffer', sys.stdin)
    backend = FileSystemBackend()
    def send_fn(data):
        outf.write(data)
        outf.flush()
    proto = Protocol(inf.read, send_fn)
    handler = UploadPackHandler(backend, [path], proto)
    # FIXME: Catch exceptions and write a single-line summary to outf.
    handler.handle()
    return 0
Beispiel #8
0
    def _connect(self, cmd, path):
        if type(cmd) is not bytes:
            raise TypeError(path)
        if type(path) is not bytes:
            raise TypeError(path)
        sockaddrs = socket.getaddrinfo(self._host, self._port,
                                       socket.AF_UNSPEC, socket.SOCK_STREAM)
        s = None
        err = socket.error("no address found for %s" % self._host)
        for (family, socktype, proto, canonname, sockaddr) in sockaddrs:
            s = socket.socket(family, socktype, proto)
            s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
            try:
                s.connect(sockaddr)
                break
            except socket.error as err:
                if s is not None:
                    s.close()
                s = None
        if s is None:
            raise err
        # -1 means system default buffering
        rfile = s.makefile('rb', -1)
        # 0 means unbuffered
        wfile = s.makefile('wb', 0)

        def close():
            rfile.close()
            wfile.close()
            s.close()

        proto = Protocol(rfile.read,
                         wfile.write,
                         close,
                         report_activity=self._report_activity)
        if path.startswith(b"/~"):
            path = path[1:]
        # TODO(jelmer): Alternative to ascii?
        proto.send_cmd(b'git-' + cmd, path,
                       b'host=' + self._host.encode('ascii'))
        return proto, lambda: _fileno_can_read(s)
Beispiel #9
0
def serve_command(handler_cls, backend, inf=sys.stdin, outf=sys.stdout):
    """Serve a single command.

    This is mostly useful for the implementation of commands used by e.g. git+ssh.

    :param handler_cls: `Handler` class to use for the request
    :param argv: execv-style command-line arguments. Defaults to sys.argv.
    :param backend: `Backend` to use
    :param inf: File-like object to read from, defaults to standard input.
    :param outf: File-like object to write to, defaults to standard output.
    :return: Exit code for use with sys.exit. 0 on success, 1 on failure.
    """
    def send_fn(data):
        outf.write(data)
        outf.flush()

    proto = Protocol(inf.read, send_fn)
    handler = handler_cls(backend, ["/"], proto)
    # FIXME: Catch exceptions and write a single-line summary to outf.
    handler.handle()
    return 0
    def __init__(self,
                 can_read,
                 read,
                 write,
                 thin_packs=True,
                 report_activity=None):
        """Create a new GitClient instance.

        :param can_read: Function that returns True if there is data available
            to be read.
        :param read: Callback for reading data, takes number of bytes to read
        :param write: Callback for writing data
        :param thin_packs: Whether or not thin packs should be retrieved
        :param report_activity: Optional callback for reporting transport
            activity.
        """
        self.proto = Protocol(read, write, report_activity)
        self._can_read = can_read
        self._capabilities = list(CAPABILITIES)
        if thin_packs:
            self._capabilities.append("thin-pack")
Beispiel #11
0
class TCPGitClient(TraditionalGitClient):
    """A Git Client that works over TCP directly (i.e. git://)."""
    def __init__(self, host, port=None, *args, **kwargs):
        if port is None:
            port = TCP_GIT_PORT
        self._host = host
        self._port = port
        TraditionalGitClient.__init__(self, *args, **kwargs)

    def _connect(self, cmd, path):
        sockaddrs = socket.getaddrinfo(self._host, self._port,
                                       socket.AF_UNSPEC, socket.SOCK_STREAM)
        s = None
        err = socket.error("no address found for %s" % self._host)
        for (family, socktype, proto, canonname, sockaddr) in sockaddrs:
            s = socket.socket(family, socktype, proto)
            s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
            try:
                s.connect(sockaddr)
                break
            except socket.error, err:
                if s is not None:
                    s.close()
                s = None
        if s is None:
            raise err
        # -1 means system default buffering
        rfile = s.makefile('rb', -1)
        # 0 means unbuffered
        wfile = s.makefile('wb', 0)
        proto = Protocol(rfile.read,
                         wfile.write,
                         report_activity=self._report_activity)
        if path.startswith("/~"):
            path = path[1:]
        proto.send_cmd('git-%s' % cmd, path, 'host=%s' % self._host)
        return proto, lambda: _fileno_can_read(s)
Beispiel #12
0
 def __init__(self, backend, read, write):
     self.backend = backend
     self.proto = Protocol(read, write)
Beispiel #13
0
 def __init__(self, fileno, read, write):
     self.proto = Protocol(read, write)
     self.fileno = fileno
Beispiel #14
0
 def _connect(self, cmd, path):
     con = get_ssh_vendor().connect_ssh(
         self.host, ["%s '%s'" % (self._get_cmd_path(cmd), path)],
         port=self.port, username=self.username)
     return (Protocol(con.read, con.write, report_activity=self._report_activity),
             con.can_read)
Beispiel #15
0
 def _connect(self, service, path):
     return Protocol(self.read, self.write), self.can_read
Beispiel #16
0
 def setUp(self):
     TestCase.setUp(self)
     self.rout = StringIO()
     self.rin = StringIO()
     self.proto = Protocol(self.rin.read, self.rout.write)
Beispiel #17
0
 def __init__(self, backend, read, write, args):
     self.backend = backend
     self.proto = Protocol(read, write)
     self.backend.set_args(args)