
    >G                        d Z ddlmZ ddlmZ ddlZddlZddlmZm	Z	 dZ
dZdZdZd	ZdZd	Zd
ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!dZ"dZ#dZ$dZ%dZ&d Z'ee e!e#egZ( e)e(e"eeeee$eeee%e&gz         Z* e)e(eeeegz         Z+d! Z,d" Z-d# Z.d$ Z/d% Z0d& Z1d'Z2dZ3d(Z4d)Z5d*Z6d+Z7 G d, d-e8      Z9d. Z:d/ Z;d0 Z< G d1 d2e8      Z=d3Z> G d4 d5e=      Z?d6 Z@d7 ZAd8 ZB G d9 d:e8      ZC G d; d<e8      ZDy)=z<Generic functions for talking the git smart server protocol.    )BytesIO)SEEK_ENDN)HangupExceptionGitProtocolErrori$  s(   0000000000000000000000000000000000000000         s   atomics   deepen-sinces
   deepen-nots   deepen-relatives   delete-refss   include-tag	   multi_ack   multi_ack_detaileds   no-dones   no-progresss	   ofs-deltas   quiets   report-statuss   shallows	   side-bands   side-band-64ks	   thin-packs   agents   symrefs   allow-tip-sha1-in-wants   allow-reachable-sha1-in-wants   capabilities^{}c                  F    dt         j                  z  j                  d      S )Nzdulwich/%d.%d.%dascii)dulwich__version__encode     #lib/third_party/dulwich/protocol.pyagent_stringr   o   s    !4!44<<WEEr   c                  *    t         dz   t               z   S )N   =)CAPABILITY_AGENTr   r   r   r   capability_agentr   s   s    d"\^33r   c                 &    t         dz   | z   dz   |z   S )Nr      :)CAPABILITY_SYMREF)from_refto_refs     r   capability_symrefr   w   s    t#h.5>>r   c                 &    t        d | D              S )Nc              3   8   K   | ]  }t        |      d      yw)r   N)parse_capability).0cs     r   	<genexpr>z+extract_capability_names.<locals>.<genexpr>|   s     <|!"1%|s   )setcapabilitiess    r   extract_capability_namesr(   {   s    <|<<<r   c                 f    | j                  dd      }t        |      dk(  r|d   d fS t        |      S )Nr   r   r   )splitlentuple)
capabilitypartss     r   r!   r!      s8    T1%E
5zQa$<r   c                 8    | D cg c]
  }t        |  c}S c c}w N)r   )symrefsks     r   symref_capabilitiesr3      s     +237aq!7333s   s   deepens	   unshallows   dones   wants   havec                   "    e Zd ZdZd Zd Zd Zy)ProtocolFilez;A dummy file for network ops that expect file-like objects.c                      || _         || _        y r0   )readwrite)selfr7   r8   s      r   __init__zProtocolFile.__init__   s    	
