]> arthur.barton.de Git - bup.git/commitdiff
Add a new 'bup newliner' that fixes progress message whitespace.
authorAvery Pennarun <apenwarr@gmail.com>
Sun, 28 Feb 2010 20:00:50 +0000 (15:00 -0500)
committerAvery Pennarun <apenwarr@gmail.com>
Sun, 28 Feb 2010 22:49:06 +0000 (17:49 -0500)
If we have multiple processes producing status messages to stderr and/or
stdout, and some of the lines ended in \r (ie. a progress message that was
supposed to be overwritten later) they would sometimes stomp on each other
and leave ugly bits lying around.

Now bup.py automatically pipes stdout/stderr to the new 'bup newliner'
command to fix this, but only if they were previously pointing at a tty.
Thus, if you redirect stdout to a file, nothing weird will happen, but if
you don't, stdout and stderr won't conflict with each other.

Anyway, the output is prettier now.  Trust me on this.

Makefile
bup.py
cmd-index.py
cmd-newliner.py [new file with mode: 0755]
cmd-save.py
helpers.py

index b9ed07b00c6bdab26c2a6af6c57395e522a8928e..eacedd047f83bdeaf0fb20816ad5f22f4c80f5ac 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,7 @@ default: all
 
 all: bup-split bup-join bup-save bup-init bup-server bup-index bup-tick \
        bup-midx bup-fuse bup-ls bup-damage bup-fsck bup-margin bup-drecurse \
-       bup-random bup-ftp \
+       bup-random bup-ftp bup-newliner \
        bup memtest _hashsplit$(SOEXT) \
        Documentation/all
        
diff --git a/bup.py b/bup.py
index 47bfb2d03ca52298196794bc0069c1b0689ae69f..56f3afe20b6362de0f49f6d886d13b63706f5ce8 100755 (executable)
--- a/bup.py
+++ b/bup.py
@@ -1,13 +1,12 @@
 #!/usr/bin/env python
-import sys, os, git
+import sys, os, subprocess
+import git
+from helpers import *
 
 argv = sys.argv
 exe = argv[0]
 exepath = os.path.split(exe)[0] or '.'
 
-def log(s):
-    sys.stderr.write(s)
-
 def usage():
     log('Usage: bup <subcmd> <options...>\n\n')
     log('Available subcommands:\n')
@@ -23,14 +22,52 @@ subcmd = argv[1]
 if subcmd == 'help':
     usage()
 
-subpath = os.path.join(exepath, 'bup-%s' % subcmd)
+def subpath(s):
+    return os.path.join(exepath, 'bup-%s' % s)
 
-if not os.path.exists(subpath):
+if not os.path.exists(subpath(subcmd)):
     log('error: unknown command "%s"\n' % subcmd)
     usage()
 
+
+already_fixed = atoi(os.environ.get('BUP_FORCE_TTY'))
+if subcmd in ['ftp']:
+    already_fixed = True
+fix_stdout = not already_fixed and os.isatty(1)
+fix_stderr = not already_fixed and os.isatty(2)
+
+def force_tty():
+    if fix_stdout or fix_stderr:
+        os.environ['BUP_FORCE_TTY'] = '1'
+
+if fix_stdout or fix_stderr:
+    realf = fix_stderr and 2 or 1
+    n = subprocess.Popen([subpath('newliner')],
+                         stdin=subprocess.PIPE, stdout=os.dup(realf),
+                         close_fds=True, preexec_fn=force_tty)
+    outf = fix_stdout and n.stdin.fileno() or 1
+    errf = fix_stderr and n.stdin.fileno() or 2
+else:
+    n = None
+    outf = 1
+    errf = 2
+
+ret = 95
 try:
-    os.execv(subpath, [subpath] + argv[2:])
-except OSError, e:
-    log('%s: %s\n' % (subpath, e))
-    sys.exit(98)
+    try:
+        p = subprocess.Popen([subpath(subcmd)] + argv[2:],
+                             stdout=outf, stderr=errf, preexec_fn=force_tty)
+        ret = p.wait()
+    except OSError, e:
+        log('%s: %s\n' % (subpath(subcmd), e))
+        ret = 98
+    except KeyboardInterrupt, e:
+        ret = 94
+finally:
+    if n:
+        n.stdin.close()
+        try:
+            n.wait()
+        except:
+            pass
+sys.exit(ret)
index 735eb7db5313cd6357fc8cc425fdb8b087abf0f5..9ad3efaeceb112dc9b39da408569e21e952801f1 100755 (executable)
@@ -63,7 +63,7 @@ def update_index(top):
     total = 0
     for (path,pst) in drecurse.recursive_dirlist([top], xdev=opt.xdev):
         if opt.verbose>=2 or (opt.verbose==1 and stat.S_ISDIR(pst.st_mode)):
-            sys.stdout.write('%-70s\n' % path)
+            sys.stdout.write('%s\n' % path)
             sys.stdout.flush()
             progress('Indexing: %d\r' % total)
         elif not (total % 128):
diff --git a/cmd-newliner.py b/cmd-newliner.py
new file mode 100755 (executable)
index 0000000..0b665aa
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+import sys, os, re
+import options
+
+optspec = """
+bup newliner
+"""
+o = options.Options('bup newliner', optspec)
+(opt, flags, extra) = o.parse(sys.argv[1:])
+
+if extra:
+    o.fatal("no arguments expected")
+
+r = re.compile(r'([\r\n])')
+lastlen = 0
+all = ''
+while 1:
+    l = r.split(all, 1)
+    if len(l) <= 1:
+        try:
+            b = os.read(sys.stdin.fileno(), 4096)
+        except KeyboardInterrupt:
+            break
+        if not b:
+            break
+        all += b
+    else:
+        assert(len(l) == 3)
+        (line, splitchar, all) = l
+        #splitchar = '\n'
+        sys.stdout.write('%-*s%s' % (lastlen, line, splitchar))
+        if splitchar == '\r':
+            lastlen = len(line)
+        else:
+            lastlen = 0
+        sys.stdout.flush()
+
+if lastlen or all:
+    sys.stdout.write('%-*s\n' % (lastlen, all))
index 2f73a9b88400ea9eee6963cb9153141d9396854a..e2b1f47358779c1ab426c735279c1ad769f1cacc 100755 (executable)
@@ -93,7 +93,7 @@ def progress_report(n):
             remainstr = '%dm%d' % (mins, secs)
         else:
             remainstr = '%ds' % secs
-    progress('Saving: %.2f%% (%d/%dk, %d/%d files) %s %s     \r'
+    progress('Saving: %.2f%% (%d/%dk, %d/%d files) %s %s\r'
              % (pct, count/1024, total/1024, fcount, ftotal,
                 remainstr, kpsstr))
 
index 2036ff4cc12a769b3a5d9ddbc73fd77f8a5e9532..75cf09cb240a4f8aa9d12b629855a3ed87d92b0e 100644 (file)
@@ -251,13 +251,19 @@ def count(l):
     return reduce(lambda x,y: x+1, l)
 
 
+def atoi(s):
+    try:
+        return int(s or '0')
+    except ValueError:
+        return 0
+
+
 saved_errors = []
 def add_error(e):
     saved_errors.append(e)
     log('%-70s\n' % e)
 
-
-istty = os.isatty(2)
+istty = os.isatty(2) or atoi(os.environ.get('BUP_FORCE_TTY'))
 def progress(s):
     if istty:
         log(s)