# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
#
# This module is part of GitPython and is released under the
# 3-Clause BSD License: https://opensource.org/license/bsd-3-clause/
import os
import os.path as osp
import subprocess
from io import BytesIO
from pathlib import Path
import ddt
import pytest
from git.objects import Blob, Tree
from git.objects.fun import tree_entries_from_data, tree_to_stream
from git.objects.tree import TreeModifier
from git.repo import Repo
from git.util import cwd
from test.lib import TestBase, with_rw_directory
from .lib.helper import PathLikeMock, with_rw_repo
@ddt.ddt
class TestTree(TestBase):
def test_serializable(self):
# Tree at the given commit contains a submodule as well.
roottree = self.rorepo.tree("6c1faef799095f3990e9970bc2cb10aa0221cf9c")
for item in roottree.traverse(ignore_self=False):
if item.type != Tree.type:
continue
# END skip non-trees
tree = item
# Trees have no dict.
self.assertRaises(AttributeError, setattr, tree, "someattr", 1)
orig_data = tree.data_stream.read()
orig_cache = tree._cache
stream = BytesIO()
tree._serialize(stream)
assert stream.getvalue() == orig_data
stream.seek(0)
testtree = Tree(self.rorepo, Tree.NULL_BIN_SHA, 0, "")
testtree._deserialize(stream)
assert testtree._cache == orig_cache
# Replaces cache, but we make sure of it.
del testtree._cache
testtree._deserialize(stream)
# END for each item in tree
def test_valid_unusual_tree_names_round_trip(self):
names = ["a b", "a\nb", "a\tb", "caf", ".gitignore"]
if os.name != "nt":
names.extend(["a\\b", "a:b", "C:relative"])
cache = []
modifier = TreeModifier(cache)
for name in names:
modifier.add(b"a" * 20, 0o100644, name)
modifier.set_done()
data = BytesIO()
tree_to_stream(cache, data.write)
assert tree_entries_from_data(data.getvalue()) == cache
@with_rw_directory
def _get_git_ordered_files(self, rw_dir):
"""Get files as git orders them, to compare in test_tree_modifier_ordering."""
# Create directory contents.
Path(rw_dir, "file").mkdir()
for filename in (
"bin",
"bin.d",
"file.to",
"file.toml",
"file.toml.bin",
"file0",
):
Path(rw_dir, filename).touch()
Path(rw_dir, "file", "a").touch()
with cwd(rw_dir):
# Prepare the repository.
subprocess.run(["git", "init", "-q"], check=True)
subprocess.run(["git", "add", "."], check=True)
subprocess.run(["git", "commit", "-m", "c1"], check=True)
# Get git output from which an ordered file list can be parsed.
rev_parse_command = ["git", "rev-parse", "HEAD^{tree}"]
tree_hash = subprocess.check_output(rev_parse_command).decode().strip()
cat_file_command = ["git", "cat-file", "-p", tree_hash]
cat_file_output = subprocess.check_output(cat_file_command).decode()
return [line.split()[-1] for line in cat_file_output.split("\n") if line]
def test_tree_modifier_ordering(self):
"""TreeModifier.set_done() sorts files in the same order git does."""
git_file_names_in_order = self._get_git_ordered_files()
hexsha = "6c1faef799095f3990e9970bc2cb10aa0221cf9c"
roottree = self.rorepo.tree(hexsha)
blob_mode = Tree.blob_id