diff options
author | Dirk Baechle <dl9obn@darc.de> | 2015-02-26 23:44:19 (GMT) |
---|---|---|
committer | Dirk Baechle <dl9obn@darc.de> | 2015-02-26 23:44:19 (GMT) |
commit | 354388a26c7ff2ed69e4e34f41880e0e1bfb0cb1 (patch) | |
tree | e4e8f3ef044c39a930235a39bb7301d35b0300ff /src/engine/SCons/Node/FS.py | |
parent | 8447a9187ac80c0a7e980510154542b49577ddaa (diff) | |
download | SCons-354388a26c7ff2ed69e4e34f41880e0e1bfb0cb1.zip SCons-354388a26c7ff2ed69e4e34f41880e0e1bfb0cb1.tar.gz SCons-354388a26c7ff2ed69e4e34f41880e0e1bfb0cb1.tar.bz2 |
- switching Node class and NodeInfo/Binfo to using slots
- memoizer subsystem now uses decorators instead of the metaclass approach
Diffstat (limited to 'src/engine/SCons/Node/FS.py')
-rw-r--r-- | src/engine/SCons/Node/FS.py | 513 |
1 files changed, 319 insertions, 194 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 4db1cb3..2402fac 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -56,10 +56,23 @@ import SCons.Warnings from SCons.Debug import Trace -do_store_info = True print_duplicate = 0 +def sconsign_none(node): + raise NotImplementedError + +def sconsign_dir(node): + """Return the .sconsign file info for this directory, + creating it first if necessary.""" + if not node._sconsign: + import SCons.SConsign + node._sconsign = SCons.SConsign.ForDirectory(node) + return node._sconsign + +_sconsign_map = {0 : sconsign_none, + 1 : sconsign_dir} + class EntryProxyAttributeError(AttributeError): """ An AttributeError subclass for recording and displaying the name @@ -268,8 +281,8 @@ def LinkFunc(target, source, env): # who want to move their soft-linked src-trees around. Those # people should use the 'hard-copy' mode, softlinks cannot be # used for that; at least I have no idea how ... - src = source[0].abspath - dest = target[0].abspath + src = source[0].get_abspath() + dest = target[0].get_abspath() dir, file = os.path.split(dest) if dir and not target[0].fs.isdir(dir): os.makedirs(dir) @@ -302,7 +315,7 @@ LocalCopy = SCons.Action.Action(LinkFunc, LocalString) def UnlinkFunc(target, source, env): t = target[0] - t.fs.unlink(t.abspath) + t.fs.unlink(t.get_abspath()) return 0 Unlink = SCons.Action.Action(UnlinkFunc, None) @@ -310,7 +323,7 @@ Unlink = SCons.Action.Action(UnlinkFunc, None) def MkdirFunc(target, source, env): t = target[0] if not t.exists(): - t.fs.mkdir(t.abspath) + t.fs.mkdir(t.get_abspath()) return 0 Mkdir = SCons.Action.Action(MkdirFunc, None, presub=None) @@ -403,7 +416,7 @@ def do_diskcheck_match(node, predicate, errorfmt): except (AttributeError, KeyError): pass if result: - raise TypeError(errorfmt % node.abspath) + raise TypeError(errorfmt % node.get_abspath()) def ignore_diskcheck_match(node, predicate, errorfmt): pass @@ -573,7 +586,20 @@ class Base(SCons.Node.Node): object identity comparisons. """ - memoizer_counters = [] + __slots__ = ['name', + 'fs', + 'abspath', + 'labspath', + 'path', + 'tpath', + 'path_elements', + 'dir', + 'cwd', + 'duplicate', + '_local', + 'sbuilder', + '_proxy', + '_func_sconsign'] def __init__(self, name, directory, fs): """Initialize a generic Node.FS.Base object. @@ -591,27 +617,26 @@ class Base(SCons.Node.Node): #: Filename with extension as it was specified when the object was #: created; to obtain filesystem path, use Python str() function self.name = SCons.Util.silent_intern(name) - #: Cached filename extension - self.suffix = SCons.Util.silent_intern(SCons.Util.splitext(name)[1]) self.fs = fs #: Reference to parent Node.FS object assert directory, "A directory must be provided" - self.abspath = SCons.Util.silent_intern(directory.entry_abspath(name)) - self.labspath = SCons.Util.silent_intern(directory.entry_labspath(name)) - if directory.path == '.': - self.path = SCons.Util.silent_intern(name) - else: - self.path = SCons.Util.silent_intern(directory.entry_path(name)) - if directory.tpath == '.': - self.tpath = SCons.Util.silent_intern(name) - else: - self.tpath = SCons.Util.silent_intern(directory.entry_tpath(name)) - self.path_elements = directory.path_elements + [self] + self.abspath = None + self.labspath = None + self.path = None + self.tpath = None + self.path_elements = None self.dir = directory self.cwd = None # will hold the SConscript directory for target nodes self.duplicate = directory.duplicate + self.changed_since_last_build = 2 + self._func_sconsign = 0 + self._func_exists = 2 + self._func_rexists = 2 + self._func_get_contents = 0 + self._func_target_from_source = 1 + self.store_info = 1 def str_for_display(self): return '"' + self.__str__() + '"' @@ -624,13 +649,13 @@ 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__)) + (self.__class__.__name__, self.get_internal_path(), klass.__name__)) def get_dir(self): return self.dir def get_suffix(self): - return self.suffix + return SCons.Util.splitext(self.name)[1] def rfile(self): return self @@ -643,8 +668,7 @@ class Base(SCons.Node.Node): return self._save_str() return self._get_str() - memoizer_counters.append(SCons.Memoize.CountValue('_save_str')) - + @SCons.Memoize.CountMethodCall def _save_str(self): try: return self._memo['_save_str'] @@ -681,21 +705,20 @@ class Base(SCons.Node.Node): rstr = __str__ - memoizer_counters.append(SCons.Memoize.CountValue('stat')) - + @SCons.Memoize.CountMethodCall def stat(self): try: return self._memo['stat'] except KeyError: pass - try: result = self.fs.stat(self.abspath) + try: result = self.fs.stat(self.get_abspath()) except os.error: result = None self._memo['stat'] = result return result def exists(self): - return self.stat() is not None + return SCons.Node._exists_map[self._func_exists](self) def rexists(self): - return self.rfile().exists() + return SCons.Node._rexists_map[self._func_rexists](self) def getmtime(self): st = self.stat() @@ -717,7 +740,7 @@ class Base(SCons.Node.Node): if hasattr(os, 'symlink'): def islink(self): - try: st = self.fs.lstat(self.abspath) + try: st = self.fs.lstat(self.get_abspath()) except os.error: return 0 return stat.S_ISLNK(st[stat.ST_MODE]) else: @@ -752,7 +775,7 @@ class Base(SCons.Node.Node): dir = self.fs.getcwd() if self == dir: return '.' - path_elems = self.path_elements + path_elems = self.get_path_elements() pathname = '' try: i = path_elems.index(dir) except ValueError: @@ -785,7 +808,26 @@ class Base(SCons.Node.Node): def get_abspath(self): """Get the absolute path of the file.""" - return self.abspath + return self.dir.entry_abspath(self.name) + + def get_labspath(self): + """Get the absolute path of the file.""" + return self.dir.entry_labspath(self.name) + + def get_internal_path(self): + if self.dir.path == '.': + return self.name + else: + return self.dir.entry_path(self.name) + + def get_tpath(self): + if self.dir.tpath == '.': + return self.name + else: + return self.dir.entry_tpath(self.name) + + def get_path_elements(self): + return self.dir.path_elements + [self] def for_signature(self): # Return just our name. Even an absolute path would not work, @@ -811,13 +853,12 @@ class Base(SCons.Node.Node): files that need different behavior. See Tool/swig.py for an example. """ - return self.dir.Entry(prefix + splitext(self.name)[0] + suffix) + return SCons.Node._target_from_source_map[self._func_target_from_source](self, prefix, suffix, splitext) def _Rfindalldirs_key(self, pathlist): return pathlist - memoizer_counters.append(SCons.Memoize.CountDict('Rfindalldirs', _Rfindalldirs_key)) - + @SCons.Memoize.CountDictCall(_Rfindalldirs_key) def Rfindalldirs(self, pathlist): """ Return all of the directories for a given path list, including @@ -856,8 +897,7 @@ class Base(SCons.Node.Node): cwd = self.cwd or self.fs._cwd return cwd.Rfindalldirs(pathlist) - memoizer_counters.append(SCons.Memoize.CountValue('rentry')) - + @SCons.Memoize.CountMethodCall def rentry(self): try: return self._memo['rentry'] @@ -878,7 +918,7 @@ class Base(SCons.Node.Node): def _glob1(self, pattern, ondisk=True, source=False, strings=False): return [] - + class Entry(Base): """This is the class for generic Node.FS entries--that is, things that could be a File or a Dir, but we're just not sure yet. @@ -887,6 +927,28 @@ class Entry(Base): time comes, and then call the same-named method in the transformed class.""" + __slots__ = ['scanner_paths', + 'cachedir_csig', + 'cachesig', + 'repositories', + 'srcdir', + 'entries', + 'searched', + '_sconsign', + 'variant_dirs', + 'root', + 'dirname', + 'on_disk_entries', + 'sccs_dir', + 'rcs_dir', + 'released_target_info', + 'contentsig'] + + def __init__(self, name, directory, fs): + Base.__init__(self, name, directory, fs) + self._func_exists = 3 + self._func_get_contents = 1 + def diskcheck_match(self): pass @@ -917,7 +979,7 @@ class Entry(Base): self.__class__ = Dir self._morph() elif must_exist: - msg = "No such file or directory: '%s'" % self.abspath + msg = "No such file or directory: '%s'" % self.get_abspath() raise SCons.Errors.UserError(msg) else: self.__class__ = File @@ -939,17 +1001,7 @@ class Entry(Base): def get_contents(self): """Fetch the contents of the entry. Returns the exact binary contents of the file.""" - try: - self = self.disambiguate(must_exist=1) - except SCons.Errors.UserError: - # There was nothing on disk with which to disambiguate - # this entry. Leave it as an Entry, but return a null - # string so calls to get_contents() in emitters and the - # like (e.g. in qt.py) don't have to disambiguate by hand - # or catch the exception. - return '' - else: - return self.get_contents() + return SCons.Node._get_contents_map[self._func_get_contents](self) def get_text_contents(self): """Fetch the decoded text contents of a Unicode encoded Entry. @@ -989,10 +1041,7 @@ class Entry(Base): # to make various tests pass. def exists(self): - """Return if the Entry exists. Check the file system to see - what we should turn into first. Assume a file if there's no - directory.""" - return self.disambiguate().exists() + return SCons.Node._exists_map[self._func_exists](self) def rel_path(self, other): d = self.disambiguate() @@ -1003,9 +1052,6 @@ class Entry(Base): def new_ninfo(self): return self.disambiguate().new_ninfo() - def changed_since_last_build(self, target, prev_ni): - return self.disambiguate().changed_since_last_build(target, prev_ni) - def _glob1(self, pattern, ondisk=True, source=False, strings=False): return self.disambiguate()._glob1(pattern, ondisk, source, strings) @@ -1019,9 +1065,6 @@ _classEntry = Entry class LocalFS(object): - if SCons.Memoize.use_memoizer: - __metaclass__ = SCons.Memoize.Memoized_Metaclass - # This class implements an abstraction layer for operations involving # a local file system. Essentially, this wraps any function in # the os, os.path or shutil modules that we use to actually go do @@ -1101,8 +1144,6 @@ class LocalFS(object): class FS(LocalFS): - memoizer_counters = [] - def __init__(self, path = None): """Initialize the Node.FS subsystem. @@ -1160,7 +1201,7 @@ class FS(LocalFS): if dir is not None: self._cwd = dir if change_os_dir: - os.chdir(dir.abspath) + os.chdir(dir.get_abspath()) except OSError: self._cwd = curr raise @@ -1249,9 +1290,9 @@ class FS(LocalFS): # The path is relative to the top-level SCons directory. if p in ('', '.'): - p = directory.labspath + p = directory.get_labspath() else: - p = directory.labspath + '/' + p + p = directory.get_labspath() + '/' + p else: if do_splitdrive: drive, p = _my_splitdrive(p) @@ -1285,9 +1326,9 @@ class FS(LocalFS): directory = self._cwd if p in ('', '.'): - p = directory.labspath + p = directory.get_labspath() else: - p = directory.labspath + '/' + p + p = directory.get_labspath() + '/' + p if drive: root = self.get_root(drive) @@ -1412,8 +1453,9 @@ class FS(LocalFS): return cwd.glob(pathname, ondisk, source, strings) class DirNodeInfo(SCons.Node.NodeInfoBase): + __slots__ = () # This should get reset by the FS initialization. - current_version_id = 1 + current_version_id = 2 fs = None @@ -1425,11 +1467,12 @@ class DirNodeInfo(SCons.Node.NodeInfoBase): if drive: root = self.fs.get_root(drive) if not os.path.isabs(s): - s = top.labspath + '/' + s + s = top.get_labspath() + '/' + s return root._lookup_abs(s, Entry) class DirBuildInfo(SCons.Node.BuildInfoBase): - current_version_id = 1 + __slots__ = () + current_version_id = 2 glob_magic_check = re.compile('[*?[]') @@ -1440,7 +1483,22 @@ class Dir(Base): """A class for directories in a file system. """ - memoizer_counters = [] + __slots__ = ['scanner_paths', + 'cachedir_csig', + 'cachesig', + 'repositories', + 'srcdir', + 'entries', + 'searched', + '_sconsign', + 'variant_dirs', + 'root', + 'dirname', + 'on_disk_entries', + 'sccs_dir', + 'rcs_dir', + 'released_target_info', + 'contentsig'] NodeInfo = DirNodeInfo BuildInfo = DirBuildInfo @@ -1470,6 +1528,22 @@ class Dir(Base): self._sconsign = None self.variant_dirs = [] self.root = self.dir.root + self.changed_since_last_build = 3 + self._func_sconsign = 1 + self._func_exists = 2 + self._func_get_contents = 2 + + self.abspath = SCons.Util.silent_intern(self.dir.entry_abspath(self.name)) + self.labspath = SCons.Util.silent_intern(self.dir.entry_labspath(self.name)) + if self.dir.path == '.': + self.path = SCons.Util.silent_intern(self.name) + else: + self.path = SCons.Util.silent_intern(self.dir.entry_path(self.name)) + if self.dir.tpath == '.': + self.tpath = SCons.Util.silent_intern(self.name) + else: + self.tpath = SCons.Util.silent_intern(self.dir.entry_tpath(self.name)) + self.path_elements = self.dir.path_elements + [self] # For directories, we make a difference between the directory # 'name' and the directory 'dirname'. The 'name' attribute is @@ -1562,8 +1636,7 @@ class Dir(Base): return self.srcdir.get_all_rdirs() + self.repositories return self.repositories - memoizer_counters.append(SCons.Memoize.CountValue('get_all_rdirs')) - + @SCons.Memoize.CountMethodCall def get_all_rdirs(self): try: return list(self._memo['get_all_rdirs']) @@ -1598,8 +1671,7 @@ class Dir(Base): def _rel_path_key(self, other): return str(other) - memoizer_counters.append(SCons.Memoize.CountDict('rel_path', _rel_path_key)) - + @SCons.Memoize.CountDictCall(_rel_path_key) def rel_path(self, other): """Return a path to "other" relative to this directory. """ @@ -1753,10 +1825,7 @@ class Dir(Base): def get_contents(self): """Return content signatures and names of all our children separated by new-lines. Ensure that the nodes are sorted.""" - contents = [] - for node in sorted(self.children(), key=lambda t: t.name): - contents.append('%s %s\n' % (node.get_csig(), node.name)) - return ''.join(contents) + return SCons.Node._get_contents_map[self._func_get_contents](self) def get_csig(self): """Compute the content signature for Directory nodes. In @@ -1770,8 +1839,6 @@ class Dir(Base): def do_duplicate(self, src): pass - changed_since_last_build = SCons.Node.Node.state_has_changed - def is_up_to_date(self): """If any child is not up-to-date, then this directory isn't, either.""" @@ -1795,12 +1862,8 @@ class Dir(Base): return self def sconsign(self): - """Return the .sconsign file info for this directory, - creating it first if necessary.""" - if not self._sconsign: - import SCons.SConsign - self._sconsign = SCons.SConsign.ForDirectory(self) - return self._sconsign + """Return the .sconsign file info for this directory. """ + return _sconsign_map[self._func_sconsign](self) def srcnode(self): """Dir has a special need for srcnode()...if we @@ -1817,6 +1880,23 @@ class Dir(Base): stamp = kid.get_timestamp() return stamp + def get_abspath(self): + """Get the absolute path of the file.""" + return self.abspath + + def get_labspath(self): + """Get the absolute path of the file.""" + return self.labspath + + def get_internal_path(self): + return self.path + + def get_tpath(self): + return self.tpath + + def get_path_elements(self): + return self.path_elements + def entry_abspath(self, name): return self.abspath + OS_SEP + name @@ -1887,8 +1967,7 @@ class Dir(Base): break return rentry_exists - memoizer_counters.append(SCons.Memoize.CountValue('srcdir_list')) - + @SCons.Memoize.CountMethodCall def srcdir_list(self): try: return self._memo['srcdir_list'] @@ -1929,8 +2008,7 @@ class Dir(Base): def _srcdir_find_file_key(self, filename): return filename - memoizer_counters.append(SCons.Memoize.CountDict('srcdir_find_file', _srcdir_find_file_key)) - + @SCons.Memoize.CountDictCall(_srcdir_find_file_key) def srcdir_find_file(self, filename): try: memo_dict = self._memo['srcdir_find_file'] @@ -2066,8 +2144,9 @@ class Dir(Base): if strings: r = [os.path.join(str(dir), x) for x in r] result.extend(r) - return sorted(result, key=lambda a: str(a)) + return sorted(result, key=lambda a: str(a)) + def _glob1(self, pattern, ondisk=True, source=False, strings=False): """ Globs for and returns a list of entry names matching a single @@ -2146,18 +2225,12 @@ class RootDir(Dir): add a separator when creating the path names of entries within this directory. """ + + __slots__ = ['_lookupDict'] + def __init__(self, drive, fs): if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.RootDir') - # We're going to be our own parent directory (".." entry and .dir - # attribute) so we have to set up some values so Base.__init__() - # won't gag won't it calls some of our methods. - self.abspath = '' - self.labspath = '' - self.path = '' - self.tpath = '' - self.path_elements = [] - self.duplicate = 0 - self.root = self + SCons.Node.Node.__init__(self) # Handle all the types of drives: if drive == '': @@ -2173,7 +2246,16 @@ class RootDir(Dir): name = drive dirname = drive + OS_SEP - Base.__init__(self, name, self, fs) + #: Filename with extension as it was specified when the object was + #: created; to obtain filesystem path, use Python str() function + self.name = SCons.Util.silent_intern(name) + self.fs = fs #: Reference to parent Node.FS object + + self.path_elements = [self] + self.dir = self + self._func_rexists = 2 + self._func_target_from_source = 1 + self.store_info = 1 # Now set our paths to what we really want them to be. The # name should already contain any necessary separators, such @@ -2184,22 +2266,65 @@ class RootDir(Dir): self.labspath = '' self.path = dirname self.tpath = dirname - self._morph() - - # Must be reset after Dir._morph() is invoked... self.dirname = dirname + self._morph() + + self.duplicate = 0 self._lookupDict = {} self._lookupDict[''] = self self._lookupDict['/'] = self - + self.root = self # The // entry is necessary because os.path.normpath() # preserves double slashes at the beginning of a path on Posix # platforms. if not has_unc: self._lookupDict['//'] = self + def _morph(self): + """Turn a file system Node (either a freshly initialized directory + object or a separate Entry object) into a proper directory object. + + Set up this directory's entries and hook it into the file + system tree. Specify that directories (this Node) don't use + signatures for calculating whether they're current. + """ + + self.repositories = [] + self.srcdir = None + + self.entries = {} + self.entries['.'] = self + self.entries['..'] = self.dir + self.cwd = self + self.searched = 0 + self._sconsign = None + self.variant_dirs = [] + self.changed_since_last_build = 3 + self._func_sconsign = 1 + self._func_exists = 2 + self._func_get_contents = 2 + + # Don't just reset the executor, replace its action list, + # because it might have some pre-or post-actions that need to + # be preserved. + # + # But don't reset the executor if there is a non-null executor + # attached already. The existing executor might have other + # targets, in which case replacing the action list with a + # Mkdir action is a big mistake. + if not hasattr(self, 'executor'): + self.builder = get_MkdirBuilder() + self.get_executor().set_action_list(self.builder.action) + else: + # Prepend MkdirBuilder action to existing action list + l = self.get_executor().action_list + a = get_MkdirBuilder().action + l.insert(0, a) + self.get_executor().set_action_list(l) + + def must_be_same(self, klass): if klass is Dir: return @@ -2278,7 +2403,8 @@ class RootDir(Dir): return _null class FileNodeInfo(SCons.Node.NodeInfoBase): - current_version_id = 1 + __slots__ = ('csig', 'timestamp', 'size') + current_version_id = 2 field_list = ['csig', 'timestamp', 'size'] @@ -2293,11 +2419,43 @@ class FileNodeInfo(SCons.Node.NodeInfoBase): if drive: root = self.fs.get_root(drive) if not os.path.isabs(s): - s = top.labspath + '/' + s + s = top.get_labspath() + '/' + s return root._lookup_abs(s, Entry) + def __getstate__(self): + """ + Return all fields that shall be pickled. Walk the slots in the class + hierarchy and add those to the state dictionary. If a '__dict__' slot is + available, copy all entries to the dictionary. Also include the version + id, which is fixed for all instances of a class. + """ + state = getattr(self, '__dict__', {}).copy() + for obj in type(self).mro(): + for name in getattr(obj,'__slots__',()): + if hasattr(self, name): + state[name] = getattr(self, name) + + state['_version_id'] = self.current_version_id + try: + del state['__weakref__'] + except KeyError: + pass + + return state + + def __setstate__(self, state): + """ + Restore the attributes from a pickled state. + """ + # TODO check or discard version + del state['_version_id'] + for key, value in state.items(): + if key not in ('__weakref__',): + setattr(self, key, value) + class FileBuildInfo(SCons.Node.BuildInfoBase): - current_version_id = 1 + __slots__ = () + current_version_id = 2 def convert_to_sconsign(self): """ @@ -2312,7 +2470,7 @@ class FileBuildInfo(SCons.Node.BuildInfoBase): else: def node_to_str(n): try: - s = n.path + s = n.get_internal_path() except AttributeError: s = str(n) else: @@ -2353,6 +2511,8 @@ class FileBuildInfo(SCons.Node.BuildInfoBase): nodeinfos = getattr(self, sattr) except AttributeError: continue + if strings is None or nodeinfos is None: + continue nodes = [] for s, ni in zip(strings, nodeinfos): if not isinstance(s, SCons.Node.Node): @@ -2366,6 +2526,8 @@ class FileBuildInfo(SCons.Node.BuildInfoBase): for bkid, bkidsig in zip(bkids, bkidsigs): result.append(str(bkid) + ': ' + ' '.join(bkidsig.format(names=names))) + if not hasattr(self,'bact'): + self.bact = "none" result.append('%s [%s]' % (self.bactsig, self.bact)) return '\n'.join(result) @@ -2373,7 +2535,22 @@ class File(Base): """A class for files in a file system. """ - memoizer_counters = [] + __slots__ = ['scanner_paths', + 'cachedir_csig', + 'cachesig', + 'repositories', + 'srcdir', + 'entries', + 'searched', + '_sconsign', + 'variant_dirs', + 'root', + 'dirname', + 'on_disk_entries', + 'sccs_dir', + 'rcs_dir', + 'released_target_info', + 'contentsig'] NodeInfo = FileNodeInfo BuildInfo = FileBuildInfo @@ -2424,6 +2601,14 @@ class File(Base): if not hasattr(self, 'released_target_info'): self.released_target_info = False + self.store_info = 1 + self._func_exists = 4 + self._func_get_contents = 3 + + # Initialize this Node's decider function to decide_source() because + # every file is a source file until it has a Builder attached... + self.changed_since_last_build = 4 + # If there was already a Builder set on this entry, then # we need to make sure we call the target-decider function, # not the source-decider. Reaching in and doing this by hand @@ -2435,22 +2620,13 @@ class File(Base): # not clear right now how to fix that, stick with what works # until it becomes clear... if self.has_builder(): - self.changed_since_last_build = self.decide_target + self.changed_since_last_build = 5 def scanner_key(self): return self.get_suffix() def get_contents(self): - if not self.rexists(): - return '' - fname = self.rfile().abspath - try: - contents = open(fname, "rb").read() - except EnvironmentError, e: - if not e.filename: - e.filename = fname - raise - return contents + return SCons.Node._get_contents_map[self._func_get_contents](self) # This attempts to figure out what the encoding of the text is # based upon the BOM bytes, and then decodes the contents so that @@ -2477,7 +2653,7 @@ class File(Base): """ if not self.rexists(): return SCons.Util.MD5signature('') - fname = self.rfile().abspath + fname = self.rfile().get_abspath() try: cs = SCons.Util.MD5filesignature(fname, chunksize=SCons.Node.FS.File.md5_chunksize*1024) @@ -2487,9 +2663,7 @@ class File(Base): raise return cs - - memoizer_counters.append(SCons.Memoize.CountValue('get_size')) - + @SCons.Memoize.CountMethodCall def get_size(self): try: return self._memo['get_size'] @@ -2505,8 +2679,7 @@ class File(Base): return size - memoizer_counters.append(SCons.Memoize.CountValue('get_timestamp')) - + @SCons.Memoize.CountMethodCall def get_timestamp(self): try: return self._memo['get_timestamp'] @@ -2522,14 +2695,6 @@ class File(Base): return timestamp - def store_info(self): - # Merge our build information into the already-stored entry. - # This accomodates "chained builds" where a file that's a target - # in one build (SConstruct file) is a source in a different build. - # See test/chained-build.py for the use case. - if do_store_info: - self.dir.sconsign().store_info(self.name, self) - convert_copy_attrs = [ 'bsources', 'bimplicit', @@ -2642,8 +2807,7 @@ class File(Base): delattr(old_entry, attr) return new_entry - memoizer_counters.append(SCons.Memoize.CountValue('get_stored_info')) - + @SCons.Memoize.CountMethodCall def get_stored_info(self): try: return self._memo['get_stored_info'] @@ -2683,8 +2847,7 @@ class File(Base): def _get_found_includes_key(self, env, scanner, path): return (id(env), id(scanner), path) - memoizer_counters.append(SCons.Memoize.CountDict('get_found_includes', _get_found_includes_key)) - + @SCons.Memoize.CountDictCall(_get_found_includes_key) def get_found_includes(self, env, scanner, path): """Return the included implicit dependencies in this file. Cache results so we only scan the file once per path @@ -2768,9 +2931,9 @@ class File(Base): # any build information that's stored in the .sconsign file # into our binfo object so it doesn't get lost. old = self.get_stored_info() - self.get_binfo().__dict__.update(old.binfo.__dict__) + self.get_binfo().merge(old.binfo) - self.store_info() + SCons.Node.store_info_map[self.store_info](self) def release_target_info(self): """Called just after this node has been marked @@ -2870,7 +3033,7 @@ class File(Base): def _rmv_existing(self): self.clear_memoized_values() - if print_duplicate: + if SCons.Node.print_duplicate: print "dup: removing existing target %s"%self e = Unlink(self, [], None) if isinstance(e, SCons.Errors.BuildError): @@ -2906,18 +3069,18 @@ class File(Base): def remove(self): """Remove this file.""" if self.exists() or self.islink(): - self.fs.unlink(self.path) + self.fs.unlink(self.get_internal_path()) return 1 return None def do_duplicate(self, src): self._createDir() - if print_duplicate: + if SCons.Node.print_duplicate: print "dup: relinking variant '%s' from '%s'"%(self, src) Unlink(self, None, None) 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) + desc = "Cannot duplicate `%s' in `%s': %s." % (src.get_internal_path(), self.dir.path, e.errstr) raise SCons.Errors.StopError(desc) self.linked = 1 # The Link() action may or may not have actually @@ -2926,36 +3089,14 @@ class File(Base): # _rexists attributes so they can be reevaluated. self.clear() - memoizer_counters.append(SCons.Memoize.CountValue('exists')) - + @SCons.Memoize.CountMethodCall def exists(self): try: return self._memo['exists'] except KeyError: pass - # Duplicate from source path if we are set up to do this. - if self.duplicate and not self.is_derived() and not self.linked: - src = self.srcnode() - if src is not self: - # At this point, src is meant to be copied in a variant directory. - src = src.rfile() - if src.abspath != self.abspath: - if src.exists(): - self.do_duplicate(src) - # Can't return 1 here because the duplication might - # not actually occur if the -n option is being used. - else: - # The source file does not exist. Make sure no old - # copy remains in the variant directory. - if print_duplicate: - print "dup: no src for %s, unlinking old variant copy"%self - if Base.exists(self) or self.islink(): - self.fs.unlink(self.path) - # Return None explicitly because the Base.exists() call - # above will have cached its value if the file existed. - self._memo['exists'] = None - return None - result = Base.exists(self) + + result = SCons.Node._exists_map[self._func_exists](self) self._memo['exists'] = result return result @@ -3032,7 +3173,7 @@ class File(Base): def builder_set(self, builder): SCons.Node.Node.builder_set(self, builder) - self.changed_since_last_build = self.decide_target + self.changed_since_last_build = 5 def built(self): """Called just after this File node is successfully built. @@ -3049,7 +3190,7 @@ class File(Base): if (not SCons.Node.interactive and not hasattr(self.attributes, 'keep_targetinfo')): # Ensure that the build infos get computed and cached... - self.store_info() + SCons.Node.store_info_map[self.store_info](self) # ... then release some more variables. self._specific_sources = False self.labspath = None @@ -3111,16 +3252,6 @@ class File(Base): except AttributeError: return 1 - def decide_source(self, target, prev_ni): - return target.get_build_env().decide_source(self, target, prev_ni) - - def decide_target(self, target, prev_ni): - return target.get_build_env().decide_target(self, target, prev_ni) - - # Initialize this Node's decider function to decide_source() because - # every file is a source file until it has a Builder attached... - changed_since_last_build = decide_source - def is_up_to_date(self): T = 0 if T: Trace('is_up_to_date(%s):' % self) @@ -3138,7 +3269,7 @@ class File(Base): e = LocalCopy(self, r, None) if isinstance(e, SCons.Errors.BuildError): raise - self.store_info() + SCons.Node.store_info_map[self.store_info](self) if T: Trace(' 1\n') return 1 self.changed() @@ -3149,8 +3280,7 @@ class File(Base): if T: Trace(' self.exists(): %s\n' % r) return not r - memoizer_counters.append(SCons.Memoize.CountValue('rfile')) - + @SCons.Memoize.CountMethodCall def rfile(self): try: return self._memo['rfile'] @@ -3252,7 +3382,7 @@ class File(Base): # Append this node's signature... sigs.append(self.get_contents_sig()) # ...and it's path - sigs.append(self.path) + sigs.append(self.get_internal_path()) # Merge this all into a single signature result = self.cachesig = SCons.Util.MD5collect(sigs) return result @@ -3268,10 +3398,6 @@ def get_default_fs(): class FileFinder(object): """ """ - if SCons.Memoize.use_memoizer: - __metaclass__ = SCons.Memoize.Memoized_Metaclass - - memoizer_counters = [] def __init__(self): self._memo = {} @@ -3314,8 +3440,7 @@ class FileFinder(object): def _find_file_key(self, filename, paths, verbose=None): return (filename, paths) - memoizer_counters.append(SCons.Memoize.CountDict('find_file', _find_file_key)) - + @SCons.Memoize.CountDictCall(_find_file_key) def find_file(self, filename, paths, verbose=None): """ find_file(str, [Dir()]) -> [nodes] |