]> arthur.barton.de Git - bup.git/blobdiff - cmd/index-cmd.py
Restore any metadata during "bup restore"; add "bup meta --edit".
[bup.git] / cmd / index-cmd.py
index 683989007988e5a38a48a27256dd33a8efd106b9..a2df5115492dcdc9b99ee0d6d7f5c01a7cd1e73a 100755 (executable)
@@ -1,14 +1,8 @@
 #!/usr/bin/env python
-import os, sys, stat, time
+import sys, stat, time, os
 from bup import options, git, index, drecurse
 from bup.helpers import *
-
-
-def merge_indexes(out, r1, r2):
-    for e in index.MergeIter([r1, r2]):
-        # FIXME: shouldn't we remove deleted entries eventually?  When?
-        out.add_ixentry(e)
-
+from bup.hashsplit import GIT_MODE_TREE, GIT_MODE_FILE
 
 class IterHelper:
     def __init__(self, l):
@@ -54,25 +48,29 @@ def check_index(reader):
     log('check: passed.\n')
 
 
-def update_index(top):
+def update_index(top, excluded_paths):
+    tmax = time.time() - 1
     ri = index.Reader(indexfile)
-    wi = index.Writer(indexfile)
+    wi = index.Writer(indexfile, tmax)
     rig = IterHelper(ri.iter(name=top))
     tstart = int(time.time())
 
     hashgen = None
     if opt.fake_valid:
         def hashgen(name):
-            return (0100644, index.FAKE_SHA)
+            return (GIT_MODE_FILE, index.FAKE_SHA)
 
     total = 0
-    for (path,pst) in drecurse.recursive_dirlist([top], xdev=opt.xdev):
+    bup_dir = os.path.abspath(git.repo())
+    for (path,pst) in drecurse.recursive_dirlist([top], xdev=opt.xdev,
+                                                 bup_dir=bup_dir,
+                                                 excluded_paths=excluded_paths):
         if opt.verbose>=2 or (opt.verbose==1 and stat.S_ISDIR(pst.st_mode)):
             sys.stdout.write('%s\n' % path)
             sys.stdout.flush()
-            progress('Indexing: %d\r' % total)
+            qprogress('Indexing: %d\r' % total)
         elif not (total % 128):
-            progress('Indexing: %d\r' % total)
+            qprogress('Indexing: %d\r' % total)
         total += 1
         while rig.cur and rig.cur.name > path:  # deleted paths
             if rig.cur.exists():
@@ -104,55 +102,75 @@ def update_index(top):
                 check_index(ri)
                 log('check: before merging: newfile\n')
                 check_index(wr)
-            mi = index.Writer(indexfile)
-            merge_indexes(mi, ri, wr)
+            mi = index.Writer(indexfile, tmax)
+
+            for e in index.merge(ri, wr):
+                # FIXME: shouldn't we remove deleted entries eventually?  When?
+                mi.add_ixentry(e)
+
             ri.close()
             mi.close()
+            wr.close()
         wi.abort()
     else:
         wi.close()
 
 
 optspec = """
-bup index <-p|m|u> [options...] <filenames...>
+bup index <-p|m|s|u> [options...] <filenames...>
 --
+ Modes:
 p,print    print the index entries for the given names (also works with -u)
 m,modified print only added/deleted/modified files (implies -p)
 s,status   print each filename with a status char (A/M/D) (implies -p)
-H,hash     print the hash for each object next to its name (implies -p)
+u,update   recursively update the index entries for the given file/dir names (default if no mode is specified)
+check      carefully check index file integrity
+ Options:
+H,hash     print the hash for each object next to its name
 l,long     print more information about each file
-u,update   (recursively) update the index entries for the given filenames
-x,xdev,one-file-system  don't cross filesystem boundaries
 fake-valid mark all index entries as up-to-date even if they aren't
 fake-invalid mark all index entries as invalid
-check      carefully check index file integrity
-f,indexfile=  the name of the index file (default 'index')
+f,indexfile=  the name of the index file (normally BUP_DIR/bupindex)
+exclude=   a path to exclude from the backup (can be used more than once)
+exclude-from= a file that contains exclude paths (can be used more than once)
 v,verbose  increase log output (can be used more than once)
+x,xdev,one-file-system  don't cross filesystem boundaries
 """
-o = options.Options('bup index', optspec)
+o = options.Options(optspec)
 (opt, flags, extra) = o.parse(sys.argv[1:])
 
 if not (opt.modified or opt['print'] or opt.status or opt.update or opt.check):
-    o.fatal('supply one or more of -p, -s, -m, -u, or --check')
+    opt.update = 1
 if (opt.fake_valid or opt.fake_invalid) and not opt.update:
     o.fatal('--fake-{in,}valid are meaningless without -u')
 if opt.fake_valid and opt.fake_invalid:
     o.fatal('--fake-valid is incompatible with --fake-invalid')
 
+# FIXME: remove this once we account for timestamp races, i.e. index;
+# touch new-file; index.  It's possible for this to happen quickly
+# enough that new-file ends up with the same timestamp as the first
+# index, and then bup will ignore it.
+tick_start = time.time()
+time.sleep(1 - (tick_start - int(tick_start)))
+
 git.check_repo_or_die()
 indexfile = opt.indexfile or git.repo('bupindex')
 
+handle_ctrl_c()
+
 if opt.check:
     log('check: starting initial check.\n')
     check_index(index.Reader(indexfile))
 
+excluded_paths = drecurse.parse_excludes(flags)
+
 paths = index.reduce_paths(extra)
 
 if opt.update:
-    if not paths:
-        o.fatal('update (-u) requested but no paths given')
+    if not extra:
+        o.fatal('update mode (-u) requested but no paths given')
     for (rp,path) in paths:
-        update_index(rp)
+        update_index(rp, excluded_paths)
 
 if opt['print'] or opt.status or opt.modified:
     for (name, ent) in index.Reader(indexfile).filter(extra or ['']):