summaryrefslogtreecommitdiff
path: root/include_server/mirror_path.py
diff options
context:
space:
mode:
Diffstat (limited to 'include_server/mirror_path.py')
-rwxr-xr-xinclude_server/mirror_path.py113
1 files changed, 113 insertions, 0 deletions
diff --git a/include_server/mirror_path.py b/include_server/mirror_path.py
new file mode 100755
index 0000000..3be5062
--- /dev/null
+++ b/include_server/mirror_path.py
@@ -0,0 +1,113 @@
+#!/usr/bin/python2.4
+
+# Copyright 2007 Google Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# """Memoizing, piecemeal mirroring of directory and link structure."""
+
+__author__ = "Nils Klarlund"
+
+
+import os
+import os.path
+
+import cache_basics
+
+class MirrorPath(object):
+ """Make a caching structure for copying all parts of the paths that
+ method DoPath is called with. This includes replication of symbolic
+ links. But the targets of symbolic links are absolutized: they are
+ replaced by the realpath of the original target, whether this target
+ was relative or absolute."""
+
+ def __init__(self,
+ simple_build_stat,
+ canonical_path):
+ """Constructor.
+
+ Arguments:
+ simple_build_stat: object of type SimpleBuildStat
+ canonical_path: function of type CanonicalPath
+ """
+ assert isinstance(simple_build_stat, cache_basics.SimpleBuildStat)
+ assert isinstance(canonical_path, cache_basics.CanonicalPath)
+ # All links encountered so far.
+ self.links = []
+ # We cache tuples (filepath, current_dir_idx) for which we've already fixed
+ # up the symbolic links.
+ self.link_stat = set([])
+ # Usual abbreviations.
+ self.simple_build_stat = simple_build_stat
+ self.canonical_path = canonical_path
+
+ def Links(self):
+ """Return the list of symbolic links created."""
+ return self.links
+
+ def DoPath(self, filepath, current_dir_idx, root):
+ """Mirror the parts of filepath not yet created under root.
+
+ Arguments:
+ filepath: a string, which is relative or absolute filename
+ current_dir_idx: a directory index
+ root: a string denoting an absolute path for an existing directory
+ """
+ assert isinstance(filepath, str)
+ assert isinstance(current_dir_idx, int)
+ assert isinstance(root, str)
+ assert root[0] == '/' and root[-1] != '/'
+ assert os.path.isdir(root), root
+
+ link_stat = self.link_stat
+ lookup = self.simple_build_stat.Lookup
+ # Working from the end (in the hope that a cache lookup will reveal
+ # the futility of further work), make sure that intermediate
+ # destinations exist, and replicate symbolic links where necessary.
+ while filepath and filepath != '/':
+ if (filepath, current_dir_idx) in link_stat:
+ # Filepath is already mirrored
+ return
+ link_stat.add((filepath, current_dir_idx))
+ # Process suffix of filepath by
+ # - making sure that the mirrored real path of the prefix exists,
+ # - and that the suffix if a symbolic link
+ # is replicated as a symbolic link.
+ assert filepath[-1] != '/', filepath
+
+ # Now identify the potential symbolic link at the end of filepath
+ (prefix_filepath, suffix) = os.path.split(filepath)
+ # Calculate the real position of the destination of the prefix
+ prefix_real = self.canonical_path.Canonicalize(prefix_filepath)
+
+ if prefix_real == '/': prefix_real = ''
+
+ # And, its counterpart under root
+ root_prefix_real = root + prefix_real
+
+ # Make sure that root_prefix_real is there
+ if not lookup(root_prefix_real):
+ if not os.path.isdir(root_prefix_real):
+ os.makedirs(root_prefix_real)
+ self.simple_build_stat.cache[root_prefix_real] = True
+
+ assert os.path.isdir(root_prefix_real)
+ # Create the mirrored symbolic link if applicable
+ if os.path.islink(filepath):
+ link_name = root_prefix_real + '/' + suffix
+ if not os.path.exists(link_name):
+ os.symlink(self.canonical_path.Canonicalize(filepath), link_name)
+ self.links.append(link_name)
+ filepath = prefix_filepath