These files are a subset of the python-2.7.2.tgz distribution from python.org. Changed files from PyMod-2.7.2 have been copied into the corresponding directories of this tree, replacing the original files in the distribution. Signed-off-by: daryl.mcdaniel@intel.com git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13197 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			842 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			842 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """Generic FAQ Wizard.
 | |
| 
 | |
| This is a CGI program that maintains a user-editable FAQ.  It uses RCS
 | |
| to keep track of changes to individual FAQ entries.  It is fully
 | |
| configurable; everything you might want to change when using this
 | |
| program to maintain some other FAQ than the Python FAQ is contained in
 | |
| the configuration module, faqconf.py.
 | |
| 
 | |
| Note that this is not an executable script; it's an importable module.
 | |
| The actual script to place in cgi-bin is faqw.py.
 | |
| 
 | |
| """
 | |
| 
 | |
| import sys, time, os, stat, re, cgi, faqconf
 | |
| from faqconf import *                   # This imports all uppercase names
 | |
| now = time.time()
 | |
| 
 | |
| class FileError:
 | |
|     def __init__(self, file):
 | |
|         self.file = file
 | |
| 
 | |
| class InvalidFile(FileError):
 | |
|     pass
 | |
| 
 | |
| class NoSuchSection(FileError):
 | |
|     def __init__(self, section):
 | |
|         FileError.__init__(self, NEWFILENAME %(section, 1))
 | |
|         self.section = section
 | |
| 
 | |
| class NoSuchFile(FileError):
 | |
|     def __init__(self, file, why=None):
 | |
|         FileError.__init__(self, file)
 | |
|         self.why = why
 | |
| 
 | |
| def escape(s):
 | |
|     s = s.replace('&', '&')
 | |
|     s = s.replace('<', '<')
 | |
|     s = s.replace('>', '>')
 | |
|     return s
 | |
| 
 | |
| def escapeq(s):
 | |
|     s = escape(s)
 | |
|     s = s.replace('"', '"')
 | |
|     return s
 | |
| 
 | |
| def _interpolate(format, args, kw):
 | |
|     try:
 | |
|         quote = kw['_quote']
 | |
|     except KeyError:
 | |
|         quote = 1
 | |
|     d = (kw,) + args + (faqconf.__dict__,)
 | |
|     m = MagicDict(d, quote)
 | |
|     return format % m
 | |
| 
 | |
| def interpolate(format, *args, **kw):
 | |
|     return _interpolate(format, args, kw)
 | |
| 
 | |
| def emit(format, *args, **kw):
 | |
|     try:
 | |
|         f = kw['_file']
 | |
|     except KeyError:
 | |
|         f = sys.stdout
 | |
|     f.write(_interpolate(format, args, kw))
 | |
| 
 | |
| translate_prog = None
 | |
| 
 | |
| def translate(text, pre=0):
 | |
|     global translate_prog
 | |
|     if not translate_prog:
 | |
|         translate_prog = prog = re.compile(
 | |
|             r'\b(http|ftp|https)://\S+(\b|/)|\b[-.\w]+@[-.\w]+')
 | |
|     else:
 | |
|         prog = translate_prog
 | |
|     i = 0
 | |
|     list = []
 | |
|     while 1:
 | |
|         m = prog.search(text, i)
 | |
|         if not m:
 | |
|             break
 | |
|         j = m.start()
 | |
|         list.append(escape(text[i:j]))
 | |
|         i = j
 | |
|         url = m.group(0)
 | |
|         while url[-1] in '();:,.?\'"<>':
 | |
|             url = url[:-1]
 | |
|         i = i + len(url)
 | |
|         url = escape(url)
 | |
|         if not pre or (pre and PROCESS_PREFORMAT):
 | |
|             if ':' in url:
 | |
|                 repl = '<A HREF="%s">%s</A>' % (url, url)
 | |
|             else:
 | |
|                 repl = '<A HREF="mailto:%s">%s</A>' % (url, url)
 | |
|         else:
 | |
|             repl = url
 | |
|         list.append(repl)
 | |
|     j = len(text)
 | |
|     list.append(escape(text[i:j]))
 | |
|     return ''.join(list)
 | |
| 
 | |
| def emphasize(line):
 | |
|     return re.sub(r'\*([a-zA-Z]+)\*', r'<I>\1</I>', line)
 | |
| 
 | |
