
    q&f,;                     F   d dl Z ddlmZ ddlmZmZ  ej                  d      ZdZdZ	 e j                  d      Z e j                  d      Zeej                  k(  sJ e	ej                  k(  sJ d	Zd
 Zd Zd Zej$                   G d d             Zd Zd Zd Zd Zd Zy)    N   )attr)errorpolicyparsers,   z>LLLLL4s20sz>LHHLHLLLLHllli    c                 \    t         j                  |      \  }}}}}}	}
t        | ||||       y)a:  parse a full v2-dirstate from a binary data into dictionaries:

    - map: a {path: entry} mapping that will be filled
    - copy_map: a {path: copy-source} mapping that will be filled
    - data: a binary blob contains v2 nodes data
    - tree_metadata:: a binary blob of the top level node (from the docket)
    N)TREE_METADATAunpackparse_nodes)mapcopy_mapdatatree_metadataroot_nodes_startroot_nodes_len_nodes_with_entry_count_nodes_with_copy_source_count_unreachable_bytes_unused_ignore_patterns_hashs              </usr/lib/python3/dist-packages/mercurial/dirstateutils/v2.pyparse_dirstater   >   s=      	]+%Xt%5~F    c                 j   t        |      D ]  }|t        |z  z   }t        ||t              }t        j	                  |      \  }}	}
}}}}}}}}}}t        | ||||       t        j                  j                  ||||      }|j                  st        |||	      }|| |<   |st        |||      ||<    y)a  parse <len> nodes from <data> starting at offset <start>

    This is used by parse_dirstate to recursively fill `map` and `copy_map`.

    All directory specific information is ignored and do not need any
    processing (DIRECTORY, ALL_UNKNOWN_RECORDED, ALL_IGNORED_RECORDED)
    N)
range	NODE_SIZEslice_with_lenNODEr   r   r   DirstateItemfrom_v2_dataany_tracked)r   r   r   startleni
node_start
node_bytes
path_startpath_len_basename_startcopy_source_startcopy_source_lenchildren_startchildren_count_descendants_with_entry_count_tracked_descendants_countflagssizemtime_smtime_nsitempaths                          r   r   r   R   s     3Z Y]*
#D*i@
 KK
#	
)& 	C4H##00gxPdJ9D	+'HTN9r   c                     | |||z    S N )r   r#   r$   s      r   r   r   {   s    $$r   c                      e Zd Z ej                         Z ej                         Z ej                  d      Z ej                  d      Z ej                  d      Z	 ej                  d      Z
 ej                  d      Zd Zy)NodeN)defaultr   c                    | j                   }|j                  |      }| j                  }|}t        |      }|j	                  d      dz   }||t        |      z   }	t        |      }
nd}	d}
||j                         \  }}}}nt        }d}d}d}t        j                  ||||	|
| j                  | j                  | j                  | j                  ||||      S )N   /   r   )r6   getentryr$   rfindv2_dataDIRSTATE_V2_DIRECTORYr   packchildren_offsetr.   descendants_with_entrytracked_descendants)selfr   paths_offsetr6   copyrA   r(   r)   basename_startr+   r,   r1   r2   r3   r4   s                  r   rE   z	Node.pack   s    yy||D!

!
t9D)A- ,s4y 8!$iO !O-2]]_*E4( *EDGHyy  ''$$
 	
r   )__name__
__module____qualname__r   ibr6   rA   parentr.   rF   rG   rH   rE   r9   r   r   r;   r;      ss    4779DDGGIETWWT"FTWWQ'Ndgga(O$TWWQ/!$''!,$
r   r;   c           	         t               }d}d}d}d}d}d}d}	t        |       dk(  rt        j                  |||||||	      }
||
fS t	        | j                         d       }g }t        dd      }|j                  |       t        |d      D ]?  \  }\  }}|dz  }||v r|dz  }t        |      }t        |||      }|xj                  dz  c_        |j                  r|xj                  dz  c_        |xj                  dz  c_        |j                  t        |||             d	}d}|t        |      k  r||   d   }t        ||       }|st!        ||||       |s|j"                  dk7  s|j$                  }|duxr" t        |t        |d
   j"                              }||rt!        ||||       |}|s0|j"                  dk7  r^B |j'                         }|j"                  dk(  sJ |j"                         t        |      dk(  sJ t        |             t        j                  |j(                  |j                  |||||	      }
