diff options
Diffstat (limited to 'src/engine/SCons/Node/FS.py')
-rw-r--r-- | src/engine/SCons/Node/FS.py | 248 |
1 files changed, 85 insertions, 163 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 10641e9..9298d98 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -31,73 +31,17 @@ that can be used by scripts or modules looking for the canonical default. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -__revision__ = "src/engine/SCons/Node/FS.py 4720 2010/03/24 03:14:11 jars" +__revision__ = "src/engine/SCons/Node/FS.py 5023 2010/06/14 22:05:46 scons" -from itertools import izip -import cStringIO import fnmatch import os -import os.path import re import shutil import stat -import string import sys import time - -try: - import codecs -except ImportError: - pass -else: - # TODO(2.2): Remove when 2.3 becomes the minimal supported version. - try: - codecs.BOM_UTF8 - except AttributeError: - codecs.BOM_UTF8 = '\xef\xbb\xbf' - try: - codecs.BOM_UTF16_LE - codecs.BOM_UTF16_BE - except AttributeError: - codecs.BOM_UTF16_LE = '\xff\xfe' - codecs.BOM_UTF16_BE = '\xfe\xff' - - # Provide a wrapper function to handle decoding differences in - # different versions of Python. Normally, we'd try to do this in the - # compat layer (and maybe it still makes sense to move there?) but - # that doesn't provide a way to supply the string class used in - # pre-2.3 Python versions with a .decode() method that all strings - # naturally have. Plus, the 2.[01] encodings behave differently - # enough that we have to settle for a lowest-common-denominator - # wrapper approach. - # - # Note that the 2.[012] implementations below may be inefficient - # because they perform an explicit look up of the encoding for every - # decode, but they're old enough (and we want to stop supporting - # them soon enough) that it's not worth complicating the interface. - # Think of it as additional incentive for people to upgrade... - try: - ''.decode - except AttributeError: - # 2.0 through 2.2: strings have no .decode() method - try: - codecs.lookup('ascii').decode - except AttributeError: - # 2.0 and 2.1: encodings are a tuple of functions, and the - # decode() function returns a (result, length) tuple. - def my_decode(contents, encoding): - return codecs.lookup(encoding)[1](contents)[0] - else: - # 2.2: encodings are an object with methods, and the - # .decode() method returns just the decoded bytes. - def my_decode(contents, encoding): - return codecs.lookup(encoding).decode(contents) - else: - # 2.3 or later: use the .decode() string method - def my_decode(contents, encoding): - return contents.decode(encoding) +import codecs import SCons.Action from SCons.Debug import logInstanceCreation @@ -256,11 +200,11 @@ def set_duplicate(duplicate): } if not duplicate in Valid_Duplicates: - raise SCons.Errors.InternalError, ("The argument of set_duplicate " + raise SCons.Errors.InternalError("The argument of set_duplicate " "should be in Valid_Duplicates") global Link_Funcs Link_Funcs = [] - for func in string.split(duplicate,'-'): + for func in duplicate.split('-'): if link_dict[func]: Link_Funcs.append(link_dict[func]) @@ -334,7 +278,7 @@ def get_MkdirBuilder(): name = "MkdirBuilder") return MkdirBuilder -class _Null: +class _Null(object): pass _null = _Null() @@ -373,25 +317,23 @@ if os.path.normcase("TeSt") == os.path.normpath("TeSt") and not _is_cygwin: return x else: def _my_normcase(x): - return string.upper(x) + return x.upper() -class DiskChecker: +class DiskChecker(object): def __init__(self, type, do, ignore): self.type = type self.do = do self.ignore = ignore - self.set_do() - def set_do(self): - self.__call__ = self.do - def set_ignore(self): - self.__call__ = self.ignore + self.func = do + def __call__(self, *args, **kw): + return self.func(*args, **kw) def set(self, list): if self.type in list: - self.set_do() + self.func = self.do else: - self.set_ignore() + self.func = self.ignore def do_diskcheck_match(node, predicate, errorfmt): result = predicate() @@ -407,7 +349,7 @@ def do_diskcheck_match(node, predicate, errorfmt): except (AttributeError, KeyError): pass if result: - raise TypeError, errorfmt % node.abspath + raise TypeError(errorfmt % node.abspath) def ignore_diskcheck_match(node, predicate, errorfmt): pass @@ -459,11 +401,14 @@ def set_diskcheck(list): dc.set(list) def diskcheck_types(): - return map(lambda dc: dc.type, diskcheckers) + return [dc.type for dc in diskcheckers] class EntryProxy(SCons.Util.Proxy): + + __str__ = SCons.Util.Delegate('__str__') + def __get_abspath(self): entry = self.get() return SCons.Subst.SpecialAttrWrapper(entry.get_abspath(), @@ -497,7 +442,7 @@ class EntryProxy(SCons.Util.Proxy): return self else: entry = self.get() - r = string.replace(entry.get_path(), os.sep, '/') + r = entry.get_path().replace(os.sep, '/') return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_posix") def __get_windows_path(self): @@ -507,7 +452,7 @@ class EntryProxy(SCons.Util.Proxy): return self else: entry = self.get() - r = string.replace(entry.get_path(), os.sep, '\\') + r = entry.get_path().replace(os.sep, '\\') return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_windows") def __get_srcnode(self): @@ -620,8 +565,8 @@ class Base(SCons.Node.Node): """ if isinstance(self, klass) or klass is Entry: return - raise TypeError, "Tried to lookup %s '%s' as a %s." %\ - (self.__class__.__name__, self.path, klass.__name__) + raise TypeError("Tried to lookup %s '%s' as a %s." %\ + (self.__class__.__name__, self.path, klass.__name__)) def get_dir(self): return self.dir @@ -647,7 +592,7 @@ class Base(SCons.Node.Node): return self._memo['_save_str'] except KeyError: pass - result = intern(self._get_str()) + result = sys.intern(self._get_str()) self._memo['_save_str'] = result return result @@ -753,8 +698,8 @@ class Base(SCons.Node.Node): try: i = path_elems.index(dir) except ValueError: pass else: path_elems = path_elems[i+1:] - path_elems = map(lambda n: n.name, path_elems) - return string.join(path_elems, os.sep) + path_elems = [n.name for n in path_elems] + return os.sep.join(path_elems) def set_src_builder(self, builder): """Set the source code builder for this node.""" @@ -911,7 +856,7 @@ class Entry(Base): self._morph() elif must_exist: msg = "No such file or directory: '%s'" % self.abspath - raise SCons.Errors.UserError, msg + raise SCons.Errors.UserError(msg) else: self.__class__ = File self._morph() @@ -990,7 +935,7 @@ class Entry(Base): def rel_path(self, other): d = self.disambiguate() if d.__class__ is Entry: - raise "rel_path() could not disambiguate File/Dir" + raise Exception("rel_path() could not disambiguate File/Dir") return d.rel_path(other) def new_ninfo(self): @@ -1010,7 +955,7 @@ class Entry(Base): _classEntry = Entry -class LocalFS: +class LocalFS(object): if SCons.Memoize.use_memoizer: __metaclass__ = SCons.Memoize.Memoized_Metaclass @@ -1249,7 +1194,7 @@ class FS(LocalFS): root = directory.root if os.sep != '/': - p = string.replace(p, os.sep, '/') + p = p.replace(os.sep, '/') return root._lookup_abs(p, fsclass, create) def Entry(self, name, directory = None, create = 1): @@ -1294,11 +1239,11 @@ class FS(LocalFS): if not isinstance(variant_dir, SCons.Node.Node): variant_dir = self.Dir(variant_dir) if src_dir.is_under(variant_dir): - raise SCons.Errors.UserError, "Source directory cannot be under variant directory." + raise SCons.Errors.UserError("Source directory cannot be under variant directory.") if variant_dir.srcdir: if variant_dir.srcdir == src_dir: return # We already did this. - raise SCons.Errors.UserError, "'%s' already has a source directory: '%s'."%(variant_dir, variant_dir.srcdir) + raise SCons.Errors.UserError("'%s' already has a source directory: '%s'."%(variant_dir, variant_dir.srcdir)) variant_dir.link(src_dir, duplicate) def Repository(self, *dirs): @@ -1327,12 +1272,12 @@ class FS(LocalFS): if start_dir.is_under(bd): # If already in the build-dir location, don't reflect return [orig], fmt % str(orig) - p = apply(os.path.join, [bd.path] + tail) + p = os.path.join(bd.path, *tail) targets.append(self.Entry(p)) tail = [dir.name] + tail dir = dir.up() if targets: - message = fmt % string.join(map(str, targets)) + message = fmt % ' '.join(map(str, targets)) return targets, message def Glob(self, pathname, ondisk=True, source=True, strings=False, cwd=None): @@ -1574,9 +1519,9 @@ class Dir(Base): i = self.path_elements.index(other) + 1 path_elems = ['..'] * (len(self.path_elements) - i) \ - + map(lambda n: n.name, other.path_elements[i:]) + + [n.name for n in other.path_elements[i:]] - result = string.join(path_elems, os.sep) + result = os.sep.join(path_elems) memo_dict[other] = result @@ -1622,7 +1567,7 @@ class Dir(Base): """A null "builder" for directories.""" global MkdirBuilder if self.builder is not MkdirBuilder: - apply(SCons.Node.Node.build, [self,], kw) + SCons.Node.Node.build(self, **kw) # # @@ -1641,7 +1586,7 @@ class Dir(Base): if p is None: # Don't use while: - else: for this condition because # if so, then parent is None and has no .path attribute. - raise SCons.Errors.StopError, parent.path + raise SCons.Errors.StopError(parent.path) parent = p listDirs.reverse() for dirnode in listDirs: @@ -1682,12 +1627,9 @@ class Dir(Base): """Return content signatures and names of all our children separated by new-lines. Ensure that the nodes are sorted.""" contents = [] - name_cmp = lambda a, b: cmp(a.name, b.name) - sorted_children = self.children()[:] - sorted_children.sort(name_cmp) - for node in sorted_children: + for node in sorted(self.children(), key=lambda t: t.name): contents.append('%s %s\n' % (node.get_csig(), node.name)) - return string.join(contents, '') + return ''.join(contents) def get_csig(self): """Compute the content signature for Directory nodes. In @@ -1783,7 +1725,7 @@ class Dir(Base): d[name] = result return result else: - return d.has_key(name) + return name in d memoizer_counters.append(SCons.Memoize.CountValue('srcdir_list')) @@ -1911,12 +1853,11 @@ class Dir(Base): in any way (or ignored, passing None is common). """ entries = self.entries - names = entries.keys() + names = list(entries.keys()) names.remove('.') names.remove('..') func(arg, self, names) - select_dirs = lambda n, e=entries: isinstance(e[n], Dir) - for dirname in filter(select_dirs, names): + for dirname in [n for n in names if isinstance(entries[n], Dir)]: entries[dirname].walk(func, arg) def glob(self, pathname, ondisk=True, source=False, strings=False): @@ -1953,9 +1894,8 @@ class Dir(Base): """ dirname, basename = os.path.split(pathname) if not dirname: - result = self._glob1(basename, ondisk, source, strings) - result.sort(lambda a, b: cmp(str(a), str(b))) - return result + return sorted(self._glob1(basename, ondisk, source, strings), + key=lambda t: str(t)) if has_glob_magic(dirname): list = self.glob(dirname, ondisk, source, strings=False) else: @@ -1964,10 +1904,9 @@ class Dir(Base): for dir in list: r = dir._glob1(basename, ondisk, source, strings) if strings: - r = map(lambda x, d=str(dir): os.path.join(d, x), r) + r = [os.path.join(str(dir), x) for x in r] result.extend(r) - result.sort(lambda a, b: cmp(str(a), str(b))) - return result + return sorted(result, key=lambda a: str(a)) def _glob1(self, pattern, ondisk=True, source=False, strings=False): """ @@ -1990,9 +1929,8 @@ class Dir(Base): # We use the .name attribute from the Node because the keys of # the dir.entries dictionary are normalized (that is, all upper # case) on case-insensitive systems like Windows. - #node_names = [ v.name for k, v in dir.entries.items() if k not in ('.', '..') ] - entry_names = filter(lambda n: n not in ('.', '..'), dir.entries.keys()) - node_names = map(lambda n, e=dir.entries: e[n].name, entry_names) + node_names = [ v.name for k, v in dir.entries.items() + if k not in ('.', '..') ] names.extend(node_names) if not strings: # Make sure the working directory (self) actually has @@ -2015,7 +1953,7 @@ class Dir(Base): # after we exit this loop. if pattern[0] != '.': #disk_names = [ d for d in disk_names if d[0] != '.' ] - disk_names = filter(lambda x: x[0] != '.', disk_names) + disk_names = [x for x in disk_names if x[0] != '.'] disk_names = fnmatch.filter(disk_names, pattern) dirEntry = dir.Entry for name in disk_names: @@ -2031,14 +1969,14 @@ class Dir(Base): names = set(names) if pattern[0] != '.': #names = [ n for n in names if n[0] != '.' ] - names = filter(lambda x: x[0] != '.', names) + names = [x for x in names if x[0] != '.'] names = fnmatch.filter(names, pattern) if strings: return names #return [ self.entries[_my_normcase(n)] for n in names ] - return map(lambda n, e=self.entries: e[_my_normcase(n)], names) + return [self.entries[_my_normcase(n)] for n in names] class RootDir(Dir): """A class for the root directory of a file system. @@ -2111,7 +2049,7 @@ class RootDir(Dir): except KeyError: if not create: msg = "No such file or directory: '%s' in '%s' (and create is False)" % (p, str(self)) - raise SCons.Errors.UserError, msg + raise SCons.Errors.UserError(msg) # There is no Node for this path name, and we're allowed # to create it. dir_name, file_name = os.path.split(p) @@ -2200,7 +2138,7 @@ class FileBuildInfo(SCons.Node.BuildInfoBase): except AttributeError: s = str(n) else: - s = string.replace(s, os.sep, '/') + s = s.replace(os.sep, '/') return s for attr in ['bsources', 'bdepends', 'bimplicit']: try: @@ -2208,7 +2146,7 @@ class FileBuildInfo(SCons.Node.BuildInfoBase): except AttributeError: pass else: - setattr(self, attr, map(node_to_str, val)) + setattr(self, attr, list(map(node_to_str, val))) def convert_from_sconsign(self, dir, name): """ Converts a newly-read FileBuildInfo object for in-SCons use @@ -2238,7 +2176,7 @@ class FileBuildInfo(SCons.Node.BuildInfoBase): except AttributeError: continue nodes = [] - for s, ni in izip(strings, nodeinfos): + for s, ni in zip(strings, nodeinfos): if not isinstance(s, SCons.Node.Node): s = ni.str_to_node(s) nodes.append(s) @@ -2247,11 +2185,11 @@ class FileBuildInfo(SCons.Node.BuildInfoBase): result = [] bkids = self.bsources + self.bdepends + self.bimplicit bkidsigs = self.bsourcesigs + self.bdependsigs + self.bimplicitsigs - for bkid, bkidsig in izip(bkids, bkidsigs): + for bkid, bkidsig in zip(bkids, bkidsigs): result.append(str(bkid) + ': ' + - string.join(bkidsig.format(names=names), ' ')) + ' '.join(bkidsig.format(names=names))) result.append('%s [%s]' % (self.bactsig, self.bact)) - return string.join(result, '\n') + return '\n'.join(result) class File(Base): """A class for files in a file system. @@ -2286,9 +2224,7 @@ class File(Base): def Dirs(self, pathlist): """Create a list of directories relative to the SConscript directory of this file.""" - # TODO(1.5) - # return [self.Dir(p) for p in pathlist] - return map(lambda p, s=self: s.Dir(p), pathlist) + return [self.Dir(p) for p in pathlist] def File(self, name): """Create a file node named 'name' relative to @@ -2336,38 +2272,24 @@ class File(Base): raise return contents - try: - import codecs - except ImportError: - get_text_contents = get_contents - else: - # This attempts to figure out what the encoding of the text is - # based upon the BOM bytes, and then decodes the contents so that - # it's a valid python string. - def get_text_contents(self): - contents = self.get_contents() - # The behavior of various decode() methods and functions - # w.r.t. the initial BOM bytes is different for different - # encodings and/or Python versions. ('utf-8' does not strip - # them, but has a 'utf-8-sig' which does; 'utf-16' seems to - # strip them; etc.) Just side step all the complication by - # explicitly stripping the BOM before we decode(). - if contents.startswith(codecs.BOM_UTF8): - contents = contents[len(codecs.BOM_UTF8):] - # TODO(2.2): Remove when 2.3 becomes floor. - #contents = contents.decode('utf-8') - contents = my_decode(contents, 'utf-8') - elif contents.startswith(codecs.BOM_UTF16_LE): - contents = contents[len(codecs.BOM_UTF16_LE):] - # TODO(2.2): Remove when 2.3 becomes floor. - #contents = contents.decode('utf-16-le') - contents = my_decode(contents, 'utf-16-le') - elif contents.startswith(codecs.BOM_UTF16_BE): - contents = contents[len(codecs.BOM_UTF16_BE):] - # TODO(2.2): Remove when 2.3 becomes floor. - #contents = contents.decode('utf-16-be') - contents = my_decode(contents, 'utf-16-be') - return contents + # This attempts to figure out what the encoding of the text is + # based upon the BOM bytes, and then decodes the contents so that + # it's a valid python string. + def get_text_contents(self): + contents = self.get_contents() + # The behavior of various decode() methods and functions + # w.r.t. the initial BOM bytes is different for different + # encodings and/or Python versions. ('utf-8' does not strip + # them, but has a 'utf-8-sig' which does; 'utf-16' seems to + # strip them; etc.) Just sidestep all the complication by + # explicitly stripping the BOM before we decode(). + if contents.startswith(codecs.BOM_UTF8): + return contents[len(codecs.BOM_UTF8):].decode('utf-8') + if contents.startswith(codecs.BOM_UTF16_LE): + return contents[len(codecs.BOM_UTF16_LE):].decode('utf-16-le') + if contents.startswith(codecs.BOM_UTF16_BE): + return contents[len(codecs.BOM_UTF16_BE):].decode('utf-16-be') + return contents def get_content_hash(self): """ @@ -2603,7 +2525,7 @@ class File(Base): if scanner: # result = [n.disambiguate() for n in scanner(self, env, path)] result = scanner(self, env, path) - result = map(lambda N: N.disambiguate(), result) + result = [N.disambiguate() for N in result] else: result = [] @@ -2741,7 +2663,7 @@ class File(Base): self._createDir() except SCons.Errors.StopError, drive: desc = "No drive `%s' for target `%s'." % (drive, self) - raise SCons.Errors.StopError, desc + raise SCons.Errors.StopError(desc) # # @@ -2760,7 +2682,7 @@ class File(Base): e = Link(self, src, None) if isinstance(e, SCons.Errors.BuildError): desc = "Cannot duplicate `%s' in `%s': %s." % (src.path, self.dir.path, e.errstr) - raise SCons.Errors.StopError, desc + raise SCons.Errors.StopError(desc) self.linked = 1 # The Link() action may or may not have actually # created the file, depending on whether the -n @@ -3019,7 +2941,7 @@ class File(Base): children = self.children() executor = self.get_executor() # sigs = [n.get_cachedir_csig() for n in children] - sigs = map(lambda n: n.get_cachedir_csig(), children) + sigs = [n.get_cachedir_csig() for n in children] sigs.append(SCons.Util.MD5signature(executor.get_contents())) sigs.append(self.path) result = self.cachesig = SCons.Util.MD5collect(sigs) @@ -3034,7 +2956,7 @@ def get_default_fs(): default_fs = FS() return default_fs -class FileFinder: +class FileFinder(object): """ """ if SCons.Memoize.use_memoizer: @@ -3117,8 +3039,8 @@ class FileFinder: if verbose and not callable(verbose): if not SCons.Util.is_String(verbose): verbose = "find_file" - verbose = ' %s: ' % verbose - verbose = lambda s, v=verbose: sys.stdout.write(v + s) + _verbose = u' %s: ' % verbose + verbose = lambda s: sys.stdout.write(_verbose + s) filedir, filename = os.path.split(filename) if filedir: @@ -3150,10 +3072,10 @@ class FileFinder: # if isinstance(node, Dir) or isinstance(node, Entry): # return node # return None - #paths = filter(None, map(filedir_lookup, paths)) + #paths = [_f for _f in map(filedir_lookup, paths) if _f] self.default_filedir = filedir - paths = filter(None, map(self.filedir_lookup, paths)) + paths = [_f for _f in map(self.filedir_lookup, paths) if _f] result = None for dir in paths: |