| revparse_prog = None
 | |
| 
 | |
| def revparse(rev):
 | |
|     global revparse_prog
 | |
|     if not revparse_prog:
 | |
|         revparse_prog = re.compile(r'^(\d{1,3})\.(\d{1,4})$')
 | |
|     m = revparse_prog.match(rev)
 | |
|     if not m:
 | |
|         return None
 | |
|     [major, minor] = map(int, m.group(1, 2))
 | |
|     return major, minor
 | |
| 
 | |
| logon = 0
 | |
| def log(text):
 | |
|     if logon:
 | |
|         logfile = open("logfile", "a")
 | |
|         logfile.write(text + "\n")
 | |
|         logfile.close()
 | |
| 
 | |
| def load_cookies():
 | |
|     if not os.environ.has_key('HTTP_COOKIE'):
 | |
|         return {}
 | |
|     raw = os.environ['HTTP_COOKIE']
 | |
|     words = [s.strip() for s in raw.split(';')]
 | |
|     cookies = {}
 | |
|     for word in words:
 | |
|         i = word.find('=')
 | |
|         if i >= 0:
 | |
|             key, value = word[:i], word[i+1:]
 | |
|             cookies[key] = value
 | |
|     return cookies
 | |
| 
 | |
| def load_my_cookie():
 | |
|     cookies = load_cookies()
 | |
|     try:
 | |
|         value = cookies[COOKIE_NAME]
 | |
|     except KeyError:
 | |
|         return {}
 | |
|     import urllib
 | |
|     value = urllib.unquote(value)
 | |
|     words = value.split('/')
 | |
|     while len(words) < 3:
 | |
|         words.append('')
 | |
|     author = '/'.join(words[:-2])
 | |
|     email = words[-2]
 | |
|     password = words[-1]
 | |
|     return {'author': author,
 | |
|             'email': email,
 | |
|             'password': password}
 | |
| 
 | |
| def send_my_cookie(ui):
 | |
|     name = COOKIE_NAME
 | |
|     value = "%s/%s/%s" % (ui.author, ui.email, ui.password)
 | |
|     import urllib
 | |
|     value = urllib.quote(value)
 | |
|     then = now + COOKIE_LIFETIME
 | |
|     gmt = time.gmtime(then)
 | |
|     path = os.environ.get('SCRIPT_NAME', '/cgi-bin/')
 | |
|     print "Set-Cookie: %s=%s; path=%s;" % (name, value, path),
 | |
|     print time.strftime("expires=%a, %d-%b-%y %X GMT", gmt)
 | |
| 
 | |
| class MagicDict:
 | |
| 
 | |
|     def __init__(self, d, quote):
 | |
|         self.__d = d
 | |
|         self.__quote = quote
 | |
| 
 | |
|     def __getitem__(self, key):
 | |
|         for d in self.__d:
 | |
|             try:
 | |
|                 value = d[key]
 | |
|                 if value:
 | |
|                     value = str(value)
 | |
|                     if self.__quote:
 | |
|                         value = escapeq(value)
 | |
|                     return value
 | |
|             except KeyError:
 | |
|                 pass
 | |
|         return ''
 | |
| 
 | |
| class UserInput:
 | |
| 
 | |
|     def __init__(self):
 | |
|         self.__form = cgi.FieldStorage()
 | |
|         #log("\n\nbody: " + self.body)
 | |
| 
 | |
|     def __getattr__(self, name):
 | |
|         if name[0] == '_':
 | |
|             raise AttributeError
 | |
|         try:
 | |
|             value = self.__form[name].value
 | |
|         except (TypeError, KeyError):
 | |
|             value = ''
 | |
|         else:
 | |
|             value = value.strip()
 | |
|         setattr(self, name, value)
 | |
|         return value
 | |
| 
 | |
|     def __getitem__(self, key):
 | |
|         return getattr(self, key)
 | |
| 
 | |
| class FaqEntry:
 | |
| 
 | |
|     def __init__(self, fp, file, sec_num):
 | |
|         self.file = file
 | |
|         self.sec, self.num = sec_num
 | |
|         if fp:
 | |
|             import rfc822
 | |
|             self.__headers = rfc822.Message(fp)
 | |
|             self.body = fp.read().strip()
 | |
|         else:
 | |
|             self.__headers = {'title': "%d.%d. " % sec_num}
 | |
