3 Writing and reading information to the .sconsign file or files.
10 # Permission is hereby granted, free of charge, to any person obtaining
11 # a copy of this software and associated documentation files (the
12 # "Software"), to deal in the Software without restriction, including
13 # without limitation the rights to use, copy, modify, merge, publish,
14 # distribute, sublicense, and/or sell copies of the Software, and to
15 # permit persons to whom the Software is furnished to do so, subject to
16 # the following conditions:
18 # The above copyright notice and this permission notice shall be included
19 # in all copies or substantial portions of the Software.
21 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
22 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
23 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
41 #XXX Get rid of the global array so this becomes re-entrant.
48 for sig_file in sig_files:
54 """Objects of this type are pickled to the .sconsign file, so it
55 should only contain simple builtin Python datatypes and no methods.
57 This class is used to store cache information about nodes between
58 scons runs for efficiency, and to store the build signature for
59 nodes so that scons can determine if they are out of date. """
61 # setup the default value for various attributes:
62 # (We make the class variables so the default values won't get pickled
63 # with the instances, which would waste a lot of space)
75 This is the controlling class for the signatures for the collection of
76 entries associated with a specific directory. The actual directory
77 association will be maintained by a subclass that is specific to
78 the underlying storage method. This class provides a common set of
79 methods for fetching and storing the individual bits of information
80 that make up signature entry.
82 def __init__(self, module=None):
84 module - the signature module being used
87 self.module = module or SCons.Sig.default_calc.module
91 # A null .sconsign entry. We define this here so that it will
92 # be easy to keep this in sync if/whenever we change the type of
93 # information returned by the get() method, below.
94 null_siginfo = (None, None, None)
96 def get(self, filename):
98 Get the .sconsign entry for a file
100 filename - the filename whose signature will be returned
101 returns - (timestamp, bsig, csig)
103 entry = self.get_entry(filename)
104 return (entry.timestamp, entry.bsig, entry.csig)
106 def get_entry(self, filename):
108 Create an entry for the filename and return it, or if one already exists,
112 return self.entries[filename]
113 except (KeyError, AttributeError):
116 def set_entry(self, filename, entry):
120 self.entries[filename] = entry
123 def set_csig(self, filename, csig):
125 Set the csig .sconsign entry for a file
127 filename - the filename whose signature will be set
128 csig - the file's content signature
131 entry = self.get_entry(filename)
133 self.set_entry(filename, entry)
135 def set_binfo(self, filename, bsig, bkids, bkidsigs, bact, bactsig):
137 Set the build info .sconsign entry for a file
139 filename - the filename whose signature will be set
140 bsig - the file's built signature
143 entry = self.get_entry(filename)
146 entry.bkidsigs = bkidsigs
148 entry.bactsig = bactsig
149 self.set_entry(filename, entry)
151 def set_timestamp(self, filename, timestamp):
153 Set the timestamp .sconsign entry for a file
155 filename - the filename whose signature will be set
156 timestamp - the file's timestamp
159 entry = self.get_entry(filename)
160 entry.timestamp = timestamp
161 self.set_entry(filename, entry)
163 def get_implicit(self, filename):
164 """Fetch the cached implicit dependencies for 'filename'"""
165 entry = self.get_entry(filename)
166 return entry.implicit
168 def set_implicit(self, filename, implicit):
169 """Cache the implicit dependencies for 'filename'."""
170 entry = self.get_entry(filename)
171 if not SCons.Util.is_List(implicit):
172 implicit = [implicit]
173 implicit = map(str, implicit)
174 entry.implicit = implicit
175 self.set_entry(filename, entry)
177 def get_binfo(self, filename):
178 """Fetch the cached implicit dependencies for 'filename'"""
179 entry = self.get_entry(filename)
180 return entry.bsig, entry.bkids, entry.bkidsigs, entry.bact, entry.bactsig
184 A Base subclass that reads and writes signature information
185 from a global .sconsign.dbm file.
187 def __init__(self, dir, module=None):
188 Base.__init__(self, module)
194 rawentries = database[self.dir.path]
199 self.entries = cPickle.loads(rawentries)
200 if type(self.entries) is not type({}):
203 except KeyboardInterrupt:
206 SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
207 "Ignoring corrupt sconsign entry : %s"%self.dir.path)
210 sig_files.append(self)
215 database[self.dir.path] = cPickle.dumps(self.entries, 1)
218 except AttributeError:
219 # Not all anydbm modules have sync() methods.
223 def __init__(self, fp=None, module=None):
225 fp - file pointer to read entries from
226 module - the signature module being used
228 Base.__init__(self, module)
231 self.entries = cPickle.load(fp)
232 if type(self.entries) is not type({}):
238 Encapsulates reading and writing a per-directory .sconsign file.
240 def __init__(self, dir, module=None):
242 dir - the directory for the file
243 module - the signature module being used
247 self.sconsign = os.path.join(dir.path, '.sconsign')
250 fp = open(self.sconsign, 'rb')
255 Dir.__init__(self, fp, module)
256 except KeyboardInterrupt:
259 SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
260 "Ignoring corrupt .sconsign file: %s"%self.sconsign)
263 sig_files.append(self)
267 Write the .sconsign file to disk.
269 Try to write to a temporary file first, and rename it if we
270 succeed. If we can't write to the temporary file, it's
271 probably because the directory isn't writable (and if so,
272 how did we build anything in this directory, anyway?), so
273 try to write directly to the .sconsign file as a backup.
274 If we can't rename, try to copy the temporary contents back
275 to the .sconsign file. Either way, always try to remove
276 the temporary file at the end.
279 temp = os.path.join(self.dir.path, '.scons%d' % os.getpid())
281 file = open(temp, 'wb')
285 file = open(self.sconsign, 'wb')
286 fname = self.sconsign
289 cPickle.dump(self.entries, file, 1)
291 if fname != self.sconsign:
293 mode = os.stat(self.sconsign)[0]
294 os.chmod(self.sconsign, 0666)
295 os.unlink(self.sconsign)
299 os.rename(fname, self.sconsign)
301 open(self.sconsign, 'wb').write(open(fname, 'rb').read())
302 os.chmod(self.sconsign, mode)
308 ForDirectory = DirFile
310 def File(name, dbm_module=None):
312 Arrange for all signatures to be stored in a global .sconsign.dbm
317 if dbm_module is None:
319 dbm_module = SCons.dblite
320 database = dbm_module.open(name, "c")