U
    楡c`j                     @   sb  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%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z. d dl/m0Z0m1Z1 e,r*d dl2m3Z3 d dl4m5Z5 e#6dZ7e78e#9  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)
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dAd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!dBee"ee" f eed$d%d&Z#eedd'd(Z$edCdeed d)f ee"ee" f ee%d  d*d+d,Z&dDee"ee" f ee%d  d$d-d.Z'ee(dd/d0Z)ee*dd1d2Z+edee,e-f e%d  d3d4d5Z.edEdeeef eed
e/d  f e0ed
ef ed
ef ed
ef ed
ef d d7
d8d9Z1e2d d:d;d<Z3e2d d:d=d>Z4ee/e dd?d@Z5  Z6S )Fr(   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.   r/   r0   r1   r2   r3   r4   r5   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__r8   
isinstancer   AssertionErrorr*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   )selfr7   r8   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   	__class__ 6/tmp/pip-unpacked-wheel-_pbxsds5/git/objects/commit.pyr;   _   s4    2zCommit.__init__)r(   .)r)   r9   c                 C   s
   t |jS N)tupler3   )clsr)   rA   rA   rB   _get_intermediate_items   s    zCommit._get_intermediate_items)r7   r)   r9   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*   r8   )rE   r7   r)   streamZ	streamlenistreamrA   rA   rB   _calculate_sha_   s    

zCommit._calculate_sha_)kwargsr9   c                    sb    fdd j D }|D ]}| j krtdq||  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@   r7   NULL_BIN_SHArN   r8   )r>   rO   attrsattrname
new_commitrA   rS   rB   replace   s    


zCommit.replace)attrr9   c                    sL   |t jkr8| jj| j\}}| _}| t|	  nt
t | | d S rC   )r(   rU   r7   rJ   rL   r8   size_deserializer   readr:   _set_cache_)r>   r]   Z_binshaZ	_typenamerL   r?   rA   rB   ra      s    
zCommit._set_cache_)r9   c                 C   s   t | j| jS rC   )r   r-   r.   rS   rA   rA   rB   authored_datetime   s    zCommit.authored_datetimec                 C   s   t | j| jS rC   )r   r0   r1   rS   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<   r2   strsplitrS   rA   rA   rB   summary   s    zCommit.summary )pathsrO   r9   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 commits--)lenr7   gitrev_listr6   
splitlines)r>   rj   rO   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)r7   rm   name_revrS   rA   rA   rB   rq      s    zCommit.name_revr'   )r7   revrj   rO   r9   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 onlyrk   
as_processT)
rV   r<   rf   osr$   rD   extendrm   rn   _iter_from_process_or_stream)rE   r7   rr   rj   rO   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   )getry   r7   )r>   rj   rO   rz   rA   rA   rB   iter_parents0  s
    	zCommit.iter_parentsc                 C   s   | j s`| jjj| jdddd}d}| dd D ]&}|d\}}}|d|||f 7 }q2|}n | jjj| j d	 j| j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.Statsrk   T)numstatrootri   r   N	z	%s	%s	%s
r   )r}   )
r3   r7   rm   Z	diff_treer6   ro   rg   Zdiffr   Z_list_from_string)r>   textZtext2lineZ
insertionsZ	deletionsfilenamerA   rA   rB   stats@  s     zCommit.statsc                 C   s   i }dddg}| j jj|dtd}|t| j d  }|	drT|dd }|d	kr|
dD ]$}|
d
d\}}| || < qf|S )a  Get the trailers of the message as 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:

        .. code-block::

            Subject line

            some body information

            another information

            key1: value1
            key2 :    value 2 with inner spaces

        dictionary will look like this:

        .. code-block::

            {
                "key1": "value1",
                "key2": "value 2 with inner spaces"
            }

        :return: Dictionary containing whitespace stripped trailer information

        rm   zinterpret-trailersz--parseT)rt   rM   r   rd   ri   :r   )r7   rm   executer   communicaterf   r2   encodedecodeendswithrg   strip)r>   dcmdrx   trailerr   keyvaluerA   rA   rB   trailersQ  s    $