|             self.body = ''
 | |
| 
 | |
|     def __getattr__(self, name):
 | |
|         if name[0] == '_':
 | |
|             raise AttributeError
 | |
|         key = '-'.join(name.split('_'))
 | |
|         try:
 | |
|             value = self.__headers[key]
 | |
|         except KeyError:
 | |
|             value = ''
 | |
|         setattr(self, name, value)
 | |
|         return value
 | |
| 
 | |
|     def __getitem__(self, key):
 | |
|         return getattr(self, key)
 | |
| 
 | |
|     def load_version(self):
 | |
|         command = interpolate(SH_RLOG_H, self)
 | |
|         p = os.popen(command)
 | |
|         version = ''
 | |
|         while 1:
 | |
|             line = p.readline()
 | |
|             if not line:
 | |
|                 break
 | |
|             if line[:5] == 'head:':
 | |
|                 version = line[5:].strip()
 | |
|         p.close()
 | |
|         self.version = version
 | |
| 
 | |
|     def getmtime(self):
 | |
|         if not self.last_changed_date:
 | |
|             return 0
 | |
|         try:
 | |
|             return os.stat(self.file)[stat.ST_MTIME]
 | |
|         except os.error:
 | |
|             return 0
 | |
| 
 | |
|     def emit_marks(self):
 | |
|         mtime = self.getmtime()
 | |
|         if mtime >= now - DT_VERY_RECENT:
 | |
|             emit(MARK_VERY_RECENT, self)
 | |
|         elif mtime >= now - DT_RECENT:
 | |
|             emit(MARK_RECENT, self)
 | |
| 
 | |
|     def show(self, edit=1):
 | |
|         emit(ENTRY_HEADER1, self)
 | |
|         self.emit_marks()
 | |
|         emit(ENTRY_HEADER2, self)
 | |
|         pre = 0
 | |
|         raw = 0
 | |
|         for line in self.body.split('\n'):
 | |
|             # Allow the user to insert raw html into a FAQ answer
 | |
|             # (Skip Montanaro, with changes by Guido)
 | |
|             tag = line.rstrip().lower()
 | |
|             if tag == '<html>':
 | |
|                 raw = 1
 | |
|                 continue
 | |
|             if tag == '</html>':
 | |
|                 raw = 0
 | |
|                 continue
 | |
|             if raw:
 | |
|                 print line
 | |
|                 continue
 | |
|             if not line.strip():
 | |
|                 if pre:
 | |
|                     print '</PRE>'
 | |
|                     pre = 0
 | |
|                 else:
 | |
|                     print '<P>'
 | |
|             else:
 | |
|                 if not line[0].isspace():
 | |
|                     if pre:
 | |
|                         print '</PRE>'
 | |
|                         pre = 0
 | |
|                 else:
 | |
|                     if not pre:
 | |
|                         print '<PRE>'
 | |
|                         pre = 1
 | |
|                 if '/' in line or '@' in line:
 | |
|                     line = translate(line, pre)
 | |
|                 elif '<' in line or '&' in line:
 | |
|                     line = escape(line)
 | |
|                 if not pre and '*' in line:
 | |
|                     line = emphasize(line)
 | |
|                 print line
 | |
|         if pre:
 | |
|             print '</PRE>'
 | |
|             pre = 0
 | |
|         if edit:
 | |
|             print '<P>'
 | |
|             emit(ENTRY_FOOTER, self)
 | |
|             if self.last_changed_date:
 | |
|                 emit(ENTRY_LOGINFO, self)
 | |
|         print '<P>'
 | |
| 
 | |
| class FaqDir:
 | |
| 
 | |
|     entryclass = FaqEntry
 | |
| 
 | |
|     __okprog = re.compile(OKFILENAME)
 | |
| 
 | |
|     def __init__(self, dir=os.curdir):
 | |
|         self.__dir = dir
 | |
|         self.__files = None
 | |
| 
 | |
|     def __fill(self):
 | |
|         if self.__files is not None:
 | |
|             return
 | |
|         self.__files = files = []
 | |
|         okprog = self.__okprog
 | |
|         for file in os.listdir(self.__dir):
 | |
|             if self.__okprog.match(file):
 | |
|                 files.append(file)
 | |
|         files.sort()
 | |
| 
 | |
|     def good(self, file):
 | |
|         return self.__okprog.match(file)
 | |
