a +br @sddlmZddlZddlZddlZddlZddlZddlm Z ddl m Z ddl m Z mZmZedZdd eDZd d eDZd d ZdJddZdKddZddZddZddZddZdLddZdMddZdd Zd!d"Zd#d$Zd%d&Z e j!dd'Gd(d)d)e"Z#d*d+Z$d,d-Z%d.d/Z&e'd0Z(d1d2Z)dNd4d5Z*d6d7Z+d8d9Z,d:d;Z-dd?a/dOdAdBZ0dddddd d d d d dC Z1dDdEZ2dFdGZ3dHdIZ4dS)P)absolute_importN)_)attr)encodingerrorpycompats()[]{}?*+-|^$\.&~# cCs i|]}t|d|dqS)\latin1)orddecode.0ir@/usr/lib64/python3.9/site-packages/mercurial/utils/stringutil.py rcCsi|]}|d|qS)r rr rrrrrcCs8d}t|trd}|d}|t}|r.|S|dS)z"Drop-in replacement for re.escape.TFr ) isinstancebytesr translate_regexescapemapencode)patZwantunirrrreescape"s   rFcCsdt||||dS)zPretty print an object.rbprefixindentlevel)join pprintgen)orrrrrrpprint1sr"c cst|tr0|rdt|Vndt|Vnt|trPdtt|Vnt|tr|sjdVdSdV|r|d7}dVd ||Vt|D]T\}}t||||d D] }|Vq|dt|kr|rd Vd ||Vqd Vq|r|d8}dVd ||Vd Vnt|tr |s6dVdSdV|r^|d7}dVd ||Vtt | D]\}\}}t||||d D] }|VqdVt||||d D] }|Vq|dt|krn|rd Vd ||Vnd Vqn|r|d8}dVd ||VdVnt|t r|s|d7}dVd ||Vt|D]\\}}t||||d D] }|Vq^|dt|krF|rd Vd ||Vnd VqF|r|d8}dVd ||VdVnt|t jrz t|} WntydVYdS0dV|r0|d7}dVd ||Vd} | s| } z t|} Wntybd} Yn0t| |||d D] }|Vqt| s4|rd Vd ||Vnd Vq4|r|d8}dVd ||Vd Vn t|VdS)aPretty print an object to a generator of atoms. ``bprefix`` is a flag influencing whether bytestrings are preferred with a ``b''`` prefix. ``indent`` controls whether collections and nested data structures span multiple lines via the indentation amount in spaces. By default, no newlines are emitted. ``level`` specifies the initial indent level. Used if ``indent > 0``. sb'%s's'%s'sbytearray['%s']s[]N[  rs, s, ]s{}{s: }sset([])sset([s])s()()sgen[]sgen[FT)rr escapestr bytearraylist enumerater lendictsorteditemssettupletypes GeneratorTypenext StopIterationrbyterepr) r!rrrrachunkkvZnextitemZlastcurrentrrrr 6s                            r cCsg}t|}d}}|t|krd}|d|d}|dkrHt|}n2||dkrz|d|drz|d|d|d}|dkr|}n|d7}|dd||dd|}|dksJ|||||f||}}qd d d |DS) z9Pretty print a representation of a possibly-nested objectrr%css|]\}}d||VqdS)s Nr)rlsrrr rzprettyrepr..) rr:r0find startswithrfindcountappendrstripr)r!linesZrsZp0Zp1Zq0Zq1rDrrr prettyreprs$     rNcCs\|dur dSt|tr4|dttj|ddSt|trB|St|rP|St|SdS)arFormat an optional printable representation from unexpanded bits ======== ================================= type(r) example ======== ================================= tuple ('', other) bytes '' callable lambda: '' % sorted(b) object other ======== ================================= Nrrr$)rr5rZrapplyZ maybebytestrrcallabler")rrrr buildreprs   rQcCst|o d|vS)z&return true if a string is binary data)boolrErrrbinary5srUcCs<|drd|ddfS|dr4d|ddfSd|fS)Nsre:resliteral:literal)rH)patternrrr _splitpattern:s   r[Tc st|\}}|dkr|zd}|s$tj}t||}Wn<tjyn}z"ttdt|WYd}~n d}~00|||jfS|dkr|r|j }nt |fdd}|||fSt d|dS) a accepts a string, possibly starting with 're:' or 'literal:' prefix. returns the matcher name, pattern, and matcher function. missing or unknown prefixes are treated as literal matches. helper for tests: >>> def test(pattern, *tests): ... kind, pattern, matcher = stringmatcher(pattern) ... return (kind, pattern, [bool(matcher(t)) for t in tests]) >>> def itest(pattern, *tests): ... kind, pattern, matcher = stringmatcher(pattern, casesensitive=False) ... return (kind, pattern, [bool(matcher(t)) for t in tests]) exact matching (no prefix): >>> test(b'abcdefg', b'abc', b'def', b'abcdefg') ('literal', 'abcdefg', [False, False, True]) regex matching ('re:' prefix) >>> test(b're:a.+b', b'nomatch', b'fooadef', b'fooadefbar') ('re', 'a.+b', [False, False, True]) force exact matches ('literal:' prefix) >>> test(b'literal:re:foobar', b'foobar', b're:foobar') ('literal', 're:foobar', [False, True]) unknown prefixes are ignored and treated as literals >>> test(b'foo:bar', b'foo', b'bar', b'foo:bar') ('literal', 'foo:bar', [False, False, True]) case insensitive regex matches >>> itest(b're:A.+b', b'nomatch', b'fooadef', b'fooadefBar') ('re', 'A.+b', [False, False, True]) case insensitive literal matches >>> itest(b'ABCDEFG', b'abc', b'def', b'abcdefg') ('literal', 'ABCDEFG', [False, False, True]) rVrinvalid regular expression: %sNrXcst|kS)N)rlowerrTZipatrryrzstringmatcher..unhandled pattern kind: %s) r[remodIcompiler ParseErrorr forcebytestrsearch__eq__rr]ProgrammingError)rZZ casesensitivekindflagsZregexematchrr^r stringmatcherBs&&     rmc Cst|\}}|dkrbzt||WStjy^}z"ttdt|WYd}~q|d}~00n|dkr|tt||Std|dS)aBuild a regexp object from a string pattern possibly starting with 're:' or 'literal:' prefix. helper for tests: >>> def test(pattern, *tests): ... regexp = substringregexp(pattern) ... return [bool(regexp.search(t)) for t in tests] >>> def itest(pattern, *tests): ... regexp = substringregexp(pattern, remod.I) ... return [bool(regexp.search(t)) for t in tests] substring matching (no prefix): >>> test(b'bcde', b'abc', b'def', b'abcdefg') [False, False, True] substring pattern should be escaped: >>> substringregexp(b'.bc').pattern '\\.bc' >>> test(b'.bc', b'abc', b'def', b'abcdefg') [False, False, False] regex matching ('re:' prefix) >>> test(b're:a.+b', b'nomatch', b'fooadef', b'fooadefbar') [False, False, True] force substring matches ('literal:' prefix) >>> test(b'literal:re:foobar', b'foobar', b're:foobar') [False, True] case insensitive literal matches >>> itest(b'BCDE', b'abc', b'def', b'abcdefg') [False, False, True] case insensitive regex matches >>> itest(b're:A.+b', b'nomatch', b'fooadef', b'fooadefBar') [False, False, True] rVr\NrXr`) r[rarcrrdrreescaperh)rZrjrirkrrrsubstringregexps& rocCs|d}|dkr|d|}|d}|dkr@||dd}|d}|dkr^|d|}|d}|dkr||d|}|S)z>Return a short representation of a user name or email address.@rNrAr$r&.rGuserfrrr shortusers       rvcCsD|d}|dkr|d|}|d}|dkr@||dd}|S)z,Return the user portion of an email address.rprNrAr$rrrsrrr emailusers   rwcCs,|d}|dkrd}||dd|S)zget email of author.rCr@NrAr$rr)authorrPrrremails rycCsVd|vr |S|d}|dkr8|d|dddS|d}|d|dd S) aReturns the name before an email address, interpreting it as per RFC 5322 >>> person(b'foo@bar') 'foo' >>> person(b'Foo Bar ') 'Foo Bar' >>> person(b'"Foo Bar" ') 'Foo Bar' >>> person(b'"Foo "buz" Bar" ') 'Foo "buz" Bar' >>> # The following are invalid, but do exist in real-life ... >>> person(b'Foo "buz" Bar ') 'Foo "buz" Bar' >>> person(b'"Foo Bar ') 'Foo Bar' rprAr@Ns "s\""rqr&)rGstripreplace)rxrurrrpersons  r})hashc@s$eZdZdZeZejddZdS) mailmappingz>Represents a username/email key or value in a mailmap fileN)default)__name__ __module__ __qualname____doc__rZibrynamerrrrrsrcCs| p| ot|dkS)auReturns True if the parsed names and emails in a mailmap entry are invalid. >>> # No names or emails fails >>> names, emails = [], [] >>> _ismailmaplineinvalid(names, emails) True >>> # Only one email fails >>> emails = [b'email@email.com'] >>> _ismailmaplineinvalid(names, emails) True >>> # One email and one name passes >>> names = [b'Test Name'] >>> _ismailmaplineinvalid(names, emails) False >>> # No names but two emails passes >>> names = [] >>> emails = [b'proper@email.com', b'commit@email.com'] >>> _ismailmaplineinvalid(names, emails) False r)r0)namesemailsrrr_ismailmaplineinvalidsrcCsi}|dur|S|D]}|dr,qgg}}g}|D]n}|drVqqB|dr|dr||dd|r|d|g}t|dkrqqB||qBt||rqt |dt|dkr|dndd }t |d |r|d ndd ||<q|S) axParses data in the .mailmap format >>> mmdata = b"\n".join([ ... b'# Comment', ... b'Name ', ... b' ', ... b'Name ', ... b'Name Commit ', ... ]) >>> mm = parsemailmap(mmdata) >>> for key in sorted(mm.keys()): ... print(key) mailmapping(email='commit1@email.xx', name=None) mailmapping(email='commit2@email.xx', name=None) mailmapping(email='commit3@email.xx', name=None) mailmapping(email='commit4@email.xx', name='Commit') >>> for val in sorted(mm.values()): ... print(val) mailmapping(email='commit1@email.xx', name='Name') mailmapping(email='name@email.xx', name=None) mailmapping(email='proper@email.xx', name='Name') mailmapping(email='proper@email.xx', name='Name') N#rArCr$r@r&r)ryrr) splitlineslstriprHsplitendswithrKrr0rr)ZmailmapcontentmailmaplinerrZ namebuilderelementZ mailmapkeyrrr parsemailmaps<        rc Cst|r |s|Stt|t|d}z ||}Wn0ty`t|jd}||tdd}Yn0d|jrp|jn|j|jr|jn|jfS)a.Returns the author field according to the mailmap cache, or the original author field. >>> mmdata = b"\n".join([ ... b'# Comment', ... b'Name ', ... b' ', ... b'Name ', ... b'Name Commit ', ... ]) >>> m = parsemailmap(mmdata) >>> mapname(m, b'Commit ') 'Name ' >>> mapname(m, b'Name ') 'Name ' >>> mapname(m, b'Commit ') 'Name ' >>> mapname(m, b'Commit ') 'Name ' >>> mapname(m, b'Unknown Name ') 'Unknown Name ' )rry)ryNs%s <%s>)isauthorwellformedrr}ryKeyErrorgetr)rrxZcommitZproperZcommit2rrrmapnamehs    rs^[^<]+\s<[^<>]+@[^<>]+>$cCst|duS)a&Return True if the author field is well formed (ie "Contributor Name ") >>> isauthorwellformed(b'Good Author ') True >>> isauthorwellformed(b'Author ') True >>> isauthorwellformed(b'Bad Author') False >>> isauthorwellformed(b'Bad Author >> isauthorwellformed(b'Bad Author author@author.com') False >>> isauthorwellformed(b'') False >>> isauthorwellformed(b'Bad Author ') False N)_correctauthorformatrl)rxrrrrsrcCstj||ddS)zCTrim string to at most maxlength (default: 400) columns in display.s...)ellipsis)rZtrim)textZ maxlengthrrrrsrcCs t|trt|}t|dSNr)r memoryviewrcodecs escape_encoderTrrrr,s r,cCst|dSr)r escape_decoderTrrr unescapestrsrc Cs8z t|WSty2ttt|YS0dS)zLPortably format an arbitrary object (e.g. exception) into a byte string.N)rbytestrUnicodeEncodeErrorrZ strtolocalstr)objrrrres  recCstt|ddS)Ns\\r )rr:rr|rTrrruireprsrcKs$Gdddtj}|a|fi|S)Nc@s(eZdZdZddZddZddZdS) z_MBTextWrapper..twa8 Extend TextWrapper for width-awareness. Neither number of 'bytes' in any encoding nor 'characters' is appropriate to calculate terminal columns for specified string. Original TextWrapper implementation uses built-in 'len()' directly, so overriding is needed to use width information of each characters. In addition, characters classified into 'ambiguous' width are treated as wide in East Asian area, but as narrow in other. This requires use decision to determine width of such characters. cSsZd}tj}tt|D]8}||||7}||kr|d|||dfSq|dfS)Nrr)r ucolwidthrZxranger0)selfZucstr space_leftrDcolwidthrrrr_cutdownsz#_MBTextWrapper..tw._cutdowncSsRt||d}|jr<||d|\}}||||d<n|sN||dS)Nr$r@)maxZbreak_long_wordsrrKpop)rZreversed_chunkscur_linecur_lenwidthrZcutresrrr_handle_long_words  z,_MBTextWrapper..tw._handle_long_wordc Sstj}g}|jdkr"td|j||rg}d}|rD|j}n|j}|jt|}|jrx|d dkrx|rx|d=|r||d}|||kr| | ||7}qxqqx|r||d|kr| |||||jr|r|d dkr|d=|r*| |d |q*|S)Nrsinvalid width %r (must be > 0)r@)rrr ValueErrorreversesubsequent_indentinitial_indentr0Zdrop_whitespacer{rKrrr) rchunksrrMrrrrrDrrr _wrap_chunkss@    z'_MBTextWrapper..tw._wrap_chunksN)rrrrrrrrrrrtws  r)textwrapZ TextWrapper_MBTextWrapper)kwargsrrrrrsgrrcCstt|t|}||kr(td|d}|ttjttj}|ttjttj}|ttjttj}t|||d}|| ttjS)NNr$)rrr) rr0r rZsysstrrZ encodingmoderfillr)rrZ initindentZ hangindentZ maxindentwrapperrrrwrap>s&      r) 1syesstruesonsalways0snosfalsesoffsnevercCst|dS)zLParse s into a boolean. If s is not a valid boolean, returns None. N) _booleansrr]rTrrr parseboolcsrcsVfddfddfdd|durJt|trJ|d}n|}|pTgS) zparse a configuration value as a list of comma/space separated strings >>> parselist(b'this,is "a small" ,test') ['this', 'is', 'a small', 'test'] csd}|t|krF|||ds8|||ddkrFd}|d7}q|t|kr\d||fS|rj|d|||ddkr|ds||dfS|||ddkr|ddddkr|ddd|||d|d<||dfS|d|||d7<||dfS) NFr$,Trrzr@r )r0isspacerK)partsrEoffsetZ whitespace) _parse_plain _parse_quoterrrrs&     ($zparselist.._parse_plaincs|t|krz|||ddkrz|d|d7}|t|krp|||dsf|||ddkrp|d7}q2||fS|t|kr|||ddkr|||ddkr|dt|kr||d|ddkr|d7}|dd7<n|d|||d7<|d7}qz|t|krt|d}|sDd|d<n&d|d|d<|dd}||d||fS|d7}|t|kr|||dd vr|d7}q||t|kr|dt|kr|||ddkr|dd7<|d7}n |dn d||fS||fS) Nr$rzrrr rr@r)r&r)r0rKrextend)rrErZ real_parts) _configlistrrrrsN     $      $ (   zparselist.._parse_quotecs@|d}|sgSdgd}}}|r<||||\}}}q$|S)Ns ,rr)rL)rEparserrr)rrrrs zparselist.._configlistNs , )rrr)valueresultr)rrrr parselistks0 rcCs tjrt|dSt|S)z8Evaluate a string containing a Python literal expressionr )rZispy3astZ literal_evalr rTrrrevalpythonliteralsr)Frr)Frr)T)r)r)rr)5Z __future__rrrrerarr6Zi18nrZ thirdpartyrrrrrrZ _respecialrZregexbytesescapemaprr"r rNrQrUr[rmrorvrwryr}rEobjectrrrrrcrrrr,rrerrrrrrrrrrr sj      I = 4  S0   l Z