ó
é*Nc           @   sø   d  Z  d d l Z d d l Z d d l Z d d l Z d d l Z d d l m Z d   Z d   Z d   Z	 d   Z
 d d d  Z d	 e j f d
     YZ d e f d     YZ d S(   sø  
Advanced merge tools for git rerere, sloppy commits and parametrization.

Wizard requires infrastructure for reusing merge resolutions across
many repositories, due to the number of user installs and highly
repetitive conflict resolution process.  This environment results
in a number of unique challenges:

    1. Users are commonly very sloppy with their text editors and
       will frequently change the line-ending style of their file.
       Because Git respects newline choice when core.autocrlf is
       off, a file that flips newline style will result in a full
       merge conflict.

    2. We version user configuration files, which means that there
       will always be a set of changes between upstream and ours.
       Since Git refuses to automatically merge changes that are
       too close to each other, these frequently result in spurious
       merge commits.

Furthermore, both of these make it difficult to reuse rerere resolutions
across installations.  Thus, an advanced Wizard merge has the following
properties:

    1. Wizard will perform a full scan of all files that were
       different between common and ours, filter out those that
       are binary (using as close to the Git heuristic as possible)
       and then check among common, ours and theirs if the newlines
       match.  The newline style of theirs always takes precedence.

    2. Wizard will genericize the ours copy so that it matches
       common and theirs, and reparametrize it once the merge
       is finished.  Consumers of this function should be careful
       to appropriately reparametrize if there are conflicts
       (we can't do it any earlier, because we want clean rerere
       postimages).

Usage of this functionality is primarily through the :func:`merge` function;
see that function more usage information.  While the ``git`` and ``newline``
functions published by this module are public, use of these functions outside
of this module is discouraged.
i’’’’N(   t   shellc      	   G   sA   t  j d   | D   } t j d d |  d d d t | } | S(   sL   
    Convenience wrapper for ``git commit-tree``.  Writes an empty log.
    c         s   s   |  ] } d  | g Vq d S(   s   -pN(    (   t   .0t   p(    (    s:   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/merge.pys	   <genexpr>8   s    t   gits   commit-treet   inputt    t   log(   t	   itertoolst   chainR    t   evalt   True(   t   treet   parentst   parent_argst   commit(    (    s:   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/merge.pyt   git_commit_tree4   s    c         C   s   t  j d d d |  |  j   j d  } g  } xK | D]C } | j   \ } } } | d k r7 | d k r7 | j |  q7 q7 W| S(   sf   
    Returns a list of files that are text and are different between
    commits ``a`` and ``b``.
    R   t   diffs	   --numstats   
t   -(   R    R	   t   stript   splitt   append(   t   at   bt   linest   filest   linet   addedt   deletedt   name(    (    s:   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/merge.pyt   git_diff_text=   s    *c         C   s    t  |  d  } | j   | j S(   s   
    Determines the newline style of ``filename``.  This will be a
    string if only one newline style was find, or a tuple of newline
    types found.
    t   U(   t   opent   readt   newlines(   t   filenamet   f(    (    s:   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/merge.pyt   get_newlineK   s    
c         C   s;   t  |  d  j   j d |  } t  |  d  j |  d S(   sa   
    Replaces the detected newline style of ``filename`` with
    ``dest_nl`` type newlines.
    R   s   
t   wbN(   R   R    t   replacet   write(   R"   t   dest_nlt   contents(    (    s:   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/merge.pyt   convert_newlineU   s    !c         C   s0  | d k r d   } n  | d k r0 d   } n  t j d d d  } t | |  } i  } t j d d d |  x | D]~ } y t |  } Wn t k
 r£ qw n Xt | t  sė | d k	 rŅ t	 j
 d |  n t	 j d	 |  d
 } n  | | | <qw Wt j d d d |  t j d d d |  }	 xÓ | D]Ė } y | | }
 Wn t k
 rYq/n Xy t |  } Wn t t j f k
 rq/n X|
 | k r/| d k rµt	 j d |  qśt	 j d | t |  t |
   t | |
  t j d d |  q/q/W|   t j d d  } t	 j d |  t j d d d |   xģ t |  |  D]Ū } y | | }
 Wn$ t k
 rt	 j d |  qMn Xy t |  } Wn t t j f k
 r·qMn X|
 | k rM| d k rćt	 j d |  q(t	 j d | t |  t |
   t | |
  t j d d |  qMqMWt j d d  } t	 j d |  t |  } t | |  } t |	 |  } t j d d d |  y t j d d |  Wnb t j k
 r	} t	 j d | j  |   r t	 j d  t j d d d d d  q