| 
 | |
|     def parse(self, file):
 | |
|         m = self.good(file)
 | |
|         if not m:
 | |
|             return None
 | |
|         sec, num = m.group(1, 2)
 | |
|         return int(sec), int(num)
 | |
| 
 | |
|     def list(self):
 | |
|         # XXX Caller shouldn't modify result
 | |
|         self.__fill()
 | |
|         return self.__files
 | |
| 
 | |
|     def open(self, file):
 | |
|         sec_num = self.parse(file)
 | |
|         if not sec_num:
 | |
|             raise InvalidFile(file)
 | |
|         try:
 | |
|             fp = open(file)
 | |
|         except IOError, msg:
 | |
|             raise NoSuchFile(file, msg)
 | |
|         try:
 | |
|             return self.entryclass(fp, file, sec_num)
 | |
|         finally:
 | |
|             fp.close()
 | |
| 
 | |
|     def show(self, file, edit=1):
 | |
|         self.open(file).show(edit=edit)
 | |
| 
 | |
|     def new(self, section):
 | |
|         if not SECTION_TITLES.has_key(section):
 | |
|             raise NoSuchSection(section)
 | |
|         maxnum = 0
 | |
|         for file in self.list():
 | |
|             sec, num = self.parse(file)
 | |
|             if sec == section:
 | |
|                 maxnum = max(maxnum, num)
 | |
|         sec_num = (section, maxnum+1)
 | |
|         file = NEWFILENAME % sec_num
 | |
|         return self.entryclass(None, file, sec_num)
 | |
| 
 | |
| class FaqWizard:
 | |
| 
 | |
|     def __init__(self):
 | |
|         self.ui = UserInput()
 | |
|         self.dir = FaqDir()
 | |
| 
 | |
|     def go(self):
 | |
|         print 'Content-type: text/html'
 | |
|         req = self.ui.req or 'home'
 | |
|         mname = 'do_%s' % req
 | |
|         try:
 | |
|             meth = getattr(self, mname)
 | |
|         except AttributeError:
 | |
|             self.error("Bad request type %r." % (req,))
 | |
|         else:
 | |
|             try:
 | |
|                 meth()
 | |
|             except InvalidFile, exc:
 | |
|                 self.error("Invalid entry file name %s" % exc.file)
 | |
|             except NoSuchFile, exc:
 | |
|                 self.error("No entry with file name %s" % exc.file)
 | |
|             except NoSuchSection, exc:
 | |
|                 self.error("No section number %s" % exc.section)
 | |
|         self.epilogue()
 | |
| 
 | |
|     def error(self, message, **kw):
 | |
|         self.prologue(T_ERROR)
 | |
|         emit(message, kw)
 | |
| 
 | |
|     def prologue(self, title, entry=None, **kw):
 | |
|         emit(PROLOGUE, entry, kwdict=kw, title=escape(title))
 | |
| 
 | |
|     def epilogue(self):
 | |
|         emit(EPILOGUE)
 | |
| 
 | |
|     def do_home(self):
 | |
|         self.prologue(T_HOME)
 | |
|         emit(HOME)
 | |
| 
 | |
|     def do_debug(self):
 | |
|         self.prologue("FAQ Wizard Debugging")
 | |
|         form = cgi.FieldStorage()
 | |
|         cgi.print_form(form)
 | |
|         cgi.print_environ(os.environ)
 | |
|         cgi.print_directory()
 | |
|         cgi.print_arguments()
 | |
| 
 | |
|     def do_search(self):
 | |
|         query = self.ui.query
 | |
|         if not query:
 | |
|             self.error("Empty query string!")
 | |
|             return
 | |
|         if self.ui.querytype == 'simple':
 | |
|             query = re.escape(query)
 | |
|             queries = [query]
 | |
|         elif self.ui.querytype in ('anykeywords', 'allkeywords'):
 | |
|             words = filter(None, re.split('\W+', query))
 | |
|             if not words:
 | |
|                 self.error("No keywords specified!")
 | |
|                 return
 | |
|             words = map(lambda w: r'\b%s\b' % w, words)
 | |
|             if self.ui.querytype[:3] == 'any':
 | |
|                 queries = ['|'.join(words)]
 | |
|             else:
 | |
|                 # Each of the individual queries must match
 | |
|                 queries = words
 | |
|         else:
 | |
|             # Default to regular expression
 | |
