You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

557 lines
18 KiB

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