]> arthur.barton.de Git - bup.git/commitdiff
vfs2: report tree metadata for commits
authorRob Browning <rlb@defaultvalue.org>
Sat, 4 Nov 2017 20:55:23 +0000 (15:55 -0500)
committerRob Browning <rlb@defaultvalue.org>
Sat, 16 Dec 2017 23:29:23 +0000 (17:29 -0600)
Don't synthesize metadata for a commit (like /foo, /foo/2017-..., or
/.tag/some-commit) by reporting the author date as the mtime, instead
use the metadata for the underlying commit tree.

Among other things, this avoids an inconsistency between the metadata
for ".../commit" and ".../commit/.".

Signed-off-by: Rob Browning <rlb@defaultvalue.org>
Tested-by: Rob Browning <rlb@defaultvalue.org>
lib/bup/t/tvfs.py
lib/bup/vfs2.py
t/test-ls.sh

index c0630125d539de2069f371aa4210e544bb684639..d850dc85148775f3b036495d9a96630d041471a9 100644 (file)
@@ -226,15 +226,17 @@ def test_resolve():
             tip_hash = exo(('git', 'show-ref', 'refs/heads/test'))[0]
             tip_oidx = tip_hash.strip().split()[0]
             tip_oid = tip_oidx.decode('hex')
-            tip_meta = Metadata()
-            tip_meta.mode = S_IFDIR | 0o755
-            tip_meta.uid = tip_meta.gid = tip_meta.size = 0
-            tip_meta.atime = tip_meta.mtime = tip_meta.ctime = save_time * 10**9
-            test_revlist = vfs.RevList(meta=tip_meta, oid=tip_oid)
             tip_tree_oidx = exo(('git', 'log', '--pretty=%T', '-n1',
                                  tip_oidx))[0].strip()
             tip_tree_oid = tip_tree_oidx.decode('hex')
             tip_tree = tree_dict(repo, tip_tree_oid)
+            test_revlist = vfs.RevList(meta=S_IFDIR | 0o755, oid=tip_oid)
+            test_revlist_w_meta = vfs.RevList(meta=tip_tree['.'].meta,
+                                              oid=tip_oid)
+            expected_latest_item = vfs.Commit(meta=S_IFDIR | 0o755,
+                                              oid=tip_tree_oid,
+                                              coid=tip_oid)
+            expected_test_tag_item = expected_latest_item
 
             wvstart('resolve: /')
             res = resolve(repo, '/')
@@ -255,7 +257,7 @@ def test_resolve():
             ignore, tag_item = res[1]
             tag_content = frozenset(vfs.contents(repo, tag_item))
             wvpasseq(frozenset([('.', tag_item),
-                                ('test-tag', test_revlist)]),
+                                ('test-tag', expected_test_tag_item)]),
                      tag_content)
 
             wvstart('resolve: /test')
@@ -264,10 +266,7 @@ def test_resolve():
             wvpasseq((('', vfs._root), ('test', test_revlist)), res)
             ignore, test_item = res[1]
             test_content = frozenset(vfs.contents(repo, test_item))