|             queries = [query]
 | |
|         self.prologue(T_SEARCH)
 | |
|         progs = []
 | |
|         for query in queries:
 | |
|             if self.ui.casefold == 'no':
 | |
|                 p = re.compile(query)
 | |
|             else:
 | |
|                 p = re.compile(query, re.IGNORECASE)
 | |
|             progs.append(p)
 | |
|         hits = []
 | |
|         for file in self.dir.list():
 | |
|             try:
 | |
|                 entry = self.dir.open(file)
 | |
|             except FileError:
 | |
|                 constants
 | |
|             for p in progs:
 | |
|                 if not p.search(entry.title) and not p.search(entry.body):
 | |
|                     break
 | |
|             else:
 | |
|                 hits.append(file)
 | |
|         if not hits:
 | |
|             emit(NO_HITS, self.ui, count=0)
 | |
|         elif len(hits) <= MAXHITS:
 | |
|             if len(hits) == 1:
 | |
|                 emit(ONE_HIT, count=1)
 | |
|             else:
 | |
|                 emit(FEW_HITS, count=len(hits))
 | |
|             self.format_all(hits, headers=0)
 | |
|         else:
 | |
|             emit(MANY_HITS, count=len(hits))
 | |
|             self.format_index(hits)
 | |
| 
 | |
|     def do_all(self):
 | |
|         self.prologue(T_ALL)
 | |
|         files = self.dir.list()
 | |
|         self.last_changed(files)
 | |
|         self.format_index(files, localrefs=1)
 | |
|         self.format_all(files)
 | |
| 
 | |
|     def do_compat(self):
 | |
|         files = self.dir.list()
 | |
|         emit(COMPAT)
 | |
|         self.last_changed(files)
 | |
|         self.format_index(files, localrefs=1)
 | |
|         self.format_all(files, edit=0)
 | |
|         sys.exit(0)                     # XXX Hack to suppress epilogue
 | |
| 
 | |
|     def last_changed(self, files):
 | |
|         latest = 0
 | |
|         for file in files:
 | |
|             entry = self.dir.open(file)
 | |
|             if entry:
 | |
|                 mtime = mtime = entry.getmtime()
 | |
|                 if mtime > latest:
 | |
|                     latest = mtime
 | |
|         print time.strftime(LAST_CHANGED, time.localtime(latest))
 | |
|         emit(EXPLAIN_MARKS)
 | |
| 
 | |
|     def format_all(self, files, edit=1, headers=1):
 | |
|         sec = 0
 | |
|         for file in files:
 | |
|             try:
 | |
|                 entry = self.dir.open(file)
 | |
|             except NoSuchFile:
 | |
|                 continue
 | |
|             if headers and entry.sec != sec:
 | |
|                 sec = entry.sec
 | |
|                 try:
 | |
|                     title = SECTION_TITLES[sec]
 | |
|                 except KeyError:
 | |
|                     title = "Untitled"
 | |
|                 emit("\n<HR>\n<H1>%(sec)s. %(title)s</H1>\n",
 | |
|                      sec=sec, title=title)
 | |
|             entry.show(edit=edit)
 | |
| 
 | |
|     def do_index(self):
 | |
|         self.prologue(T_INDEX)
 | |
|         files = self.dir.list()
 | |
|         self.last_changed(files)
 | |
|         self.format_index(files, add=1)
 | |
| 
 | |
|     def format_index(self, files, add=0, localrefs=0):
 | |
|         sec = 0
 | |
|         for file in files:
 | |
|             try:
 | |
|                 entry = self.dir.open(file)
 | |
|             except NoSuchFile:
 | |
|                 continue
 | |
|             if entry.sec != sec:
 | |
|                 if sec:
 | |
|                     if add:
 | |
|                         emit(INDEX_ADDSECTION, sec=sec)
 | |
|                     emit(INDEX_ENDSECTION, sec=sec)
 | |
|                 sec = entry.sec
 | |
|                 try:
 | |
|                     title = SECTION_TITLES[sec]
 | |
|                 except KeyError:
 | |
|                     title = "Untitled"
 | |
|                 emit(INDEX_SECTION, sec=sec, title=title)
 | |
|             if localrefs:
 | |
|                 emit(LOCAL_ENTRY, entry)
 | |
|             else:
 | |
|                 emit(INDEX_ENTRY, entry)
 | |