t  n Xt j d d  } t	 j d |  | S(   st  
    Performs a merge.  Throws a :class:`MergeError` if the merge fails
    (and leaves the current working directory in a state amenable
    to manual conflict resolution), or returns a tree id of the successful
    merge (the directory state is undefined and should not be relied upon).
    This function is not responsible for actually coming
    up with the real merge commit, because it can fail.

    If ``prepare_config`` is used, you are expected to reverse the effects
    of this on whatever the final tree is; otherwise you will lose
    those changes.

    Arguments:

        * ``common_id``: base commit to calculate merge off of
        * ``theirs_id``: changes to merge in from commit
        * ``prepare_config``: function that removes any user-specific
          values from files.  This function is expected to ``git add``
          any files it changes.
        * ``resolve_conflicts``: this function attempts to resolve
          conflicts automatically.  Returns ``True`` if all conflicts
          are resolved, and ``False`` otherwise.  It is permitted
          to resolve some but not all conflicts.

    .. note::

        Wizard has a strange idea of repository topology (due to lack of
        rebases, see documentation about doctoring retroactive commits),
        so we require the common and theirs commits, instead of
        using the normal Git algorithm.
    c           S   s   d  S(   N(   t   None(    (    (    s:   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/merge.pyt   <lambda>   s    c           S   s   t  S(   N(   t   False(    (    (    s:   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/merge.pyR,      s    R   s	   rev-parset   HEADt   resets   --hardsF   Canonical version (theirs) of %s has mixed newline style, forced to \ns?   Canonical version (theirs) of %s had no newline style, using \ns   
s	   %s^{tree}s3   Our file %s had no newlines, ignoring newline styles1   Converting our file %s (3) from %s to %s newlinest   adds
   write-trees%   Merge wrote virtual tree for ours: %ss4   Merge trivially succeeds for %s, ignoring line checks6   Common file %s had no newlines, ignoring newline styles4   Converting common file %s (1) from %s to %s newliness'   Merge wrote virtual tree for common: %st   merges"   Merge failed with these message:

s    Resolved conflicts automaticallyR   s   -as   -ms   Resolution tree is %sN(   R+   R    R	   R   t   callR$   t   IOErrort
   isinstancet   strt   loggingt   warningt   debugt   KeyErrort	   CallErrort   infot   reprR*   R   t   stderrt
   MergeError(   t	   common_idt	   theirs_idt   prepare_configt   resolve_conflictst   ours_idt   ours_theirs_difft   theirs_newlinest   filet   nlt   theirs_treet	   theirs_nlt   ours_nlt	   ours_treet	   common_nlt   common_treet   common_virtual_idt   ours_virtual_idt   theirs_virtual_idt   et   result_tree(    (    s:   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/merge.pyR1   ]   s    #
	""	
t   Errorc           B   s   e  Z d  Z RS(   s   Base error class for merge(   t   __name__t
   __module__t   __doc__(    (    (    s:   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/merge.pyRS   č   s   R>   c           B   s   e  Z d  Z RS(   s(   Merge terminated with a conflict, oh no!(   RT   RU   RV   (    (    (    s:   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/merge.pyR>   ģ   s   (   RV   R6   R   t   tempfilet   ost   wizardR    R   R   R$   R*   R+   R1   RS   R>   (    (    (    s:   /afs/athena.mit.edu/contrib/scripts/wizard/wizard/merge.pyt   <module>*   s   				
		