Explorar o código

Add dulwich.porcelain.ls_tree.

Jelmer Vernooij %!s(int64=8) %!d(string=hai) anos
pai
achega
5afa48af64
Modificáronse 6 ficheiros con 108 adicións e 6 borrados
  1. 4 0
      NEWS
  2. 17 0
      bin/dulwich
  3. 16 5
      dulwich/objects.py
  4. 32 0
      dulwich/porcelain.py
  5. 12 1
      dulwich/tests/test_objects.py
  6. 27 0
      dulwich/tests/test_porcelain.py

+ 4 - 0
NEWS

@@ -11,6 +11,10 @@
     to "Apache License, version 2.0 or later or GNU General Public License,
     version 2.0 or later". (#153)
 
+ IMPROVEMENTS
+
+  * Add ``dulwich.porcelain.ls_tree`` implementation. (Jelmer Vernooij)
+
 0.14.1	2016-07-05
 
  BUG FIXES

+ 17 - 0
bin/dulwich

@@ -358,6 +358,22 @@ def cmd_ls_remote(args):
         sys.stdout.write("%s\t%s\n" % (ref, refs[ref]))
 
 
+def cmd_ls_tree(args):
+    parser = optparse.OptionParser()
+    parser.add_option("-r", "--recursive", action="store_true",
+                      help="Recusively list tree contents.")
+    parser.add_option("--name-only", action="store_true",
+                      help="Only display name.")
+    options, args = parser.parse_args(args)
+    try:
+        treeish = args.pop(0)
+    except IndexError:
+        treeish = None
+    porcelain.ls_tree(
+        '.', treeish, outstream=sys.stdout, recursive=options.recursive,
+        name_only=options.name_only)
+
+
 def cmd_pack_objects(args):
     opts, args = getopt(args, '', ['stdout'])
     opts = dict(opts)
@@ -395,6 +411,7 @@ commands = {
     "init": cmd_init,
     "log": cmd_log,
     "ls-remote": cmd_ls_remote,
+    "ls-tree": cmd_ls_tree,
     "pack-objects": cmd_pack_objects,
     "receive-pack": cmd_receive_pack,
     "repack": cmd_repack,

+ 16 - 5
dulwich/objects.py

@@ -825,6 +825,21 @@ def key_entry_name_order(entry):
     return entry[0]
 
 
+def pretty_format_tree_entry(name, mode, hexsha):
+    """Pretty format tree entry.
+
+    :param name: Name of the directory entry
+    :param mode: Mode of entry
+    :param hexsha: Hexsha of the referenced object
+    :return: string describing the tree entry
+    """
+    if mode & stat.S_IFDIR:
+        kind = "tree"
+    else:
+        kind = "blob"
+    return "%04o %s %s\t%s\n" % (mode, kind, hexsha, name)
+
+
 class Tree(ShaFile):
     """A Git tree object"""
 
@@ -948,11 +963,7 @@ class Tree(ShaFile):
     def as_pretty_string(self):
         text = []
         for name, mode, hexsha in self.iteritems():
-            if mode & stat.S_IFDIR:
-                kind = "tree"
-            else:
-                kind = "blob"
-            text.append("%04o %s %s\t%s\n" % (mode, kind, hexsha, name))
+            text.append(pretty_format_tree_entry(name, mode, hexsha))
         return "".join(text)
 
     def lookup_path(self, lookup_obj, path):

+ 32 - 0
dulwich/porcelain.py

@@ -30,6 +30,7 @@ Currently implemented:
  * fetch
  * init
  * ls-remote
+ * ls-tree
  * pull
  * push
  * rm
@@ -54,6 +55,8 @@ from contextlib import (
     contextmanager,
 )
 import os
+import posixpath
+import stat
 import sys
 import time
 
@@ -72,6 +75,7 @@ from dulwich.objects import (
     Commit,
     Tag,
     parse_timezone,
+    pretty_format_tree_entry,
     )
 from dulwich.objectspec import (
     parse_object,
@@ -860,3 +864,31 @@ def pack_objects(repo, object_ids, packf, idxf, delta_window_size=None):
         entries = [(k, v[0], v[1]) for (k, v) in entries.items()]
         entries.sort()
         write_pack_index(idxf, entries, data_sum)
+
+
+def ls_tree(repo, tree_ish=None, outstream=sys.stdout, recursive=False,
+        name_only=False):
+    """List contents of a tree.
+
+    :param repo: Path to the repository
+    :param tree_ish: Tree id to list
+    :param outstream: Output stream (defaults to stdout)
+    :param recursive: Whether to recursively list files
+    :param name_only: Only print item name
+    """
+    def list_tree(store, treeid, base):
+        for (name, mode, sha) in store[treeid].iteritems():
+            if base:
+                name = posixpath.join(base, name)
+            if name_only:
+                outstream.write(name + b"\n")
+            else:
+                outstream.write(pretty_format_tree_entry(name, mode, sha))
+            if stat.S_ISDIR(mode):
+                list_tree(store, sha, name)
+    if tree_ish is None:
+        tree_ish = "HEAD"
+    with open_repo_closing(repo) as r:
+        c = r[tree_ish]
+        treeid = c.tree
+        list_tree(r.object_store, treeid, "")

+ 12 - 1
dulwich/tests/test_objects.py

@@ -48,8 +48,9 @@ from dulwich.objects import (
     hex_to_filename,
     check_hexsha,
     check_identity,
-    parse_timezone,
     object_class,
+    parse_timezone,
+    pretty_format_tree_entry,
     parse_tree,
     _parse_tree_py,
     sorted_tree_items,
@@ -1130,3 +1131,13 @@ class ShaFileSerializeTests(TestCase):
 
         with self.assert_serialization_on_change(tag):
             tag.message = b'new message'
+
+
+class PrettyFormatTreeEntryTests(TestCase):
+
+    def test_format(self):
+        self.assertEquals(
+                '40000 tree 40820c38cfb182ce6c8b261555410d8382a5918b\tfoo\n',
+                pretty_format_tree_entry("foo", 0o40000,
+                    "40820c38cfb182ce6c8b261555410d8382a5918b"))
+

+ 27 - 0
dulwich/tests/test_porcelain.py

@@ -802,3 +802,30 @@ class RepackTests(PorcelainTestCase):
         filename = os.path.basename(fullpath)
         porcelain.add(repo=self.repo.path, paths=filename)
         porcelain.repack(self.repo)
+
+
+class LsTreeTests(PorcelainTestCase):
+
+    def test_empty(self):
+        porcelain.commit(repo=self.repo.path, message=b'test status',
+            author=b'', committer=b'')
+
+        f = StringIO()
+        porcelain.ls_tree(self.repo, "HEAD", outstream=f)
+        self.assertEquals(f.getvalue(), "")
+
+    def test_simple(self):
+        # Commit a dummy file then modify it
+        fullpath = os.path.join(self.repo.path, 'foo')
+        with open(fullpath, 'w') as f:
+            f.write('origstuff')
+
+        porcelain.add(repo=self.repo.path, paths=['foo'])
+        porcelain.commit(repo=self.repo.path, message=b'test status',
+            author=b'', committer=b'')
+
+        f = StringIO()
+        porcelain.ls_tree(self.repo, "HEAD", outstream=f)
+        self.assertEquals(
+                f.getvalue(),
+                '100644 blob 8b82634d7eae019850bb883f06abf428c58bc9aa\tfoo\n')