|             entry.emit_marks()
 | |
|         if sec:
 | |
|             if add:
 | |
|                 emit(INDEX_ADDSECTION, sec=sec)
 | |
|             emit(INDEX_ENDSECTION, sec=sec)
 | |
| 
 | |
|     def do_recent(self):
 | |
|         if not self.ui.days:
 | |
|             days = 1
 | |
|         else:
 | |
|             days = float(self.ui.days)
 | |
|         try:
 | |
|             cutoff = now - days * 24 * 3600
 | |
|         except OverflowError:
 | |
|             cutoff = 0
 | |
|         list = []
 | |
|         for file in self.dir.list():
 | |
|             entry = self.dir.open(file)
 | |
|             if not entry:
 | |
|                 continue
 | |
|             mtime = entry.getmtime()
 | |
|             if mtime >= cutoff:
 | |
|                 list.append((mtime, file))
 | |
|         list.sort()
 | |
|         list.reverse()
 | |
|         self.prologue(T_RECENT)
 | |
|         if days <= 1:
 | |
|             period = "%.2g hours" % (days*24)
 | |
|         else:
 | |
|             period = "%.6g days" % days
 | |
|         if not list:
 | |
|             emit(NO_RECENT, period=period)
 | |
|         elif len(list) == 1:
 | |
|             emit(ONE_RECENT, period=period)
 | |
|         else:
 | |
|             emit(SOME_RECENT, period=period, count=len(list))
 | |
|         self.format_all(map(lambda (mtime, file): file, list), headers=0)
 | |
|         emit(TAIL_RECENT)
 | |
| 
 | |
|     def do_roulette(self):
 | |
|         import random
 | |
|         files = self.dir.list()
 | |
|         if not files:
 | |
|             self.error("No entries.")
 | |
|             return
 | |
|         file = random.choice(files)
 | |
|         self.prologue(T_ROULETTE)
 | |
|         emit(ROULETTE)
 | |
|         self.dir.show(file)
 | |
| 
 | |
|     def do_help(self):
 | |
|         self.prologue(T_HELP)
 | |
|         emit(HELP)
 | |
| 
 | |
|     def do_show(self):
 | |
|         entry = self.dir.open(self.ui.file)
 | |
|         self.prologue(T_SHOW)
 | |
|         entry.show()
 | |
| 
 | |
|     def do_add(self):
 | |
|         self.prologue(T_ADD)
 | |
|         emit(ADD_HEAD)
 | |
|         sections = SECTION_TITLES.items()
 | |
|         sections.sort()
 | |
|         for section, title in sections:
 | |
|             emit(ADD_SECTION, section=section, title=title)
 | |
|         emit(ADD_TAIL)
 | |
| 
 | |
|     def do_delete(self):
 | |
|         self.prologue(T_DELETE)
 | |
|         emit(DELETE)
 | |
| 
 | |
|     def do_log(self):
 | |
|         entry = self.dir.open(self.ui.file)
 | |
|         self.prologue(T_LOG, entry)
 | |
|         emit(LOG, entry)
 | |
|         self.rlog(interpolate(SH_RLOG, entry), entry)
 | |
| 
 | |
|     def rlog(self, command, entry=None):
 | |
|         output = os.popen(command).read()
 | |
|         sys.stdout.write('<PRE>')
 | |
|         athead = 0
 | |
|         lines = output.split('\n')
 | |
|         while lines and not lines[-1]:
 | |
|             del lines[-1]
 | |
|         if lines:
 | |
|             line = lines[-1]
 | |
|             if line[:1] == '=' and len(line) >= 40 and \
 | |
|                line == line[0]*len(line):
 | |
|                 del lines[-1]
 | |
|         headrev = None
 | |
|         for line in lines:
 | |
|             if entry and athead and line[:9] == 'revision ':
 | |
|                 rev = line[9:].split()
 | |
|                 mami = revparse(rev)
 | |
|                 if not mami:
 | |
|                     print line
 | |
|                 else:
 | |
|                     emit(REVISIONLINK, entry, rev=rev, line=line)
 | |
|                     if mami[1] > 1:
 | |
|                         prev = "%d.%d" % (mami[0], mami[1]-1)
 | |
|                         emit(DIFFLINK, entry, prev=prev, rev=rev)
 | |
|                     if headrev:
 | |
