B
    %dq                 @   sn  d dl Z d dlZd dlmZmZ d dlmZ d dlmZm	Z	m
Z
mZ d dlmZ d dlmZ ddlmZ dd	lmZ dd
lmZmZmZmZmZmZ d dlmZmZmZmZmZ d dl Z d dl!m"Z" d dl#Z#d dl$m%Z% d dl&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0 d dl1m2Z2m3Z3 e.r6d dl4m5Z5 d dl6m7Z7 e#8dZ9e9:e#;  dZ<G dd dej=eeeZ>dS )    N)PopenPIPE)IStream)
hex_to_binActorStatsfinalize_process)Diffable)Git   )Tree)base)SerializableTraversableIterableObj
parse_datealtz_to_utctz_strparse_actor_and_datefrom_timestamp)timedaylightaltzonetimezone	localtime)BytesIO)defaultdict)
AnyIOIteratorListSequenceTupleUnionTYPE_CHECKINGcastDict)PathLikeLiteral)Repo)SymbolicReferencezgit.objects.commit)Commitc                   s  e Zd ZU dZdZdZdZdZdZe	d e
d< dZd	ZdEdeeed
f eed
f eed
f ed
ef eed
f eed
f ed
ef eeed
f eed  d
f eed
f eed
f d
d fddZed ed dddZedd edddZed dddZed
d fddZeejdddZeejddd Z eeeef dd!d"Z!dFee"ee" f eed$d%d&Z#eedd'd(Z$edGdeed d)f ee"ee" f ee%d  d*d+d,Z&dHee"ee" f ee%d  d$d-d.Z'ee(dd/d0Z)ee*eef dd1d2Z+ee,eeef  dd3d4Z-ee*ee,e f dd5d6Z.edee/e0f e%d  d7d8d9Z1edIdeeef eed
e,d  f e2ed
ef ed
ef ed
eejf ed
eejf d d;
d<d=Z3e4d d>d?d@Z5e4d d>dAdBZ6ee,e ddCdDZ7  Z8S )Jr)   zWraps a git Commit object.

    This class will act lazily on some of its attributes and will query the
    value on demand only if it involves calling the git binary.ZGIT_AUTHOR_DATEZGIT_COMMITTER_DATEzi18n.commitencodingzUTF-8committype)treeauthorauthored_dateauthor_tz_offset	committercommitted_datecommitter_tz_offsetmessageparentsencodinggpgsighexshaNr'   )repobinshar,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   returnc                s   t t| || || _|dk	r:t|ts:tdt| |dk	rH|| _|dk	rV|| _	|dk	rd|| _
|dk	rr|| _|dk	r|| _|dk	r|| _|	dk	r|	| _|
dk	r|
| _|dk	r|| _|dk	r|| _|dk	r|| _dS )a  Instantiate a new Commit. All keyword arguments taking None as default will
        be implicitly set on first query.

        :param binsha: 20 byte sha1
        :param parents: tuple( Commit, ... )
            is a tuple of commit ids or actual Commits
        :param tree: Tree object
        :param author: Actor
            is the author Actor object
        :param authored_date: int_seconds_since_epoch
            is the authored DateTime - use time.gmtime() to convert it into a
            different format
        :param author_tz_offset: int_seconds_west_of_utc
            is the timezone that the authored_date is in
        :param committer: Actor
            is the committer string
        :param committed_date: int_seconds_since_epoch
            is the committed DateTime - use time.gmtime() to convert it into a
            different format
        :param committer_tz_offset: int_seconds_west_of_utc
            is the timezone that the committed_date is in
        :param message: string
            is the commit message
        :param encoding: string
            encoding of the message, defaults to UTF-8
        :param parents:
            List or tuple of Commit objects which are our parent(s) in the commit
            dependency graph
        :return: git.Commit

        :note:
            Timezone information is in the same format and in the same sign
            as what time.altzone returns. The sign is inverted compared to git's
            UTC timezone.Nz(Tree needs to be a Tree instance, was %s)superr)   __init__r9   
