summaryrefslogtreecommitdiffstats
path: root/Tools/scripts
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1991-06-04 20:36:54 (GMT)
committerGuido van Rossum <guido@python.org>1991-06-04 20:36:54 (GMT)
commitec758ead391daa2ce0e5697aa0e67ec3ba0f37af (patch)
tree7f2d186afd41d797882d5b5be3330e921804ebe9 /Tools/scripts
parent0481447f4135c11d42ae25f55696af8e8d52fe74 (diff)
downloadcpython-ec758ead391daa2ce0e5697aa0e67ec3ba0f37af.zip
cpython-ec758ead391daa2ce0e5697aa0e67ec3ba0f37af.tar.gz
cpython-ec758ead391daa2ce0e5697aa0e67ec3ba0f37af.tar.bz2
Initial revision
Diffstat (limited to 'Tools/scripts')
-rwxr-xr-xTools/scripts/byteyears.py29
-rwxr-xr-xTools/scripts/eptags.py50
-rwxr-xr-xTools/scripts/findlinksto.py29
-rwxr-xr-xTools/scripts/mkreal.py65
-rwxr-xr-xTools/scripts/objgraph.py213
-rwxr-xr-xTools/scripts/pdeps.py167
-rwxr-xr-xTools/scripts/ptags.py49
-rwxr-xr-xTools/scripts/suff.py29
-rwxr-xr-xTools/scripts/which.py44
-rwxr-xr-xTools/scripts/xxci.py77
10 files changed, 752 insertions, 0 deletions
diff --git a/Tools/scripts/byteyears.py b/Tools/scripts/byteyears.py
new file mode 100755
index 0000000..8c5ec69
--- /dev/null
+++ b/Tools/scripts/byteyears.py
@@ -0,0 +1,29 @@
+#! /usr/local/python
+
+# byteyears file ...
+#
+# Print a number representing the product of age and size of each file,
+# in suitable units.
+
+import sys, posix, time
+from stat import *
+
+secs_per_year = 365.0 * 24.0 * 3600.0
+now = time.time()
+status = 0
+
+for file in sys.argv[1:]:
+ try:
+ st = posix.stat(file)
+ except posix.error, msg:
+ sys.stderr.write('can\'t stat ' + `file` + ': ' + `msg` + '\n')
+ status = 1
+ st = ()
+ if st:
+ mtime = st[ST_MTIME]
+ size = st[ST_SIZE]
+ age = now - mtime
+ byteyears = float(size) * float(age) / secs_per_year
+ print file + '\t\t' + `int(byteyears)`
+
+sys.exit(status)
diff --git a/Tools/scripts/eptags.py b/Tools/scripts/eptags.py
new file mode 100755
index 0000000..1c682d3
--- /dev/null
+++ b/Tools/scripts/eptags.py
@@ -0,0 +1,50 @@
+#! /usr/local/python
+
+# eptags
+#
+# Create a TAGS file for Python programs, usable with GNU Emacs (version 18).
+# Tagged are:
+# - functions (even inside other defs or classes)
+# - classes
+# Warns about files it cannot open.
+# No warnings about duplicate tags.
+
+import sys
+import regexp
+
+def main():
+ outfp = open('TAGS', 'w')
+ args = sys.argv[1:]
+ for file in args:
+ treat_file(file, outfp)
+
+matcher = regexp.compile('^[ \t]*(def|class)[ \t]+([a-zA-Z0-9_]+)[ \t]*\(')
+
+def treat_file(file, outfp):
+ try:
+ fp = open(file, 'r')
+ except:
+ print 'Cannot open', file
+ return
+ charno = 0
+ lineno = 0
+ tags = []
+ size = 0
+ while 1:
+ line = fp.readline()
+ if not line: break
+ lineno = lineno + 1
+ res = matcher.exec(line)
+ if res:
+ (a, b), (a1, b1), (a2, b2) = res
+ name = line[a2:b2]
+ pat = line[a:b]
+ tag = pat + '\177' + `lineno` + ',' + `charno` + '\n'
+ tags.append(name, tag)
+ size = size + len(tag)
+ charno = charno + len(line)
+ outfp.write('\f\n' + file + ',' + `size` + '\n')
+ for name, tag in tags:
+ outfp.write(tag)
+
+main()
diff --git a/Tools/scripts/findlinksto.py b/Tools/scripts/findlinksto.py
new file mode 100755
index 0000000..6a2a75b
--- /dev/null
+++ b/Tools/scripts/findlinksto.py
@@ -0,0 +1,29 @@
+#! /usr/local/python
+
+# findlinksto
+#
+# find symbolic links to a given path
+
+import posix, path, sys
+
+def visit(pattern, dirname, names):
+ if path.islink(dirname):
+ names[:] = []
+ return
+ if path.ismount(dirname):
+ print 'descend into', dirname
+ n = len(pattern)
+ for name in names:
+ name = path.cat(dirname, name)
+ try:
+ linkto = posix.readlink(name)
+ if linkto[:n] = pattern:
+ print name, '->', linkto
+ except posix.error:
+ pass
+
+def main(pattern, args):
+ for dirname in args:
+ path.walk(dirname, visit, pattern)
+
+main(sys.argv[1], sys.argv[2:])
diff --git a/Tools/scripts/mkreal.py b/Tools/scripts/mkreal.py
new file mode 100755
index 0000000..3fd4b03
--- /dev/null
+++ b/Tools/scripts/mkreal.py
@@ -0,0 +1,65 @@
+#! /usr/local/python
+
+# mkreal
+#
+# turn a symlink to a directory into a real directory
+
+import sys
+import posix
+import path
+from stat import *
+
+cat = path.cat
+
+error = 'mkreal error'
+
+BUFSIZE = 32*1024
+
+def mkrealfile(name):
+ st = posix.stat(name) # Get the mode
+ mode = S_IMODE(st[ST_MODE])
+ linkto = posix.readlink(name) # Make sure again it's a symlink
+ f_in = open(name, 'r') # This ensures it's a file
+ posix.unlink(name)
+ f_out = open(name, 'w')
+ while 1:
+ buf = f_in.read(BUFSIZE)
+ if not buf: break
+ f_out.write(buf)
+ del f_out # Flush data to disk before changing mode
+ posix.chmod(name, mode)
+
+def mkrealdir(name):
+ st = posix.stat(name) # Get the mode
+ mode = S_IMODE(st[ST_MODE])
+ linkto = posix.readlink(name)
+ files = posix.listdir(name)
+ posix.unlink(name)
+ posix.mkdir(name, mode)
+ posix.chmod(name, mode)
+ linkto = cat('..', linkto)
+ #
+ for file in files:
+ if file not in ('.', '..'):
+ posix.symlink(cat(linkto, file), cat(name, file))
+
+def main():
+ sys.stdout = sys.stderr
+ progname = path.basename(sys.argv[0])
+ args = sys.argv[1:]
+ if not args:
+ print 'usage:', progname, 'path ...'
+ sys.exit(2)
+ status = 0
+ for name in args:
+ if not path.islink(name):
+ print progname+':', name+':', 'not a symlink'
+ status = 1
+ else:
+ if path.isdir(name):
+ mkrealdir(name)
+ else:
+ mkrealfile(name)
+ sys.exit(status)
+
+main()
diff --git a/Tools/scripts/objgraph.py b/Tools/scripts/objgraph.py
new file mode 100755
index 0000000..b45bba2
--- /dev/null
+++ b/Tools/scripts/objgraph.py
@@ -0,0 +1,213 @@
+#!/usr/local/python
+
+# objgraph
+#
+# Read "nm -o" input (on IRIX: "nm -Bo") of a set of libraries or modules
+# and print various interesting listings, such as:
+#
+# - which names are used but not defined in the set (and used where),
+# - which names are defined in the set (and where),
+# - which modules use which other modules,
+# - which modules are used by which other modules.
+#
+# Usage: objgraph [-cdu] [file] ...
+# -c: print callers per objectfile
+# -d: print callees per objectfile
+# -u: print usage of undefined symbols
+# If none of -cdu is specified, all are assumed.
+# Use "nm -o" to generate the input (on IRIX: "nm -Bo"),
+# e.g.: nm -o /lib/libc.a | objgraph
+
+
+import sys
+import string
+import path
+import getopt
+import regexp
+
+# Types of symbols.
+#
+definitions = 'TRGDSBAEC'
+externals = 'UV'
+ignore = 'Nntrgdsbavuc'
+
+# Regular expression to parse "nm -o" output.
+#
+matcher = regexp.compile('(.*):\t?........ (.) (.*)$')
+
+# Store "item" in "dict" under "key".
+# The dictionary maps keys to lists of items.
+# If there is no list for the key yet, it is created.
+#
+def store(dict, key, item):
+ if dict.has_key(key):
+ dict[key].append(item)
+ else:
+ dict[key] = [item]
+
+# Return a flattened version of a list of strings: the concatenation
+# of its elements with intervening spaces.
+#
+def flat(list):
+ s = ''
+ for item in list:
+ s = s + ' ' + item
+ return s[1:]
+
+# Global variables mapping defined/undefined names to files and back.
+#
+file2undef = {}
+def2file = {}
+file2def = {}
+undef2file = {}
+
+# Read one input file and merge the data into the tables.
+# Argument is an open file.
+#
+def readinput(file):
+ while 1:
+ s = file.readline(200) # Arbitrary, but reasonable limit
+ if not s:
+ break
+ # If you get an exception on this line,
+ # it is probably caused by an unexpected input line:
+ (ra, rb), (r1a, r1b), (r2a, r2b), (r3a, r3b) = matcher.exec(s)
+ fn, name, type = s[r1a:r1b], s[r3a:r3b], s[r2a:r2b]
+ if type in definitions:
+ store(def2file, name, fn)
+ store(file2def, fn, name)
+ elif type in externals:
+ store(file2undef, fn, name)
+ store(undef2file, name, fn)
+ elif not type in ignore:
+ print fn + ':' + name + ': unknown type ' + type
+
+# Print all names that were undefined in some module and where they are
+# defined.
+#
+def printcallee():
+ flist = file2undef.keys()
+ flist.sort()
+ for file in flist:
+ print file + ':'
+ elist = file2undef[file]
+ elist.sort()
+ for ext in elist:
+ if len(ext) >= 8:
+ tabs = '\t'
+ else:
+ tabs = '\t\t'
+ if not def2file.has_key(ext):
+ print '\t' + ext + tabs + ' *undefined'
+ else:
+ print '\t' + ext + tabs + flat(def2file[ext])
+
+# Print for each module the names of the other modules that use it.
+#
+def printcaller():
+ files = file2def.keys()
+ files.sort()
+ for file in files:
+ callers = []
+ for label in file2def[file]:
+ if undef2file.has_key(label):
+ callers = callers + undef2file[label]
+ if callers:
+ callers.sort()
+ print file + ':'
+ lastfn = ''
+ for fn in callers:
+ if fn <> lastfn:
+ print '\t' + fn
+ lastfn = fn
+ else:
+ print file + ': unused'
+
+# Print undefine names and where they are used.
+#
+def printundef():
+ undefs = {}
+ for file in file2undef.keys():
+ for ext in file2undef[file]:
+ if not def2file.has_key(ext):
+ store(undefs, ext, file)
+ elist = undefs.keys()
+ elist.sort()
+ for ext in elist:
+ print ext + ':'
+ flist = undefs[ext]
+ flist.sort()
+ for file in flist:
+ print '\t' + file
+
+# Print warning messages about names defined in more than one file.
+#
+def warndups():
+ savestdout = sys.stdout
+ sys.stdout = sys.stderr
+ names = def2file.keys()
+ names.sort()
+ for name in names:
+ if len(def2file[name]) > 1:
+ print 'warning:', name, 'multiply defined:',
+ print flat(def2file[name])
+ sys.stdout = savestdout
+
+# Main program
+#
+def main():
+ try:
+ optlist, args = getopt.getopt(sys.argv[1:], 'cdu')
+ except getopt.error:
+ sys.stdout = sys.stderr
+ print 'Usage:', path.basename(sys.argv[0]), '[-cdu] [file] ...'
+ print '-c: print callers per objectfile'
+ print '-d: print callees per objectfile'
+ print '-u: print usage of undefined symbols'
+ print 'If none of -cdu is specified, all are assumed.'
+ print 'Use "nm -o" to generate the input (on IRIX: "nm -Bo"),'
+ print 'e.g.: nm -o /lib/libc.a | objgraph'
+ return 1
+ optu = optc = optd = 0
+ for opt, void in optlist:
+ if opt = '-u':
+ optu = 1
+ elif opt = '-c':
+ optc = 1
+ elif opt = '-d':
+ optd = 1
+ if optu = optc = optd = 0:
+ optu = optc = optd = 1
+ if not args:
+ args = ['-']
+ for file in args:
+ if file = '-':
+ readinput(sys.stdin)
+ else:
+ readinput(open(file, 'r'))
+ #
+ warndups()
+ #
+ more = (optu + optc + optd > 1)
+ if optd:
+ if more:
+ print '---------------All callees------------------'
+ printcallee()
+ if optu:
+ if more:
+ print '---------------Undefined callees------------'
+ printundef()
+ if optc:
+ if more:
+ print '---------------All Callers------------------'
+ printcaller()
+ return 0
+
+# Call the main program.
+# Use its return value as exit status.
+# Catch interrupts to avoid stack trace.
+#
+try:
+ sys.exit(main())
+except KeyboardInterrupt:
+ sys.exit(1)
diff --git a/Tools/scripts/pdeps.py b/Tools/scripts/pdeps.py
new file mode 100755
index 0000000..2533015
--- /dev/null
+++ b/Tools/scripts/pdeps.py
@@ -0,0 +1,167 @@
+#! /usr/local/python
+
+# pdeps
+#
+# Find dependencies between a bunch of Python modules.
+#
+# Usage:
+# pdeps file1.py file2.py ...
+#
+# Output:
+# Four tables separated by lines like '--- Closure ---':
+# 1) Direct dependencies, listing which module imports which other modules
+# 2) The inverse of (1)
+# 3) Indirect dependencies, or the closure of the above
+# 4) The inverse of (3)
+#
+# To do:
+# - command line options to select output type
+# - option to automatically scan the Python library for referenced modules
+# - option to limit output to particular modules
+
+
+import sys
+import regexp
+import path
+import string
+
+
+# Main program
+#
+def main():
+ args = sys.argv[1:]
+ if not args:
+ print 'usage: pdeps file.py file.py ...'
+ return 2
+ #
+ table = {}
+ for arg in args:
+ process(arg, table)
+ #
+ print '--- Uses ---'
+ printresults(table)
+ #
+ print '--- Used By ---'
+ inv = inverse(table)
+ printresults(inv)
+ #
+ print '--- Closure of Uses ---'
+ reach = closure(table)
+ printresults(reach)
+ #
+ print '--- Closure of Used By ---'
+ invreach = inverse(reach)
+ printresults(invreach)
+ #
+ return 0
+
+
+# Compiled regular expressions to search for import statements
+#
+m_import = regexp.compile('^[ \t]*from[ \t]+([^ \t]+)[ \t]+')
+m_from = regexp.compile('^[ \t]*import[ \t]+([^#]+)')
+
+
+# Collect data from one file
+#
+def process(filename, table):
+ fp = open(filename, 'r')
+ mod = path.basename(filename)
+ if mod[-3:] = '.py':
+ mod = mod[:-3]
+ table[mod] = list = []
+ while 1:
+ line = fp.readline()
+ if not line: break
+ while line[-1:] = '\\':
+ nextline = fp.readline()
+ if not nextline: break
+ line = line[:-1] + nextline
+ result = m_import.exec(line)
+ if not result:
+ result = m_from.exec(line)
+ if result:
+ (a, b), (a1, b1) = result
+ words = string.splitfields(line[a1:b1], ',')
+ # print '#', line, words
+ for word in words:
+ word = string.strip(word)
+ if word not in list:
+ list.append(word)
+
+
+# Compute closure (this is in fact totally general)
+#
+def closure(table):
+ modules = table.keys()
+ #
+ # Initialize reach with a copy of table
+ #
+ reach = {}
+ for mod in modules:
+ reach[mod] = table[mod][:]
+ #
+ # Iterate until no more change
+ #
+ change = 1
+ while change:
+ change = 0
+ for mod in modules:
+ for mo in reach[mod]:
+ if mo in modules:
+ for m in reach[mo]:
+ if m not in reach[mod]:
+ reach[mod].append(m)
+ change = 1
+ #
+ return reach
+
+
+# Invert a table (this is again totally general).
+# All keys of the original table are made keys of the inverse,
+# so there may be empty lists in the inverse.
+#
+def inverse(table):
+ inv = {}
+ for key in table.keys():
+ if not inv.has_key(key):
+ inv[key] = []
+ for item in table[key]:
+ store(inv, item, key)
+ return inv
+
+
+# Store "item" in "dict" under "key".
+# The dictionary maps keys to lists of items.
+# If there is no list for the key yet, it is created.
+#
+def store(dict, key, item):
+ if dict.has_key(key):
+ dict[key].append(item)
+ else:
+ dict[key] = [item]
+
+
+# Tabulate results neatly
+#
+def printresults(table):
+ modules = table.keys()
+ maxlen = 0
+ for mod in modules: maxlen = max(maxlen, len(mod))
+ modules.sort()
+ for mod in modules:
+ list = table[mod]
+ list.sort()
+ print string.ljust(mod, maxlen), ':',
+ if mod in list:
+ print '(*)',
+ for ref in list:
+ print ref,
+ print
+
+
+# Call main and honor exit status
+try:
+ sys.exit(main())
+except KeyboardInterrupt:
+ sys.exit(1)
diff --git a/Tools/scripts/ptags.py b/Tools/scripts/ptags.py
new file mode 100755
index 0000000..b3a693e
--- /dev/null
+++ b/Tools/scripts/ptags.py
@@ -0,0 +1,49 @@
+#! /usr/local/python
+
+# ptags
+#
+# Create a tags file for Python programs, usable with vi.
+# Tagged are:
+# - functions (even inside other defs or classes)
+# - classes
+# - filenames
+# Warns about files it cannot open.
+# No warnings about duplicate tags.
+
+import sys
+import regexp
+import path
+
+tags = [] # Modified global variable!
+
+def main():
+ args = sys.argv[1:]
+ for file in args: treat_file(file)
+ if tags:
+ fp = open('tags', 'w')
+ tags.sort()
+ for s in tags: fp.write(s)
+
+matcher = regexp.compile('^[ \t]*(def|class)[ \t]+([a-zA-Z0-9_]+)[ \t]*\(')
+
+def treat_file(file):
+ try:
+ fp = open(file, 'r')
+ except:
+ print 'Cannot open', file
+ return
+ base = path.basename(file)
+ if base[-3:] = '.py': base = base[:-3]
+ s = base + '\t' + file + '\t' + '1\n'
+ tags.append(s)
+ while 1:
+ line = fp.readline()
+ if not line: break
+ res = matcher.exec(line)
+ if res:
+ (a, b), (a1, b1), (a2, b2) = res
+ name = line[a2:b2]
+ s = name + '\t' + file + '\t/^' + line[a:b] + '/\n'
+ tags.append(s)
+
+main()
diff --git a/Tools/scripts/suff.py b/Tools/scripts/suff.py
new file mode 100755
index 0000000..7fda113
--- /dev/null
+++ b/Tools/scripts/suff.py
@@ -0,0 +1,29 @@
+#! /usr/local/python
+
+# suff
+#
+# show different suffixes amongst arguments
+
+import sys
+
+def main():
+ files = sys.argv[1:]
+ suffixes = {}
+ for file in files:
+ suff = getsuffix(file)
+ if not suffixes.has_key(suff):
+ suffixes[suff] = []
+ suffixes[suff].append(file)
+ keys = suffixes.keys()
+ keys.sort()
+ for suff in keys:
+ print `suff`, len(suffixes[suff])
+
+def getsuffix(file):
+ suff = ''
+ for i in range(len(file)):
+ if file[i] = '.':
+ suff = file[i:]
+ return suff
+
+main()
diff --git a/Tools/scripts/which.py b/Tools/scripts/which.py
new file mode 100755
index 0000000..b9b888b
--- /dev/null
+++ b/Tools/scripts/which.py
@@ -0,0 +1,44 @@
+#! /usr/local/python
+
+# Variant of "which".
+# On stderr, near and total misses are reported.
+
+import sys, posix, string, path
+from stat import *
+
+def msg(str):
+ sys.stderr.write(str + '\n')
+
+pathlist = string.splitfields(posix.environ['PATH'], ':')
+
+sts = 0
+
+for prog in sys.argv[1:]:
+ ident = ()
+ for dir in pathlist:
+ file = path.cat(dir, prog)
+ try:
+ st = posix.stat(file)
+ if S_ISREG(st[ST_MODE]):
+ mode = S_IMODE(st[ST_MODE])
+ if mode % 2 or mode/8 % 2 or mode/64 % 2:
+ if ident:
+ if st[:3] = ident:
+ s = ': same as '
+ else:
+ s = ': also '
+ msg(prog + s + file)
+ else:
+ print file
+ ident = st[:3]
+ else:
+ msg(file + ': not executable')
+ else:
+ msg(file + ': not a disk file')
+ except posix.error:
+ pass
+ if not ident:
+ msg(prog + ': not found')
+ sts = 1
+
+sys.exit(sts)
diff --git a/Tools/scripts/xxci.py b/Tools/scripts/xxci.py
new file mode 100755
index 0000000..e747c8d
--- /dev/null
+++ b/Tools/scripts/xxci.py
@@ -0,0 +1,77 @@
+#! /usr/local/python
+
+# xxci
+#
+# check in files for which rcsdiff returns nonzero exit status
+
+import sys
+import posix
+import stat
+import path
+import commands
+
+MAXSIZE = 200*1024 # Files this big must be binaries and are skipped.
+
+def getargs():
+ args = sys.argv[1:]
+ if args:
+ return args
+ print 'No arguments, checking almost *'
+ for file in posix.listdir('.'):
+ if not skipfile(file):
+ args.append(file)
+ if not args:
+ print 'Nothing to do -- exit 1'
+ sys.exit(1)
+ args.sort()
+ return args
+
+badnames = ['tags', 'xyzzy']
+badprefixes = ['.', ',', '@', '#', 'o.']
+badsuffixes = \
+ ['~', '.a', '.o', '.old', '.bak', '.orig', '.new', '.prev', '.not']
+# XXX Should generalize even more to use fnmatch!
+
+def skipfile(file):
+ if file in badnames or \
+ badprefix(file) or badsuffix(file) or \
+ path.islink(file) or path.isdir(file):
+ return 1
+ # Skip huge files -- probably binaries.
+ try:
+ st = posix.stat(file)
+ except posix.error:
+ return 1 # Doesn't exist -- skip it
+ return st[stat.ST_SIZE] >= MAXSIZE
+
+def badprefix(file):
+ for bad in badprefixes:
+ if file[:len(bad)] = bad: return 1
+ return 0
+
+def badsuffix(file):
+ for bad in badsuffixes:
+ if file[-len(bad):] = bad: return 1
+ return 0
+
+def go(args):
+ for file in args:
+ print file + ':'
+ if run('rcsdiff -c', file):
+ if askyesno('Check in ' + file + ' ? '):
+ sts = run('rcs -l', file) # ignored
+ # can't use run() here because it's interactive
+ sts = posix.system('ci -l ' + file)
+
+def run(cmd, file):
+ sts, output = commands.getstatusoutput(cmd + commands.mkarg(file))
+ if sts:
+ print output
+ print 'Exit status', sts
+ return sts
+
+def askyesno(prompt):
+ s = raw_input(prompt)
+ return s in ['y', 'yes']
+
+go(getargs())