r   c                      y r0   r   r9   s    r   tellzProtocolFile.tell       r   c                      y r0   r   r<   s    r   closezProtocolFile.close   r>   r   N)__name__
__module____qualname____doc__r:   r=   r@   r   r   r   r5   r5      s    Er   r5   c                 \    | dz   dj                  |D cg c]  }|dz   	 c}      z   S c c}w )N    r       )join)cmdargsas      r   format_cmd_pktrL      s0    :t!<t!1u9t!<===!<s   )
c                 ~    | j                  d      }| d | | |dz   d  }}|dd  dk(  sJ ||d d j                  d      fS )NrF   r   rG   )findr*   )line	splice_atrI   rJ   s       r   parse_cmd_pktrR      sX    		$IZi $y1}"7C9Sb	&&&r   c                 N    | ydt        |       dz   z  j                  d      | z   S )zWrap data in a pkt-line.

    Args:
      data: The data to wrap, as a str or None.
    Returns: The data prefixed with its length in pkt-line format; if data was
        None, returns the flush-pkt ('0000').
    s   0000z%04x   r   )r+   r   )datas    r   pkt_linerV      s/     |c$i!m$,,W5<<r   c                   `    e Zd ZdZddZd Zd Zd Zd Zd Z	d	 Z
d
 Zd Zd Zd Zd Zd Zy)Protocola  Class for interacting with a remote git process over the wire.

    Parts of the git wire protocol use 'pkt-lines' to communicate. A pkt-line
    consists of the length of the line as a 4-byte hex string, followed by the
    payload data. The length includes the 4-byte header. The special line
    '0000' indicates the end of a section of input and is called a 'flush-pkt'.

    For details on the pkt-line format, see the cgit distribution:
        Documentation/technical/protocol-common.txt
    Nc                 J    || _         || _        || _        || _        d | _        y r0   )r7   r8   _closereport_activity
_readahead)r9   r7   r8   r@   r[   s        r   r:   zProtocol.__init__   s&    	
.r   c                 >    | j                   r| j                          y y r0   )rZ   r<   s    r   r@   zProtocol.close   s    ;;KKM r   c                     | S r0   r   r<   s    r   	__enter__zProtocol.__enter__   s    r   c                 $    | j                          y r0   )r@   )r9   exc_typeexc_valexc_tbs       r   __exit__zProtocol.__exit__   s    

r   c                    | j                   | j                  }n| j                   j                  }d| _         	  |d      }|s
t               t        |d      }|dk(  r| j                  r| j	                  dd       y| j                  r| j	                  |d        ||dz
        }t        |      dz   |k7  rt        dt        |      dz   |fz        |S # t        j                  $ r}t        |      d}~ww xY w)a   Reads a pkt-line from the remote git process.

        This method may read from the readahead buffer; see unread_pkt_line.

        Returns: The next string from the stream, without the length prefix, or
            None for a flush-pkt ('0000').
        NrT      r   r7   z9Length of pkt read %04x does not match length prefix %04x)	r\   r7   r   intr[   r+   r   socketerror)r9   r7   sizestrsizepkt_contentses         r   read_pkt_linezProtocol.read_pkt_line   s     ??"99D??''D"DO	 1gG%''w#Dqy''((F3##$$T62q>L < 1$,&O<(1,d34    || 	&"1%%	&s   AC <)C C7'C22C7c                 f    	 | j                         }| j                  |       y# t        $ r Y yw xY w)zTest whether the protocol stream has reached EOF.

        Note that this refers to the actual stream EOF and not just a
        flush-pkt.

        Returns: True if the stream is at EOF, False otherwise.
        TF)rn   r   unread_pkt_line)r9   	next_lines     r   eofzProtocol.eof   s<    	**,I 	Y'  		s   $ 	00c                 d    | j                   t        d      t        t        |            | _         y)a=  Unread a single line of data into the readahead buffer.

        This method can be used to unread a single pkt-line into a fixed
        readahead buffer.

        Args:
          data: The data to unread, without the length prefix.
        Raises:
          ValueError: If more than one pkt-line is unread.
        Nz'Attempted to unread multiple pkt-lines.)r\   
ValueErrorr   rV   r9   rU   s     r   rp   zProtocol.unread_pkt_line  s*     ??&FGG!(4.1r   c              #   `   K   | j                         }|r| | j                         }|ryyw)zRead a sequence of pkt-lines from the remote git process.

        Returns: Yields each line of data up to but not including the next
            flush-pkt.
        N)rn   )r9   pkts     r   read_pkt_seqzProtocol.read_pkt_seq  s1        "I$$&C s   )..c                     	 t        |      }| j                  |       | j                  r| j                  t        |      d       yy# t        j
                  $ r}t        |      d}~ww xY w)zSends a pkt-line to the remote git process.

        Args:
          line: A string containing the data to send, without the length
            prefix.
        r8   N)rV   r8   r[   r+   rh   ri   r   )r9   rP   rm   s      r   write_pkt_linezProtocol.write_pkt_line"  s]    	&D>DJJt##$$SY8 $|| 	&"1%%	&s   AA A*A%%A*c                 0     G d dt               } ||       S )z5Return a writable file-like object for this protocol.c                   $    e Zd Zd Zd Zd Zd Zy))Protocol.write_file.<locals>.ProtocolFilec                      || _         d| _        y Nr   )_proto_offset)r9   protos     r   r:   z2Protocol.write_file.<locals>.ProtocolFile.__init__5  s    # r   c                 v    | j                   j                  |       | xj                  t        |      z  c_        y r0   )r   r8   r   r+   ru   s     r   r8   z/Protocol.write_file.<locals>.ProtocolFile.write9  s&    !!$'D	)r   c                     | j                   S r0   )r   r<   s    r   r=   z.Protocol.write_file.<locals>.ProtocolFile.tell=  s    ||#r   c                      y r0   r   r<   s    r   r@   z/Protocol.write_file.<locals>.ProtocolFile.close@  s    r   N)rA   rB   rC   r:   r8   r=   r@   r   r   r   r5   r}   4  s    !*$r   r5   )object)r9   r5   s     r   