isinstancer   AssertionErrorr+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   )selfr8   r9   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   )	__class__ _/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/git/objects/commit.pyr<   `   s4    2zCommit.__init__)r)   .)r*   r:   c             C   s
   t |jS )N)tupler4   )clsr*   rA   rA   rB   _get_intermediate_items   s    zCommit._get_intermediate_items)r8   r*   r:   c             C   s>   t  }|| | }|d |jt| j||}|jS )zCalculate the sha of a commit.

        :param repo: Repo object the commit should be part of
        :param commit: Commit object for which to generate the sha
        r   )	r   
_serializetellseekodbstorer   r+   r9   )rD   r8   r*   streamZ	streamlenistreamrA   rA   rB   _calculate_sha_   s    

zCommit._calculate_sha_)kwargsr:   c                sf    fdd j D }x|D ]}| j krtdqW ||  j j jf|}  j||_|S )zCreate new commit object from existing commit object.

        Any values provided as keyword arguments will replace the
        corresponding attribute in the new object.
        c                s   i | ]}t  ||qS rA   )getattr).0k)r?   rA   rB   
<dictcomp>   s    z"Commit.replace.<locals>.<dictcomp>zinvalid attribute name)	__slots__
ValueErrorupdater@   r8   NULL_BIN_SHArM   r9   )r?   rN   attrsattrname
new_commitrA   )r?   rB   replace   s    


zCommit.replace)attrr:   c                sL   |t jkr8| jj| j\}}| _}| t|	  nt
t | | d S )N)r)   rS   r8   rI   rK   r9   size_deserializer   readr;   _set_cache_)r?   r[   Z_binsha	_typenamerK   )r@   rA   rB   r_      s    
zCommit._set_cache_)r:   c             C   s   t | j| jS )N)r   r.   r/   )r?   rA   rA   rB   authored_datetime   s    zCommit.authored_datetimec             C   s   t | j| jS )N)r   r1   r2   )r?   rA   rA   rB   committed_datetime   s    zCommit.committed_datetimec             C   s4   t | jtr| jddd S | jddd S dS )z):return: First line of the commit message
r   r      
N)r=   r3   strsplit)r?   rA   rA   rB   summary   s    zCommit.summary )pathsrN   r:   c             K   s@   |r$t | jjj| jd|f| S t | jjj| jf| S )a  Count the number of commits reachable from this commit

        :param paths:
            is an optional path or a list of paths restricting the return value
            to commits actually containing the paths

        :param kwargs:
            Additional options to be passed to git-rev-list. They must not alter
            the output style of the command, or parsing will yield incorrect results
        :return: int defining the number of reachable commitsz--)lenr8   gitrev_listr7   
splitlines)r?   ri   rN   rA   rA   rB   count   s     zCommit.countc             C   s   | j j| S )z
        :return:
            String describing the commits hex sha based on the closest Reference.
            Mostly useful for UI purposes)r8   rk   name_rev)r?   rA   rA   rB   ro      s    zCommit.name_revr(   )r8   revri   rN   r:   c             K   sj   d|krt ddg}|rDt|ttjfr2|f}nt|}|| |jj||fddi|}| 	||S )an  Find all commits matching the given criteria.

        :param repo: is the Repo
        :param rev: revision specifier, see git-rev-parse for viable options
        :param paths:
            is an optional path or list of paths, if set only Commits that include the path
            or paths will be considered
        :param kwargs:
            optional keyword arguments to git rev-list where
            ``max_count`` is the maximum number of commits to fetch
            ``skip`` is the number of commits to skip
            ``since`` all commits since i.e. '1970-01-01'
        :return: iterator yielding Commit itemsprettyz<--pretty cannot be used as parsing expects single sha's onlyz--
as_processT)
rT   r=   re   osr%   rC   extendrk   rl   _iter_from_process_or_stream)rD   r8   rp   ri   rN   Z	args_listZ	paths_tupprocrA   rA   rB   
iter_items  s    
zCommit.iter_itemsc             K   s4   | dd}|dkrd}||d< | j| j| |f|S )aA  Iterate _all_ parents of this commit.

        :param paths:
            Optional path or list of paths limiting the Commits to those that
            contain at least one of the paths
        :param kwargs: All arguments allowed by git-rev-list
        :return: Iterator yielding Commit objects which are parents of selfskipr   r   )getrw   r8   )r?   ri   rN   rx   rA   rA   rB   iter_parents1  s
    	zCommit.iter_parentsc             C   s   | j sf| jjj| jddddd}d}x:| dd D ]&}|d\}}}|d|||f 7 }q6W |}n"| jjj| j d	 j| jdddd
}t	| j|S )zCreate a git stat from changes between this commit and its first parent
        or from all changes done if this is the very first commit.

        :return: git.Statsz--T)numstat
no_renamesrootrh   r   N	z	%s	%s	%s
r   )r{   r|   )
r4   r8   rk   Z	diff_treer7   rm   rf   diffr   Z_list_from_string)r?   textZtext2line
insertionsZ	deletionsfilenamerA   rA   rB   statsA  s    "zCommit.statsc             C   s   dd | j  D S )aM  Get the trailers of the message as a dictionary

        :note: This property is deprecated, please use either ``Commit.trailers_list`` or ``Commit.trailers_dict``.

        :return:
            Dictionary containing whitespace stripped trailer information.
            Only contains the latest instance of each trailer key.
        c             S   s   i | ]\}}|d  |qS )r   rA   )rP   rQ   vrA   rA   rB   rR   \  s   z#Commit.trailers.<locals>.<dictcomp>)trailers_dictitems)r?   rA   rA   rB   trailersR  s    
zCommit.trailersc             C   s   dddg}| j jj|dtd}|t| j d d}|	 }|sLg S g }x8|
dD ]*}|
d	d
\}}||	 |	 f q\W |S )a  Get the trailers of the message as a list

        Git messages can contain trailer information that are similar to RFC 822
        e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers).

        This functions calls ``git interpret-trailers --parse`` onto the message
        to extract the trailer information, returns the raw trailer data as a list.

        Valid message with trailer::

            Subject line

            some body information

            another information

            key1: value1.1
            key1: value1.2
            key2 :    value 2 with inner spaces


        Returned list will look like this::

            [
                ("key1", "value1.1"),
                ("key1", "value1.2"),
                ("key2", "value 2 with inner spaces"),
            ]


        :return:
            List containing key-value tuples of whitespace stripped trailer information.
        rk   zinterpret-trailersz--parseT)rr   rL   r   utf8rc   :r   )r8   rk   executer   communicatere   r3   encodedecodestriprf   append)r?   cmdrv   trailerZtrailer_listtkeyvalrA   rA   rB   trailers_list`  s    #
