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
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
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)
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
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)
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
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
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)
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")
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)
def __init__(self, backend, read, write): self.backend = backend self.proto = Protocol(read, write)
def __init__(self, fileno, read, write): self.proto = Protocol(read, write) self.fileno = fileno
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)
def _connect(self, service, path): return Protocol(self.read, self.write), self.can_read
def setUp(self): TestCase.setUp(self) self.rout = StringIO() self.rin = StringIO() self.proto = Protocol(self.rin.read, self.rout.write)
def __init__(self, backend, read, write, args): self.backend = backend self.proto = Protocol(read, write) self.backend.set_args(args)