home *** CD-ROM | disk | FTP | other *** search
/ Chip 2006 June / CHIP 2006-06.2.iso / program / freeware / Democracy-0.8.2.exe / xulrunner / python / util.py < prev    next >
Encoding:
Text File  |  2006-04-10  |  7.3 KB  |  204 lines

  1. import re
  2. import subprocess
  3. import string
  4. import os
  5. import urllib
  6. import threading
  7. import traceback
  8. import time
  9. import sys
  10.  
  11. # Perform escapes needed for Javascript string contents.
  12. def quoteJS(x):
  13.     x = x.replace("\\", "\\\\") # \       -> \\
  14.     x = x.replace("\"", "\\\"") # "       -> \"  
  15.     x = x.replace("'",  "\\'")  # '       -> \'
  16.     x = x.replace("\n", "\\n")  # newline -> \n
  17.     x = x.replace("\r", "\\r")  # CR      -> \r
  18.     return x
  19.  
  20. # Parse a configuration file in a very simple format. Each line is
  21. # either whitespace or "Key = Value". Whitespace is ignored at the
  22. # beginning of Value, but the remainder of the line is taken
  23. # literally, including any whitespace. There is no way to put a
  24. # newline in a value. Returns the result as a dict.
  25. def readSimpleConfigFile(path):
  26.     ret = {}
  27.  
  28.     f = open(path, "rt")
  29.     for line in f.readlines():
  30.         # Skip blank lines
  31.         if re.match("^[ \t]*$", line):
  32.             continue
  33.  
  34.         # Otherwise it'd better be a configuration setting
  35.         match = re.match(r"^([^ ]+) *= *([^\r\n]*)[\r\n]*$", line)
  36.         if not match:
  37.             print "WARNING: %s: ignored bad configuration directive '%s'" % \
  38.                 (path, line)
  39.             continue
  40.         
  41.         key = match.group(1)
  42.         value = match.group(2)
  43.         if key in ret:
  44.             print "WARNING: %s: ignored duplicate directive '%s'" % \
  45.                 (path, line)
  46.             continue
  47.  
  48.         ret[key] = value
  49.  
  50.     return ret
  51.  
  52. # Given a dict, write a configuration file in the format that
  53. # readSimpleConfigFile reads.
  54. def writeSimpleConfigFile(path, data):
  55.     f = open(path, "wt")
  56.  
  57.     for (k, v) in data.iteritems():
  58.         f.write("%s = %s\n" % (k, v))
  59.     
  60.     f.close()
  61.  
  62. # Called at build-time to ask Subversion for the revision number of
  63. # this checkout. Going to fail without Cygwin. Yeah, oh well. Pass the
  64. # file or directory you want to use as a reference point. Returns an
  65. # integer on success or None on failure.
  66. def queryRevision(file):
  67.     try:
  68.         p1 = subprocess.Popen(["svn", "info", file], stdout=subprocess.PIPE) 
  69.         p2 = subprocess.Popen(["grep", "Revision:"], \
  70.                               stdin=p1.stdout, stdout=subprocess.PIPE) 
  71.         output = re.search('Revision: (.*)', p2.communicate()[0])
  72.         if not output:
  73.             return None
  74.         else:
  75.             return int(output.group(1))
  76.     except:
  77.         # whatever
  78.         return None
  79.  
  80. # 'path' is a path that could be passed to open() to open a file on
  81. # this platform. It must be an absolute path. Return the file:// URL
  82. # that would refer to the same file.
  83. def absolutePathToFileURL(path):
  84.     parts = string.split(path, os.sep)
  85.     parts = [urllib.quote(x, ':') for x in parts]
  86.     if len(parts) > 0 and parts[0] == '':
  87.         # Don't let "/foo/bar" become "file:////foo/bar", but leave
  88.         # "c:/foo/bar" becoming "file://c:/foo/bar" -- technically :
  89.         # should become | (but only in a drive name?) but most
  90.         # consumers will let us get by with that.
  91.         parts = parts[1:]
  92.     return "file:///" + '/'.join(parts)
  93.  
  94.  
  95. # Shortcut for 'failed' with the exception flag.
  96. def failedExn(when, **kwargs):
  97.     failed(when, withExn = True, **kwargs)
  98.  
  99. # Puts up a dialog with debugging information encouraging the user to
  100. # file a ticket. (Also print a call trace to stderr or whatever, which
  101. # hopefully will end up on the console or in a log.) 'when' should be
  102. # something like "when trying to play a video." The user will see
  103. # it. If 'withExn' is true, last-exception information will be printed
  104. # to. If 'detail' is true, it will be included in the report and the
  105. # the console/log, but not presented in the dialog box flavor text.
  106. def failed(when, withExn = False, details = None):
  107.     print "failed() called; generating crash report."
  108.  
  109.     header = ""
  110.     try:
  111.         import config # probably works at runtime only
  112.         header += "App:        %s\n" % config.get(config.LONG_APP_NAME)
  113.         header += "Publisher:  %s\n" % config.get(config.PUBLISHER)
  114.         header += "Platform:   %s\n" % config.get(config.APP_PLATFORM)
  115.         header += "Version:    %s\n" % config.get(config.APP_VERSION)
  116.         header += "Serial:     %s\n" % config.get(config.APP_SERIAL)
  117.         header += "Revision:   %s\n" % config.get(config.APP_REVISION)
  118.     except:
  119.         pass
  120.     header += "Time:       %s\n" % time.asctime()
  121.     header += "When:       %s\n" % when
  122.     header += "\n"
  123.  
  124.     if withExn:
  125.         header += "Exception\n---------\n"
  126.         if details:
  127.             header += "Details: %s" % (details, )
  128.         header += traceback.format_exc()
  129.         header += "\n"
  130.     else:
  131.         header += "Call stack\n----------\n"
  132.         if details:
  133.             header += "Details: %s" % (details, )
  134.         header += ''.join(traceback.format_stack())
  135.         header += "\n"
  136.  
  137.     header += "Threads\n-------\n"
  138.     header += "Current: %s\n" % threading.currentThread().getName()
  139.     header += "Active:\n"
  140.     for t in threading.enumerate():
  141.         header += " - %s%s\n" % \
  142.             (t.getName(),
  143.              t.isDaemon() and ' [Daemon]' or '')
  144.  
  145.     # Combine the header with the logfile contents, if available, to
  146.     # make the dialog box crash message. {{{ and }}} are Trac
  147.     # Wiki-formatting markers that force a fixed-width font when the
  148.     # report is pasted into a ticket.
  149.     report = "{{{\n%s}}}\n" % header
  150.  
  151.     def readLog(logFile, logName="Log"):
  152.         try:
  153.             f = open(logFile, "rt")
  154.             logContents = "%s\n---\n" % logName
  155.             logContents += f.read()
  156.             f.close()
  157.         except:
  158.             logContents = "Couldn't read logfile '%s':\n" % (logFile, )
  159.             logContents += traceback.format_exc()
  160.         return logContents
  161.  
  162.     logFile = config.get(config.LOG_PATHNAME)
  163.     downloaderLogFile = config.get(config.DOWNLOADER_LOG_PATHNAME)
  164.     if logFile is None:
  165.         logContents = "No logfile available on this platform.\n"
  166.     else:
  167.         logContents = readLog(logFile)
  168.     if downloaderLogFile is not None:
  169.         logContents += "\n" + readLog(downloaderLogFile, "Downloader Log")
  170.  
  171.     report += "{{{\n%s}}}\n" % logContents
  172.  
  173.     # Dump the header for the report we just generated to the log, in
  174.     # case there are multiple failures or the user sends in the log
  175.     # instead of the report from the dialog box. (Note that we don't
  176.     # do this until we've already read the log into the dialog
  177.     # message.)
  178.     print "----- CRASH REPORT (DANGER CAN HAPPEN) -----"
  179.     print header
  180.     print "----- END OF CRASH REPORT -----"
  181.  
  182.     try:
  183.         import app
  184.         app.Controller.instance.getBackendDelegate(). \
  185.             notifyUnkownErrorOccurence(when, log = report)
  186.     except:
  187.         pass
  188.  
  189.  
  190. class AutoflushingStream:
  191.     """Converts a stream to an auto-flushing one.  It behaves in exactly the
  192.     same way, except all write() calls are automatically followed by a
  193.     flush().
  194.     """
  195.     def __init__(self, stream):
  196.         self.__dict__['stream'] = stream
  197.     def write(self, *args):
  198.         self.stream.write(*args)
  199.         self.stream.flush()
  200.     def __getattr__(self, name):
  201.         return self.stream.__getattr__(name)
  202.     def __setattr__(self, name, value):
  203.         return self.stream.__setattr__(name, value)
  204.