zCommit.trailers_listc             C   s2   t t}x | jD ]\}}|| | qW t|S )a  Get the trailers of the message as a dictionary

        Git messages can contain trailer information that are similar to RFC 822
        e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers).

        This functions calls ``git interpret-trailers --parse`` onto the message
        to extract the trailer information. The key value pairs are stripped of
        leading and trailing whitespaces before they get saved into a dictionary.

        Valid message with trailer::

            Subject line

            some body information

            another information

            key1: value1.1
            key1: value1.2
            key2 :    value 2 with inner spaces


        Returned dictionary will look like this::

            {
                "key1": ["value1.1", "value1.2"],
                "key2": ["value 2 with inner spaces"],
            }


        :return:
            Dictionary containing whitespace stripped trailer information.
            Mapping trailer keys to a list of their corresponding values.
        )r   listr   r   dict)r?   dr   r   rA   rA   rB   r     s    $zCommit.trailers_dict)r8   proc_or_streamr:   c             c   s   t |dr&tt|}|jdk	r>|j}nt |dr>tt|}|}|j}x\| }|sRP | }t|dkrv|dd\}}t|dkst	d| | |t
|V  qFW t |drtt|}t| dS )a;  Parse out commit information into a list of Commit objects
        We expect one-line per commit, and parse the actual commit information directly
        from our lighting fast object database

        :param proc: git-rev-list process instance - one sha per line
        :return: iterator returning Commit objectswaitNreadline(   r   zInvalid line: %s)hasattrr#   r   stdoutr   r   r   rj   rf   r>   r   r   )rD   r8   r   rK   r   r   r7   _rA   rA   rB   ru     s(    






z#Commit._iter_from_process_or_streamF)
r8   r,   r3   parent_commitsheadr-   r0   author_datecommit_dater:   c
             C   s  |dkr2y|j jg}W q^ tk
r.   g }Y q^X n,x*|D ]"}
t|
| s8td|
d|  q8W | }tj}|pxt|}|pt	|}t
t }tot jdk}|rtnt}|| jd}|rt|\}}n|rt|\}}n
|| }}|| jd}|	rt|	\}}n|r t|\}}n
|| }}| jd\}}|||| j}t|ts^tdt|trt||}| || j||||||||||}| |||_|rddl}y|j j ||d W nH tk
r   |j!j"j#||j j$|d	| d}|j j%|d
| d Y nX |S )a2  Commit the given tree, creating a commit object.

        :param repo: Repo object the commit should be part of
        :param tree: Tree object or hex or bin sha
            the tree of the new commit
        :param message: Commit message. It may be an empty string if no message is provided.
            It will be converted to a string , in any case.
        :param parent_commits:
            Optional Commit objects to use as parents for the new commit.
            If empty list, the commit will have no parents at all and become
            a root commit.
            If None , the current head commit will be the parent of the
            new commit object
        :param head:
            If True, the HEAD will be advanced to the new commit automatically.
            Else the HEAD will remain pointing on the previous commit. This could
            lead to undesired results when diffing files.
        :param author: The name of the author, optional. If unset, the repository
            configuration is used to obtain this value.
        :param committer: The name of the committer, optional. If unset, the
            repository configuration is used to obtain this value.
        :param author_date: The timestamp for the author field
        :param commit_date: The timestamp for the committer field

        :return: Commit object representing the new commit

        :note:
            Additional information about the committer and Author are taken from the
            environment or from the git configuration, see git-commit-tree for
            more informationNzParent commit 'z' must be of type r   rh   .z)conf_encoding could not be coerced to str)Zlogmsgzcommit (initial): %szcommit: Switching to %s)&r   r*   rT   r=   Zconfig_readerrs   environr   r0   r-   intr   r   r   tm_isdstr   r   ry   env_author_dater   env_committer_dateconf_encodingrf   	get_valuedefault_encodingre   	TypeErrorr,   rV   rM   r9   git.refsZ