zCommit.trailers)r7   proc_or_streamr9   c                 c   s   t |dr&tt|}|jdk	r>|j}nt |dr>tt|}|}|j}| }|sPq| }t|dkrt|dd\}}t|dkst	d| | |t
|V  qDt |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   rl   rg   r=   r   r   )rE   r7   r   rL   r   r   r6   _rA   rA   rB   rw     s&    






z#Commit._iter_from_process_or_streamF)
r7   r+   r2   parent_commitsheadr,   r/   author_datecommit_dater9   c
                 C   s  |dkr2z|j jg}W qZ tk
r.   g }Y qZX n(|D ]"}
t|
| s6td|
d|  q6| }tj}|ptt|}|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sZtdt|trp||}| || j||||||||||}| |||_|r
ddl}z|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   ri   .z)conf_encoding could not be coerced to str)Zlogmsgzcommit (initial): %szcommit: Switching to %s)&r   r)   rV   r<   Zconfig_readerru   environr   r/   r,   intr   r   r   tm_isdstr   r   r{   env_author_dater   env_committer_dateconf_encodingrg   	get_valuedefault_encodingrf   	TypeErrorr+   rX   rN   r8   git.refsZ
set_commitrefsZHeadcreaterefZset_reference)rE   r7   r+   r2   r   r   r,   r/   r   r   pZ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   r[   rm   ZmasterrA   rA   rB   create_from_tree  sz    +




zCommit.create_from_tree)rL   r9   c           	      C   sZ  |j }|d| j d | jD ]}|d| d q | 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 zF| dr|d	 | jd
d
D ]}|d| d
 d qW n tk
r    Y nX |d t| jtrL|| j| j n
|| j | S )Nztree %s
asciiz
parent %s
z%s %s <%s> %s %s
r,   r/   zencoding %s
r5   s   gpgsigrd    re   )writer+   r   r3   r,   namer/   emailr-   r   r.   r4   r0   r1   r   __getattribute__r5   rstriprg   AttributeErrorr<   r2   rf   )	r>   rL   r   r   aanamecfmtZsiglinerA   rA   rB   rG   ?  sb    
		
zCommit._serializec              	   C   s  |j }t| jt|  d tjd> d| _g | _d}| }|dsL|}qx| j	t
| | jt| d d q6t| j| _|}| }| }|dr| }|d	r| }qq| j| _d| _|}| }|r|d
d dkr||d	d d | jd| _n|d
d dkr||d	d d d }	d}
| }|sNq|d
d d	krp| }d}
q|	|dd 7 }	q>|	d| jd| _|
rq|  }qz"t|| jd\| _| _| _W n* tk
r   tjd|| jdd Y nX z"t|| jd\| _| _| _W n* tk
rH   tjd|| jdd Y nX | | _z| 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      ri   Ns   parentr   r   s	   mergetag     r   
   s	   encoding ignore   s   gpgsig re   FTr\   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   r7   r   rg   Ztree_idr+   r3   
startswithappendr*   r   rD   r   r4   r5   r   findr   r   r,   r-   r.   UnicodeDecodeErrorlogerrorr/   r0   r1   r`   r2   )r>   rL   r   Z	next_lineZparent_lineZauthor_lineZcommitter_lineencbufsigZis_next_headerZsigbufrA   rA   rB   r_   z  s    &
,


$

zCommit._deserializec                 C   s8   g }| j r4td| j tj}|D ]}|t|  q |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: (.*) <(.*?)>$)r2   refindall	MULTILINEr   r   )r>   
co_authorsresultsr,   rA   rA   rB   r     s    zCommit.co_authors)NNNNNNNNNNN)ri   )ri   )ri   )NFNNNN)7__name__
__module____qualname____doc__r   r   r   r   r*   r%   __annotations__rU   Z_id_attribute_bytesr    r   r   r   floatrf   r   r;   classmethodr   rF   rN   r   r\   ra   propertydatetimerb   rc   rh   r$   rp   rq   r   ry   r|   r   r   r#   r   r   r   rw   r   boolr   r   rG   r_   r   __classcell__rA   rA   r?   rB   r(   <   s   
           








M	  *$/ *      




 ;mr(   )=r   r   
subprocessr   r   Zgitdbr   Zgit.utilr   r   r   r   Zgit.diffr	   Zgit.cmdr
   r+   r   ri   r   utilr   r   r   r   r   r   r   r   r   r   r   ru   ior   logging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