write_filezProtocol.write_file1  s    	6 	 D!!r   c                 n    |r3| j                  t        t        |g            |dd z          |dd }|r2yy)zWrite multiplexed data to the sideband.

        Args:
          channel: An int specifying the channel to write to.
          blob: A blob of data (as a string) to send on this channel.
        N  )rz   bytes	bytearray)r9   channelblobs      r   write_sidebandzProtocol.write_sidebandE  s<     i	&: ;d6El JK<D r   c                 :    | j                  t        |g|        y)zSend a command and some arguments to a git server.

        Only used for the TCP git protocol (git://).

        Args:
          cmd: The remote service to access.
          args: List of arguments to send to remove service.
        N)rz   rL   )r9   rI   rJ   s      r   send_cmdzProtocol.send_cmdS  s     	N3667r   c                 8    | j                         }t        |      S )zRead a command and some arguments from the git client

        Only used for the TCP git protocol (git://).

        Returns: A tuple of (command, [list of arguments]).
        )rn   rR   )r9   rP   s     r   read_cmdzProtocol.read_cmd^  s     !!#T""r   )NN)rA   rB   rC   rD   r:   r@   r_   rd   rn   rr   rp   rx   rz   r   r   r   r   r   r   r   rX   rX      sI    	" H2	'&"( 	8#r   rX   i    c                   6     e Zd ZdZddef fd	Zd Zd Z xZS )ReceivableProtocola  Variant of Protocol that allows reading up to a size without blocking.

    This class has a recv() method that behaves like socket.recv() in addition
    to a read() method.

    If you want to read n bytes from the wire and block until exactly n bytes
    (or EOF) are read, use read(n). If you want to read at most n bytes from
    the wire but don't care if you get less, use recv(n). Note that recv(n)
    will still block until at least one byte is read.
    Nc                     t         t        |   | j                  |||       || _        t               | _        || _        y )N)r@   r[   )superr   r:   r7   _recvr   _rbuf	_rbufsize)r9   recvr8   r@   r[   rbufsize	__class__s         r   r:   zReceivableProtocol.__init__x  s@     	 $0IIuE? 	1 	
 
Y
!r   c                    |dkD  sJ | j                   }|j                         }|j                  dt               |j                         |z
  }||k\  rw|j                  |       |j	                  |      }t               | _         | j                   j                  |j	                                | j                   j                  d       |S t               | _         	 ||z
  }| j                  |      }|snUt        |      }||k(  r|s|S ||k(  r|j                  |       ~n)||k  sJ d||fz         |j                  |       ||z  }~n|j                  |       |j	                         S )Nr   z_recv(%d) returned %d bytes)	r   r=   seekr   r7   r   r8   r   r+   )	r9   rk   bufstartbuf_lenrvleftrU   ns	            r   r7   zReceivableProtocol.read  sD    axx
 jj
H((*u$d?HHUO$B DJJJSXXZ(JJOOAIY
'>D ::d#DD	ADy Dy		$9G;tQiGG9IIdOqLG3 6 	xxzr   c                    |dkD  sJ | j                   }|j                         }|j                  dt               |j                         }|j                  |       ||z
  }|s_| j	                  | j
                        }t        |      |k(  r|S t               }|j                  |       |j                  d       ~|| _         |j                  |      S r   )
r   r=   r   r   r   r   r+   r   r8   r7   )r9   rk   r   r   r   r   rU   s          r   r   zReceivableProtocol.recv  s    axxjj
H((*::dnn-D4yD )CIIdOHHQKDJxx~r   )	rA   rB   rC   rD   	_RBUFSIZEr:   r7   r   __classcell__)r   s   @r   r   r   l  s!    	 "&ti";zr   r   c                     d| vr| g fS | j                         j                  d      \  } }| |j                         j                  d      fS )zExtract a capabilities list from a string, if present.

    Args:
      text: String to extract from
    Returns: Tuple with text with capabilities removed and list of capabilities
    rG   rF   )rstripr*   strip)textr'   s     r   extract_capabilitiesr     sO     DRx,,U3D,,$$&,,T233r   c                     | j                         j                  d      }t        |      dk  r| g fS dj                  |dd       |dd fS )ax  Extract a capabilities list from a want line, if present.

    Note that want lines have capabilities separated from the rest of the line
    by a space instead of a null byte. Thus want lines have the form:

        want obj-id cap1 cap2 ...

    Args:
      text: Want line to extract from
    Returns: Tuple with text with capabilities removed and list of capabilities
    rF   r	   Nr   )r   r*   r+   rH   )r   
split_texts     r   extract_want_line_capabilitiesr     sO     $$T*J
:RxIIj!n%z!"~66r   c                 6    d| v rt         S d| v rt        S t        S )z.Extract the ack type from a capabilities list.r   r
   )MULTI_ACK_DETAILED	MULTI_ACK