set_commitrefsZHeadcreaterefZset_reference)rD   r8   r,   r3   r   r   r-   r0   r   r   pcrenvZ	unix_timeZis_dstoffsetZauthor_date_strZauthor_timeZauthor_offsetZcommitter_date_strZcommitter_timeZcommitter_offsetZenc_sectionZ
enc_optionr   rY   rk   ZmasterrA   rA   rB   create_from_tree  sv    +





zCommit.create_from_tree)rK   r:   c       	      C   sb  |j }|d| j d x | jD ]}|d| d q"W | j}|j}| j}d}||d||j| jt	| j
f | j |j}||d||j| jt	| jf | j | j| jkr|d| j d yJ| dr|d	 x0| jd
d
D ]}|d| d
 d qW W n tk
r(   Y nX |d t| jtrT|| j| j n
|| j | S )Nztree %s
asciiz
parent %s
z%s %s <%s> %s %s
r-   r0   zencoding %s
r6   s   gpgsigrc    rd   )writer,   r   r4   r-   namer0   emailr.   r   r/   r5   r1   r2   r   __getattribute__r6   rstriprf   AttributeErrorr=   r3   re   )	r?   rK   r   r   aZanamecfmtZsiglinerA   rA   rB   rF   y  sN    


zCommit._serializec          	   C   s  |j }t| jt|  d tjd> d| _g | _d}xD| }|dsN|}P | j	t
| | jt| d d q8W t| j| _|}| }| }x*|dr| }x|d	r| }qW qW | j| _d| _|}| }x|r|d
d dkr||d	d d | jd| _n|d
d dkr||d	d d d }	d}
xD| }|s\P |d
d d	kr|| }d}
P |	|dd 7 }	qNW |	d| jd| _|
rq|  }qW y"t|| jd\| _| _| _W n* tk
r
   tjd|| jdd Y nX y"t|| jd\| _| _| _W n* tk
rX   tjd|| jdd Y nX | | _y| j| jd| _W n, tk
r   tjd| j| jdd Y nX | S )z
        :param from_rev_list: if true, the stream format is coming from the rev-list command
            Otherwise it is assumed to be a plain data stream from our object
        r      rh   Ns   parentr   s	   mergetag     r   
   s	   encoding ignore   s   gpgsig rd   FTrZ   z3Failed to decode author line '%s' using encoding %s)exc_infoz6Failed to decode committer line '%s' using encoding %sz/Failed to decode message '%s' using encoding %s)r   r   r8   r   rf   Ztree_idr,   r4   
startswithr   r+   r   rC   r   r5   r6   r   findr   r   r-   r.   r/   UnicodeDecodeErrorlogerrorr0   r1   r2   r^   r3   )r?   rK   r   Z	next_lineZparent_lineZauthor_lineZcommitter_lineencbufsigZis_next_headerZsigbufrA   rA   rB   r]     s    &
.$""
zCommit._deserializec             C   s<   g }| j r8td| j tj}x|D ]}|t|  q"W |S )z
        Search the commit message for any co-authors of this commit.
        Details on co-authors: https://github.blog/2018-01-29-commit-together-with-co-authors/

        :return: List of co-authors for this commit (as Actor objects).
        z^Co-authored-by: (.*) <(.*?)>$)r3   refindall	MULTILINEr   r   )r?   
co_authorsresultsr-   rA   rA   rB   r   !  s    
zCommit.co_authors)NNNNNNNNNNN)rh   )rh   )rh   )NFNNNN)9__name__
__module____qualname____doc__r   r   r   r   r+   r&   __annotations__rS   Z_id_attribute_bytesr!   r   r   r   floatre   r   r<   classmethodr    rE   rM   r   rZ   r_   propertydatetimera   rb   rg   r%   rn   ro   r   rw   rz   r   r   r$   r   r   r   r   r   r   ru   boolr   r   rF   r]   r   __classcell__rA   rA   )r@   rB   r)   =   s~   
          z>	 $$1( *     P ;mr)   )?r   r   
subprocessr   r   Zgitdbr   Zgit.utilr   r   r   r   Zgit.diffr	   Zgit.cmdr
   r,   r   rh   r   utilr   r   r   r   r   r   r   r   r   r   r   rs   ior   loggingcollectionsr   typingr   r   r   r   r   r    r!   r"   r#   r$   Z	git.typesr%   r&   Zgit.repor'   r   r(   	getLoggerr   
addHandlerNullHandler__all__ZObjectr)   rA   rA   rA   rB   <module>   s.    	0
