OLD | NEW |
(Empty) | |
| 1 #! /usr/bin/env python |
| 2 # |
| 3 # SCons - a Software Constructor |
| 4 # |
| 5 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The S
Cons Foundation |
| 6 # |
| 7 # Permission is hereby granted, free of charge, to any person obtaining |
| 8 # a copy of this software and associated documentation files (the |
| 9 # "Software"), to deal in the Software without restriction, including |
| 10 # without limitation the rights to use, copy, modify, merge, publish, |
| 11 # distribute, sublicense, and/or sell copies of the Software, and to |
| 12 # permit persons to whom the Software is furnished to do so, subject to |
| 13 # the following conditions: |
| 14 # |
| 15 # The above copyright notice and this permission notice shall be included |
| 16 # in all copies or substantial portions of the Software. |
| 17 # |
| 18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
| 19 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
| 20 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 21 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| 22 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| 23 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 24 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 25 |
| 26 __revision__ = "src/script/sconsign.py 5134 2010/08/16 23:02:40 bdeegan" |
| 27 |
| 28 __version__ = "2.0.1" |
| 29 |
| 30 __build__ = "r5134" |
| 31 |
| 32 __buildsys__ = "cooldog" |
| 33 |
| 34 __date__ = "2010/08/16 23:02:40" |
| 35 |
| 36 __developer__ = "bdeegan" |
| 37 |
| 38 import os |
| 39 import sys |
| 40 import time |
| 41 |
| 42 ############################################################################## |
| 43 # BEGIN STANDARD SCons SCRIPT HEADER |
| 44 # |
| 45 # This is the cut-and-paste logic so that a self-contained script can |
| 46 # interoperate correctly with different SCons versions and installation |
| 47 # locations for the engine. If you modify anything in this section, you |
| 48 # should also change other scripts that use this same header. |
| 49 ############################################################################## |
| 50 |
| 51 # Strip the script directory from sys.path() so on case-insensitive |
| 52 # (WIN32) systems Python doesn't think that the "scons" script is the |
| 53 # "SCons" package. Replace it with our own library directories |
| 54 # (version-specific first, in case they installed by hand there, |
| 55 # followed by generic) so we pick up the right version of the build |
| 56 # engine modules if they're in either directory. |
| 57 |
| 58 script_dir = sys.path[0] |
| 59 |
| 60 if script_dir in sys.path: |
| 61 sys.path.remove(script_dir) |
| 62 |
| 63 libs = [] |
| 64 |
| 65 if "SCONS_LIB_DIR" in os.environ: |
| 66 libs.append(os.environ["SCONS_LIB_DIR"]) |
| 67 |
| 68 local_version = 'scons-local-' + __version__ |
| 69 local = 'scons-local' |
| 70 if script_dir: |
| 71 local_version = os.path.join(script_dir, local_version) |
| 72 local = os.path.join(script_dir, local) |
| 73 libs.append(os.path.abspath(local_version)) |
| 74 libs.append(os.path.abspath(local)) |
| 75 |
| 76 scons_version = 'scons-%s' % __version__ |
| 77 |
| 78 prefs = [] |
| 79 |
| 80 if sys.platform == 'win32': |
| 81 # sys.prefix is (likely) C:\Python*; |
| 82 # check only C:\Python*. |
| 83 prefs.append(sys.prefix) |
| 84 prefs.append(os.path.join(sys.prefix, 'Lib', 'site-packages')) |
| 85 else: |
| 86 # On other (POSIX) platforms, things are more complicated due to |
| 87 # the variety of path names and library locations. Try to be smart |
| 88 # about it. |
| 89 if script_dir == 'bin': |
| 90 # script_dir is `pwd`/bin; |
| 91 # check `pwd`/lib/scons*. |
| 92 prefs.append(os.getcwd()) |
| 93 else: |
| 94 if script_dir == '.' or script_dir == '': |
| 95 script_dir = os.getcwd() |
| 96 head, tail = os.path.split(script_dir) |
| 97 if tail == "bin": |
| 98 # script_dir is /foo/bin; |
| 99 # check /foo/lib/scons*. |
| 100 prefs.append(head) |
| 101 |
| 102 head, tail = os.path.split(sys.prefix) |
| 103 if tail == "usr": |
| 104 # sys.prefix is /foo/usr; |
| 105 # check /foo/usr/lib/scons* first, |
| 106 # then /foo/usr/local/lib/scons*. |
| 107 prefs.append(sys.prefix) |
| 108 prefs.append(os.path.join(sys.prefix, "local")) |
| 109 elif tail == "local": |
| 110 h, t = os.path.split(head) |
| 111 if t == "usr": |
| 112 # sys.prefix is /foo/usr/local; |
| 113 # check /foo/usr/local/lib/scons* first, |
| 114 # then /foo/usr/lib/scons*. |
| 115 prefs.append(sys.prefix) |
| 116 prefs.append(head) |
| 117 else: |
| 118 # sys.prefix is /foo/local; |
| 119 # check only /foo/local/lib/scons*. |
| 120 prefs.append(sys.prefix) |
| 121 else: |
| 122 # sys.prefix is /foo (ends in neither /usr or /local); |
| 123 # check only /foo/lib/scons*. |
| 124 prefs.append(sys.prefix) |
| 125 |
| 126 temp = [os.path.join(x, 'lib') for x in prefs] |
| 127 temp.extend([os.path.join(x, |
| 128 'lib', |
| 129 'python' + sys.version[:3], |
| 130 'site-packages') for x in prefs]) |
| 131 prefs = temp |
| 132 |
| 133 # Add the parent directory of the current python's library to the |
| 134 # preferences. On SuSE-91/AMD64, for example, this is /usr/lib64, |
| 135 # not /usr/lib. |
| 136 try: |
| 137 libpath = os.__file__ |
| 138 except AttributeError: |
| 139 pass |
| 140 else: |
| 141 # Split /usr/libfoo/python*/os.py to /usr/libfoo/python*. |
| 142 libpath, tail = os.path.split(libpath) |
| 143 # Split /usr/libfoo/python* to /usr/libfoo |
| 144 libpath, tail = os.path.split(libpath) |
| 145 # Check /usr/libfoo/scons*. |
| 146 prefs.append(libpath) |
| 147 |
| 148 try: |
| 149 import pkg_resources |
| 150 except ImportError: |
| 151 pass |
| 152 else: |
| 153 # when running from an egg add the egg's directory |
| 154 try: |
| 155 d = pkg_resources.get_distribution('scons') |
| 156 except pkg_resources.DistributionNotFound: |
| 157 pass |
| 158 else: |
| 159 prefs.append(d.location) |
| 160 |
| 161 # Look first for 'scons-__version__' in all of our preference libs, |
| 162 # then for 'scons'. |
| 163 libs.extend([os.path.join(x, scons_version) for x in prefs]) |
| 164 libs.extend([os.path.join(x, 'scons') for x in prefs]) |
| 165 |
| 166 sys.path = libs + sys.path |
| 167 |
| 168 ############################################################################## |
| 169 # END STANDARD SCons SCRIPT HEADER |
| 170 ############################################################################## |
| 171 |
| 172 import SCons.compat # so pickle will import cPickle instead |
| 173 |
| 174 import whichdb |
| 175 import pickle |
| 176 import imp |
| 177 |
| 178 import SCons.SConsign |
| 179 |
| 180 def my_whichdb(filename): |
| 181 if filename[-7:] == ".dblite": |
| 182 return "SCons.dblite" |
| 183 try: |
| 184 f = open(filename + ".dblite", "rb") |
| 185 f.close() |
| 186 return "SCons.dblite" |
| 187 except IOError: |
| 188 pass |
| 189 return _orig_whichdb(filename) |
| 190 |
| 191 _orig_whichdb = whichdb.whichdb |
| 192 whichdb.whichdb = my_whichdb |
| 193 |
| 194 def my_import(mname): |
| 195 if '.' in mname: |
| 196 i = mname.rfind('.') |
| 197 parent = my_import(mname[:i]) |
| 198 fp, pathname, description = imp.find_module(mname[i+1:], |
| 199 parent.__path__) |
| 200 else: |
| 201 fp, pathname, description = imp.find_module(mname) |
| 202 return imp.load_module(mname, fp, pathname, description) |
| 203 |
| 204 class Flagger(object): |
| 205 default_value = 1 |
| 206 def __setitem__(self, item, value): |
| 207 self.__dict__[item] = value |
| 208 self.default_value = 0 |
| 209 def __getitem__(self, item): |
| 210 return self.__dict__.get(item, self.default_value) |
| 211 |
| 212 Do_Call = None |
| 213 Print_Directories = [] |
| 214 Print_Entries = [] |
| 215 Print_Flags = Flagger() |
| 216 Verbose = 0 |
| 217 Readable = 0 |
| 218 |
| 219 def default_mapper(entry, name): |
| 220 try: |
| 221 val = eval("entry."+name) |
| 222 except: |
| 223 val = None |
| 224 return str(val) |
| 225 |
| 226 def map_action(entry, name): |
| 227 try: |
| 228 bact = entry.bact |
| 229 bactsig = entry.bactsig |
| 230 except AttributeError: |
| 231 return None |
| 232 return '%s [%s]' % (bactsig, bact) |
| 233 |
| 234 def map_timestamp(entry, name): |
| 235 try: |
| 236 timestamp = entry.timestamp |
| 237 except AttributeError: |
| 238 timestamp = None |
| 239 if Readable and timestamp: |
| 240 return "'" + time.ctime(timestamp) + "'" |
| 241 else: |
| 242 return str(timestamp) |
| 243 |
| 244 def map_bkids(entry, name): |
| 245 try: |
| 246 bkids = entry.bsources + entry.bdepends + entry.bimplicit |
| 247 bkidsigs = entry.bsourcesigs + entry.bdependsigs + entry.bimplicitsigs |
| 248 except AttributeError: |
| 249 return None |
| 250 result = [] |
| 251 for i in range(len(bkids)): |
| 252 result.append(nodeinfo_string(bkids[i], bkidsigs[i], " ")) |
| 253 if result == []: |
| 254 return None |
| 255 return "\n ".join(result) |
| 256 |
| 257 map_field = { |
| 258 'action' : map_action, |
| 259 'timestamp' : map_timestamp, |
| 260 'bkids' : map_bkids, |
| 261 } |
| 262 |
| 263 map_name = { |
| 264 'implicit' : 'bkids', |
| 265 } |
| 266 |
| 267 def field(name, entry, verbose=Verbose): |
| 268 if not Print_Flags[name]: |
| 269 return None |
| 270 fieldname = map_name.get(name, name) |
| 271 mapper = map_field.get(fieldname, default_mapper) |
| 272 val = mapper(entry, name) |
| 273 if verbose: |
| 274 val = name + ": " + val |
| 275 return val |
| 276 |
| 277 def nodeinfo_raw(name, ninfo, prefix=""): |
| 278 # This just formats the dictionary, which we would normally use str() |
| 279 # to do, except that we want the keys sorted for deterministic output. |
| 280 d = ninfo.__dict__ |
| 281 try: |
| 282 keys = ninfo.field_list + ['_version_id'] |
| 283 except AttributeError: |
| 284 keys = sorted(d.keys()) |
| 285 l = [] |
| 286 for k in keys: |
| 287 l.append('%s: %s' % (repr(k), repr(d.get(k)))) |
| 288 if '\n' in name: |
| 289 name = repr(name) |
| 290 return name + ': {' + ', '.join(l) + '}' |
| 291 |
| 292 def nodeinfo_cooked(name, ninfo, prefix=""): |
| 293 try: |
| 294 field_list = ninfo.field_list |
| 295 except AttributeError: |
| 296 field_list = [] |
| 297 if '\n' in name: |
| 298 name = repr(name) |
| 299 outlist = [name+':'] + [_f for _f in [field(x, ninfo, Verbose) for x in fiel
d_list] if _f] |
| 300 if Verbose: |
| 301 sep = '\n ' + prefix |
| 302 else: |
| 303 sep = ' ' |
| 304 return sep.join(outlist) |
| 305 |
| 306 nodeinfo_string = nodeinfo_cooked |
| 307 |
| 308 def printfield(name, entry, prefix=""): |
| 309 outlist = field("implicit", entry, 0) |
| 310 if outlist: |
| 311 if Verbose: |
| 312 print " implicit:" |
| 313 print " " + outlist |
| 314 outact = field("action", entry, 0) |
| 315 if outact: |
| 316 if Verbose: |
| 317 print " action: " + outact |
| 318 else: |
| 319 print " " + outact |
| 320 |
| 321 def printentries(entries, location): |
| 322 if Print_Entries: |
| 323 for name in Print_Entries: |
| 324 try: |
| 325 entry = entries[name] |
| 326 except KeyError: |
| 327 sys.stderr.write("sconsign: no entry `%s' in `%s'\n" % (name, lo
cation)) |
| 328 else: |
| 329 try: |
| 330 ninfo = entry.ninfo |
| 331 except AttributeError: |
| 332 print name + ":" |
| 333 else: |
| 334 print nodeinfo_string(name, entry.ninfo) |
| 335 printfield(name, entry.binfo) |
| 336 else: |
| 337 for name in sorted(entries.keys()): |
| 338 entry = entries[name] |
| 339 try: |
| 340 ninfo = entry.ninfo |
| 341 except AttributeError: |
| 342 print name + ":" |
| 343 else: |
| 344 print nodeinfo_string(name, entry.ninfo) |
| 345 printfield(name, entry.binfo) |
| 346 |
| 347 class Do_SConsignDB(object): |
| 348 def __init__(self, dbm_name, dbm): |
| 349 self.dbm_name = dbm_name |
| 350 self.dbm = dbm |
| 351 |
| 352 def __call__(self, fname): |
| 353 # The *dbm modules stick their own file suffixes on the names |
| 354 # that are passed in. This is causes us to jump through some |
| 355 # hoops here to be able to allow the user |
| 356 try: |
| 357 # Try opening the specified file name. Example: |
| 358 # SPECIFIED OPENED BY self.dbm.open() |
| 359 # --------- ------------------------- |
| 360 # .sconsign => .sconsign.dblite |
| 361 # .sconsign.dblite => .sconsign.dblite.dblite |
| 362 db = self.dbm.open(fname, "r") |
| 363 except (IOError, OSError), e: |
| 364 print_e = e |
| 365 try: |
| 366 # That didn't work, so try opening the base name, |
| 367 # so that if the actually passed in 'sconsign.dblite' |
| 368 # (for example), the dbm module will put the suffix back |
| 369 # on for us and open it anyway. |
| 370 db = self.dbm.open(os.path.splitext(fname)[0], "r") |
| 371 except (IOError, OSError): |
| 372 # That didn't work either. See if the file name |
| 373 # they specified just exists (independent of the dbm |
| 374 # suffix-mangling). |
| 375 try: |
| 376 open(fname, "r") |
| 377 except (IOError, OSError), e: |
| 378 # Nope, that file doesn't even exist, so report that |
| 379 # fact back. |
| 380 print_e = e |
| 381 sys.stderr.write("sconsign: %s\n" % (print_e)) |
| 382 return |
| 383 except KeyboardInterrupt: |
| 384 raise |
| 385 except pickle.UnpicklingError: |
| 386 sys.stderr.write("sconsign: ignoring invalid `%s' file `%s'\n" % (se
lf.dbm_name, fname)) |
| 387 return |
| 388 except Exception, e: |
| 389 sys.stderr.write("sconsign: ignoring invalid `%s' file `%s': %s\n" %
(self.dbm_name, fname, e)) |
| 390 return |
| 391 |
| 392 if Print_Directories: |
| 393 for dir in Print_Directories: |
| 394 try: |
| 395 val = db[dir] |
| 396 except KeyError: |
| 397 sys.stderr.write("sconsign: no dir `%s' in `%s'\n" % (dir, a
rgs[0])) |
| 398 else: |
| 399 self.printentries(dir, val) |
| 400 else: |
| 401 for dir in sorted(db.keys()): |
| 402 self.printentries(dir, db[dir]) |
| 403 |
| 404 def printentries(self, dir, val): |
| 405 print '=== ' + dir + ':' |
| 406 printentries(pickle.loads(val), dir) |
| 407 |
| 408 def Do_SConsignDir(name): |
| 409 try: |
| 410 fp = open(name, 'rb') |
| 411 except (IOError, OSError), e: |
| 412 sys.stderr.write("sconsign: %s\n" % (e)) |
| 413 return |
| 414 try: |
| 415 sconsign = SCons.SConsign.Dir(fp) |
| 416 except KeyboardInterrupt: |
| 417 raise |
| 418 except pickle.UnpicklingError: |
| 419 sys.stderr.write("sconsign: ignoring invalid .sconsign file `%s'\n" % (n
ame)) |
| 420 return |
| 421 except Exception, e: |
| 422 sys.stderr.write("sconsign: ignoring invalid .sconsign file `%s': %s\n"
% (name, e)) |
| 423 return |
| 424 printentries(sconsign.entries, args[0]) |
| 425 |
| 426 ############################################################################## |
| 427 |
| 428 import getopt |
| 429 |
| 430 helpstr = """\ |
| 431 Usage: sconsign [OPTIONS] FILE [...] |
| 432 Options: |
| 433 -a, --act, --action Print build action information. |
| 434 -c, --csig Print content signature information. |
| 435 -d DIR, --dir=DIR Print only info about DIR. |
| 436 -e ENTRY, --entry=ENTRY Print only info about ENTRY. |
| 437 -f FORMAT, --format=FORMAT FILE is in the specified FORMAT. |
| 438 -h, --help Print this message and exit. |
| 439 -i, --implicit Print implicit dependency information. |
| 440 -r, --readable Print timestamps in human-readable form. |
| 441 --raw Print raw Python object representations. |
| 442 -s, --size Print file sizes. |
| 443 -t, --timestamp Print timestamp information. |
| 444 -v, --verbose Verbose, describe each field. |
| 445 """ |
| 446 |
| 447 opts, args = getopt.getopt(sys.argv[1:], "acd:e:f:hirstv", |
| 448 ['act', 'action', |
| 449 'csig', 'dir=', 'entry=', |
| 450 'format=', 'help', 'implicit', |
| 451 'raw', 'readable', |
| 452 'size', 'timestamp', 'verbose']) |
| 453 |
| 454 |
| 455 for o, a in opts: |
| 456 if o in ('-a', '--act', '--action'): |
| 457 Print_Flags['action'] = 1 |
| 458 elif o in ('-c', '--csig'): |
| 459 Print_Flags['csig'] = 1 |
| 460 elif o in ('-d', '--dir'): |
| 461 Print_Directories.append(a) |
| 462 elif o in ('-e', '--entry'): |
| 463 Print_Entries.append(a) |
| 464 elif o in ('-f', '--format'): |
| 465 Module_Map = {'dblite' : 'SCons.dblite', |
| 466 'sconsign' : None} |
| 467 dbm_name = Module_Map.get(a, a) |
| 468 if dbm_name: |
| 469 try: |
| 470 dbm = my_import(dbm_name) |
| 471 except: |
| 472 sys.stderr.write("sconsign: illegal file format `%s'\n" % a) |
| 473 print helpstr |
| 474 sys.exit(2) |
| 475 Do_Call = Do_SConsignDB(a, dbm) |
| 476 else: |
| 477 Do_Call = Do_SConsignDir |
| 478 elif o in ('-h', '--help'): |
| 479 print helpstr |
| 480 sys.exit(0) |
| 481 elif o in ('-i', '--implicit'): |
| 482 Print_Flags['implicit'] = 1 |
| 483 elif o in ('--raw',): |
| 484 nodeinfo_string = nodeinfo_raw |
| 485 elif o in ('-r', '--readable'): |
| 486 Readable = 1 |
| 487 elif o in ('-s', '--size'): |
| 488 Print_Flags['size'] = 1 |
| 489 elif o in ('-t', '--timestamp'): |
| 490 Print_Flags['timestamp'] = 1 |
| 491 elif o in ('-v', '--verbose'): |
| 492 Verbose = 1 |
| 493 |
| 494 if Do_Call: |
| 495 for a in args: |
| 496 Do_Call(a) |
| 497 else: |
| 498 for a in args: |
| 499 dbm_name = whichdb.whichdb(a) |
| 500 if dbm_name: |
| 501 Map_Module = {'SCons.dblite' : 'dblite'} |
| 502 dbm = my_import(dbm_name) |
| 503 Do_SConsignDB(Map_Module.get(dbm_name, dbm_name), dbm)(a) |
| 504 else: |
| 505 Do_SConsignDir(a) |
| 506 |
| 507 sys.exit(0) |
| 508 |
| 509 # Local Variables: |
| 510 # tab-width:4 |
| 511 # indent-tabs-mode:nil |
| 512 # End: |
| 513 # vim: set expandtab tabstop=4 shiftwidth=4: |
OLD | NEW |