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