#!/usr/bin/env python2.5
-import sys, re, errno, stat, tempfile, struct, mmap
+import sys, re, errno, stat, tempfile, struct, mmap, time
import options, git
from helpers import *
class IxEntry:
- def __init__(self, name, m, ofs):
+ def __init__(self, name, m, ofs, tstart):
self._m = m
self._ofs = ofs
self.name = str(name)
+ self.tstart = tstart
(self.dev, self.ctime, self.mtime, self.uid, self.gid,
self.size, self.sha,
self.flags) = struct.unpack(INDEX_SIG, buffer(m, ofs, ENTLEN))
self.gid = st.st_gid
self.size = st.st_size
self.flags |= IX_EXISTS
- if old != new:
+ if int(st.st_ctime) >= self.tstart or old != new:
self.flags &= ~IX_HASHVALID
return 1 # dirty
else:
self.save()
def __iter__(self):
+ tstart = int(time.time())
ofs = len(INDEX_HDR)
while ofs < len(self.m):
eon = self.m.find('\0', ofs)
assert(eon >= 0)
yield IxEntry(buffer(self.m, ofs, eon-ofs),
- self.m, eon+1)
+ self.m, eon+1, tstart = tstart)
ofs = eon + 1 + ENTLEN
def save(self):
% os.path.realpath(p))
continue
if stat.S_ISDIR(st.st_mode):
- p += '/'
+ p = _slashappend(p)
lds.append((p, st))
for p,st in reversed(sorted(lds)):
dirty += handle_path(ri, wi, path, p, st, xdev,
return self.cur
+def _slashappend(s):
+ if s and not s.endswith('/'):
+ return s + '/'
+ else:
+ return s
+
def update_index(path):
ri = IndexReader(indexfile)
wi = IndexWriter(indexfile)
if rpath[-1] == '/':
rpath = rpath[:-1]
(dir, name) = os.path.split(rpath)
- if dir and dir[-1] != '/':
- dir += '/'
+ dir = _slashappend(dir)
if stat.S_ISDIR(st.st_mode) and (not rpath or rpath[-1] != '/'):
name += '/'
can_delete_siblings = True
for path in extra:
rp = os.path.realpath(path)
st = os.lstat(rp)
- if stat.S_ISDIR(st.st_mode) and not rp.endswith('/'):
- rp += '/'
- path += '/'
+ if stat.S_ISDIR(st.st_mode):
+ rp = _slashappend(rp)
+ path = _slashappend(path)
xpaths.append((rp, path))
paths = []
update_index(rp)
if opt['print'] or opt.status or opt.modified:
- pi = iter(paths or [('/', '/')])
+ pi = iter(paths or [(_slashappend(os.path.realpath('.')), '')])
(rpin, pin) = pi.next()
for ent in IndexReader(indexfile):
if ent.name < rpin:
if opt.modified and ent.flags & IX_HASHVALID:
continue
name = pin + ent.name[len(rpin):]
+ if not name:
+ name = '.'
if opt.status:
if not ent.flags & IX_EXISTS:
print 'D ' + name
rm -rf "$BUP_DIR"
WVPASS bup init
-WVSTART "split"
+WVSTART "index"
+D=bupdata.tmp
+rm -rf $D
+mkdir $D
+WVPASSEQ "$(bup index -p)" ""
+WVPASSEQ "$(bup index -p $D)" ""
+WVFAIL [ -e $D.fake ]
+WVFAIL bup index -u $D.fake
+WVPASS bup index -u $D
+WVPASSEQ "$(bup index -p $D)" "$D/"
+touch $D/a $D/b
+mkdir $D/d $D/d/e
+WVPASSEQ "$(bup index -s $D/)" "A $D/"
+WVPASSEQ "$(bup index -s $D/b)" ""
+bup tick
+WVPASSEQ "$(bup index -us $D/b)" "A $D/b"
+WVPASSEQ "$(bup index -us $D)" \
+"A $D/d/e/
+A $D/d/
+A $D/b
+A $D/a
+A $D/"
+WVPASSEQ "$(bup index -us $D/b $D/a --fake-valid)" \
+" $D/b
+ $D/a"
+WVPASSEQ "$(bup index -us $D/a)" " $D/a" # stays unmodified
+touch $D/a
+WVPASS bup index -u $D/a # becomes modified
+WVPASSEQ "$(bup index -s $D)" \
+"A $D/d/e/
+A $D/d/
+ $D/b
+M $D/a
+A $D/"
+WVPASSEQ "$(cd $D && bup index -m .)" \
+"./d/e/
+./d/
+./a
+./"
+WVPASSEQ "$(cd $D && bup index -m)" \
+"d/e/
+d/
+a
+."
+
+WVSTART "split"
WVPASS bup split --bench -b <testfile1 >tags1.tmp
WVPASS bup split -vvvv -b testfile2 >tags2.tmp
WVPASS bup split -t testfile2 >tags2t.tmp