-            expected_latest_item = vfs.Commit(meta=S_IFDIR | 0o755,
-                                              oid=tip_tree_oid,
-                                              coid=tip_oid)
-            wvpasseq(frozenset([('.', test_revlist),
+            wvpasseq(frozenset([('.', test_revlist_w_meta),
                                 (save_time_str, expected_latest_item),
                                 ('latest', expected_latest_item)]),
                      test_content)
@@ -410,18 +409,18 @@ def test_duplicate_save_dates():
             name, revlist = res[-1]
             wvpasseq('test', name)
             wvpasseq(('.',
-                      '1970-01-02-034640-10',
-                      '1970-01-02-034640-09',
-                      '1970-01-02-034640-08',
-                      '1970-01-02-034640-07',
-                      '1970-01-02-034640-06',
-                      '1970-01-02-034640-05',
-                      '1970-01-02-034640-04',
-                      '1970-01-02-034640-03',
-                      '1970-01-02-034640-02',
-                      '1970-01-02-034640-01',
                       '1970-01-02-034640-00',
+                      '1970-01-02-034640-01',
+                      '1970-01-02-034640-02',
+                      '1970-01-02-034640-03',
+                      '1970-01-02-034640-04',
+                      '1970-01-02-034640-05',
+                      '1970-01-02-034640-06',
+                      '1970-01-02-034640-07',
+                      '1970-01-02-034640-08',
+                      '1970-01-02-034640-09',
+                      '1970-01-02-034640-10',
                       'latest'),
-                     tuple(x[0] for x in vfs.contents(repo, revlist)))
+                     tuple(sorted(x[0] for x in vfs.contents(repo, revlist))))
 
 # FIXME: add tests for the want_meta=False cases.
index 316d14052cf44c723d5e333e53281675e8013115..49f0c4a114eb79967cce577fe3757fdfcbe7d4e3 100644 (file)
@@ -284,12 +284,12 @@ def tree_data_and_bupm(repo, oid):
             break
     return data, None
 
-def _find_dir_item_metadata(repo, item):
-    """Return the metadata for the tree or commit item, or None if the
-    tree has no metadata (i.e. older bup save, or non-bup tree).
+def _find_treeish_oid_metadata(repo, oid):
+    """Return the metadata for the tree or commit oid, or None if the tree
+    has no metadata (i.e. older bup save, or non-bup tree).
 
     """
-    tree_data, bupm_oid = tree_data_and_bupm(repo, item.oid)
+    tree_data, bupm_oid = tree_data_and_bupm(repo, oid)
     if bupm_oid:
         with _FileReader(repo, bupm_oid) as meta_stream:
             return _read_dir_meta(meta_stream)
@@ -331,19 +331,29 @@ def fopen(repo, item):
     assert S_ISREG(item_mode(item))
     return _FileReader(repo, item.oid)
 
-def _commit_meta_from_auth_sec(author_sec):
-    m = Metadata()
-    m.mode = default_dir_mode
-    m.uid = m.gid = m.size = 0
-    m.atime = m.mtime = m.ctime = author_sec * 10**9
-    return m
+def _commit_item_from_data(oid, data):
+    info = parse_commit(data)
+    return Commit(meta=default_dir_mode,
+                  oid=info.tree.decode('hex'),
+                  coid=oid)
 
-def _commit_meta_from_oidx(repo, oidx):
-    it = repo.cat(oidx)
+def _commit_item_from_oid(repo, oid, require_meta):
+    it = repo.cat(oid.encode('hex'))
     _, typ, size = next(it)
     assert typ == 'commit'
-    author_sec = parse_commit(''.join(it)).author_sec
-    return _commit_meta_from_auth_sec(author_sec)
+    commit = _commit_item_from_data(oid, ''.join(it))
+    if require_meta:
+        meta = _find_treeish_oid_metadata(repo, commit.tree)
+        if meta:
+            commit = commit._replace(meta=meta)
+    return commit
+
+def _revlist_item_from_oid(repo, oid, require_meta):
+    if require_meta:
+        meta = _find_treeish_oid_metadata(repo, oid) or default_dir_mode
+    else:
+        meta = default_dir_mode
+    return RevList(oid=oid, meta=meta)
 
 def parse_rev_auth_secs(f):
     tree, author_secs = f.readline().split(None, 2)
@@ -366,9 +376,7 @@ def root_items(repo, names=None):
         # in parallel (i.e. meta vs refs).
         for name, oid in tuple(repo.refs([], limit_to_heads=True)):
             assert(name.startswith('refs/heads/'))
-            name = name[11:]
-            m = _commit_meta_from_oidx(repo, oid.encode('hex'))
-            yield name, RevList(meta=m, oid=oid)
+            yield name[11:], _revlist_item_from_oid(repo, oid, False)
         return
 
     if '.' in names:
@@ -385,8 +393,7 @@ def root_items(repo, names=None):
             continue
         assert typ == 'commit'
         commit = parse_commit(''.join(it))
-        yield ref, RevList(meta=_commit_meta_from_auth_sec(commit.author_sec),
-                           oid=oidx.decode('hex'))
+        yield ref, _revlist_item_from_oid(repo, oidx.decode('hex'), False)
 
 def ordered_tree_entries(tree_data, bupm=None):
     """Yields (name, mangled_name, kind, gitmode, oid) for each item in
@@ -519,11 +526,10 @@ def revlist_items(repo, oid, names):
     oidx = oid.encode('hex')
     names = frozenset(name for name in (names or tuple()) \
                       if _save_name_rx.match(name) or name in ('.', 'latest'))
-
     # Do this before we open the rev_list iterator so we're not nesting
     if (not names) or ('.' in names):
-        yield '.', RevList(oid=oid, meta=_commit_meta_from_oidx(repo, oidx))
-    
+        yield '.', _revlist_item_from_oid(repo, oid, True)
+
     revs = repo.rev_list((oidx,), format='%T %at', parse=parse_rev_auth_secs)
     rev_items, rev_names = tee(revs)
     revs = None  # Don't disturb the tees
@@ -565,10 +571,7 @@ def tags_items(repo, names):
         it = repo.cat(oidx)
         _, typ, size = next(it)
         if typ == 'commit':
-            tree_oid = parse_commit(''.join(it)).tree.decode('hex')
-            assert len(tree_oid) == 20
-            # FIXME: more efficient/bulk?
-            return RevList(meta=_commit_meta_from_oidx(repo, oidx), oid=oid)
+            return _commit_item_from_data(oid, ''.join(it))
         for _ in it: pass
         if typ == 'blob':
             return Item(meta=default_file_mode, oid=oid)
@@ -714,7 +717,7 @@ def _resolve_path(repo, path, parent=None, want_meta=True, deref=False):
                     return tuple(past)
                 # It's treeish
                 if want_meta and type(item) in real_tree_types:
-                    dir_meta = _find_dir_item_metadata(repo, item)
+                    dir_meta = _find_treeish_oid_metadata(repo, item.oid)
                     if dir_meta:
                         item = item._replace(meta=dir_meta)
                 if not future:
index cf9039e9c5f52fb16ee40061ac5b0bbde4960664..8b87778c4f2cc55043e81dcca5ebea5b1d6edca2 100755 (executable)
@@ -101,27 +101,27 @@ WVPASSEQ "$(WVPASS bup ls -d src/latest)" "src/latest"
 WVSTART "ls (long)"
 
 WVPASSEQ "$(WVPASS bup ls -l / | tr -s ' ' ' ')" \
-"drwxr-xr-x 0/0 0 1977-09-05 12:56 src"
+"drwxr-xr-x 0/0 0 1970-01-01 00:00 src"
 
 WVPASSEQ "$(WVPASS bup ls -lA / | tr -s ' ' ' ')" \
 "drwxr-xr-x 0/0 0 1970-01-01 00:00 .tag
-drwxr-xr-x 0/0 0 1977-09-05 12:56 src"
+drwxr-xr-x 0/0 0 1970-01-01 00:00 src"
 
 WVPASSEQ "$(WVPASS bup ls -lAF / | tr -s ' ' ' ')" \
 "drwxr-xr-x 0/0 0 1970-01-01 00:00 .tag/
-drwxr-xr-x 0/0 0 1977-09-05 12:56 src/"
+drwxr-xr-x 0/0 0 1970-01-01 00:00 src/"
 
 WVPASSEQ "$(WVPASS bup ls -la / | tr -s ' ' ' ')" \
 "drwxr-xr-x 0/0 0 1970-01-01 00:00 .
 drwxr-xr-x 0/0 0 1970-01-01 00:00 ..
 drwxr-xr-x 0/0 0 1970-01-01 00:00 .tag
-drwxr-xr-x 0/0 0 1977-09-05 12:56 src"
+drwxr-xr-x 0/0 0 1970-01-01 00:00 src"
 
 WVPASSEQ "$(WVPASS bup ls -laF / | tr -s ' ' ' ')" \
 "drwxr-xr-x 0/0 0 1970-01-01 00:00 ./
 drwxr-xr-x 0/0 0 1970-01-01 00:00 ../
 drwxr-xr-x 0/0 0 1970-01-01 00:00 .tag/
-drwxr-xr-x 0/0 0 1977-09-05 12:56 src/"
+drwxr-xr-x 0/0 0 1970-01-01 00:00 src/"
 
 symlink_mode="$(WVPASS ls -l src/symlink | cut -b -10)" || exit $?
 socket_mode="$(WVPASS ls -l src/socket | cut -b -10)" || exit $?
@@ -159,7 +159,7 @@ $symlink_mode $user/$group $symlink_size $symlink_date symlink -> file"
 
 WVPASSEQ "$(bup ls -la src/latest | tr -s ' ' ' ')" \
 "drwx------ $user/$group 0 2009-10-03 23:48 .
-drwxr-xr-x 0/0 0 1977-09-05 12:56 ..
+drwxr-xr-x 0/0 0 1970-01-01 00:00 ..
 -rw------- $user/$group 0 2009-10-03 23:48 .dotfile
 -rwx------ $user/$group 0 2009-10-03 23:48 executable
 prw------- $user/$group 0 2009-10-03 23:48 fifo