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