]> arthur.barton.de Git - bup.git/blobdiff - lib/bup/ls.py
Add -n, -A, -F, --file-type, --numeric-ids and detailed -l to "bup ls".
[bup.git] / lib / bup / ls.py
index a86a904a0a83d28dc7a7f155c2e40896b71bfc22..002e15d60f824f97c474deb96fa50b7c31d5352a 100644 (file)
@@ -1,28 +1,47 @@
 """Common code for listing files from a bup repository."""
-import stat
-from bup import options, vfs
+import copy, stat
+from bup import metadata, options, vfs
 from helpers import *
 
 
-def node_name(text, n, show_hash = False,
-              show_filesize = False,
-              filesize = None,
+def node_info(n, name,
+              show_hash = False,
+              long_fmt = False,
+              classification = None,
+              numeric_ids = False,
               human_readable = False):
-    """Add symbols to a node's name to differentiate file types."""
-    prefix = ''
+    """Return a string containing the information to display for the node
+    n.  Classification may be "all", "type", or None.
+
+    """
+    result = ''
     if show_hash:
-        prefix += "%s " % n.hash.encode('hex')
-    if show_filesize:
-        if human_readable:
-            prefix += "%10s " % format_filesize(filesize)
+        result += "%s " % n.hash.encode('hex')
+    if long_fmt:
+        meta = copy.copy(n.metadata())
+        meta.size = n.size()
+        result += metadata.summary_str(meta,
+                                       numeric_ids = numeric_ids,
+                                       human_readable = human_readable) + ' '
+    result += name
+    if classification:
+        if n.metadata():
+            mode = n.metadata().mode
         else:
-            prefix += "%14d " % filesize
-    if stat.S_ISDIR(n.mode):
-        return '%s%s/' % (prefix, text)
-    elif stat.S_ISLNK(n.mode):
-        return '%s%s@' % (prefix, text)
-    else:
-        return '%s%s' % (prefix, text)
+            mode = n.mode
+        if stat.S_ISREG(mode):
+            if classification == 'all' \
+               and stat.S_IMODE(mode) & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH):
+                result += '*'
+        elif stat.S_ISDIR(mode):
+            result += '/'
+        elif stat.S_ISLNK(mode):
+            result += '@'
+        elif stat.S_ISFIFO(mode):
+            result += '|'
+        elif stat.S_ISSOCK(mode):
+            result += '='
+    return result
 
 
 optspec = """
@@ -30,16 +49,22 @@ optspec = """
 --
 s,hash   show hash for each file
 a,all    show hidden files
-l        show file sizes
+A,almost-all    show hidden files except . and ..
+l        use a detailed, long listing format
+F,classify append type indicator: dir/ sym@ fifo| sock= exec*
+file-type append type indicator: dir/ sym@ fifo| sock=
 human-readable    print human readable file sizes (i.e. 3.9K, 4.7M)
+n,numeric-ids list numeric IDs (user, group, etc.) rather than names
 """
 
 def do_ls(args, pwd, default='.', onabort=None, spec_prefix=''):
     """Output a listing of a file or directory in the bup repository.
 
-    When stdout is attached to a tty, the output is formatted in columns. When
-    not attached to tty (for example when the output is piped to another
-    command), one file is listed per line.
+    When a long listing is not requested and stdout is attached to a
+    tty, the output is formatted in columns. When not attached to tty
+    (for example when the output is piped to another command), one
+    file is listed per line.
+
     """
     if onabort:
         o = options.Options(optspec % spec_prefix, onabort=onabort)
@@ -47,7 +72,32 @@ def do_ls(args, pwd, default='.', onabort=None, spec_prefix=''):
         o = options.Options(optspec % spec_prefix)
     (opt, flags, extra) = o.parse(args)
 
+    # Handle order-sensitive options.
+    classification = None
+    show_hidden = None
+    for flag in flags:
+        (option, parameter) = flag
+        if option in ('-F', '--classify'):
+            classification = 'all'
+        elif option == '--file-type':
+            classification = 'type'
+        elif option in ('-a', '--all'):
+            show_hidden = 'all'
+        elif option in ('-A', '--almost-all'):
+            show_hidden = 'almost'
+
     L = []
+    def output_node_info(node, name):
+        info = node_info(node, name,
+                         show_hash = opt.hash,
+                         long_fmt = opt.l,
+                         classification = classification,
+                         numeric_ids = opt.numeric_ids,
+                         human_readable = opt.human_readable)
+        if not opt.l and istty1:
+            L.append(info)
+        else:
+            print info
 
     ret = 0
     for path in (extra or [default]):
@@ -55,28 +105,21 @@ def do_ls(args, pwd, default='.', onabort=None, spec_prefix=''):
             n = pwd.try_resolve(path)
 
             if stat.S_ISDIR(n.mode):
+                if show_hidden == 'all':
+                    for implied, name in ((n, '.'), (n.parent, '..')):
+                        output_node_info(implied, name)
                 for sub in n:
                     name = sub.name
-                    fsize = sub.size() if opt.l else None
-                    nname = node_name(name, sub, opt.hash, opt.l, fsize,
-                                      opt.human_readable)
-                    if opt.all or not len(name)>1 or not name.startswith('.'):
-                        if istty1:
-                            L.append(nname)
-                        else:
-                            print nname
+                    if show_hidden in ('almost', 'all') \
+                       or not len(name)>1 or not name.startswith('.'):
+                        output_node_info(sub, name)
             else:
-                nname = node_name(path, n, opt.hash, opt.l, None,
-                                  opt.human_readable)
-                if istty1:
-                    L.append(nname)
-                else:
-                    print nname
+                output_node_info(n, path)
         except vfs.NodeError, e:
             log('error: %s\n' % e)
             ret = 1
 
-    if istty1:
+    if L:
         sys.stdout.write(columnate(L, ''))
 
     return ret