|                         emit(DIFFLINK, entry, prev=rev, rev=headrev)
 | |
|                     else:
 | |
|                         headrev = rev
 | |
|                     print
 | |
|                 athead = 0
 | |
|             else:
 | |
|                 athead = 0
 | |
|                 if line[:1] == '-' and len(line) >= 20 and \
 | |
|                    line == len(line) * line[0]:
 | |
|                     athead = 1
 | |
|                     sys.stdout.write('<HR>')
 | |
|                 else:
 | |
|                     print line
 | |
|         print '</PRE>'
 | |
| 
 | |
|     def do_revision(self):
 | |
|         entry = self.dir.open(self.ui.file)
 | |
|         rev = self.ui.rev
 | |
|         mami = revparse(rev)
 | |
|         if not mami:
 | |
|             self.error("Invalid revision number: %r." % (rev,))
 | |
|         self.prologue(T_REVISION, entry)
 | |
|         self.shell(interpolate(SH_REVISION, entry, rev=rev))
 | |
| 
 | |
|     def do_diff(self):
 | |
|         entry = self.dir.open(self.ui.file)
 | |
|         prev = self.ui.prev
 | |
|         rev = self.ui.rev
 | |
|         mami = revparse(rev)
 | |
|         if not mami:
 | |
|             self.error("Invalid revision number: %r." % (rev,))
 | |
|         if prev:
 | |
|             if not revparse(prev):
 | |
|                 self.error("Invalid previous revision number: %r." % (prev,))
 | |
|         else:
 | |
|             prev = '%d.%d' % (mami[0], mami[1])
 | |
|         self.prologue(T_DIFF, entry)
 | |
|         self.shell(interpolate(SH_RDIFF, entry, rev=rev, prev=prev))
 | |
| 
 | |
|     def shell(self, command):
 | |
|         output = os.popen(command).read()
 | |
|         sys.stdout.write('<PRE>')
 | |
|         print escape(output)
 | |
|         print '</PRE>'
 | |
| 
 | |
|     def do_new(self):
 | |
|         entry = self.dir.new(section=int(self.ui.section))
 | |
|         entry.version = '*new*'
 | |
|         self.prologue(T_EDIT)
 | |
|         emit(EDITHEAD)
 | |
|         emit(EDITFORM1, entry, editversion=entry.version)
 | |
|         emit(EDITFORM2, entry, load_my_cookie())
 | |
|         emit(EDITFORM3)
 | |
|         entry.show(edit=0)
 | |
| 
 | |
|     def do_edit(self):
 | |
|         entry = self.dir.open(self.ui.file)
 | |
|         entry.load_version()
 | |
|         self.prologue(T_EDIT)
 | |
|         emit(EDITHEAD)
 | |
|         emit(EDITFORM1, entry, editversion=entry.version)
 | |
|         emit(EDITFORM2, entry, load_my_cookie())
 | |
|         emit(EDITFORM3)
 | |
|         entry.show(edit=0)
 | |
| 
 | |
|     def do_review(self):
 | |
|         send_my_cookie(self.ui)
 | |
|         if self.ui.editversion == '*new*':
 | |
|             sec, num = self.dir.parse(self.ui.file)
 | |
|             entry = self.dir.new(section=sec)
 | |
|             entry.version = "*new*"
 | |
|             if entry.file != self.ui.file:
 | |
|                 self.error("Commit version conflict!")
 | |
|                 emit(NEWCONFLICT, self.ui, sec=sec, num=num)
 | |
|                 return
 | |
|         else:
 | |
|             entry = self.dir.open(self.ui.file)
 | |
|             entry.load_version()
 | |
|         # Check that the FAQ entry number didn't change
 | |
|         if self.ui.title.split()[:1] != entry.title.split()[:1]:
 | |
|             self.error("Don't change the entry number please!")
 | |
|             return
 | |
|         # Check that the edited version is the current version
 | |
|         if entry.version != self.ui.editversion:
 | |
|             self.error("Commit version conflict!")
 | |
|             emit(VERSIONCONFLICT, entry, self.ui)
 | |
|             return
 | |
|         commit_ok = ((not PASSWORD
 | |
|                       or self.ui.password == PASSWORD)
 | |
|                      and self.ui.author
 | |
|                      and '@' in self.ui.email
 | |
|                      and self.ui.log)
 | |
|         if self.ui.commit:
 | |
|             if not commit_ok:
 | |
