CfcgdZddlZddlZddlZddlZddlZ ddlZ ddl m Z m Z m Z m Z mZmZmZmZmZmZmZmZeeeeee ee efZddlmZej4dZGddeZGdd eZGd d eZGd d e Z!ejDdddizejFZ$ejDdZ%ejDdZ&ejDdZ'ejDdZ(ejDdZ)ejDdejFZ*ejDdejFZ+ejDdejFZ,ejDdejFZ-ejDdejFZ.ejDdZ/ejDdZ0ejDdZ1ejDdejFZ2ejDdejFZ3ejDd Z4ejDd!Z5ejDd"ejFZ6ejDd#ejFZ7ejDd$ejFZ8ejDd%ejFZ9ejDd&ejFZ:ejDd'Z;Gd(d)e Zy#e$rYwxYw#e$rYwxYw)-a Facilities for reading and writing Debian changelogs The aim of this module is to provide programmatic access to Debian changelogs to query and manipulate them. The format for the changelog is defined in `deb-changelog(5) `_ Stability: The API is not marked as stable but hasn't changed incompatibly since 2007. Potential users of these classes are asked to work with the `python-debian` maintainers to improve, extend and stabilise this API. Overview ======== Create a changelog object using the constuctor. Pass it the contents of the file if there are some entries, or ``None`` to create an empty changelog:: >>> import debian.changelog >>> ch = debian.changelog.Changelog() >>> maintainer, email = 'John Doe', 'joe@example.com' >>> timestamp = 1617222715 >>> # You might want to use get_maintainer() a la: >>> # maintainer, email = debian.changelog.get_maintainer() >>> ch.new_block( ... package='example', ... version='0.1', ... distributions='unstable', ... urgency='low', ... author="%s <%s>" % (maintainer, email), ... # You can also omit timestamp, if you are fine with "now" ... # We use a hard-coded timestamp for deterministic output ... date=debian.changelog.format_date(timestamp=1617222715, localtime=False) ... ) >>> ch.add_change('') >>> ch.add_change(' * Some change') >>> ch.add_change('') >>> print(ch, end='') example (0.1) unstable; urgency=low * Some change -- John Doe Wed, 31 Mar 2021 20:31:55 -0000 If you have the full contents of a changelog, but are only interested in the most recent versions you can pass the ``max_blocks`` keyword parameter to the constuctor to limit the number of blocks of the changelog that will be parsed. If you are only interested in the most recent version of the package then pass ``max_blocks=1``:: >>> import gzip >>> from debian.changelog import Changelog >>> with gzip.open('/usr/share/doc/dpkg/changelog.Debian.gz') as fh: # doctest: +SKIP ... ch = Changelog(fh, max_blocks=1) >>> print(''' ... Package: %s ... Version: %s ... Urgency: %s''' % (ch.package, ch.version, ch.urgency)) # doctest: +SKIP Package: dpkg Version: 1.18.24 Urgency: medium See `/usr/share/doc/python-debian/examples/changelog/` or the `git repository `_ for examples of usage. The :class:`Changelog` class is the key class within this module. Changelog Classes ----------------- N) AnyDictIterableIteratorIOListOptionalPatternUnionTextTupleTypeVar)Versionzdebian.changelogc,eZdZdZdZfdZdZxZS)ChangelogParseErrorz0Indicates that the changelog could not be parsedTc8||_tt|yN)_linesuperr__init__)selfline __class__s 2/usr/lib/python3/dist-packages/debian/changelog.pyrzChangelogParseError.__init__s  !413c d|jzS)NzCould not parse changelog: )rrs r__str__zChangelogParseError.__str__s,TZZ77r__name__ __module__ __qualname____doc__ is_user_errorrr __classcell__rs@rrrs:M4 8rrceZdZdZy)ChangelogCreateErrorz`Indicates that changelog could not be created, as all the information required was not givenN)r r!r"r#rrr(r(srr(c,eZdZdZdZfdZdZxZS) VersionErrorzBIndicates that the version does not conform to the required formatTc8||_tt|yr)_versionrr+r)rversionrs rrzVersionError.__init__s  lD*,rc d|jzS)NzCould not parse version: )r-rs rrzVersionError.__str__s*T]]::rrr&s@rr+r+sLM- ;rr+ceZdZdZ ddZdZdZeeedZdZ d Z d Z d Z d Z ed ZedZddZdZdZy) ChangeBlocka!Holds all the information about one block from the changelog. See `deb-changelog(5) `_ for more details about the format of the changelog block and the necessary data. :param package: str, name of the package :param version: str or Version, version of the package :param distributions: str, distributions to which the package is released :param urgency: str, urgency of the upload :param urgency_comment: str, comment about the urgency setting :param changes: list of str, individual changelog entries for this block :param author: str, name and email address of the changelog author :param date: str, date of the changelog in RFC822 (`date -R`) format :param other_pairs: dict, key=value pairs from the header of the changelog, other than the urgency value that is specified separately :param encoding: specify the encoding to be used; note that Debian Policy mandates the use of UTF-8. Nc d|_|j|||_||_|xsd|_|xsd|_|xsg|_||_||_g|_ | xsi|_ | |_ d|_ d|_ y)NunknownF ) _raw_version _set_versionpackage distributionsurgencyurgency_comment_changesauthordate _trailing other_pairs _encoding _no_trailer_trailer_separator) rr8r.r9r:r;changesr=r>r@encodings rrzChangeBlock.__init__s! '" *+) .4" 2   &,"! "&rcF|jyt|jSr)r6rrs r _get_versionzChangeBlock._get_versions"    $t(())rc8|t||_yd|_yr)strr6rr.s rr7zChangeBlock._set_versions   #G D  $D rz/The package version that this block pertains todocci}|jjD]M\}}|dj|ddjz}tj |}|d|z}|||<O|S)z: Obtain a dict from the block header (other than urgency) rNzXS-%s)r@itemsupperlowerxbcs_rematch)r norm_dictkeyvaluems rother_keys_normalisedz!ChangeBlock.other_keys_normalisedsx  ,,224 #LS%a&,,.3qr7==?2C c"Aym"IcN  # rc|jS)z; Get the changelog entries for this block as a list of str )r<rs rrDzChangeBlock.changess}}rc:|jj|y)z, Add a sign-off (trailer) line to the block N)r?append)rrs radd_trailing_linezChangeBlock.add_trailing_line s d#rc>|js |g|_y|j}|jd}t|D]2\}}tj |}||j ||d}n|j|s|j |||_y)z$ Append a change entry to the block FNT)r<reverse enumerate blanklinerSinsertr[)rchangerDaddedich_entryrWs r add_changezChangeBlock.add_changes}}#HDMmmG OO E(1  8OOH-9NN1f- E   OO v&#DMrc dj|j}g}|j|D]W}|jd}t jd|D]+}|j t |jd-Y|S)N rz\d+)joinr<finditergrouprer[int)rtype_rerDbugsrS closes_listbugmatchs r_get_bugs_closed_genericz$ChangeBlock._get_bugs_closed_generic's{((4==)%%g. 4E++a.KKK < 4 Cq 123 4 4 rc,|jtS)z+ List of (Debian) bugs closed by the block )rrclosesrs r bugs_closedzChangeBlock.bugs_closed1s,,V44rc,|jtS)z, List of Launchpad bugs closed by the block )rrcloseslprs rlp_bugs_closedzChangeBlock.lp_bugs_closed7s,,X66rchd}|j td||jdzz }|j td|d|jzdzz }|j td||jdzz }|j td |d |jz|j zz }|j jD]\}}|d |d |z }|d z }|j td|jD] }||d zz } |jsl|dz }|j|d|jzz }n |s td|j||j|jzz }n |s td|d z }|jD] }||d zz } |S)Nr4zPackage not specifiedrhzVersion not specified(z) zDistribution not specifiedz; zUrgency not specifiedzurgency=z, = zChanges not specifiedz --zAuthor not specifiedzDate not specified)r8r(r6r9r:r;r@rOrDrBr=r>rCr?)rallow_missing_authorblockrUrVrbrs r_formatzChangeBlock._format=s << &'>? ? ##    $&'>? ? t(((4//    %&'CD D ##d** << &'>? ? dll*T-A-AAA ,,224 .LS% #u- -E .   <<> !&'>? ?lln #F Vd] "E # UNE{{&t{{**)*+ABByy$00499<<)*+?@@ TMENN !D TD[ E ! rc"|jSrrrs rrzChangeBlock.__str__c||~rcJt|j|jSrrIencoderArs r __bytes__zChangeBlock.__bytes__g4y//r) NNNNNNNNNutf-8F)r r!r"r#rrGr7propertyr.rXrDr\rfrrrurxrrrr)rrr1r1s2#!%!!'8* %l =G  $ $,55 77 $L0rr1z?^(\w%(name_chars)s*) \(([^\(\) \t]+)\)((\s+%(name_chars)s+)+)\; name_charsz [-+0-9a-z.]z^\s*$z ^\s\s+.*$z[^ -- (.*) <(.*)>( ?)((\w+\,\s*)?\d{1,2}\s+\w+\s+\d{4}\s+\d{1,2}:\d\d:\d\d\s+[-+]\d{4}\s*)$z`^ --(?: (.*) <(.*)>( ?)((\w+\,\s*)?\d{1,2}\s+\w+\s+\d{4}\s+\d{1,2}:\d\d:\d\d\s+[-+]\d{4}))?\s*$z^(.*)\s+<(.*)>$z^([-0-9a-z]+)=\s*(.*\S)$z^([-0-9a-z]+)((\s+.*)?)$z ^X[BCS]+-z^(;;\s*)?Local variables:z^vim:z ^\$\w+:.*\$z^\# z ^/\*.*\*/z5closes:\s*(?:bug)?\#?\s?\d+(?:,\s*(?:bug)?\#?\s?\d+)*zlp:\s+\#\d+(?:,\s*\#\d+)*zW^(\w+\s+\w+\s+\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}\s+[\w\s]*\d{4})\s+(.*)\s+(<|\()(.*)(\)|>)z:^(\w+\s+\w+\s+\d{1,2},?\s*\d{4})\s+(.*)\s+(<|\()(.*)(\)|>)z&^(\w[-+0-9a-z.]*) \(([^\(\) \t]+)\)\;?z"^([\w.+-]+)(-| )(\S+) Debian (\S+)z#^Changes from version (.*) to (.*):z$^Changes for [\w.+-]+-[\w.+-]+:?\s*$z^Old Changelog:\s*$z^(?:\d+:)?\w[\w.+~-]*:?\s*$ceZdZdZ d.dZedZ d/dZdZdZ e ee d Z e d d Z e d d Z e dd Ze dd Ze dd ZdZdZe eed ZdZe dZdZd0dZdZdZdZdZdZdZe d ed! Zd"Ze d#ed$ Z d%Z!d&Z"e d'e"d( Z#d)Z$e d*e$d+ Z% d1d,Z&d-Z'y)2 ChangelogaL Represents a debian/changelog file. To get the properly formatted changelog back out of the object merely call `str()` on it. The returned string should be a properly formatted changelog. :param file: str, list of str, or file-like. The contents of the changelog, either as a ``str``, ``unicode`` object, or an iterator of lines such as a filehandle, (each line is either a ``str`` or ``unicode``) :param max_blocks: int, optional (Default: ``None``, no limit) The maximum number of blocks to parse from the input. :param allow_empty_author: bool, optional (Default: `False`), Whether to allow an empty author in the trailer line of a change block. :param strict: bool, optional (Default: ``False``, use a warning) Whether to raise an exception if there are errors. :param encoding: str, If the input is a str or iterator of str, the encoding to use when interpreting the input. There are a number of errors that may be thrown by the module: - :class:`ChangelogParseError`: Indicates that the changelog could not be parsed, i.e. there is a line that does not conform to the requirements, or a line was found out of its normal position. May be thrown when using the method `parse_changelog`. The constructor will not throw this exception. - :class:`ChangelogCreateError`: Some information required to create the changelog was not available. This can be thrown when `str()` is used on the object, and will occur if a required value is `None`. - :class:`VersionError`: The string used to create a Version object cannot be parsed as it doesn't conform to the specification of a version number. Can be thrown when creating a Changelog object from an existing changelog, or instantiating a Version object directly to assign to the version attribute of a Changelog object. If you have a changelog that may have no author information yet as it is still a work in progress, i.e. the author line is just:: -- rather than:: -- Author Thu, 12 Dec 2006 12:23:34 +0000 then you can pass ``allow_empty_author=True`` to the Changelog constructor. If you do this then the ``author`` and ``date`` attributes may be ``None``. Nc^||_g|_g|_||j||||yy)N) max_blocksallow_empty_authorstrict)rA_blocksinitial_blank_linesparse_changelog)rfilerrrrEs rrzChangelog.__init__sC" #%    #5 !  rcH|r t|tj|yr)rloggerwarning)messagers r _parse_errorzChangelog._parse_errors %g. .wrcd}d}d}d} d} |xs |j}||jd|yg|_g|_t |} g} |} d}t |t r|j|}t |tr3|js|jd|y|j}|D]}t |ts|j|}|jd }| ||fvrAtj|}tj|}||t|j|k\ry|j!d | _|j!d | _|j!d j'| _|j+d d d }i}i}|j+dD]#}|j}t,j|}||jd|z|A|j!d }|j!d }|j/|vr#|jd|j/z||||j/<|j/dk(rat0j|}||jd|z||j!d | _|j!d }||| _|||<&|| _|} 2|B| |k(r|jj9|V|jdj;|vt<j|}t>j|}t@j|}tBj|}tDj|}||)| |k7r$|jdj;|| }| }  |||A| |k(r|jj9|n|jdj;|StFj|tHj|~tJj|itLj|TtNj|?tPj|*tRj|tTj|)| |k7r$|jdj;|| }| } $|jd| d||| |k(r|jj9|^|jdj;|~| || fvrtVj|} tXj|}!tZj|}"tj|}| | j9|| } |!|!j!d dk7r+|jd|z||!j!d | _.|!j!d d|!j!d d| _/|!j!d| _0| | _1|jj9| g} t |} |} |"M|s|jd|z|| | _1|jj9| g} t |} |} || j9| t@j|}tBj|}tDj|}|||| j9|b|jd| d||| j9|| | k(r8||k(r |jdj;|| j9|Jd| z| || fvs | | k(rE||k7r?|jd| z|| | _1d| _2|jj9| yyy)ag Read and parse a changelog file If you create an Changelog object without specifying a changelog file, you can parse a changelog file with this method. If the changelog doesn't parse cleanly, a :class:`ChangelogParseError` exception is thrown. The constructor will parse the changelog on a best effort basis. z first headingznext heading of EOFzstart of change datazmore change data or trailerz slurp to endNzEmpty changelog file.rEr|rN;,z$Invalid key-value pair after ';': %szRepeated key-value: %sr:z!Badly formatted urgency value: %sz"Unexpected line while looking for z: r5z Badly formatted trailer line: %sz <>zUnknown state: %szFound eof where expected %sT)3rArrrr1 isinstancebytesdecoderIstrip splitlinesrstriptoplinerSr`lenrkr8r6lstripr9splitkeyvaluerQvalue_rer:r;r@r[r\emacs_variables vim_variables cvs_keywordcomments more_commentsold_format_re1old_format_re2old_format_re3old_format_re4old_format_re5old_format_re6old_format_re7old_format_re8changereendlineendline_nodetailsrCr=r>r<rB)#rrrrrrE first_headingnext_heading_or_eofstart_of_change_datamore_changes_or_trailer slurp_to_end current_blockrDstate old_stater top_match blank_matchpairsall_keysr@pairkv_matchrUrV val_matchcomment emacs_match vim_match cvs_matchcomments_matchmore_comments_match change_match end_matchend_no_details_matchs# rrzChangelog.parse_changelogsi ( 35"?% -t~~ <   5v >  #% #X6  dE ";;x(D dC ::<!!"96B??$DR :DdC({{8,;;t$D(;<<#MM$/ 'ood3 (". #DLL 1Z ?,5OOA,>M)1:1CM.2;//!2D2K2K2MM/ JJsA.q1E!H"$K % C 05#zz|#+>>$#7#+ -- F M &(%&nnQ/ (q 199;(2 --!%'*yy{!34:<16-99;)3(0u(=I(0 $ 1 1$G$)%*+1!39B8J 5*3//!*<#*#6DKM$A/4K,7581 M1 44;;DA LL,>>tD '--d3?*006B*006B*006B*006B*006B*006B*006B % 6 R(::4@$) , %%&'-/ -0077= R(::4@/1HII'~~d3 #MM$/ '8'>'>t'D$'ood3 +NN4(3E* q)T1))>EvO;D??1;M 8$??1-yq/A,CM()2);M&-4M*LL'' 6 G$/$BM/E)5-))>EvO -4M*LL'' 6 G$/$BM/E ,NN4( + 1 1$ 7I%-^^D%9N*7*=*=d*C'!-1K2>t, %%&'-/NN4(,& 33LL$66t<NN4(91E99ueR :h -|< <\)!%88   -5v ?%,M "(,M % LL   . 9*rc4|jdjS)z,Return a Version object for the last versionrrr.rs r get_versionzChangelog.get_version||A&&&rc>t||jd_y)zwSet the version of the last changelog block version can be a full version string, or a Version object rN)rrr.rJs r set_versionzChangelog.set_versions #*'"2 QrzhVersion object for latest changelog block. (Property that can both get and set the version.)rKc.|jjSr)r. full_versionrs rzChangelog.sT\\..rz+The full version number of the last versionc.|jjSr)r.epochrs rrzChangelog.sT\\''rzFThe epoch number of the last revision, or `None` if no epoch was used.c.|jjSrr.debian_revisionrs rrzChangelog.T\\11rz:The debian part of the version number of the last version.c.|jjSrrrs rrzChangelog.rrc.|jjSr)r.upstream_versionrs rrzChangelog.sT\\22rz1sT\\!_22rzfA string indicating the distributions that the package will be uploaded to in the most recent version.c,||jd_yrrr:)rr:s r set_urgencyzChangelog.set_urgency7s") Qrc4|jdjSrr rs rrzChangelog.<sT\\!_,,rzTA string indicating the urgency with which the most recent version will be uploaded.c@|jdj|y)a and a new dot point to a changelog entry Adds a change entry to the most recent version. The change entry should conform to the required format of the changelog (i.e. start with two spaces). No line wrapping or anything will be performed, so it is advisable to do this yourself if it is a long entry. The change will be appended to the current changes, no support is provided for per-maintainer changes. rN)rrf)rrbs rrfzChangelog.add_changeBs Q""6*rc,||jd_y)z+ set the author of the top changelog entry rNrr=)rr=s r set_authorzChangelog.set_authorOs"( Qrc4|jdjSrrrs rrzChangelog.UsT\\!_++rzj The author of the most recent change. This should be a properly formatted name/email pair.c,||jd_y)z set the date of the top changelog entry :param date: str a properly formatted date string (`date -R` format; see Policy) rNrr>)rr>s rset_datezChangelog.set_date[s $ Qrc4|jdjSrrrs rrzChangelog.esT\\!_))rz The date associated with the current entry. Should be a properly formatted string with the date and timezone. See the :func:`format_date()` function.c | xs |j} t||||||||| | } |jr| jd|jj d| y)a Add a new changelog block to the changelog Start a new :class:`ChangeBlock` entry representing a new version of the package. The arguments (all optional) are passed directly to the :class:`ChangeBlock` constructor; they specify the values that can be provided to the `set_*` methods of this class. If they are omitted the associated attributes *must* be assigned to before the changelog is formatted as a str or written to a file. r4rN)rAr1rr\ra) rr8r.r9r:r;rDr=r>r@rEr~s r new_blockzChangelog.new_blockls^,-t~~GWm#_#VT;J <<  # #B ' Au%rc8|jt|y)z Write the changelog entry to a filehandle Write the changelog out to the filehandle passed. The file argument must be an open file object. N)writerI)r filehandles rwrite_to_open_filezChangelog.write_to_open_files T#r)NNFFr)NFTNr) NNNNNNNNNN)(r r!r"r#r staticmethodrrrrrr.rrdebian_versionrrrrr8rrrrrrrrrrr9r r:rfrr=rr>rrr)rrrrs5r $)! "  $(+0#!% H/T' 3[ AG. 9L '  E 1 HN1 HO 2 J ' * [ 5G 99 >0 " !!624E M*,k G +( +Z @F$ )8 3 D $"&"&>$rrc.tj}d|vrFtj|d}|r,d|vr|j d|d<|j d|d<d|vsd|vrJd|vrFtj|d}|r,d|vr|j d|d<|j d|d<d}d|vr|d}nQd|vr|d}nG t j dd tjtjj}d}d|vr |d}||fSd|vr |d}||fSd}tjjd r4t!d d 5}|j#j%}ddd|st'j(}|r? tjtjj*}|sd}n|d |} |r|}||fS#tttf$rYwxYw#1swYxYw#ttf$rd}YAwxYw)aGet the maintainer information in the same manner as dch. This function gets the information about the current user for the maintainer field using environment variables of gecos information as appropriate. It uses the same algorithm as dch to get the information, namely DEBEMAIL, DEBFULLNAME, EMAIL, NAME, /etc/mailname and gecos. :returns: a tuple of the full name, email pair as strings. Either of the pair may be None if that value couldn't be determined. DEBEMAIL DEBFULLNAMErNrEMAILNNAMEz,.*r4z /etc/mailnamezUTF-8r@)osenviron maintainerrerSrkrlsubpwdgetpwuidgetuidpw_gecosKeyErrorAttributeError NameErrorpathexistsopenreadlinersocketgetfqdnpw_name)env match_obj maintainer email_addressaddrfusers rget_maintainerr>s' **CS &&s:7 C'%.__Q%7M"'ooa0C O S 8 c>$**3w<8I +)2);C &(q1G J' 3[  CLL,E,N,NOJ MSJ 2  &&1 CG .  &&+ 77>>/ *o8 ,Azz|))+ ,>>#D  2||BIIK088 D&*D1D  M  &&?.)4    , ,#I.  s1AGG41HG10G14G=HHcBtjj||S)a format a datestamp in the required format for the changelog :param timestamp: float, optional. The timestamp (seconds since epoch) for which the date string should be created. If not specified, the current time is used. :param localtime: bool, optional (default True). Use the local timezone in the date string. :returns: str, date stamp formatted according to the changelog specification (i.e. RFC822). )emailutils formatdate) timestamp localtimes r format_daterEs ;; ! !)Y 77r)NT)?r# email.utilsr@loggingr%rlr4r) ImportErrortypingrrrrrrr r r r r rrIterableDataSourcedebian.debian_supportr getLoggerr Exceptionrr(r+objectr1compile IGNORECASErr`rrrr'rrrRrrrrrrtrwrrrrrrrrrr>rEr)rrrQs$JD           4  *   - . 8) 89 ;9 ;x0&x0v "**!]#$MM   BJJx 2::l # "**2 3BJJrzz,- 2::12== A 2::12== A "**["-- 0"**92==I 7BMM2 bjj( 2::g  <( <MM  2::2BMM B23-MM)MM)MM+MM2BMMB:;s$s$lJ'Z 8m  6  s"K'/K3'K0/K03K<;K<