o k`_@sdZddlZddlZddlZddlZddlmZddlm Z ddl m Z m Z ddl TddlmZmZmZmZmZmZmZddlmZdd lmZdd lmZdd lmZmZmZdd l m!Z!dd l"m#Z#m$Z$m%Z%ddl&m'Z'ddZ(ddZ)ddZ*ddZ+ddZ,ddZ-ddZ.ddZ/dd Z0d3d!d"Z1d#d$Z2Gd%d&d&eZ3Gd'd(d(e4Z5Gd)d*d*eZ6Gd+d,d,eZ7Gd-d.d.eZ8d/d0Z9Gd1d2d2e:Z;dS)4a Note about Unicode ------------------ The Subversion bindings are not unicode-aware and they expect to receive UTF-8 encoded `string` parameters, On the other hand, all paths manipulated by Trac are `str` objects. Therefore: * before being handed out to SVN, the Trac paths have to be encoded to UTF-8, using `_to_svn()` * before being handed out to Trac, a SVN path has to be decoded from UTF-8, using `_from_svn()` Whenever a value has to be stored as utf8, we explicitly mark the variable name with "_utf8", in order to avoid any possible confusion. Warning: `SubversionNode.get_content()` returns an object from which one can read a stream of bytes. NO guarantees can be given about what that stream of bytes represents. It might be some text, encoded in some way or another. SVN properties *might* give some hints about the content, but they actually only reflect the beliefs of whomever set those properties... N)quote)ISystemInfoProvider) ListOption ChoiceOption)*) ChangesetNode RepositoryIRepositoryConnectorInvalidRepositoryNoSuchChangeset NoSuchNode)CachedRepository)embedded_numbers) threading)exception_to_unicode to_unicodeto_utf8)_)from_utimestamp to_datetimeutc)HrefcCs0ddlmamamamatjtjtjtj ia dS)Nr)fsreposcoredelta) svnrrrr svn_node_dirr DIRECTORY svn_node_fileFILE_kindmapr#r#C/usr/lib/python3/dist-packages/tracopt/versioncontrol/svn/svn_fs.py _import_svnFsr%cGstd|dd|S)zExpect a pool and a list of `str` path components. Returns an UTF-8 encoded string suitable for the Subversion python bindings (the returned path never starts with a leading "/") /utf-8)rsvn_path_canonicalizejoinlstripencode)poolargsr#r#r$_to_svnLsr.cCst|tr t|d}|S)zExpect an UTF-8 encoded string and transform it to a `str` object But Subversion repositories built from conversion utilities can have non-UTF-8 byte strings, so we have to convert using `to_unicode`. r') isinstancebytesrpathr#r#r$ _from_svnVs  r3cCst|dS)Nascii)rr+)valuer#r#r$_quote_b`r6cCs|r|dpdS)z(Remove leading "/", except for the root.r&)stripr1r#r#r$_normalize_pathesr9cCs^|dur+|d}|dkrt|S|d}|d|dr-|t|ddp*dSdSdS)zdRemove the leading scope from repository paths. Return `None` if the path is not is scope. Nr&)r*r9r8 startswithlenscopefullpathr#r#r$_path_within_scopeis  r@cCs>|dkr|duS|r|dnd}|d}|d|dS)z>Check whether the given `fullpath` is within the given `scope`r&N)r*r8r;r=r#r#r$_is_path_within_scopevs  rBcCs(t}||_t}tj|_||_|SN)rsvn_opt_revision_value_tnumbersvn_opt_revision_tsvn_opt_revision_numberkindr5)numr5revisionr#r#r$_svn_revs rKcCst}tj|_|SrC)rrFsvn_opt_revision_headrH)rJr#r#r$ _svn_headsrMcCst|ptjSrC)rPoolapplication_pool)parentr#r#r$rNsrNcCs |r |r|dSdSdSrC)validdestroyr,r#r#r$ _pool_destroys  rTc@s,eZdZdZdZddZddZddZd S) SvnCachedRepositoryz_Subversion-specific cached repository, zero-pads revision numbers in the cache tables. TcCsd|S)Nz%010dr#selfrevr#r#r$db_revszSvnCachedRepository.db_revcCs t|pdSNr)intrVr#r#r$rev_db zSvnCachedRepository.rev_dbcCs |j|SrC)r normalize_revrVr#r#r$r^r]z!SvnCachedRepository.normalize_revN)__name__ __module__ __qualname____doc__has_linear_changesetsrYr\r^r#r#r#r$rUs  rUc@sneZdZeeeedddddZedddddZe dd gd d dZ d Z d dZ ddZ ddZddZd S)SubversionConnectorrbranchesztrunk, branches/*zComma separated list of paths categorized as branches. If a path ends with '*', then all the directory entries found below that path will be included. Example: `/trunk, /branches/*, /projectAlpha/trunk, /sandbox/*` )doctagsztags/*zComma separated list of paths categorized as tags. If a path ends with '*', then all the directory entries found below that path will be included. Example: `/tags/*, /projectAlpha/tags/A-1.0, /projectAlpha/tags/A-v1.1` eol_style)nativeLFCRLFCRaEnd-of-Line character sequences when `svn:eol-style` property is `native`. If `native`, substitute with the native EOL marker on the server. Otherwise, if `LF`, `CRLF` or `CR`, substitute with the specified EOL marker. (''since 1.0.2'')Nc Csd|_ztWnty&}z||_|jjdddWYd}~dSd}~ww|jdtjtj tj f}t d|tj d|_|ddkrPt d |jd |_dSdS) Nz"Failed to load Subversion bindingsT)exc_infozSubversion bindings importeds%d.%d.%dr'rr:z-Subversion >= 1.0 required, found %(version)s)version)_versionr% ImportErrorerrorloginfodebugr SVN_VER_MAJOR SVN_VER_MINOR SVN_VER_MICROstr SVN_VER_TAGr)rWernr#r#r$__init__s(    zSubversionConnector.__init__ccs|jr d|jfVdSdS)N Subversion)rorWr#r#r$get_system_infosz#SubversionConnector.get_system_infoccs>d}|jrd}d|dfVd|dfVd|dfVdS)Nr: direct-svnfssvnfsr)rq)rWprior#r#r$get_supported_typessz'SubversionConnector.get_supported_typescCsJ|j|j|jd|d|jt|||j}|dkr#t|j||j}|S)zReturn a `SubversionRepository`. The repository is wrapped in a `CachedRepository`, unless `type` is 'direct-svnfs'. )rgrerhr) updatergre setdefaultrhSubversionRepositoryrrrUenv)rWtypedirparamsrr#r#r$get_repositorys z"SubversionConnector.get_repository)r_r`ra implementsrr rrergrrhrqr{r~rrr#r#r#r$rds"    rdc@seZdZdZdZddZd7ddZd8dd Zd d Zd d Z ddZ ddZ ddZ ddZ ddZddZddZd7ddZd8ddZd d!Zd"d#Zd9d%d&Zd'd(Zd)d*Zd:d+d,Zd;d.d/Zd0d1Zd8d2d3Z 4dr;osnamesvn_uri_canonicalizer6 ra_url_utf8clear) rWr2rrr path_utf8root_path_utf8 root_pathrzr ra_prefixr#r#r$r{sX    zSubversionRepository.__init__NcCs$d|_|dur |||_d|_dS)z'Reset notion of `youngest` and `oldest`N)youngestr^oldest)rW youngest_revr#r#r$r,s  zSubversionRepository.clearcCsD|s|j}||}t|j||}t|t||j||}|tvS)z:Check if `path` exists at `rev` (or latest if unspecified)) r,r^r revision_rootr check_pathr.r>r")rWr2rXr,rev_root node_typer#r#r$has_node3s zSubversionRepository.has_nodecCst|S)z`Take any path specification and produce a path suitable for the rest of the API )r9)rWr2r#r#r$normalize_path=sz#SubversionRepository.normalize_pathc Cs|dust|tr|dvr|jSz$t|}d|kr$|jkr%|WS|jd||jp.d|jWt |tt fy[}z|jd||jpIdt |WYd}~t |d}~ww)zhTake any revision specification and produce a revision suitable for the rest of the API N)rAheadlatestrrz-%r cannot be normalized in %s: out of [0, %r]z (default)z!%r cannot be normalized in %s: %s) r/rxlowerrr[rrrtreponame ValueError TypeErrorrr )rWrXnormrevrzr#r#r$r^Cs*   z"SubversionRepository.normalize_revcCs d|_d|_t|jd|_dS)z=Dispose of low-level resources associated to this repository.N)rrrTr,r}r#r#r$closeYs  zSubversionRepository.closecCs|jS)zRetrieve the base path corresponding to the Subversion repository itself. This is the same as the `.path` property minus the intra-repository scope, if one was specified. )rr}r#r#r$get_base`szSubversionRepository.get_basec cs|j|gD]I}|dr@t|}z"dd||D}t|dddD] }|jt j kr4|Vq)Wqt y?Yqwz||VWqt yQYqwdS)z Retrieve known branches or tags.rcSsg|]}|qSr#r#).0nr#r#r$ osz>SubversionRepository._get_tags_or_branches..cSst|jSrC)rr2r)rr#r#r$pr7z.keyN) rgetendswithrdirnameget_node get_entriessortedrHrr Exception)rWpathsr2folderentriesnoder#r#r$_get_tags_or_branchesis(     z*SubversionRepository._get_tags_or_branchesccsL|dD] }d|j|jdfVq|dD] }d|j|j|jfVqdS)z|Retrieve known branches, as (name, id) pairs. Purposedly ignores `rev` and always takes the last revision. reNrg)rr2 created_path created_rev)rWrXrr#r#r$get_quickjump_entries|s z*SubversionRepository.get_quickjump_entriescCs:|jddd}|rt|}|r|d}||SdS)zkRetrieve the "native" URL from which this repository is reachable from Subversion clients. urlrAr&N)rrrstriprr*)rWr2rXrhrefr#r#r$ get_path_urls z!SubversionRepository.get_path_urlcCs||}t|||j|jS)zIProduce a `SubversionChangeset` from given revision specification)r^SubversionChangesetr>r,rVr#r#r$ get_changesets z"SubversionRepository.get_changesetcCs |j|fS)z7Build a value identifying the `rev` in this repository.)rrVr#r#r$get_changeset_uids z&SubversionRepository.get_changeset_uidcCsL|pd}|r|dkr|ddkr|dd}||p|j}t||||jS)zProduce a `SubversionNode` from given path and optionally revision specifications. No revision given means use the latest. rAr&rN)r^rSubversionNoder,rWr2rXr#r#r$rs  zSubversionRepository.get_nodec CsL|||}g}|D]\}}}||ks|r||kr|S||q |S)zReturn the revisions affecting `path` between `first` and `last` revs. If `first` is not given, it goes down to the revision in which the branch was created. )r get_historyappend) rWr2lastfirstrrevsprchgr#r#r$_get_node_revss  z#SubversionRepository._get_node_revsc CsZi}|D]&\}}|j}g}|D]\}}} ||ks||kr n||q|||<q|SrC)r2rr) rW node_infos path_revsrrr2rrrrr#r#r$_get_changed_revss   z&SubversionRepository._get_changed_revsc cst||j|}||kr||}}||fdkrdSt|j||}t|||tjkr-dSt|}t|}t |||} d} | rrt | | |} | ||}}| rpt | |\}} | | |krg ~~dSt |}|| fV| s@~~dS)z`path` is a str path in the scope. Generator yielding `(path, rev)` pairs, where `path` is a `str` object. Must start with `(path, created rev)`. (wraps ``fs.node_history``) )r:rNr:)r.r>rrrrr svn_node_nonerN node_history history_prevrhistory_locationr3) rWr2startendr,rroottmp1tmp2 history_ptr cross_copiesrXr#r#r$_historys:     zSubversionRepository._historyrAcCs6|dkr||d|d|p|jD]\}}|SdSNr:)rr,)rWrXr2r,rprevr#r#r$ _previous_revs"z"SubversionRepository._previous_revcCs|jdurd|_|jS)z.Gives an approximation of the oldest revision.Nr:)rr}r#r#r$get_oldest_revs z#SubversionRepository.get_oldest_revcCsR|js&t|j|j|_|jdkr&|dd|j|jD] \}}||_|jS|jS)z]Retrieve the latest revision in the repository. (wraps ``fs.youngest_rev``) r&rAr:)rrrrr,r>rrr#r#r$get_youngest_revs  z%SubversionRepository.get_youngest_revcCs||}|||S)ziReturn revision immediately preceeding `rev`, eventually below given `path` or globally. )r^r)rWrXr2r#r#r$ previous_revs  z!SubversionRepository.previous_revFcCs||}|d}|j}t|j}||kr>||||d||D]\}}|S|s6||||s6|S|d7}||ksdS)zhReturn revision immediately following `rev`, eventually below given `path` or globally. r:N)r^rrNr,rrr)rWrXr2find_initial_revnextrsubpoolrr#r#r$next_revs    zSubversionRepository.next_revcCs||||kS)z9Check relative order between two revision specifications.)r^)rWrev1rev2r#r#r$rev_older_thansz#SubversionRepository.rev_older_thanc csh||}||}d}t|j}d}|r|r||kr|||||r|r6|d7}||dtjfVd}d}||d||D]N\} } t |j | | tj f}|j | |d}|r|d7}|d|kro|d|dtj fVn|j |d|d}|d|dtjfV|d|ddf}n|}qB|r|d7}|Vn d}|j ||d}|r|r||ksdSdSdSdS)zURetrieve creation and deletion events that happened on given `path`. Frr:NrSunknownT)rr^rNr,rrrDELETErr@r>ADDrEDITCOPY) rWr2rXlimitexpect_deletionrnumrevsnewerolderrrr#r#r$get_path_historysF      z%SubversionRepository.get_path_historyrccs.d}}||}||}|||r|||}nt||d|||r/|||}nt||d|j|jkrJttd|j|||j||dt|j}|j rt } t | |\} } t |j||} t |j||} dd}d}d}t| t||j|d | t||j|| | ||d ||| td d | jDd dd}| j|D]>\}}}d}}|tjkr|t|||}|tjkr|t|||}ntt | t||j|j|}||||fVqdSt |j||} t |j||} t | t||j|| t||j||r||t!j"tj#fVdSdS)zDetermine differences between two arbitrary pairs of paths and revisions. (wraps ``repos.svn_repos_dir_delta``) NzThe Base for Diff is invalidzThe Target for Diff is invalidzDiff mismatch: Base is a %(oldnode)s (%(oldpath)s in revision %(oldrev)s) and Target is a %(newnode)s (%(newpath)s in revision %(newrev)s).)oldnodeoldpatholdrevnewnodenewpathnewrevcSsdSrr#)rr2r,r#r#r$authz_cbkz2SubversionRepository.get_changes..authz_cbrrAr:css$|] \}}}t|||fVqdSrCr3)rr2rHchanger#r#r$ {sz3SubversionRepository.get_changes..cSs|dSrZr#)entryr#r#r$r}sz2SubversionRepository.get_changes..r)$r^rrr rH TracErrorrrNr,isdirDiffChangeEditorr make_editorrrrrsvn_repos_dir_deltar.r>rdeltas__dict__rrrrr)rr"rr2contents_changedrr!r)rWold_pathold_revnew_pathnew_revignore_ancestryold_nodenew_nodereditore_ptre_batonold_rootnew_rootr  text_deltas entry_propsrr2rHrr#r#r$ get_changesJs               z SubversionRepository.get_changesrCNN)rAN)rA)rAF)r)r_r`rarbrcr{rrrr^rrrrrrrrrrrrrrrrrrr(r#r#r#r$rs8 3         #  -rc@szeZdZdddZddZdddZd d Zdd d Zd dZddZ ddZ ddZ ddZ ddZ ddZddZdS) rNc Cs|j|_|j|_t||_|j}t||j||_|r||_n"z t|j|||_Wnt j y?}z t ||t ||d}~wwt |j|j|}|tvrRt ||t|j|j|}t|} t|j|j|} t|j| ry| |_t|j| |_n|||_|_t||||t|dSrC)rr>rNr,r._scoped_path_utf8rrrrrr rrr"node_created_pathr3node_created_revrBrr@rrr{) rWr2rXrr, parent_rootrzrcp_utf8cpcrr#r#r$r{s0   zSubversionNode.__init__cCs|jrdSt|S)z.Retrieve raw content as a "read()"able object.N)rFileContentStreamr}r#r#r$ get_contentszSubversionNode.get_contentTcCs0|jrdS|dur|jjdn|}t|||S)z4Retrieve processed content as a "read()"able object.Nrh)rrrrr1)rWkeyword_substitutioneol_hintrhr#r#r$get_processed_contents  z$SubversionNode.get_processed_contentccsb|jrdSt|j}t|j|j|}|D]}t|j t |}t ||j |j |j|jVqdS)zoYield `SubversionNode` corresponding to entries in this directory. (wraps ``fs.dir_entries``) N)isfilerNr,r dir_entriesrr*rr)r2r3rrXr)rWr,ritemr2r#r#r$rs zSubversionNode.get_entriesc csd}d}t|j}d}|j|jd|j|D]A\}}t|j|}|dkrP|rP||tj f}|rN|d|dkr;tj }ntj }|d|d|f}|d7}|V|}|rX||krXnq|rf|ra||krh|VdSdSdS)z.Yield change events that happened on this pathNrr:) rNr,rrr2rXr@r>rrrr) rWrrrr,rr2rXrr#r#r$rs.      zSubversionNode.get_historyc sg|jr`fdd}z8t|j}td}t|jjt|j}t |}|jj d|ddl m}||||||||jWSt jtfy_}z ttd|jt|d|d}~wwS) zaReturn a list the last changed revision for each line. (wraps ``client.blame2``) cs|dSrC)r)line_norJauthordateliner, annotationsr#r$blame_receiverr7z6SubversionNode.get_annotations..blame_receiverrzopening ra_local session to %r)clientz'svn blame failed on %(path)s: %(error)s)r2rqN)r6rKrXrr)rrr6r*rrrrrsrr@blame2create_contextr,rAttributeErrorrrr2r)rWr?rXr file_url_utf8r@rzr#r=r$get_annotationss6       zSubversionNode.get_annotationscC&t|j|j|j}dd|DS)zdReturn `dict` of node properties at current revision. (wraps ``fs.node_proplist``) cSsi|] \}}t|t|qSr#r)rrr5r#r#r$ sz1SubversionNode.get_properties..)r node_proplistrr*r,itemsrWpropsr#r#r$get_propertiesszSubversionNode.get_propertiescCs|jrdSt|j|j|jS)zfRetrieve byte size of a file. Return `None` for a folder. (wraps ``fs.file_length``) N)rr file_lengthrr*r,r}r#r#r$get_content_lengthsz!SubversionNode.get_content_lengthcCs|jrdS|tjS)zqRetrieve mime-type property of a file. Return `None` for a folder. (wraps ``fs.revision_prop``) N)r _get_proprSVN_PROP_MIME_TYPEr}r#r#r$get_content_type's zSubversionNode.get_content_typecCs2t|j|jtj|j}|sdStt||jS)ziRetrieve timestamp of last modification, in micro-seconds. (wraps ``fs.revision_prop``) N) r revision_proprrrSVN_PROP_REVISION_DATEr,rsvn_time_from_cstring)rW_dater#r#r$get_last_modified0s z SubversionNode.get_last_modifiedcCst|j|j||j}t|SrC)r node_proprr*r,r)rWrr5r#r#r$rO;szSubversionNode._get_propcCs&t|j|j}|rt|dSdS)zReturn the revision in which the node's path was created. (wraps ``fs.revision_root_revision(fs.closest_copy)``) rN)r closest_copyrr*revision_root_revision)rW root_and_pathr#r#r$get_branch_origin@sz SubversionNode.get_branch_originc Csg}|j|j|jf}|rt|\}}}d}t||}|rr|\}}|d}t|} d} ||kr:|t|dd} t ||} | rr| \} }|d}t |j | |j }| r\|d| 7}t |jt|} | rm|| | f|| |f}|s |S)aRetrieve the list of `(path,rev)` copy ancestors of this node. Most recent ancestor first. Each ancestor `(path, rev)` corresponds to the path and revision of the source at the time the copy or move operation was performed. N/)r*rXrrrXr*rYr<r8 copied_fromrrr,r@r>r3r) rW ancestorsprevious previous_pathr previous_rootrrr2rXrelpathr]ui_pathr#r#r$get_copy_ancestryIs4        z SubversionNode.get_copy_ancestryr))TNrC)r_r`rar{r2r5rrrErLrNrQrVrOr[rdr#r#r#r$rs #       rc@s.eZdZd ddZddZddZdd ZdS) rNc Cs|j|_||_||_|j|_t||_z|tj}Wn tj y't |w|tj }t |}t |}|tj }|rJt||j}t|} nd} t|||||| dSrC)rrrXr>rrNr, _get_revproprSVN_PROP_REVISION_LOGrr SVN_PROP_REVISION_AUTHORr3rSrTrrr{) rWrrXr>r,messager:rUtsr;r#r#r$r{ns&    zSubversionChangeset.__init__cCrF)zVRetrieve `dict` of Subversion properties for this revision (revprops) cSs2i|]\}}|tjtjtjfvrt|t|qSr#)rrfrgrSr3)rkvr#r#r$rGs z6SubversionChangeset.get_properties..)rrevision_proplistrrXr,rIrJr#r#r$rLsz"SubversionChangeset.get_propertiesc#st|j}t|}t|j|j|}z t|j||}Wnty/t |j|j|}Ynwt ||\}}t ||||d}ii}} g} i} |j D]\} } t| }t|j|s_qP| j} | j}t| }t|}| j}t| dd}t|j|sd\}}|s|s|jdkrtj}ne|r|tjkr|rtj}|| |d<nQqP| js|stj}|r|rtj}|||d<n9tj}|| vr| |}n t|j||}|| |<|t|||}t|}t |||}t|j|r||}}t!| j"}t#|j|p|}t#|j|}| $|||||g|d7}qP|j%t&|D]\}}|| vr7tj'| |d<(| |q fdd t)| D} | *| D]} t+| VqJdS) z`Retrieve file changes for a given revision. (wraps ``repos.svn_repos_replay``) ractionN)Nrr&r:rcsg|] \}}|vr|qSr#r#)rirmovesr#r$rs z3SubversionChangeset.get_changes..),rNr,rrrrXrChangeCollectorrCRevisionChangeCollectorrrsvn_repos_replaychangesrIr3rBr>r2 base_pathbase_revgetattrrrCHANGE_ACTION_DELETErr*addedrrrr+r,r" item_kindr@rrsetMOVEadd enumeratesorttuple)rWr,tmprr!r"r#idxcopies deletionsrtrevrootsrrrbase_path_utf8r2rurv change_actionrmb_rootcbase_path_utf8 cbase_path cbase_revrHrjrkr#ror$r(s               zSubversionChangeset.get_changesc CsHz t|j|j||jWStjy#}z |jd||jd}~ww)Nz %r of the %r cannot be retrieved) rrRrrXr,rrrrrt)rWrrzr#r#r$resz SubversionChangeset._get_revproprC)r_r`rar{rLr(rer#r#r#r$rls   \rcCsGdddtj}|S)Nc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)z*DiffChangeEditor..DiffChangeEditorcSs g|_dSrC)rr}r#r#r$r{ z3DiffChangeEditor..DiffChangeEditor.__init__cSs dtjfS)Nr&)rr)rW base_revisiondir_poolr#r#r$ open_rootrz4DiffChangeEditor..DiffChangeEditor.open_rootcSs |j|tjtjf|tjfSrC)rrrrrr)rWr2 dir_baton copyfrom_path copyfrom_revrr#r#r$ add_directory s z8DiffChangeEditor..DiffChangeEditor.add_directorycSs ||dfSrr#)rWr2rrrr#r#r$open_directoryr]z9DiffChangeEditor..DiffChangeEditor.open_directorycSs.|\}}|tjkr|j|tj|fdSdSrC)rrrrrr)rWrrr5r,r2rr#r#r$change_dir_props z:DiffChangeEditor..DiffChangeEditor.change_dir_propcSs|j|dtjfdSrC)rrrr)rWr2rJrr,r#r#r$ delete_entrysz7DiffChangeEditor..DiffChangeEditor.delete_entrycS|j|tjtjfdSrC)rrrr!rr)rWr2rrcopyfrom_revisionrr#r#r$add_filesz3DiffChangeEditor..DiffChangeEditor.add_filecSrrC)rrrr!rr)rWr2r dummy_rev file_poolr#r#r$ open_filesz4DiffChangeEditor..DiffChangeEditor.open_fileN) r_r`rar{rrrrrrrr#r#r#r$rs r)rEditor)rr#r#r$rs!rc@seZdZgdddgddgddgdgd gd Zeejeee Z e d Z e d Zd ddejdkr7dnd dZdZdZdZdZd Zd1ddZddZddZddZd2ddZdd Zd!d"Zd#d$Zd%d&Zd'd(Z d)d*Z!d+d,Z"d-d.Z#d/d0Z$dS)3r1)LastChangedRevisionRevRevisionLastChangedDateDate LastChangedByAuthorHeadURLURLIdHeader)rXr;r:ridheaderz[ \t\v\n\b\r\f]+z%[abdDPrRu_%HI] s  r)rjrkrlriiNcCsd|_d|_|j|_||_|j|_t|_|r(||t j |_ | |j |_ |j|ddkrB|t jdkrBd|_|j||_t t|j|j|j|_dS)N riT) translatedbufferrrrrNr,_get_keyword_valuesrOrSVN_PROP_KEYWORDSkeywords_build_keywords_re keywords_reNEWLINESrSVN_PROP_EOL_STYLE native_eolnewlineStreamr file_contentsrr*stream)rWrr3eolr#r#r$r{;s&    zFileContentStream.__init__cCs|SrCr#r}r#r#r$ __enter__Pr zFileContentStream.__enter__cCs |dSrC)r)rWetevtbr#r#r$__exit__Sr]zFileContentStream.__exit__cCs d|_d|_t|jd|_dSrC)rrrTr,r}r#r#r$rVs  zFileContentStream.closecCs>|jdur td|jdur|js||j|S||j|S)NzI/O operation on closed file)rrrr _read_dumb_read_substitute)rWrr#r#r$read\s zFileContentStream.readcCst|j|||jSrC)rrRrr,)rWrrXr#r#r$redszFileContentStream._get_revpropcssdSttd|jsdS|j}t|jt}||}| |}t |j }t | tj|j }|jd}|j||jpD|} |jd|jpNd} d|j|||f} id|d|d| d|d| d d| |||fd |d |jd |d |d|d|d| d| ddddd| dd||||fifdd} i} |jD]\}tfdd|Dr| fdd|DqD]}d|vrq|dd\}|jvr|j| || <q| rdd| DSdS) Nr&rA rXr:rr;rrz%az%bz%dz%Dz%Pz%rz%Rz%uz%_z%%%z%Iz%Hcs|d}||SrZ)groupr)match)datar#r$expands  z5FileContentStream._get_keyword_values..expandc3s|]}|vVqdSrCr#rkw)rr#r$rsz8FileContentStream._get_keyword_values..c3s|] }|fVqdSrCr#r)rrr#r$rs=r:cSs&i|]\}}|dt|dqS)r')r+rx)rrr5r#r#r$rGsz9FileContentStream._get_keyword_values..)listfilterKEYWORD_SPLIT_REsplitrr last_modifiedr_format_shortdate_format_longdaterxrr3rerrgr2r*rrrXr)rKEYWORD_GROUPSrIanyrKEYWORDSKEYWORD_EXPAND_REsub)rWrrmtime shortdatelongdaterr:r2rroot_urlid_rvaluesaliaseskeyword definitionr#)rrrr$rgs        z%FileContentStream._get_keyword_valuescCs(|rtddttj|tjSdS)Ns [$] (?P%s) (?: :[ ][^$ ]+?[ ] | ::[ ](?P[^$ ]+?)[ #] )? [$]|)recompiler)mapescapeVERBOSE)rWrr#r#r$rs z$FileContentStream._build_keywords_recCs |dS)Nz%Y-%m-%d %H:%M:%SZ)strftime)rWrr#r#r$rrz#FileContentStream._format_shortdatecCs2|d}d}d}|||||jddS)Nz.%Y-%m-%d %H:%M:%S +0000 (%%(a)s, %d %%(b)s %Y))MonTueWedThuFriSatSun) JanFebMarAprMayJunJulAugSepOctNovDecr:)ab)rweekdaymonth)rWrtextweekdaysmonthsr#r#r$rs   z"FileContentStream._format_longdatecCs ||SrC)r)rWrrr#r#r$rrzFileContentStream._read_dumbcCs|durd}|j}|j} d|krt|kr+nn||_||d|_|d|St||jkrF|||jp:d7}|sF||_d|_|S|jrN|dnd}|dkr^|||7}d}q |dkrs|||d|7}||d}d} |dd}|dkr|||7}d}n ||jkr|j |}|rn|||d|7}||d}qv|dks|sq |d7}|| |d||7}||d}q )NrTrr$r:) rrr<KEYWORD_MAX_SIZEr CHUNK_SIZErfind_translate_newliner_translate_keyword)rWrrrrposrr#r#r$rsV        z"FileContentStream._read_substitutecCs|jr |d|j}|S)Nr)rrr)rWrr#r#r$r sz$FileContentStream._translate_newlinecCs|d}|j|}|dur|S|d}|dur0|jt|d}|dkr.d|||fS|St|}d|||||t|krCdfSdfS) Nrfixedrs $%s: %.*s $s$%s:: %-*.*s%s$# )rrrrr<)rWrrrr5r rr#r#r$r s   z$FileContentStream._translate_keywordr)rC)%r_r`rar functoolsreducer{unionrrrrrrrrrrrrrrrr{rrrrrerrrrrrr r r#r#r#r$r1%sB    36 r1rC)sP  $          O+Q&