Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(205)

Side by Side Diff: scons-2.0.1/engine/SCons/SConsign.py

Issue 6711079: Added an unmodified copy of SCons to third_party. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/third_party/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « scons-2.0.1/engine/SCons/SConf.py ('k') | scons-2.0.1/engine/SCons/Scanner/C.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 """SCons.SConsign
2
3 Writing and reading information to the .sconsign file or files.
4
5 """
6
7 #
8 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The S Cons Foundation
9 #
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:
17 #
18 # The above copyright notice and this permission notice shall be included
19 # in all copies or substantial portions of the Software.
20 #
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.
28 #
29
30 __revision__ = "src/engine/SCons/SConsign.py 5134 2010/08/16 23:02:40 bdeegan"
31
32 import SCons.compat
33
34 import os
35 # compat layer imports "cPickle" for us if it's available.
36 import pickle
37
38 import SCons.dblite
39 import SCons.Warnings
40
41 def corrupt_dblite_warning(filename):
42 SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
43 "Ignoring corrupt .sconsign file: %s"%filename)
44
45 SCons.dblite.ignore_corrupt_dbfiles = 1
46 SCons.dblite.corruption_warning = corrupt_dblite_warning
47
48 #XXX Get rid of the global array so this becomes re-entrant.
49 sig_files = []
50
51 # Info for the database SConsign implementation (now the default):
52 # "DataBase" is a dictionary that maps top-level SConstruct directories
53 # to open database handles.
54 # "DB_Module" is the Python database module to create the handles.
55 # "DB_Name" is the base name of the database file (minus any
56 # extension the underlying DB module will add).
57 DataBase = {}
58 DB_Module = SCons.dblite
59 DB_Name = ".sconsign"
60 DB_sync_list = []
61
62 def Get_DataBase(dir):
63 global DataBase, DB_Module, DB_Name
64 top = dir.fs.Top
65 if not os.path.isabs(DB_Name) and top.repositories:
66 mode = "c"
67 for d in [top] + top.repositories:
68 if dir.is_under(d):
69 try:
70 return DataBase[d], mode
71 except KeyError:
72 path = d.entry_abspath(DB_Name)
73 try: db = DataBase[d] = DB_Module.open(path, mode)
74 except (IOError, OSError): pass
75 else:
76 if mode != "r":
77 DB_sync_list.append(db)
78 return db, mode
79 mode = "r"
80 try:
81 return DataBase[top], "c"
82 except KeyError:
83 db = DataBase[top] = DB_Module.open(DB_Name, "c")
84 DB_sync_list.append(db)
85 return db, "c"
86 except TypeError:
87 print "DataBase =", DataBase
88 raise
89
90 def Reset():
91 """Reset global state. Used by unit tests that end up using
92 SConsign multiple times to get a clean slate for each test."""
93 global sig_files, DB_sync_list
94 sig_files = []
95 DB_sync_list = []
96
97 normcase = os.path.normcase
98
99 def write():
100 global sig_files
101 for sig_file in sig_files:
102 sig_file.write(sync=0)
103 for db in DB_sync_list:
104 try:
105 syncmethod = db.sync
106 except AttributeError:
107 pass # Not all anydbm modules have sync() methods.
108 else:
109 syncmethod()
110
111 class SConsignEntry(object):
112 """
113 Wrapper class for the generic entry in a .sconsign file.
114 The Node subclass populates it with attributes as it pleases.
115
116 XXX As coded below, we do expect a '.binfo' attribute to be added,
117 but we'll probably generalize this in the next refactorings.
118 """
119 current_version_id = 1
120 def __init__(self):
121 # Create an object attribute from the class attribute so it ends up
122 # in the pickled data in the .sconsign file.
123 _version_id = self.current_version_id
124 def convert_to_sconsign(self):
125 self.binfo.convert_to_sconsign()
126 def convert_from_sconsign(self, dir, name):
127 self.binfo.convert_from_sconsign(dir, name)
128
129 class Base(object):
130 """
131 This is the controlling class for the signatures for the collection of
132 entries associated with a specific directory. The actual directory
133 association will be maintained by a subclass that is specific to
134 the underlying storage method. This class provides a common set of
135 methods for fetching and storing the individual bits of information
136 that make up signature entry.
137 """
138 def __init__(self):
139 self.entries = {}
140 self.dirty = False
141 self.to_be_merged = {}
142
143 def get_entry(self, filename):
144 """
145 Fetch the specified entry attribute.
146 """
147 return self.entries[filename]
148
149 def set_entry(self, filename, obj):
150 """
151 Set the entry.
152 """
153 self.entries[filename] = obj
154 self.dirty = True
155
156 def do_not_set_entry(self, filename, obj):
157 pass
158
159 def store_info(self, filename, node):
160 entry = node.get_stored_info()
161 entry.binfo.merge(node.get_binfo())
162 self.to_be_merged[filename] = node
163 self.dirty = True
164
165 def do_not_store_info(self, filename, node):
166 pass
167
168 def merge(self):
169 for key, node in self.to_be_merged.items():
170 entry = node.get_stored_info()
171 try:
172 ninfo = entry.ninfo
173 except AttributeError:
174 # This happens with SConf Nodes, because the configuration
175 # subsystem takes direct control over how the build decision
176 # is made and its information stored.
177 pass
178 else:
179 ninfo.merge(node.get_ninfo())
180 self.entries[key] = entry
181 self.to_be_merged = {}
182
183 class DB(Base):
184 """
185 A Base subclass that reads and writes signature information
186 from a global .sconsign.db* file--the actual file suffix is
187 determined by the database module.
188 """
189 def __init__(self, dir):
190 Base.__init__(self)
191
192 self.dir = dir
193
194 db, mode = Get_DataBase(dir)
195
196 # Read using the path relative to the top of the Repository
197 # (self.dir.tpath) from which we're fetching the signature
198 # information.
199 path = normcase(dir.tpath)
200 try:
201 rawentries = db[path]
202 except KeyError:
203 pass
204 else:
205 try:
206 self.entries = pickle.loads(rawentries)
207 if not isinstance(self.entries, dict):
208 self.entries = {}
209 raise TypeError
210 except KeyboardInterrupt:
211 raise
212 except Exception, e:
213 SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
214 "Ignoring corrupt sconsign entry : %s (%s)\n "%(self.dir.tpath, e))
215 for key, entry in self.entries.items():
216 entry.convert_from_sconsign(dir, key)
217
218 if mode == "r":
219 # This directory is actually under a repository, which means
220 # likely they're reaching in directly for a dependency on
221 # a file there. Don't actually set any entry info, so we
222 # won't try to write to that .sconsign.dblite file.
223 self.set_entry = self.do_not_set_entry
224 self.store_info = self.do_not_store_info
225
226 global sig_files
227 sig_files.append(self)
228
229 def write(self, sync=1):
230 if not self.dirty:
231 return
232
233 self.merge()
234
235 db, mode = Get_DataBase(self.dir)
236
237 # Write using the path relative to the top of the SConstruct
238 # directory (self.dir.path), not relative to the top of
239 # the Repository; we only write to our own .sconsign file,
240 # not to .sconsign files in Repositories.
241 path = normcase(self.dir.path)
242 for key, entry in self.entries.items():
243 entry.convert_to_sconsign()
244 db[path] = pickle.dumps(self.entries, 1)
245
246 if sync:
247 try:
248 syncmethod = db.sync
249 except AttributeError:
250 # Not all anydbm modules have sync() methods.
251 pass
252 else:
253 syncmethod()
254
255 class Dir(Base):
256 def __init__(self, fp=None, dir=None):
257 """
258 fp - file pointer to read entries from
259 """
260 Base.__init__(self)
261
262 if not fp:
263 return
264
265 self.entries = pickle.load(fp)
266 if not isinstance(self.entries, dict):
267 self.entries = {}
268 raise TypeError
269
270 if dir:
271 for key, entry in self.entries.items():
272 entry.convert_from_sconsign(dir, key)
273
274 class DirFile(Dir):
275 """
276 Encapsulates reading and writing a per-directory .sconsign file.
277 """
278 def __init__(self, dir):
279 """
280 dir - the directory for the file
281 """
282
283 self.dir = dir
284 self.sconsign = os.path.join(dir.path, '.sconsign')
285
286 try:
287 fp = open(self.sconsign, 'rb')
288 except IOError:
289 fp = None
290
291 try:
292 Dir.__init__(self, fp, dir)
293 except KeyboardInterrupt:
294 raise
295 except:
296 SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
297 "Ignoring corrupt .sconsign file: %s"%self.scons ign)
298
299 global sig_files
300 sig_files.append(self)
301
302 def write(self, sync=1):
303 """
304 Write the .sconsign file to disk.
305
306 Try to write to a temporary file first, and rename it if we
307 succeed. If we can't write to the temporary file, it's
308 probably because the directory isn't writable (and if so,
309 how did we build anything in this directory, anyway?), so
310 try to write directly to the .sconsign file as a backup.
311 If we can't rename, try to copy the temporary contents back
312 to the .sconsign file. Either way, always try to remove
313 the temporary file at the end.
314 """
315 if not self.dirty:
316 return
317
318 self.merge()
319
320 temp = os.path.join(self.dir.path, '.scons%d' % os.getpid())
321 try:
322 file = open(temp, 'wb')
323 fname = temp
324 except IOError:
325 try:
326 file = open(self.sconsign, 'wb')
327 fname = self.sconsign
328 except IOError:
329 return
330 for key, entry in self.entries.items():
331 entry.convert_to_sconsign()
332 pickle.dump(self.entries, file, 1)
333 file.close()
334 if fname != self.sconsign:
335 try:
336 mode = os.stat(self.sconsign)[0]
337 os.chmod(self.sconsign, 0666)
338 os.unlink(self.sconsign)
339 except (IOError, OSError):
340 # Try to carry on in the face of either OSError
341 # (things like permission issues) or IOError (disk
342 # or network issues). If there's a really dangerous
343 # issue, it should get re-raised by the calls below.
344 pass
345 try:
346 os.rename(fname, self.sconsign)
347 except OSError:
348 # An OSError failure to rename may indicate something
349 # like the directory has no write permission, but
350 # the .sconsign file itself might still be writable,
351 # so try writing on top of it directly. An IOError
352 # here, or in any of the following calls, would get
353 # raised, indicating something like a potentially
354 # serious disk or network issue.
355 open(self.sconsign, 'wb').write(open(fname, 'rb').read())
356 os.chmod(self.sconsign, mode)
357 try:
358 os.unlink(temp)
359 except (IOError, OSError):
360 pass
361
362 ForDirectory = DB
363
364 def File(name, dbm_module=None):
365 """
366 Arrange for all signatures to be stored in a global .sconsign.db*
367 file.
368 """
369 global ForDirectory, DB_Name, DB_Module
370 if name is None:
371 ForDirectory = DirFile
372 DB_Module = None
373 else:
374 ForDirectory = DB
375 DB_Name = name
376 if not dbm_module is None:
377 DB_Module = dbm_module
378
379 # Local Variables:
380 # tab-width:4
381 # indent-tabs-mode:nil
382 # End:
383 # vim: set expandtab tabstop=4 shiftwidth=4:
OLDNEW
« no previous file with comments | « scons-2.0.1/engine/SCons/SConf.py ('k') | scons-2.0.1/engine/SCons/Scanner/C.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698