a  _@sdZddlZddlZddlZddlZddlZddlmZmZm Z m Z m Z ddl Z ddl Z ddlmZddlmZmZmZmZmZmZmZddlmZddlmZmZddlmZdd lm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;mZ>m?Z?m@Z@mAZAmBZBmCZCmDZDdd lEmFZFmGZGdd lHmIZImJZJeKeLZMGd d d eNZOGdddeNZPGdddeOZQGdddeOZRGdddeNZSGdddeSZTGdddeTZUddZVddZWddZXd d!ZYGd"d#d#eNZZe2e1dfZ[Gd$d%d%eNZ\Gd&d'd'eNZ]Gd(d)d)eNZ^Gd*d+d+eTZ_Gd,d-d-eSZ`eUe_e`d.ZaGd/d0d0e jbZcGd1d2d2e jdZeejffd3d4Zgejfdejhejifd5d6Zjd7d8Zkd9d:Zld;d<ZmeLd=kregdS)>aGit smart network protocol server implementation. For more detailed implementation on the network protocol, see the Documentation/technical directory in the cgit distribution, and in particular: * Documentation/technical/protocol-capabilities.txt * Documentation/technical/pack-protocol.txt Currently supported capabilities: * include-tag * thin-pack * multi_ack_detailed * multi_ack * side-band-64k * ofs-delta * no-progress * report-status * delete-refs * shallow * symref N)ListTupleDictOptionalIterable) tar_stream)ApplyDeltaErrorChecksumMismatchGitProtocolError HookErrorNotGitRepositoryUnexpectedCommandErrorObjectFormatException) log_utils)Commit valid_hexsha)write_pack_objects)%BufferedPktLineWritercapability_agentCAPABILITIES_REFCAPABILITY_AGENTCAPABILITY_DELETE_REFSCAPABILITY_INCLUDE_TAGCAPABILITY_MULTI_ACK_DETAILEDCAPABILITY_MULTI_ACKCAPABILITY_NO_DONECAPABILITY_NO_PROGRESSCAPABILITY_OFS_DELTACAPABILITY_QUIETCAPABILITY_REPORT_STATUSCAPABILITY_SHALLOWCAPABILITY_SIDE_BAND_64KCAPABILITY_THIN_PACKCOMMAND_DEEPEN COMMAND_DONE COMMAND_HAVECOMMAND_SHALLOWCOMMAND_UNSHALLOW COMMAND_WANT MULTI_ACKMULTI_ACK_DETAILEDProtocol ProtocolFileReceivableProtocolSIDE_BAND_CHANNEL_DATASIDE_BAND_CHANNEL_PROGRESSSIDE_BAND_CHANNEL_FATAL SINGLE_ACK TCP_GIT_PORTZERO_SHAack_typeextract_capabilitiesextract_want_line_capabilitiessymref_capabilities)ANNOTATED_TAG_SUFFIXwrite_info_refs)BaseRepoRepoc@seZdZdZddZdS)Backendz2A backend for the Git smart server implementation.cCst|jdS)zOpen the repository at a path. Args: path: Path to the repository Raises: NotGitRepository: no git repository was found at path Returns: Instance of BackendRepo N)NotImplementedErroropen_repositoryselfpathrB0/usr/lib/python3/dist-packages/dulwich/server.pyr>s zBackend.open_repositoryN)__name__ __module__ __qualname____doc__r>rBrBrBrCr<}sr<c@sLeZdZdZdZdZeeefdddZee edddZ d d d Z dS) BackendRepozRepository abstraction used by the Git server. The methods required here are a subset of those provided by dulwich.repo.Repo. NreturncCstdS)zZ Get all the refs in the repository Returns: dict of name -> sha Nr=r@rBrBrCget_refsszBackendRepo.get_refs)namerJcCsdS)aReturn the cached peeled value of a ref, if available. Args: name: Name of the ref to peel Returns: The peeled value of the ref. If the ref is known not point to a tag, this will be the SHA the ref refers to. If no cached information about a tag is available, this method may return None, but it should attempt to peel the tag if possible. NrB)r@rNrBrBrC get_peeleds zBackendRepo.get_peeledcCstdS)a  Yield the objects required for a list of commits. Args: progress: is a callback to send progress messages to the client get_tagged: Function that returns a dict of pointed-to sha -> tag sha for including tags. NrK)r@determine_wants graph_walkerprogress get_taggedrBrBrC fetch_objectss zBackendRepo.fetch_objects)N) rDrErFrG object_storerefsrbytesrMrrOrTrBrBrBrCrHs rHc@s(eZdZdZddZeedddZdS) DictBackendz?Trivial backend that looks up Git repositories in a dictionary.cCs ||_dSN)repos)r@rZrBrBrC__init__szDictBackend.__init__)rArJcCsBtd|z |j|WSty<tdt|dYn0dS)NzOpening repository at %sz'No git repository was found at %(path)s)rA)loggerdebugrZKeyErrorr dictr?rBrBrCr>s    zDictBackend.open_repositoryN)rDrErFrGr[strr:r>rBrBrBrCrXsrXcs.eZdZdZejffdd ZddZZS)FileSystemBackendzDSimple backend looking up Git repositories in the local file system.cs6tt|tj|tjtjdtj|_dS)N) superrar[osrAabspathsepreplaceroot)r@rh __class__rBrCr[s zFileSystemBackend.__init__cCshtd|tjtj|j|tj}tj|}tj|j}| |s`t d||jft |S)Nzopening repository at %szPath %r not inside root %r) r\r]rdrArejoinrhrfnormcase startswithr r;)r@rAreZnormcase_abspathZ normcase_rootrBrBrCr>s   z!FileSystemBackend.open_repository) rDrErFrGrdrfr[r> __classcell__rBrBrirCrasrac@s"eZdZdZdddZddZdS)Handlerz*Smart protocol command handler base class.NcCs||_||_||_dSrY)backendproto stateless_rpcr@rprqrrrBrBrCr[szHandler.__init__cCst|jdSrY)r=handlerLrBrBrCrtszHandler.handle)N)rDrErFrGr[rtrBrBrBrCros rocseZdZdZdfdd ZeddZeeeddd Z eeedd d Z eeedd d Z eeddddZ ee dddZddddZZS) PackHandlerzProtocol handler for packs.Ncs$tt||||d|_d|_dSNF)rcrur[_client_capabilities_done_receivedrsrirBrCr[szPackHandler.__init__cCs td|ddd|DS)NzSending capabilities: %scSsg|] }d|qS) rB).0crBrBrC ryz/PackHandler.capability_line..)r\infork)cls capabilitiesrBrBrCcapability_lines zPackHandler.capability_linerIcCst|jdSrY)r=rrrBrBrCrszPackHandler.capabilitiescCstttttgSrY)rr"rrrrrBrBrCinnocuous_capabilitiessz"PackHandler.innocuous_capabilitiescCsgS)zAReturn a list of capabilities that we require the client to have.rBrrBrBrCrequired_capabilitiessz!PackHandler.required_capabilities)capsrJcCst|}|||D](}|tdr2q||vrtd|q|D]}||vrPtd|qPt||_t d|dS)N=z7Client asked for capability %r that was not advertised.z/Client does not support required capability %r.zClient capabilities: %s) setrupdaterrmrr rrwr\r~)r@rZallowable_capscaprBrBrCset_client_capabilitiess    z#PackHandler.set_client_capabilities)rrJcCs |jdurtd|||jvS)Nz=Server attempted to access capability %r before asking client)rwr )r@rrBrBrChas_capabilitys  zPackHandler.has_capabilitycCs d|_dS)NT)rxrLrBrBrC notify_doneszPackHandler.notify_done)N)rDrErFrGr[ classmethodrrrWrrrrboolrrrnrBrBrirCrus rucsTeZdZdZdfdd ZeddZedd Zd d Zdd d Z ddZ Z S)UploadPackHandlerz4Protocol handler for uploading a pack to the client.NFcs<tt|j|||d||d|_d|_||_d|_dS)NrrrF)rcrr[r>repoZ _graph_walkeradvertise_refs_processing_have_linesr@rpargsrqrrrrirBrCr[!s zUploadPackHandler.__init__c Cstttttttttg SrY) rrr!r"rrrr rrrBrBrCr-s zUploadPackHandler.capabilitiescCs tttfSrY)r!r"rrrBrBrCr4sz'UploadPackHandler.required_capabilitiescCs&|ts|jrdS|jt|dSrY)rrrrqwrite_sidebandr/)r@messagerBrBrCrR9s  zUploadPackHandler.progresscCsv|tsiS|dur |j}|durBt|jdd}|durBiSi}|D]"\}}||}||krN|||<qN|S)aGet a dict of peeled values of tags to their original tag shas. Args: refs: dict of refname -> sha of possible tags; defaults to all of the backend's refs. repo: optional Repo instance for getting peeled refs; defaults to the backend's repo, if available Returns: dict of peeled_sha -> tag_sha, where tag_sha is the sha of a tag whose peeled value is peeled_sha. Nr)rrrrMgetattritemsrO)r@rVrZtaggedrNsha peeled_sharBrBrCrS?s    zUploadPackHandler.get_taggedcsfdd}tjjjjjjjgfdd}jj|jjd}d_ t dkrhdSd_  t  jsdSd t |d ttd||jddS) Ncsjt|SrYrqrr.xrLrBrCwrite`sz'UploadPackHandler.handle..writecs|SrY)extendrP)rV)rQwantsrBrC wants_wrapperhsz/UploadPackHandler.handle..wants_wrapper)rSTrFzcounting objects: %d, done. ascii)_ProtocolGraphWalkerrrUrOrV get_symrefsrTrRrSrlen handle_donerrrxencoderr,rqwrite_pkt_line)r@rrZ objects_iterrB)rQr@rrCrt_s6    zUploadPackHandler.handle)NF)NN) rDrErFrGr[rrrrRrSrtrnrBrBrirCrs    rcCs|s dg}n|ddd}|d}|dur>||vr>t|t|dkr^|tdfvr^|dfSt|dkr|ttttfvrt |dst dt |S|t kr|t |dfSt d|dS) acSplit a line read from the wire. Args: line: The line read from the wire. allowed: An iterable of command names that should be allowed. Command names not listed below as possible return values will be ignored. If None, any commands from the possible return values are allowed. Returns: a tuple having one of the following forms: ('want', obj_id) ('have', obj_id) ('done', None) (None, None) (for a flush-pkt) Raises: UnexpectedCommandError: if the line cannot be parsed into one of the allowed return values. N rzrrbz Invalid shaz%Received invalid line from client: %r)rstripsplitr rr$r(r%r&r'rr tupler#int)lineallowedfieldscommandrBrBrC_split_proto_lines$  rc sifdd}g}|D](}|}t|tr||jdfqt}t}|r|\} } | |kr|| | d|fdd|| DqP|| qP||fS)aFind shallow commits according to a given depth. Args: store: An ObjectStore for looking up objects. heads: Iterable of head SHAs to start walking from. depth: The depth of ancestors to include. A depth of one includes only the heads themselves. Returns: A tuple of (shallow, not_shallow), sets of SHAs that should be considered shallow and unshallow according to the arguments. Note that these sets may overlap if a commit is reachable along multiple paths. cs&|d}|s"|j}||<|SrY)getparents)rresult)rstorerBrC get_parentss   z"_find_shallow..get_parentsrc3s|]}|fVqdSrYrB)r{p) new_depthrBrC ryz _find_shallow..) Zpeel_sha isinstancerappendidrpopaddr) rheadsdepthrZtodoZhead_shaobj not_shallowshallowrZ cur_depthrB)rrrrC _find_shallows"      rc Cs||}t|g}t|g}|r|}|j|vr8dS|jdkrDq|jD]4}||vrXqJ||||} | j|krJ| | qJqdS)NTscommitF) collectionsdequerpopleftrZ type_namerr commit_timer) rhaveswantearliestopendingZknownZcommitparentZ parent_objrBrBrC_want_satisfieds"       rcsJt|}|r$tfdd|D}nd}|D]}t|||s,dSq,dS)a~Check whether all the current wants are satisfied by a set of haves. Args: store: Object store to retrieve objects from haves: A set of commits we know the client has. wants: A set of commits the client wants Note: Wants are specified with set_wants rather than passed in since in the current interface they are determined outside this class. csg|]}|jqSrB)r)r{hrrBrCr}ryz(_all_wants_satisfied..rFT)rminr)rrrrrrBrrC_all_wants_satisfieds rc@seZdZdZddZddZddZdd Zd d Zd d Z e Z ddZ ddZ ddZ d"ddZddZddZddZddZdd Zd!S)#ra7A graph walker that knows the git protocol. As a graph walker, this class implements ack(), next(), and reset(). It also contains some base methods for interacting with the wire and walking the commit tree. The work of determining which acks to send is passed on to the implementation instance stored in _impl. The reason for this is that we do not know at object creation time what ack level the protocol requires. A call to set_ack_type() is required to set up the implementation, before any calls to next() or ack() are made. cCsj||_||_||_||_|j|_|j|_|j|_g|_t|_ t|_ t|_ d|_ g|_ d|_d|_dS)NFr)handlerrrOrrqrrr_wantsrrclient_shallow unshallow_cached_cache _cache_index_impl)r@rrUrOrrBrBrCr[sz_ProtocolGraphWalker.__init__c Cs|}t|}|js |jstt|D]\}\}}z||}Wnt y`Yq0Yn0|d|}|s|d|j |j t |7}|j|d||kr0|j|d|tdq0|jd|jrgS|j} | sgSt| \}} |j | |t| tttdf} t|| \} }g} | tkrv||vrZtd|| ||| \} }q:|| | ttfvr|| ||| |jr|j rgS| S)a-Determine the wants for a set of heads. The given heads are advertised to the client, who then specifies which refs they want using 'want' lines. This portion of the protocol is the same regardless of ack type, and in fact is used to set the ack type of the ProtocolGraphWalker. If the client has the 'shallow' capability, this method also reads and responds to the 'shallow' and 'deepen' lines from the client. These are not part of the wants per se, but they set up necessary state for walking the graph. Additionally, later code depends on this method consuming everything up to the first 'have' line. Args: heads: a dict of refname->SHA1 to advertise Returns: a list of SHA1s requested by the client rzrNzClient wants invalid object %s)!rrvaluesrrr enumeratesortedrrOr^rrrr7rqrr8 read_pkt_liner6r set_ack_typer4r(r&r#rr rread_proto_line set_wantsunread_proto_line_handle_shallow_requesteof)r@rsymrefsrirefrrrrrrrZ want_revsrBrBrCrP)s`                 z$_ProtocolGraphWalker.determine_wantscCs0t|trt|d}|j|d|dS)Nrrz)rrr`rrqZunread_pkt_line)r@rvaluerBrBrCrws z&_ProtocolGraphWalker.unread_proto_linecCs$t|dkrtd||j|S)N(zinvalid sha %r)r ValueErrorrackr@Zhave_refrBrBrCr|s  z_ProtocolGraphWalker.ackcCsd|_d|_dS)NTr)rrrLrBrBrCresetsz_ProtocolGraphWalker.resetcCsN|js |js|jrdSt|jS|jd7_|jt|jkrBdS|j|jS)Nr)rrrrnextrrrrLrBrBrCrs  z_ProtocolGraphWalker.nextcCst|j|S)aRead a line from the wire. Args: allowed: An iterable of command names that should be allowed. Returns: A tuple of (command, value); see _split_proto_line. Raises: UnexpectedCommandError: If an error occurred reading the line. )rrqr)r@rrBrBrCrs z$_ProtocolGraphWalker.read_proto_linec Cs|ttf\}}|tkr |}q.|j|q|dt|j||\}}|j|||j|j}||j@}|_ t |D]} |j td| q~t |D]} |j t d| q|j ddS)NrYrz)rr#r&rrrrrrrrrqrr') r@rrvalrrrZ new_shallowrrrBrBrCrs"    z,_ProtocolGraphWalker._handle_shallow_requestcCs|jdSrY)rrrLrBrBrCrsz _ProtocolGraphWalker.notify_donerycCs(|r d|}|jd||ddS)NrzsACK rrqr)r@rr4rBrBrCsend_acksz_ProtocolGraphWalker.send_ackcCs|jddS)NsNAK rrLrBrBrCsend_naksz_ProtocolGraphWalker.send_nakcCs|j||SrY)rrr@Z done_requiredZ done_receivedrBrBrCrsz _ProtocolGraphWalker.handle_donecCs ||_dSrY)r)r@rrBrBrCrsz_ProtocolGraphWalker.set_wantscCst|j||jS)a0Check whether all the current wants are satisfied by a set of haves. Args: haves: A set of commits we know the client has. Note: Wants are specified with set_wants rather than passed in since in the current interface they are determined outside this class. )rrr)r@rrBrBrCall_wants_satisfiedsz(_ProtocolGraphWalker.all_wants_satisfiedcCs"tttttti}||||_dSrY)r)MultiAckGraphWalkerImplr*MultiAckDetailedGraphWalkerImplr1SingleAckGraphWalkerImplr)r@r4Z impl_classesrBrBrCrs z!_ProtocolGraphWalker.set_ack_typeN)ry)rDrErFrGr[rPrrrr__next__rrrrrrrrrrBrBrBrCr s" N    rc@s4eZdZdZddZddZddZeZdd Zd S) rz@Graph walker implementation that speaks the single-ack protocol.cCs||_g|_dSrYwalker_commonr@rrBrBrCr[sz!SingleAckGraphWalkerImpl.__init__cCs"|js|j||j|dSrY)rrrrrrBrBrCrs zSingleAckGraphWalkerImpl.ackcCs:|jt\}}|dtfvr*|jdS|tkr6|SdSrY)rr_GRAPH_WALKER_COMMANDSr$rr%r@rrrBrBrCrs   zSingleAckGraphWalkerImpl.nextcCs.|js|j|r|sdS|s*|js*dSdS)NFT)rrrrrBrBrCrs  z$SingleAckGraphWalkerImpl.handle_doneN rDrErFrGr[rrrrrBrBrBrCrs  rc@s4eZdZdZddZddZddZeZdd Zd S) rz?Graph walker implementation that speaks the multi-ack protocol.cCs||_d|_g|_dSrv)r _found_baserrrBrBrCr[ sz MultiAckGraphWalkerImpl.__init__cCs8|j||js4|j|d|j|jr4d|_dS)NcontinueT)rrrrrrrrBrBrCrs  zMultiAckGraphWalkerImpl.ackcCsb|jt\}}|dur&|jqq|tkr<|jdS|tkr|jrX|j|d|SqdS)Nr) rrrrr$rr%rrrrBrBrCrs  zMultiAckGraphWalkerImpl.nextcCsB|r |s dS|s|jsdS|jr4|j|jdn |jdSNFTrrrrrrBrBrCr-s  z#MultiAckGraphWalkerImpl.handle_doneNrrBrBrBrCr s rc@s4eZdZdZddZddZddZeZdd Zd S) rzEGraph walker implementation speaking the multi-ack-detailed protocol.cCs||_g|_dSrYrrrBrBrCr[Hsz(MultiAckDetailedGraphWalkerImpl.__init__cCs|j||j|ddS)Nscommon)rrrrrrBrBrCrLs z#MultiAckDetailedGraphWalkerImpl.ackcCsz|jt\}}|durR|j|jr:|j|jdd|j|jjrtdSq|tkrh|j qvq|t kr|SqdS)Nrsready) rrrrrrrrrr$rr%rrBrBrCrQs  z$MultiAckDetailedGraphWalkerImpl.nextcCsB|r |s dS|s|jsdS|jr4|j|jdn |jdSrr rrBrBrCrns  z+MultiAckDetailedGraphWalkerImpl.handle_doneNrrBrBrBrCrEs rcseZdZdZdfdd ZeeedddZe e eeefe e eefd d d Z e e eefdd d dZ ddZ ddddZZS)ReceivePackHandlerz8Protocol handler for downloading a pack from the client.NFcs0tt|j|||d||d|_||_dS)Nrr)rcr r[r>rrrrirBrCr[s  zReceivePackHandler.__init__rIcCsttttttgSrY)rrrrr!rrrBrBrCrszReceivePackHandler.capabilities)rVrJc Csttttttjtjtf}g}d}|D]}|dt kr$d}q$|rz0t |j dd}|j j |j j||dWq|y}z,|dt|ddd fWYd}~qd}~00n |d|D]\}} } d } z| t kr"t|vrtd z|j j| |Wn|yd } Yn0n0z|j j| || Wn|yPd } Yn0Wntyld} Yn0|| | fq|S)NFrTrecv)unpackokr  zutf-8r z8Attempted to delete refs without delete-refs capability.sfailed to deletesfailed to writesbad ref)IOErrorOSErrorr rAssertionErrorsocketerrorzlibrr3rrqrrUZ add_thin_packreadrr`rgrrrr rVZremove_if_equalsZ set_if_equalsr^) r@rVZall_exceptionsstatusZwill_send_packrr eZoldsharrZ ref_statusrBrBrC _apply_packsN       zReceivePackHandler._apply_pack)rrJcstr0tfddj}fdd}njj}dd}|D]T\}}|dkrf|d|dqD|d kr|d |dqD|d |d |dqD|d|dS) Ncsjt|SrYr)drLrBrCryz3ReceivePackHandler._report_status..csjddSrY)flushrqrrBr@writerrBrCrsz0ReceivePackHandler._report_status..flushcSsdSrYrBrBrBrBrCrsr sunpack rr sok sng rz)rr!rrrqr)r@rrrrNmsgrBrrC_report_statuss    z!ReceivePackHandler._report_statusc Cst|jjdd}|sdSz ||}|r6|jt|Wn6tyn}z|jtt |WYd}~n d}~00dS)Nz post-receive) rZhooksrZexecuterqrr/r r0repr)r@ client_refshookoutputerrrBrBrC_on_post_receives z#ReceivePackHandler._on_post_receivecCsT|js |jst|j}t|jj}|s@tt fg}|j |ddd|ddd| | t|dtdt|D],}||}|j |dd|ddq|j d|jrdSg}|j }|durdSt|\}}|||r&|||j }q||}|||trP||dS)Nrrrzrr)rrrrrrMrrVrrr3rqrrrr7rangerrr5rrrrr&rrr )r@rVrrrr"rrrBrBrCrtsB  "       zReceivePackHandler.handle)NF)rDrErFrGr[rrrWrrrrr r&rtrnrBrBrirCr s 5 r cs&eZdZdfdd ZddZZS)UploadArchiveHandlerNcs(tt||||||d|_dS)Nr)rcr(r[r>r)r@rprrqrrrirBrCr[s zUploadArchiveHandler.__init__cs(fdd}g}jD]8}|dd\}}|dkrBtd|||dqd}d }d }jj} |t|kr||} | d kr|d7}||}n:| d kr|d7}|| d }njj | } | | | j } |d7}qhj dj dt | | t||dD]} || qj ddS)Ncsjt|SrYrrrLrBrCr$sz*UploadArchiveHandler.handle..writerzrsargumentzunknown command %srryZtarrs--prefixs--formatrsACK)mtimeprefixformat)rqZ read_pkt_seqrr rrrrUrdecoderVtreerrtime)r@rZ argumentsZpktkeyrr*r+rrZargumentZ commit_shar-chunkrBrLrCrt#s:          zUploadArchiveHandler.handle)N)rDrErFr[rtrnrBrBrirCr(sr()sgit-upload-packsgit-receive-packsgit-upload-archivec@seZdZddZddZdS)TCPGitRequestHandlercOs$||_tjj|g|Ri|dSrY)handlers socketserverStreamRequestHandlerr[)r@r2rkwargsrBrBrCr[NszTCPGitRequestHandler.__init__cCsjt|jj|jj}|\}}td|||j |d}t |sNt d|||j j ||}|dS)NzHandling %s request, args=%szInvalid service %s)r-Z connectionr ZwfilerZread_cmdr\r~r2rcallabler serverrprt)r@rqrrrrrBrBrCrtRs  zTCPGitRequestHandler.handleN)rDrErFr[rtrBrBrBrCr1Lsr1c@s>eZdZdZejjZddZe dfddZ ddZ d d Z dS) TCPGitServerTcOst|jg|Ri|SrY)r1r2)r@rr5rBrBrC _make_handlercszTCPGitServer._make_handlerNcCsLtt|_|dur|j|||_td||tj |||f|j dS)Nz&Listening for TCP connections on %s:%d) r_DEFAULT_HANDLERSr2rrpr\r~r3 TCPServerr[r9)r@rpZ listen_addrportr2rBrBrCr[fs  zTCPGitServer.__init__cCstd|dS)NzHandling request from %sT)r\r~r@ZrequestZclient_addressrBrBrCverify_requestps zTCPGitServer.verify_requestcCstd|dS)Nz7Exception happened during processing of request from %s)r\Z exceptionr=rBrBrC handle_errortszTCPGitServer.handle_error) rDrErFZallow_reuse_addressr3r; serve_foreverZserver9r2r[r>r?rBrBrBrCr8^s  r8cCsddl}|}|jdddddd|jd d d ttd d ||\}}tt|dkrf|d}nd}t |}t ||j |j }| dS)z*Entry point for starting a TCP git server.rNz-lz--listen_addresslisten_addressZ localhostzBinding IP address.)destdefaulthelpz-pz--portr<zBinding TCP port.)rBtyperCrDr.)optparseZ OptionParserZ add_optionrr2 parse_argsrZdefault_logging_configrrar8rAr<r@)argvrGparserZoptionsrZgitdirrpr7rBrBrCmainys$    rKcsF|durt}fdd}t|j|}|||dd|}|dS)aServe a single command. This is mostly useful for the implementation of commands used by e.g. git+ssh. Args: handler_cls: `Handler` class to use for the request argv: execv-style command-line arguments. Defaults to sys.argv. backend: `Backend` to use inf: File-like object to read from, defaults to standard input. outf: File-like object to write to, defaults to standard output. Returns: Exit code for use with sys.exit. 0 on success, 1 on failure. Ncs|dSrY)rr)dataoutfrBrCsend_fns zserve_command..send_fnrr)rar+rrt)Z handler_clsrIrpinfrNrOrqrrBrMrC serve_commands  rQcCs|}t||jS)zGenerate an info refs file.)rMr9rU)rrVrBrBrCgenerate_info_refssrRccs*|jjD]}dt|jjdVqdS)z Generate an index for for packs.sP rN)rUpacksrdfsencoderLfilename)rZpackrBrBrCgenerate_objects_info_packss  rVcCsF|tjdddt||tjddddt|dS)zGenerate server info for dumb file access. This generates info/refs and objects/info/packs, similar to "git update-server-info". r~rVryZobjectsrSN)Z_put_named_filerdrArkrRrV)rrBrBrCupdate_server_infos   rW__main__)nrGrrdrsysr.typingrrrrrrr3Zdulwich.archiverZdulwich.errorsrr r r r r rZdulwichrZdulwich.objectsrrZ dulwich.packrZdulwich.protocolrrrrrrrrrrrrrr r!r"r#r$r%r&r'r(r)r*r+r,r-r.r/r0r1r2r3r4r5r6r7Z dulwich.refsr8r9Z dulwich.repor:r;Z getLoggerrDr\objectr<rHrXrarorurrrrrrrrrrr r(r:r4r1r;r8rIrKstdinstdoutrQrRrVrWrBrBrBrCsh $  ' + 7q')Q ,;A*