Quellcode durchsuchen

Add recipes to documentation

Maciej Katafiasz vor 5 Monaten
Ursprung
Commit
ba4a16eab2
2 geänderte Dateien mit 110 neuen und 0 gelöschten Zeilen
  1. 2 0
      docs/index.txt
  2. 108 0
      docs/recipes/index.txt

+ 2 - 0
docs/index.txt

@@ -19,6 +19,8 @@ Documentation
 
     tutorial/index
 
+    recipes/index
+
     api/index
 
 

+ 108 - 0
docs/recipes/index.txt

@@ -0,0 +1,108 @@
+.. _recipes:
+
+========================
+Recipes for common tasks
+========================
+
+How do I check out files with Dulwich?
+======================================
+
+The answer depends on the exact meaning of "check out" that is
+intended. There are several common goals it could be describing, and
+correspondingly several options to achieve them.
+
+Make sure a working tree on disk matches a particular commit (like ``git checkout``)
+------------------------------------------------------------------------------------
+
+:py:func:`dulwich.porcelain.checkout` is a very high-level function
+that operates on the working tree and behaves very similar to the
+``git checkout`` command. It packages a lot of functionality into a
+single command, just as Git's porcelain does, which is useful when
+matching Git's CLI is the goal, but might be less desirable for
+programmatic access to a repository's contents.
+
+Retrieve a single file's contents at a particular commit
+--------------------------------------------------------
+
+:py:func:`dulwich.object_store.tree_lookup_path` can a retrieve the
+object SHA given its path and the SHA of a tree to look it up in. This
+makes it very easy to access a specific file as stored in the
+repo. Note that this function operates on *trees*, not *commits*
+(every commit contains a tree for its contents, but a commit's ID is
+not the same as its tree's ID).
+
+With the retrieved SHA it's possible to get a file's blob directly
+from the repository's object store, and thus its content bytes. It's
+also possible to write it out to disk, using
+:py:func:`dulwich.index.build_file_from_blob`, which takes care of
+things like symlinks and file permissions.
+
+.. code-block:: python
+
+    from dulwich.repo import Repo
+    from dulwich.objectspec import parse_commit
+    from dulwich.object_store import tree_lookup_path
+
+    repo = Repo("/path/to/some/repo")
+    # parse_commit will understand most commonly-used types of Git refs, including
+    # short SHAs, tag names, branch names, HEAD, etc.
+    commit = parse_commit(repo, "v1.0.0")
+
+    path = b"README.md"
+    mode, sha = tree_lookup_path(repo.get_object, commit.tree, path)
+    # Normalizer takes care of line ending conversion and applying smudge
+    # filters during checkout. See the Git Book for more details:
+    # https://git-scm.com/book/ms/v2/Customizing-Git-Git-Attributes
+    blob = repo.get_blob_normalizer().checkout_normalize(repo[sha], path)
+
+    print(f"The readme at {commit.id.decode('ascii')} is:")
+    print(blob.data.decode("utf-8"))
+
+
+Retrieve all or a subset of files at a particular commit
+--------------------------------------------------------
+
+A dedicated helper function
+:py:func:`dulwich.object_store.iter_commit_contents` exists to
+simplify the common requirement of programmatically getting the
+contents of a repo as stored at a specific commit. Unlike
+:py:func:`!porcelain.checkout`, it is not tied to a working tree, or
+even files.
+
+When paired with :py:func:`dulwich.index.build_file_from_blob`, it's
+very easy to write out the retrieved files to an arbitrary location on
+disk, independent of any working trees. This makes it ideal for tasks
+such as retrieving a pristine copy of the contained files without any
+of Git's tracking information, for use in deployments, automation, and
+similar.
+
+.. code-block:: python
+
+    import stat
+    from pathlib import Path
+
+    from dulwich.repo import Repo
+    from dulwich.object_store import iter_commit_contents
+    from dulwich.index import build_file_from_blob
+
+    repo = Repo("/path/to/another/repo")
+    normalize = repo.get_blob_normalizer().checkout_normalize
+    commit = repo[repo.head()]
+    encoding = commit.encoding or "utf-8"
+
+    # Scan the repo at current HEAD. Retrieve all files marked as
+    # executable under bin/ and write them to disk
+    for entry in iter_commit_contents(repo, commit.id, include=[b"bin"]):
+        if entry.mode & stat.S_IXUSR:
+            # Strip the leading bin/ from returned paths, write to
+            # current directory
+            path = Path(entry.path.decode(encoding)).relative_to("bin/")
+            # Make sure the target directory exists
+            path.parent.mkdir(parents=True, exist_ok=True)
+
+            blob = normalize(repo[entry.sha], entry.path)
+            build_file_from_blob(
+                blob, entry.mode,
+                str(path)
+            )
+            print(f"Wrote executable {path}")