SINGLE_ACKr&   s    r   ack_typer     s$    ,!!		%r   c                   $    e Zd ZdZddZd Zd Zy)BufferedPktLineWritera  Writer that wraps its data in pkt-lines and has an independent buffer.

    Consecutive calls to write() wrap the data in a pkt-line and then buffers
    it until enough lines have been written such that their total length
    (including length prefix) reach the buffer size.
    c                 L    || _         || _        t               | _        d| _        y)zInitialize the BufferedPktLineWriter.

        Args:
          write: A write callback for the underlying writer.
          bufsize: The internal buffer size, including length prefixes.
        r   N)_write_bufsizer   _wbuf_buflen)r9   r8   bufsizes      r   r:   zBufferedPktLineWriter.__init__  s"     Y
r   c                 Z   t        |      }t        |      }| j                  |z   | j                  z
  }|dk\  r4||z
  }| j                  j                  |d|        | j                          nd}||d }| j                  j                  |       | xj                  t        |      z  c_        y)z&Write data, wrapping it in a pkt-line.r   N)rV   r+   r   r   r   r8   flush)r9   rU   rP   line_lenoverr   saveds          r   r8   zBufferedPktLineWriter.write  s    ~t9||h&619tOEJJT&5\*JJLEUV

E
"r   c                     | j                   j                         }|r| j                  |       d| _        t	               | _         y)zFlush all data from the buffer.r   N)r   getvaluer   _lenr   ru   s     r   r   zBufferedPktLineWriter.flush"  s3    zz""$KK	Y
r   N)r   )rA   rB   rC   rD   r:   r8   r   r   r   r   r   r     s    
#r   r   c                   "    e Zd ZdZd Zd Zd Zy)PktLineParserzBPacket line parser that hands completed packets off to a callback.c                 0    || _         t               | _        y r0   )
handle_pktr   r\   )r9   r   s     r   r:   zPktLineParser.__init__.  s    $!)r   c                    | j                   j                  |       | j                   j                         }t        |      dk  ryt        |      dk\  rct	        |dd d      }|dk(  r| j                  d       |dd }n)|t        |      k  r| j                  |d|        ||d }nnt        |      dk\  rct               | _         | j                   j                  |       y)zAParse a fragment of data and call back for any completed packets.rT   Nrf   r   )r\   r8   r   r+   rg   r   r   )r9   rU   r   rk   s       r   parsezPktLineParser.parse2  s    d#oo&&(s8a<#h!ms2Aw#Dqy%!"gS!Ad,$%j #h!m ")c"r   c                 6    | j                   j                         S )zRead back any unused data.)r\   r   r<   s    r   get_tailzPktLineParser.get_tailE  s    ''))r   N)rA   rB   rC   rD   r:   r   r   r   r   r   r   r   +  s    L$#&*r   r   )ErD   ior   osr   rh   r   dulwich.errorsr   r   TCP_GIT_PORTZERO_SHAr   r   r   SIDE_BAND_CHANNEL_DATASIDE_BAND_CHANNEL_PROGRESSSIDE_BAND_CHANNEL_FATALCAPABILITY_ATOMICCAPABILITY_DEEPEN_SINCECAPABILITY_DEEPEN_NOTCAPABILITY_DEEPEN_RELATIVECAPABILITY_DELETE_REFSCAPABILITY_INCLUDE_TAGCAPABILITY_MULTI_ACKCAPABILITY_MULTI_ACK_DETAILEDCAPABILITY_NO_DONECAPABILITY_NO_PROGRESSCAPABILITY_OFS_DELTACAPABILITY_QUIETCAPABILITY_REPORT_STATUSCAPABILITY_SHALLOWCAPABILITY_SIDE_BANDCAPABILITY_SIDE_BAND_64KCAPABILITY_THIN_PACKr   r   !CAPABILITY_ALLOW_TIP_SHA1_IN_WANT'CAPABILITY_ALLOW_REACHABLE_SHA1_IN_WANTCAPABILITIES_REFCOMMON_CAPABILITIESr%   KNOWN_UPLOAD_CAPABILITIESKNOWN_RECEIVE_CAPABILITIESr   r   r   r(   r!   r3   COMMAND_DEEPENCOMMAND_SHALLOWCOMMAND_UNSHALLOWCOMMAND_DONECOMMAND_WANTCOMMAND_HAVEr   r5   rL   rR   rV   rX   r   r   r   r   r   r   r   r   r   r   <module>r      s  , C   
 
	      ) % / ' ' #  5  ' #  +  # + #   $= !*I ' &     %")/   ! 	 F4?=4   6 >'
=n#v n#b 	h hV
47$)F )X*F *r   