o aЗ@sXdZddlZddlZddlZddlZddlZzddlZWn ey%Ynwz-ddl m Z m Z m Z m Z mZmZmZmZmZmZmZmZeeeeee ee efZWn ey\YnwddlmZGdddeZGdddeZGd d d eZGd d d eZe d ddiej!Z"e dZ#e dZ$e dZ%e dZ&e dZ'e dej!Z(e dej!Z)e dej!Z*e dej!Z+e dej!Z,e dZ-e dZ.e dZ/e dej!Z0e dej!Z1e dZ2e d Z3e d!ej!Z4e d"ej!Z5e d#ej!Z6e d$ej!Z7e d%ej!Z8e d&Z9Gd'd(d(eZ:d)d*Z;d.d,d-Z`_ 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: ... 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)Versionc,eZdZdZdZfddZddZZS)ChangelogParseErrorz0Indicates that the changelog could not be parsedTc||_tt|dSN)_linesuperr__init__selfline __class__2/usr/lib/python3/dist-packages/debian/changelog.pyrzChangelogParseError.__init__cC d|jS)NzCould not parse changelog: )rrrrr__str__ zChangelogParseError.__str____name__ __module__ __qualname____doc__ is_user_errorrr __classcell__rrrrrs  rc@seZdZdZdS)ChangelogCreateErrorz`Indicates that changelog could not be created, as all the information required was not givenN)r#r$r%r&rrrrr)sr)cr) VersionErrorzBIndicates that the version does not conform to the required formatTcrr)_versionrr*rrversionrrrrrzVersionError.__init__cCr)NzCould not parse version: )r+rrrrr s zVersionError.__str__r"rrrrr*s  r*c@seZdZdZ          d!ddZddZdd Zeeed d Zd d Z ddZ ddZ ddZ ddZ eddZeddZd"ddZddZdd ZdS)# 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. Nutf-8c Csld|_||||_||_|pd|_|pd|_|pg|_||_||_g|_ | p)i|_ | |_ d|_ d|_ dS)NunknownF ) _raw_version _set_versionpackage distributionsurgencyurgency_comment_changesauthordate _trailing other_pairs _encoding _no_trailer_trailer_separator) rr5r-r6r7r8changesr:r;r=encodingrrrrs      zChangeBlock.__init__cCs|jdurdSt|jSr)r3rrrrr _get_versions  zChangeBlock._get_versioncCs |dur t||_dSd|_dSr)strr3r,rrrr4s zChangeBlock._set_versionz/The package version that this block pertains todoccCsZi}|jD]#\}}|d|dd}t|}|dur&d|}|||<q|S)z: Obtain a dict from the block header (other than urgency) rNzXS-%s)r=itemsupperlowerxbcs_rematch)r norm_dictkeyvaluemrrrother_keys_normaliseds  z!ChangeBlock.other_keys_normalisedcC|jS)z; Get the changelog entries for this block as a list of str )r9rrrrrAszChangeBlock.changescCs|j|dS)z, Add a sign-off (trailer) line to the block N)r<appendrrrradd_trailing_line zChangeBlock.add_trailing_linecCs||js |g|_dS|j}|d}t|D]\}}t|}|dur-|||d}nq||s9||||_dS)z$ Append a change entry to the block FNT)r9reverse enumerate blanklinerLinsertrS)rchangerAaddedich_entryrPrrr add_changes      zChangeBlock.add_changecCsTd|j}g}||D]}|d}td|D] }|t|dqq |S)N rz\d+)joinr9finditergrouprerSint)rtype_rerAbugsrL closes_listbugmatchrrr_get_bugs_closed_generic%s  z$ChangeBlock._get_bugs_closed_genericcC |tS)z+ List of (Debian) bugs closed by the block )riclosesrrrr bugs_closed/ zChangeBlock.bugs_closedcCrj)z, List of Launchpad bugs closed by the block )ricloseslprrrrlp_bugs_closed5rmzChangeBlock.lp_bugs_closedFcCshd}|jdur td||jd7}|jdurtd|d|jd7}|jdur-td||jd7}|jdur=td |d |j|j7}|jD] \}}|d ||f7}qL|d 7}|durgtd |D]}||d 7}qk|j s|d7}|j dur|d|j 7}n|std|j dur||j |j 7}n|std|d 7}|j D]}||d 7}q|S)Nr1zPackage not specifiedr_zVersion not specified(z) zDistribution not specifiedz; zUrgency not specifiedzurgency=z, %s=%s zChanges not specifiedz --zAuthor not specifiedzDate not specified)r5r)r3r6r7r8r=rHrAr?r:r;r@r<)rallow_missing_authorblockrNrOrZrrrr_format;sD         zChangeBlock._formatcC|Srrtrrrrr azChangeBlock.__str__cCt||jSrrDencoder>rrrr __bytes__erUzChangeBlock.__bytes__) NNNNNNNNNr/F)r#r$r%r&rrCr4propertyr-rQrArTr^rirlrortr r{rrrrr.s>      & r.z?^(\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*$c@seZdZdZ     dIddZeddZ   dJd d Zd d ZddZ e ee ddZ e ddddZ e ddddZ e ddddZe ddddZe ddddZddZddZe eed dZd!d"Ze d#d$Zd%d&ZdKd'd(Zd)d*Zd+d,Zd-d.Zd/d0Zd1d2Zd3d4Ze d5ded6dZd7d8Ze d9ded:dZ d;d<Z!d=d>Z"e d?de"d@dZ#dAdBZ$e dCde$dDdZ%          dLdEdFZ&dGdHZ'dS)M 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``. NFr/cCs4||_g|_g|_|dur|j||||ddSdS)N) max_blocksallow_empty_authorstrict)r>_blocksinitial_blank_linesparse_changelog)rfilerrrrBrrrrs zChangelog.__init__cCs|rt|t|dSr)rwarningswarn)messagerrrr _parse_errorszChangelog._parse_errorTc#Cs$d}d}d}d} d} |p|j}|dur|d|dSg|_g|_t|d} g} |} d}t|tr6||}t|trK| sG|d|dS| }|D]}t|tsZ||}| d }| ||fvrt |}t |}|dur|durt|j|krdS|d | _|d | _|d | _|d d d }i}i}|dD]i}| }t |}|dur|d||q|d }|d }||vr|d|||||<|dkr t |}|dur|d||q|d | _|d }|dur || _q|||<q|| _|} qM|dur2| |kr)|j|qM|jd|qMt |}t |}t |}t! |}t" |}|dusU|durg| |krg|jd|| }| } qM|dusv|dusv|dur| |kr|j|n|jd|qMt# |dust$ |dust% |dust& |dust' |dust( |dust) |dust* |dur| |kr|jd|| }| } qM|d| |f|| |kr|j|qM|jd|qM| || fvrt+ |} t, |}!t- |}"t |}| dur$| || } qM|!dure|!d dkr?|d|||!d | _.d|!d |!d f| _/|!d| _0| | _1|j| g} t|d} |} qM|"dur|sv|d||qM| | _1|j| g} t|d} |} qM|dur| |qMt |}t! |}t" |}|dus|dus|dur| |qM|d| |f|| |qM| | kr||kr|jd|qM| |qMJd| | || fvs| | kr||kr|d| || | _1d| _2|j| dSdSdS)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.rBrqrG;,z$Invalid key-value pair after ';': %szRepeated key-value: %sr7z!Badly formatted urgency value: %sz(Unexpected line while looking for %s: %sr2z Badly formatted trailer line: %sz%s <%s>FzUnknown state: %szFound eof where expected %sT)3r>rrrr. isinstancebytesdecoderDstrip splitlinesrstriptoplinerLrXlenrbr5r3lstripr6splitkeyvaluerJvalue_rer7r8r=rSrTemacs_variables vim_variables cvs_keywordcomments more_commentsold_format_re1old_format_re2old_format_re3old_format_re4old_format_re5old_format_re6old_format_re7old_format_re8changereendlineendline_nodetailsr@r:r;r9r?)#rrrrrrB first_headingnext_heading_or_eofstart_of_change_datamore_changes_or_trailer slurp_to_end current_blockrAstate old_stater top_match blank_matchpairsall_keysr=pairkv_matchrNrO val_matchcomment emacs_match vim_match cvs_matchcomments_matchmore_comments_match change_match end_matchend_no_details_matchrrrrsp                                                                  zChangelog.parse_changelogcC |jdjS)z,Return a Version object for the last versionr)rr-rrrr get_version zChangelog.get_versioncCst||jd_dS)zwSet the version of the last changelog block version can be a full version string, or a Version object rN)rrr-r,rrr set_versionszChangelog.set_versionzhVersion object for latest changelog block. (Property that can both get and set the version.)rEcC|jjSr)r- full_versionrrrrzChangelog.z+The full version number of the last versioncCrr)r-epochrrrrrrzFThe epoch number of the last revision, or `None` if no epoch was used.cCrrr-debian_revisionrrrrrrz:The debian part of the version number of the last version.cCrrrrrrrrrcCrr)r-upstream_versionrrrrrrzz&Changelog.versions..rrrrrrszChangelog.versionscCr)NcSrr)r3rrrrrrz+Changelog._raw_versions..rrrrr _raw_versionszChangelog._raw_versionscCsFg}|jD] }||dq|jD] }||j|dqd|S)Nrq)rrr1)rrSrrtr`)rrrpiecesrrsrrrrts    zChangelog._formatcCrurrvrrrrr rwzChangelog.__str__cCrxrryrrrrr{rUzChangelog.__bytes__cC t|jSr)iterrrrrr__iter__r!zChangelog.__iter__cCs<t|tr |t|St|tr|}n|j|}|j|S)z select a changelog entry by number, version string, or Version :param n: integer or str representing a version or Version object )rrDrrdrindexr)rnidxrrr __getitem__s     zChangelog.__getitem__cCrr)rrrrrr__len__&r!zChangelog.__len__cC||jd_dSNrrr6)rr6rrrset_distributions*rzChangelog.set_distributionscCrrrrrrrr/ zfA string indicating the distributions that the package will be uploaded to in the most recent version.cCrrrr7)rr7rrr set_urgency5rzChangelog.set_urgencycCrrrrrrrr:rzTA string indicating the urgency with which the most recent version will be uploaded.cCs|jd|dS)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)rr^)rrZrrrr^@s zChangelog.add_changecCr)z+ set the author of the top changelog entry rNrr:)rr:rrr set_authorMrUzChangelog.set_authorcCrrrrrrrrSrzj The author of the most recent change. This should be a properly formatted name/email pair.cCr)z set the date of the top changelog entry :param date: str a properly formatted date string (`date -R` format; see Policy) rNrr;)rr;rrrset_dateYszChangelog.set_datecCrrrrrrrrcrz 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 Cs@| p|j} t||||||||| | } | d|jd| dS)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. r1rN)r>r.rTrrY) rr5r-r6r7r8rAr:r;r=rBrsrrr new_blockjs   zChangelog.new_blockcCs||dS)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)writer )r filehandlerrrwrite_to_open_fileszChangelog.write_to_open_file)NNFFr/)NFTNr|) NNNNNNNNNN)(r#r$r%r&r staticmethodrrrrr}r-rrdebian_versionrrrrr5rrrrtr r{rrrrr6rr7r^rr:rr;rrrrrrrs9   K        rc Cstj}d|vr"t|d}|r"d|vr|d|d<|d|d<d|vs*d|vrId|vrIt|d}|rId|vrB|d|d<|d|d<d}d|vrT|d}n%d|vr]|d}nztdd tt j }Wn t t t fyxYnwd}d|vr|d}||fSd|vr|d}||fSd}tjd rtd d d }|}Wdn1swY|st}|rz tt j}Wn t t fyd}Yn w|sd}nd ||f}|r|}||fS)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 DEBFULLNAMErGrEMAILNNAMEz,.*r1z /etc/mailnamezUTF-8rz%s@%s)osenviron maintainerrerLrbrcsubpwdgetpwuidgetuidpw_gecosKeyErrorAttributeError NameErrorpathexistsopenreadlinersocketgetfqdnpw_name)env match_obj maintainer email_addressaddrfuserrrrget_maintainersd    rTcCstj||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 localtimerrr format_dates r)NT)=r& email.utilsrrrcrrr ImportErrortypingrrrrrrrr r r r r rIterableDataSourcedebian.debian_supportr Exceptionrr)r*objectr.compile IGNORECASErrXrrrrrrrKrrrrrrkrnrrrrrrrrrrrrrrrsc  8  <       wM