]> arthur.barton.de Git - bup.git/blobdiff - cmd/save-cmd.py
build: fix C-side dependencies
[bup.git] / cmd / save-cmd.py
index 5140ac027ecff4cef3b93ff93cd7ab05a6295c00..a6190b0a09623a6654d7e860b3a8405f5df33066 100755 (executable)
@@ -118,12 +118,6 @@ else:
 handle_ctrl_c()
 
 
-def eatslash(dir):
-    if dir.endswith(b'/'):
-        return dir[:-1]
-    else:
-        return dir
-
 # Metadata is stored in a file named .bupm in each directory.  The
 # first metadata entry will be the metadata for the current directory.
 # The remaining entries will be for each of the other directory
@@ -132,8 +126,11 @@ def eatslash(dir):
 # Since the git tree elements are sorted according to
 # git.shalist_item_sort_key, the metalist items are accumulated as
 # (sort_key, metadata) tuples, and then sorted when the .bupm file is
-# created.  The sort_key must be computed using the element's real
-# name and mode rather than the git mode and (possibly mangled) name.
+# created.  The sort_key should have been computed using the element's
+# mangled name and git mode (after hashsplitting), but the code isn't
+# actually doing that but rather uses the element's real name and mode.
+# This makes things a bit more difficult when reading it back, see
+# vfs.ordered_tree_entries().
 
 # Maintain a stack of information representing the current location in
 # the archive being constructed.  The current path is recorded in
@@ -159,31 +156,37 @@ def _pop(force_tree, dir_metadata=None):
     part = parts.pop()
     shalist = shalists.pop()
     metalist = metalists.pop()
-    if metalist and not force_tree:
-        if dir_metadata: # Override the original metadata pushed for this dir.
-            metalist = [(b'', dir_metadata)] + metalist[1:]
-        sorted_metalist = sorted(metalist, key = lambda x : x[0])
-        metadata = b''.join([m[1].encode() for m in sorted_metalist])
-        metadata_f = BytesIO(metadata)
-        mode, id = hashsplit.split_to_blob_or_tree(w.new_blob, w.new_tree,
-                                                   [metadata_f],
-                                                   keep_boundaries=False)
-        shalist.append((mode, b'.bupm', id))
     # FIXME: only test if collision is possible (i.e. given --strip, etc.)?
     if force_tree:
         tree = force_tree
     else:
         names_seen = set()
         clean_list = []
+        metaidx = 1 # entry at 0 is for the dir
         for x in shalist:
             name = x[1]
             if name in names_seen:
                 parent_path = b'/'.join(parts) + b'/'
                 add_error('error: ignoring duplicate path %s in %s'
                           % (path_msg(name), path_msg(parent_path)))
+                if not stat.S_ISDIR(x[0]):
+                    del metalist[metaidx]
             else:
                 names_seen.add(name)
                 clean_list.append(x)
+                if not stat.S_ISDIR(x[0]):
+                    metaidx += 1
+
+        if dir_metadata: # Override the original metadata pushed for this dir.
+            metalist = [(b'', dir_metadata)] + metalist[1:]
+        sorted_metalist = sorted(metalist, key = lambda x : x[0])
+        metadata = b''.join([m[1].encode() for m in sorted_metalist])
+        metadata_f = BytesIO(metadata)
+        mode, id = hashsplit.split_to_blob_or_tree(w.new_blob, w.new_tree,
+                                                   [metadata_f],
+                                                   keep_boundaries=False)
+        clean_list.append((mode, b'.bupm', id))
+
         tree = w.new_tree(clean_list)
     if shalists:
         shalists[-1].append((GIT_MODE_TREE,
@@ -390,7 +393,6 @@ for (transname,ent) in r.filter(extra, wantrecurse=wantrecurse_during):
         continue
 
     # it's not a directory
-    id = None
     if hashvalid:
         id = ent.sha
         git_name = git.mangle_name(file, ent.mode, ent.gitmode)
@@ -403,6 +405,7 @@ for (transname,ent) in r.filter(extra, wantrecurse=wantrecurse_during):
         (meta.atime, meta.mtime, meta.ctime) = (ent.atime, ent.mtime, ent.ctime)
         metalists[-1].append((sort_key, meta))
     else:
+        id = None
         if stat.S_ISREG(ent.mode):
             try:
                 f = hashsplit.open_noatime(ent.name)
@@ -417,22 +420,21 @@ for (transname,ent) in r.filter(extra, wantrecurse=wantrecurse_during):
                 except (IOError, OSError) as e:
                     add_error('%s: %s' % (ent.name, e))
                     lastskip_name = ent.name
-        else:
-            if stat.S_ISDIR(ent.mode):
-                assert(0)  # handled above
-            elif stat.S_ISLNK(ent.mode):
-                try:
-                    rl = os.readlink(ent.name)
-                except (OSError, IOError) as e:
-                    add_error(e)
-                    lastskip_name = ent.name
-                else:
-                    (mode, id) = (GIT_MODE_SYMLINK, w.new_blob(rl))
+        elif stat.S_ISDIR(ent.mode):
+            assert(0)  # handled above
+        elif stat.S_ISLNK(ent.mode):
+            try:
+                rl = os.readlink(ent.name)
+            except (OSError, IOError) as e:
+                add_error(e)
+                lastskip_name = ent.name
             else:
-                # Everything else should be fully described by its
-                # metadata, so just record an empty blob, so the paths
-                # in the tree and .bupm will match up.
-                (mode, id) = (GIT_MODE_FILE, w.new_blob(b''))
+                (mode, id) = (GIT_MODE_SYMLINK, w.new_blob(rl))
+        else:
+            # Everything else should be fully described by its
+            # metadata, so just record an empty blob, so the paths
+            # in the tree and .bupm will match up.
+            (mode, id) = (GIT_MODE_FILE, w.new_blob(b''))
 
         if id:
             ent.validate(mode, id)
@@ -448,8 +450,8 @@ for (transname,ent) in r.filter(extra, wantrecurse=wantrecurse_during):
             except (OSError, IOError) as e:
                 add_error(e)
                 lastskip_name = ent.name
-            else:
-                metalists[-1].append((sort_key, meta))
+                meta = metadata.Metadata()
+            metalists[-1].append((sort_key, meta))
 
     if exists and wasmissing:
         count += oldsize