314 next_path = None |
314 next_path = None |
315 if index < len(sorted_map): |
315 if index < len(sorted_map): |
316 # Determine if the next entry is in the same sub-tree, if so don't |
316 # Determine if the next entry is in the same sub-tree, if so don't |
317 # pack yet |
317 # pack yet |
318 next_path = sorted_map[index][0] |
318 next_path = sorted_map[index][0] |
319 should_pack = not get_folder(next_path).startswith(current_folder) |
319 should_pack = not is_ancestor(next_path, current_folder) |
320 if should_pack: |
320 if should_pack: |
321 pack_directory_children(current_node, copy_map, data, stack) |
321 pack_directory_children(current_node, copy_map, data, stack) |
322 while stack and current_node.path != b"": |
322 while stack and current_node.path != b"": |
323 # Go up the tree and write until we reach the folder of the next |
323 # Go up the tree and write until we reach the folder of the next |
324 # entry (if any, otherwise the root) |
324 # entry (if any, otherwise the root) |
325 parent = current_node.parent |
325 parent = current_node.parent |
326 in_parent_folder_of_next_entry = next_path is not None and ( |
326 in_ancestor_of_next_path = next_path is not None and ( |
327 get_folder(next_path).startswith(get_folder(stack[-1].path)) |
327 is_ancestor(next_path, get_folder(stack[-1].path)) |
328 ) |
328 ) |
329 if parent is None or in_parent_folder_of_next_entry: |
329 if parent is None or in_ancestor_of_next_path: |
330 break |
330 break |
331 pack_directory_children(parent, copy_map, data, stack) |
331 pack_directory_children(parent, copy_map, data, stack) |
332 current_node = parent |
332 current_node = parent |
333 |
333 |
334 # Special case for the root node since we don't write it to disk, only its |
334 # Special case for the root node since we don't write it to disk, only its |
355 Return the folder of the path that's given, an empty string for root paths. |
355 Return the folder of the path that's given, an empty string for root paths. |
356 """ |
356 """ |
357 return path.rsplit(b'/', 1)[0] if b'/' in path else b'' |
357 return path.rsplit(b'/', 1)[0] if b'/' in path else b'' |
358 |
358 |
359 |
359 |
|
360 def is_ancestor(path, maybe_ancestor): |
|
361 """Returns whether `maybe_ancestor` is an ancestor of `path`. |
|
362 |
|
363 >>> is_ancestor(b"a", b"") |
|
364 True |
|
365 >>> is_ancestor(b"a/b/c", b"a/b/c") |
|
366 False |
|
367 >>> is_ancestor(b"hgext3rd/__init__.py", b"hgext") |
|
368 False |
|
369 >>> is_ancestor(b"hgext3rd/__init__.py", b"hgext3rd") |
|
370 True |
|
371 """ |
|
372 if maybe_ancestor == b"": |
|
373 return True |
|
374 if path <= maybe_ancestor: |
|
375 return False |
|
376 path_components = path.split(b"/") |
|
377 ancestor_components = maybe_ancestor.split(b"/") |
|
378 return all(c == o for c, o in zip(path_components, ancestor_components)) |
|
379 |
|
380 |
360 def move_to_correct_node_in_tree(target_folder, current_node, stack): |
381 def move_to_correct_node_in_tree(target_folder, current_node, stack): |
361 """ |
382 """ |
362 Move inside the dirstate node tree to the node corresponding to |
383 Move inside the dirstate node tree to the node corresponding to |
363 `target_folder`, creating the missing nodes along the way if needed. |
384 `target_folder`, creating the missing nodes along the way if needed. |
364 """ |
385 """ |
365 while target_folder != current_node.path: |
386 while target_folder != current_node.path: |
366 if target_folder.startswith(current_node.path): |
387 if is_ancestor(target_folder, current_node.path): |
367 # We need to go down a folder |
388 # We need to go down a folder |
368 prefix = target_folder[len(current_node.path) :].lstrip(b'/') |
389 prefix = target_folder[len(current_node.path) :].lstrip(b'/') |
369 subfolder_name = prefix.split(b'/', 1)[0] |
390 subfolder_name = prefix.split(b'/', 1)[0] |
370 if current_node.path: |
391 if current_node.path: |
371 subfolder_path = current_node.path + b'/' + subfolder_name |
392 subfolder_path = current_node.path + b'/' + subfolder_name |