__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.
Also, remember all directories that had to be followed to find out what paths
mean. This is of particular importance to the '..' operator, which may
involve temporary excursions into directories that otherwise contain no files
of relevance to the build. But the directories must still be replicated on the
server for the semantics of '..' to work. These are called must_exist_dirs.
"""
def __init__(self,
simple_build_stat,
canonical_path,
realpath_map,
systemdir_prefix_cache):
"""Constructor.
Arguments:
simple_build_stat: object of type SimpleBuildStat
canonical_path: function of type CanonicalPath
realpath_map: a CanonicalMapToIndex; see cache_basics.py
systemdir_prefix_cache: a SystemdirPrefixCache; see cache_basics.py.
"""
assert isinstance(simple_build_stat, cache_basics.SimpleBuildStat)
assert isinstance(canonical_path, cache_basics.CanonicalPath)
self.links = []
self.link_stat = set([])
self.simple_build_stat = simple_build_stat
self.canonical_path = canonical_path
self.must_exist_dirs = []
self.realpath_map = realpath_map
self.systemdir_prefix_cache = systemdir_prefix_cache
def Links(self):
"""Return the list of symbolic links created."""
return self.links
def MustExistDirs(self):
return self.must_exist_dirs
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
while filepath and filepath != '/':
if (filepath, current_dir_idx) in link_stat:
return
link_stat.add((filepath, current_dir_idx))
assert filepath[-1] != '/', filepath
(prefix_filepath, suffix) = os.path.split(filepath)
prefix_real = self.canonical_path.Canonicalize(prefix_filepath)
if prefix_real == '/': prefix_real = ''
root_prefix_real = root + prefix_real
if not lookup(root_prefix_real):
if not os.path.isdir(root_prefix_real):
realpath_map = self.realpath_map
realpath_idx = realpath_map.Index(prefix_real)
if not self.systemdir_prefix_cache.StartsWithSystemdir(realpath_idx,
realpath_map):
self.must_exist_dirs.append(root_prefix_real)
os.makedirs(root_prefix_real)
else:
break
self.simple_build_stat.cache[root_prefix_real] = True
assert os.path.isdir(root_prefix_real)
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