|                 self.cantcommit()
 | |
|             else:
 | |
|                 self.commit(entry)
 | |
|             return
 | |
|         self.prologue(T_REVIEW)
 | |
|         emit(REVIEWHEAD)
 | |
|         entry.body = self.ui.body
 | |
|         entry.title = self.ui.title
 | |
|         entry.show(edit=0)
 | |
|         emit(EDITFORM1, self.ui, entry)
 | |
|         if commit_ok:
 | |
|             emit(COMMIT)
 | |
|         else:
 | |
|             emit(NOCOMMIT_HEAD)
 | |
|             self.errordetail()
 | |
|             emit(NOCOMMIT_TAIL)
 | |
|         emit(EDITFORM2, self.ui, entry, load_my_cookie())
 | |
|         emit(EDITFORM3)
 | |
| 
 | |
|     def cantcommit(self):
 | |
|         self.prologue(T_CANTCOMMIT)
 | |
|         print CANTCOMMIT_HEAD
 | |
|         self.errordetail()
 | |
|         print CANTCOMMIT_TAIL
 | |
| 
 | |
|     def errordetail(self):
 | |
|         if PASSWORD and self.ui.password != PASSWORD:
 | |
|             emit(NEED_PASSWD)
 | |
|         if not self.ui.log:
 | |
|             emit(NEED_LOG)
 | |
|         if not self.ui.author:
 | |
|             emit(NEED_AUTHOR)
 | |
|         if not self.ui.email:
 | |
|             emit(NEED_EMAIL)
 | |
| 
 | |
|     def commit(self, entry):
 | |
|         file = entry.file
 | |
|         # Normalize line endings in body
 | |
|         if '\r' in self.ui.body:
 | |
|             self.ui.body = re.sub('\r\n?', '\n', self.ui.body)
 | |
|         # Normalize whitespace in title
 | |
|         self.ui.title = ' '.join(self.ui.title.split())
 | |
|         # Check that there were any changes
 | |
|         if self.ui.body == entry.body and self.ui.title == entry.title:
 | |
|             self.error("You didn't make any changes!")
 | |
|             return
 | |
| 
 | |
|         # need to lock here because otherwise the file exists and is not writable (on NT)
 | |
|         command = interpolate(SH_LOCK, file=file)
 | |
|         p = os.popen(command)
 | |
|         output = p.read()
 | |
| 
 | |
|         try:
 | |
|             os.unlink(file)
 | |
|         except os.error:
 | |
|             pass
 | |
|         try:
 | |
|             f = open(file, 'w')
 | |
|         except IOError, why:
 | |
|             self.error(CANTWRITE, file=file, why=why)
 | |
|             return
 | |
|         date = time.ctime(now)
 | |
|         emit(FILEHEADER, self.ui, os.environ, date=date, _file=f, _quote=0)
 | |
|         f.write('\n')
 | |
|         f.write(self.ui.body)
 | |
|         f.write('\n')
 | |
|         f.close()
 | |
| 
 | |
|         import tempfile
 | |
|         tf = tempfile.NamedTemporaryFile()
 | |
|         emit(LOGHEADER, self.ui, os.environ, date=date, _file=tf)
 | |
|         tf.flush()
 | |
|         tf.seek(0)
 | |
| 
 | |
|         command = interpolate(SH_CHECKIN, file=file, tfn=tf.name)
 | |
|         log("\n\n" + command)
 | |
|         p = os.popen(command)
 | |
|         output = p.read()
 | |
|         sts = p.close()
 | |
|         log("output: " + output)
 | |
|         log("done: " + str(sts))
 | |
|         log("TempFile:\n" + tf.read() + "end")
 | |
| 
 | |
|         if not sts:
 | |
|             self.prologue(T_COMMITTED)
 | |
|             emit(COMMITTED)
 | |
|         else:
 | |
|             self.error(T_COMMITFAILED)
 | |
|             emit(COMMITFAILED, sts=sts)
 | |
|         print '<PRE>%s</PRE>' % escape(output)
 | |
| 
 | |
|         try:
 | |
|             os.unlink(tf.name)
 | |
|         except os.error:
 | |
|             pass
 | |
| 
 | |
|         entry = self.dir.open(file)
 | |
|         entry.show()
 | |
| 
 | |
| wiz = FaqWizard()
 | |
| wiz.go()
 |