||
fS )a5  
    Pack `map` and `copy_map` into the dirstate v2 binary format and return
    the tuple of (data, metadata) bytearrays.

    The on-disk format expects a tree-like structure where the leaves are
    written first (and sorted per-directory), going up levels until the root
    node and writing that one to the docket. See more details on the on-disk
    format in `mercurial/helptext/internals/dirstate-v2`.

    Since both `map` and `copy_map` are flat dicts we need to figure out the
    hierarchy. This algorithm does so without having to build the entire tree
    in-memory: it only keeps the minimum number of nodes around to satisfy the
    format.

    # Algorithm explanation

    This explanation does not talk about the different counters for tracked
    descendants and storing the copies, but that work is pretty simple once this
    algorithm is in place.

    ## Building a subtree

    First, sort `map`: this makes it so the leaves of the tree are contiguous
    per directory (i.e. a/b/c and a/b/d will be next to each other in the list),
    and enables us to use the ordering of folders to have a "cursor" of the
    current folder we're in without ever going twice in the same branch of the
    tree. The cursor is a node that remembers its parent and any information
    relevant to the format (see the `Node` class), building the relevant part
    of the tree lazily.
    Then, for each file in `map`, move the cursor into the tree to the
    corresponding folder of the file: for example, if the very first file
    is "a/b/c", we start from `Node[""]`, create `Node["a"]` which points to
    its parent `Node[""]`, then create `Node["a/b"]`, which points to its parent
    `Node["a"]`. These nodes are kept around in a stack.
    If the next file in `map` is in the same subtree ("a/b/d" or "a/b/e/f"), we
    add it to the stack and keep looping with the same logic of creating the
    tree nodes as needed. If however the next file in `map` is *not* in the same
    subtree ("a/other", if we're still in the "a/b" folder), then we know that
    the subtree we're in is complete.

    ## Writing the subtree

    We have the entire subtree in the stack, so we start writing it to disk
    folder by folder. The way we write a folder is to pop the stack into a list
    until the folder changes, revert this list of direct children (to satisfy
    the format requirement that children be sorted). This process repeats until
    we hit the "other" subtree.

    An example:
        a
        dir1/b
        dir1/c
        dir2/dir3/d
        dir2/dir3/e
        dir2/f

    Would have us:
        - add to the stack until "dir2/dir3/e"
        - realize that "dir2/f" is in a different subtree
        - pop "dir2/dir3/e", "dir2/dir3/d", reverse them so they're sorted and
          pack them since the next entry is "dir2/dir3"
        - go back up to "dir2"
        - add "dir2/f" to the stack
        - realize we're done with the map
        - pop "dir2/f", "dir2/dir3" from the stack, reverse and pack them
        - go up to the root node, do the same to write "a", "dir1" and "dir2" in
          that order

    ## Special case for the root node

    The root node is not serialized in the format, but its information is
    written to the docket. Again, see more details on the on-disk format in
    `mercurial/helptext/internals/dirstate-v2`.
    r   s       s                       c                 *    | d   j                  d      S )Nr   r>   )split)xs    r   <lambda>zpack_dirstate.<locals>.<lambda>  s    1Q4::d3C r   )keyr   Nr?   T)	bytearrayr$   r
   rE   sorteditemsr;   append	enumerate
