فهرست منبع

Add support for format argument to Repo.init() and Repo.init_bare() (#1584)

This allows creating repositories with different format versions by
specifying the repository format version (0 or 1) which sets the
core.repositoryformatversion configuration value.
Jelmer Vernooij 1 ماه پیش
والد
کامیت
475b3ec780
3فایلهای تغییر یافته به همراه67 افزوده شده و 6 حذف شده
  1. 5 0
      NEWS
  2. 26 6
      dulwich/repo.py
  3. 36 0
      tests/test_repository.py

+ 5 - 0
NEWS

@@ -1,5 +1,10 @@
 0.22.9	UNRELEASED
 
+ * Add support for ``format`` argument to ``Repo.init()`` and ``Repo.init_bare()``
+   to specify repository format version (0 or 1). This allows creating repositories
+   with different format versions by setting the ``core.repositoryformatversion``
+   configuration value. (Jelmer Vernooij)
+
  * Fix ``porcelain.add()`` to stage both untracked and modified files when no
    paths are specified. Previously, only untracked files were staged, inconsistent
    with Git's behavior. Now behaves like ``git add -A`` when called without paths.

+ 26 - 6
dulwich/repo.py

@@ -401,14 +401,20 @@ class BaseRepo:
         # For now, just mimic the old behaviour
         return sys.platform != "win32"
 
-    def _init_files(self, bare: bool, symlinks: Optional[bool] = None) -> None:
+    def _init_files(
+        self, bare: bool, symlinks: Optional[bool] = None, format: Optional[int] = None
+    ) -> None:
         """Initialize a default set of named files."""
         from .config import ConfigFile
 
         self._put_named_file("description", b"Unnamed repository")
         f = BytesIO()
         cf = ConfigFile()
-        cf.set("core", "repositoryformatversion", "0")
+        if format is None:
+            format = 0
+        if format not in (0, 1):
+            raise ValueError(f"Unsupported repository format version: {format}")
+        cf.set("core", "repositoryformatversion", str(format))
         if self._determine_file_mode():
             cf.set("core", "filemode", True)
         else:
@@ -1737,6 +1743,7 @@ class Repo(BaseRepo):
         config=None,
         default_branch=None,
         symlinks: Optional[bool] = None,
+        format: Optional[int] = None,
     ):
         for d in BASE_DIRECTORIES:
             os.mkdir(os.path.join(controldir, *d))
@@ -1753,7 +1760,7 @@ class Repo(BaseRepo):
             except KeyError:
                 default_branch = DEFAULT_BRANCH
         ret.refs.set_symbolic_ref(b"HEAD", LOCAL_BRANCH_PREFIX + default_branch)
-        ret._init_files(bare=bare, symlinks=symlinks)
+        ret._init_files(bare=bare, symlinks=symlinks, format=format)
         return ret
 
     @classmethod
@@ -1765,12 +1772,14 @@ class Repo(BaseRepo):
         config=None,
         default_branch=None,
         symlinks: Optional[bool] = None,
+        format: Optional[int] = None,
     ) -> "Repo":
         """Create a new repository.
 
         Args:
           path: Path in which to create the repository
           mkdir: Whether to create the directory
+          format: Repository format version (defaults to 0)
         Returns: `Repo` instance
         """
         if mkdir:
@@ -1785,6 +1794,7 @@ class Repo(BaseRepo):
             config=config,
             default_branch=default_branch,
             symlinks=symlinks,
+            format=format,
         )
 
     @classmethod
@@ -1827,7 +1837,14 @@ class Repo(BaseRepo):
 
     @classmethod
     def init_bare(
-        cls, path, *, mkdir=False, object_store=None, config=None, default_branch=None
+        cls,
+        path,
+        *,
+        mkdir=False,
+        object_store=None,
+        config=None,
+        default_branch=None,
+        format: Optional[int] = None,
     ):
         """Create a new bare repository.
 
@@ -1835,6 +1852,7 @@ class Repo(BaseRepo):
 
         Args:
           path: Path to create bare repository in
+          format: Repository format version (defaults to 0)
         Returns: a `Repo` instance
         """
         if mkdir:
@@ -1846,6 +1864,7 @@ class Repo(BaseRepo):
             object_store=object_store,
             config=config,
             default_branch=default_branch,
+            format=format,
         )
 
     create = init_bare
@@ -2032,7 +2051,7 @@ class MemoryRepo(BaseRepo):
         return self._config
 
     @classmethod
-    def init_bare(cls, objects, refs):
+    def init_bare(cls, objects, refs, format: Optional[int] = None):
         """Create a new bare repository in memory.
 
         Args:
@@ -2040,11 +2059,12 @@ class MemoryRepo(BaseRepo):
             as iterable
           refs: Refs as dictionary, mapping names
             to object SHA1s
+          format: Repository format version (defaults to 0)
         """
         ret = cls()
         for obj in objects:
             ret.object_store.add_object(obj)
         for refname, sha in refs.items():
             ret.refs.add_if_new(refname, sha)
-        ret._init_files(bare=True)
+        ret._init_files(bare=True, format=format)
         return ret

+ 36 - 0
tests/test_repository.py

@@ -342,6 +342,42 @@ class RepositoryRootTests(TestCase):
         self.assertEqual(os.listdir(repo_dir), [".git"])
         self.assertFilesystemHidden(os.path.join(repo_dir, ".git"))
 
+    def test_init_format(self) -> None:
+        tmp_dir = self.mkdtemp()
+        self.addCleanup(shutil.rmtree, tmp_dir)
+
+        # Test format 0
+        t0 = Repo.init(tmp_dir + "0", mkdir=True, format=0)
+        self.addCleanup(t0.close)
+        self.assertEqual(t0.get_config().get("core", "repositoryformatversion"), b"0")
+
+        # Test format 1
+        t1 = Repo.init(tmp_dir + "1", mkdir=True, format=1)
+        self.addCleanup(t1.close)
+        self.assertEqual(t1.get_config().get("core", "repositoryformatversion"), b"1")
+
+        # Test default format
+        td = Repo.init(tmp_dir + "d", mkdir=True)
+        self.addCleanup(td.close)
+        self.assertEqual(td.get_config().get("core", "repositoryformatversion"), b"0")
+
+        # Test invalid format
+        with self.assertRaises(ValueError):
+            Repo.init(tmp_dir + "bad", mkdir=True, format=99)
+
+    def test_init_bare_format(self) -> None:
+        tmp_dir = self.mkdtemp()
+        self.addCleanup(shutil.rmtree, tmp_dir)
+
+        # Test format 1 for bare repo
+        t = Repo.init_bare(tmp_dir + "bare", mkdir=True, format=1)
+        self.addCleanup(t.close)
+        self.assertEqual(t.get_config().get("core", "repositoryformatversion"), b"1")
+
+        # Test invalid format for bare repo
+        with self.assertRaises(ValueError):
+            Repo.init_bare(tmp_dir + "badbr", mkdir=True, format=2)
+
     @skipIf(sys.platform == "win32", "fails on Windows")
     def test_fetch(self) -> None:
         r = self.open_repo("a.git")