You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by tv...@apache.org on 2021/02/04 08:09:13 UTC

[buildstream] 05/43: _casbaseddirectory: Corrections to list_relative_files, adds _resolve

This is an automated email from the ASF dual-hosted git repository.

tvb pushed a commit to branch jmac/cas_to_cas_oct_v2
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit 64763b3c4d96aaeff8e14b7fdcba73a51e0f4b03
Author: Jim MacArthur <ji...@codethink.co.uk>
AuthorDate: Tue Oct 2 16:15:45 2018 +0100

    _casbaseddirectory: Corrections to list_relative_files, adds _resolve
---
 buildstream/storage/_casbaseddirectory.py | 85 +++++++++++++++++++++++++++----
 1 file changed, 76 insertions(+), 9 deletions(-)

diff --git a/buildstream/storage/_casbaseddirectory.py b/buildstream/storage/_casbaseddirectory.py
index e5c83c5..388b8ec 100644
--- a/buildstream/storage/_casbaseddirectory.py
+++ b/buildstream/storage/_casbaseddirectory.py
@@ -285,6 +285,67 @@ class CasBasedDirectory(Directory):
                 directory = directory.descend(c, create=True)
         return directory
 
+    def _resolve(self, name):
+        """ Resolves any name to an object. If the name points to a symlink in this 
+        directory, it returns the thing it points to, recursively. Returns a CasBasedDirectory, FileNode or None. Never creates a directory or otherwise alters the directory. """
+        # First check if it's a normal object and return that
+
+        if name not in self.index:
+            return None
+        index_entry = self.index[name]
+        if isinstance(index_entry.buildstream_object, Directory):
+            return index_entry.buildstream_object
+        elif isinstance(index_entry.pb_object, remote_execution_pb2.FileNode):
+            return index_entry.pb_object
+        
+        assert isinstance(index_entry.pb_object, remote_execution_pb2.SymlinkNode)
+        symlink = index_entry.pb_object
+        components = symlink.target.split(CasBasedDirectory._pb2_path_sep)
+
+        absolute = symlink.target.startswith(CasBasedDirectory._pb2_absolute_path_prefix)
+        if absolute:
+            start_directory = self.find_root()
+            # Discard the first empty element
+            components.pop(0)
+        else:
+            start_directory = self
+        directory = start_directory
+        print("Resolve {}: starting from {}".format(symlink.target, start_directory))
+        while True:
+            if not components:
+                # We ran out of path elements and ended up in a directory
+                return directory
+            c = components.pop(0)
+            if c == "..":
+                print("  resolving {}: up-dir".format(c))
+                # If directory.parent *is* None, this is an attempt to access
+                # '..' from the root, which is valid under POSIX; it just
+                # returns the root.                
+                if directory.parent is not None:
+                    directory = directory.parent
+            else:
+                if c in directory.index:
+                    f = directory._resolve(c)
+                    # Ultimately f must now be a file or directory
+                    if isinstance(f, CasBasedDirectory):
+                        directory = f
+                        print("  resolving {}: dir".format(c))
+
+                    else:
+                        # This is a file or None (i.e. broken symlink)
+                        print("  resolving {}: file/broken link".format(c))
+                        if components:
+                            # Oh dear. We have components left to resolve, but the one we're trying to resolve points to a file.
+                            raise VirtualDirectoryError("Reached a file called {} while trying to resolve a symlink; cannot proceed".format(c))
+                        else:
+                            return f
+                else:
+                    print("  resolving {}: nonexistent!".format(c))
+                    return None
+
+        # Shouldn't get here.
+        
+
     def _check_replacement(self, name, path_prefix, fileListResult):
         """ Checks whether 'name' exists, and if so, whether we can overwrite it.
         If we can, add the name to 'overwritten_files' and delete the existing entry.
@@ -541,21 +602,27 @@ class CasBasedDirectory(Directory):
         """
 
         print("Running list_relative_paths on relpath {}".format(relpath))
-        symlink_list = filter(lambda i: isinstance(i[1].pb_object, remote_execution_pb2.SymlinkNode), self.index.items())
-        file_list = filter(lambda i: isinstance(i[1].pb_object, remote_execution_pb2.FileNode), self.index.items())
+        symlink_list = list(filter(lambda i: isinstance(i[1].pb_object, remote_execution_pb2.SymlinkNode), self.index.items()))
+        file_list = list(filter(lambda i: isinstance(i[1].pb_object, remote_execution_pb2.FileNode), self.index.items()))
+        directory_list = list(filter(lambda i: isinstance(i[1].buildstream_object, CasBasedDirectory), self.index.items()))
         print("Running list_relative_paths on relpath {}. files={}, symlinks={}".format(relpath, [f[0] for f in file_list], [s[0] for s in symlink_list]))
 
         for (k, v) in sorted(symlink_list):
-            print("Yielding symlink {}".format(k))
-            yield os.path.join(relpath, k)
-        for (k, v) in sorted(file_list):
-            print("Yielding file {}".format(k))
-            yield os.path.join(relpath, k)
-        else:
+            target = self._resolve(k)
+            if isinstance(target, CasBasedDirectory):
+                print("Adding the resolved symlink {} which resolves to {} to our directory list".format(k, target))
+                directory_list.append((k,IndexEntry(k, buildstream_object=target)))
+            else:
+                # Broken symlinks are also considered files!
+                file_list.append((k,v))
+        if file_list == [] and relpath != "":
             print("Yielding empty directory name {}".format(relpath))
             yield relpath
+        else:
+            for (k, v) in sorted(file_list):
+                print("Yielding file {}".format(k))
+                yield os.path.join(relpath, k)
 
-        directory_list = filter(lambda i: isinstance(i[1].buildstream_object, CasBasedDirectory), self.index.items())
         for (k, v) in sorted(directory_list):
             print("Yielding from subdirectory name {}".format(k))
             yield from v.buildstream_object.list_relative_paths(relpath=os.path.join(relpath, k))