get_foldermove_to_correct_node_in_treer.   trackedrH   rG   is_ancestorpack_directory_childrenr6   rQ   poprF   )r   r   r   r   r   nodes_with_entry_countnodes_with_copy_source_countunreachable_bytesunusedignore_patterns_hashr   
sorted_mapstackcurrent_nodeindexr6   rA   current_foldershould_pack	next_pathrQ   in_ancestor_of_next_paths                         r   pack_dirstaterq      s   V ;DN#$  F'
3x1}%**"( 
 ]""		)CDJ ET?L	LL )*a 8 #&}e!#8(A-(#D)3L%
 	##q(#==,,1,++q0+T$|45	3z?" #5)!,I))^DDK#L(D%HL--4 &,,+4D+@ ,	:eBinn+EF ) >%='$F% L--43#&N 99;L#6\%6%66#u:?&CJ&?!&&$$##$M r   c                 8    d| v r| j                  dd      d   S dS )zU
    Return the folder of the path that's given, an empty string for root paths.
    r>   r?   r   r   )rsplit)r6   s    r   r^   r^   S  s%     '+dl4;;tQ";;r   c                     |dk(  ry| |k  ry| j                  d      }|j                  d      }t        d t        ||      D              S )a  Returns whether `maybe_ancestor` is an ancestor of `path`.

    >>> is_ancestor(b"a", b"")
    True
    >>> is_ancestor(b"a/b/c", b"a/b/c")
    False
    >>> is_ancestor(b"hgext3rd/__init__.py", b"hgext")
    False
    >>> is_ancestor(b"hgext3rd/__init__.py", b"hgext3rd")
    True
    r   TFr>   c              3   ,   K   | ]  \  }}||k(    y wr8   r9   ).0cos      r   	<genexpr>zis_ancestor.<locals>.<genexpr>l  s     L$!QqAvLs   )rT   allzip)r6   maybe_ancestorpath_componentsancestor_componentss       r   ra   ra   Z  sR     ~jj&O(..t4L#o7J"KLLLr   c                    | |j                   k7  rt        | |j                         r| t        |j                         d j                  d      }|j	                  dd      d   }|j                   r|j                   dz   |z   }n|}|d   }|j                   | k(  r|}n@|xj
                  dz  c_        t        |d|      }|j                  |       n|j                  }| |j                   k7  r|S )z
    Move inside the dirstate node tree to the node corresponding to
    `target_folder`, creating the missing nodes along the way if needed.
    Nr>   r?   r   rX   )	r6   ra   r$   lstriprT   r.   r;   r\   rQ   )target_folderrk   rj   prefixsubfolder_namesubfolder_path	next_nodes          r   r_   r_   o  s    
 <,,
,}l&7&78"3|'8'8#9#;<CCDIF#\\$215N  !-!2!2T!9N!J!/b	I~~.  )++q0+#ND,G\* (..L) <,,
,* r   c                 R   g }|d   j                   dk7  r|t        |d   j                         | j                   k(  rW|j                  |j                                |d   j                   dk7  r&t        |d   j                         | j                   k(  rW|s"t	        j
                  d| j                   z        |j                          t               }|D ]  }|j                  |t        |            }|j                  |       |j                  |j                          |j                  |j                  |j                   d             | xj                  |j                  z  c_        | xj                  |j                  z  c_         t        |      | _        |j                  |       y)z_
    Write the binary representation of the direct sorted children of `node` to
    `data`
    rX   r   s   no direct children for %r)r   rJ   N)r6   r^   r\   rc   r   ProgrammingErrorreverserY   rE   r$   extendr@   rH   rG   rF   )noder   r   rj   direct_childrenpacked_childrenchildpackeds           r   rb   rb     sJ   
 O
)..C
JuRy~~$>$))$Kuyy{+ )..C
JuRy~~$>$))$K$$%ADII%MNN kO  DXCIFv&EJJHLLS12  E$=$== ##u'C'CC#D t9DKK r   )struct
thirdpartyr    r   r   	importmodr   TREE_METADATA_SIZEr   Structr
   r   r2   rD   r   r   r   sr;   rq   r^   ra   r_   rb   r9   r   r   <module>r      s      
&

9
%
  	 m,& v}}%& ]/// //DII    G(&R% -
 -
 -
``F<M*:!r   