summaryrefslogtreecommitdiffstats
path: root/Tools/faqwiz
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/faqwiz')
-rw-r--r--Tools/faqwiz/faqwiz.py1186
1 files changed, 593 insertions, 593 deletions
diff --git a/Tools/faqwiz/faqwiz.py b/Tools/faqwiz/faqwiz.py
index 29712eb..f604fd2 100644
--- a/Tools/faqwiz/faqwiz.py
+++ b/Tools/faqwiz/faqwiz.py
@@ -12,25 +12,25 @@ The actual script to place in cgi-bin is faqw.py.
"""
import sys, string, time, os, stat, re, cgi, faqconf
-from faqconf import * # This imports all uppercase names
+from faqconf import * # This imports all uppercase names
now = time.time()
class FileError:
def __init__(self, file):
- self.file = file
+ self.file = file
class InvalidFile(FileError):
pass
class NoSuchSection(FileError):
def __init__(self, section):
- FileError.__init__(self, NEWFILENAME %(section, 1))
- self.section = 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
+ FileError.__init__(self, file)
+ self.why = why
def escape(s):
s = string.replace(s, '&', '&')
@@ -45,9 +45,9 @@ def escapeq(s):
def _interpolate(format, args, kw):
try:
- quote = kw['_quote']
+ quote = kw['_quote']
except KeyError:
- quote = 1
+ quote = 1
d = (kw,) + args + (faqconf.__dict__,)
m = MagicDict(d, quote)
return format % m
@@ -57,9 +57,9 @@ def interpolate(format, *args, **kw):
def emit(format, *args, **kw):
try:
- f = kw['_file']
+ f = kw['_file']
except KeyError:
- f = sys.stdout
+ f = sys.stdout
f.write(_interpolate(format, args, kw))
translate_prog = None
@@ -67,32 +67,32 @@ 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]+')
+ translate_prog = prog = re.compile(
+ r'\b(http|ftp|https)://\S+(\b|/)|\b[-.\w]+@[-.\w]+')
else:
- prog = translate_prog
+ 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">&lt;%s&gt;</A>' % (url, url)
- else:
- repl = url
- list.append(repl)
+ 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">&lt;%s&gt;</A>' % (url, url)
+ else:
+ repl = url
+ list.append(repl)
j = len(text)
list.append(escape(text[i:j]))
return string.join(list, '')
@@ -105,43 +105,43 @@ revparse_prog = None
def revparse(rev):
global revparse_prog
if not revparse_prog:
- revparse_prog = re.compile(r'^(\d{1,3})\.(\d{1-4})$')
+ revparse_prog = re.compile(r'^(\d{1,3})\.(\d{1-4})$')
m = revparse_prog.match(rev)
if not m:
- return None
+ return None
[major, minor] = map(string.atoi, m.group(1, 2))
return major, minor
def load_cookies():
if not os.environ.has_key('HTTP_COOKIE'):
- return {}
+ return {}
raw = os.environ['HTTP_COOKIE']
words = map(string.strip, string.split(raw, ';'))
cookies = {}
for word in words:
- i = string.find(word, '=')
- if i >= 0:
- key, value = word[:i], word[i+1:]
- cookies[key] = value
+ i = string.find(word, '=')
+ 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]
+ value = cookies[COOKIE_NAME]
except KeyError:
- return {}
+ return {}
import urllib
value = urllib.unquote(value)
words = string.split(value, '/')
while len(words) < 3:
- words.append('')
+ words.append('')
author = string.join(words[:-2], '/')
email = words[-2]
password = words[-1]
return {'author': author,
- 'email': email,
- 'password': password}
+ 'email': email,
+ 'password': password}
def send_my_cookie(ui):
name = COOKIE_NAME
@@ -156,147 +156,147 @@ def send_my_cookie(ui):
class MagicDict:
def __init__(self, d, quote):
- self.__d = d
- self.__quote = 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 ''
+ 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()
+ self.__form = cgi.FieldStorage()
def __getattr__(self, name):
- if name[0] == '_':
- raise AttributeError
- try:
- value = self.__form[name].value
- except (TypeError, KeyError):
- value = ''
- else:
- value = string.strip(value)
- setattr(self, name, value)
- return value
+ if name[0] == '_':
+ raise AttributeError
+ try:
+ value = self.__form[name].value
+ except (TypeError, KeyError):
+ value = ''
+ else:
+ value = string.strip(value)
+ setattr(self, name, value)
+ return value
def __getitem__(self, key):
- return getattr(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 = string.strip(fp.read())
- else:
- self.__headers = {'title': "%d.%d. " % sec_num}
- self.body = ''
+ self.file = file
+ self.sec, self.num = sec_num
+ if fp:
+ import rfc822
+ self.__headers = rfc822.Message(fp)
+ self.body = string.strip(fp.read())
+ else:
+ self.__headers = {'title': "%d.%d. " % sec_num}
+ self.body = ''
def __getattr__(self, name):
- if name[0] == '_':
- raise AttributeError
- key = string.join(string.split(name, '_'), '-')
- try:
- value = self.__headers[key]
- except KeyError:
- value = ''
- setattr(self, name, value)
- return value
+ if name[0] == '_':
+ raise AttributeError
+ key = string.join(string.split(name, '_'), '-')
+ try:
+ value = self.__headers[key]
+ except KeyError:
+ value = ''
+ setattr(self, name, value)
+ return value
def __getitem__(self, key):
- return getattr(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 = string.strip(line[5:])
- p.close()
- self.version = version
+ 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 = string.strip(line[5:])
+ 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
+ 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)
+ 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 string.split(self.body, '\n'):
- # Allow the user to insert raw html into a FAQ answer
- # (Skip Montanaro, with changes by Guido)
- tag = string.lower(string.rstrip(line))
- if tag == '<html>':
- raw = 1
- continue
- if tag == '</html>':
- raw = 0
- continue
- if raw:
- print line
- continue
- if not string.strip(line):
- if pre:
- print '</PRE>'
- pre = 0
- else:
- print '<P>'
- else:
- if line[0] not in string.whitespace:
- 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>'
+ emit(ENTRY_HEADER1, self)
+ self.emit_marks()
+ emit(ENTRY_HEADER2, self)
+ pre = 0
+ raw = 0
+ for line in string.split(self.body, '\n'):
+ # Allow the user to insert raw html into a FAQ answer
+ # (Skip Montanaro, with changes by Guido)
+ tag = string.lower(string.rstrip(line))
+ if tag == '<html>':
+ raw = 1
+ continue
+ if tag == '</html>':
+ raw = 0
+ continue
+ if raw:
+ print line
+ continue
+ if not string.strip(line):
+ if pre:
+ print '</PRE>'
+ pre = 0
+ else:
+ print '<P>'
+ else:
+ if line[0] not in string.whitespace:
+ 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:
@@ -305,517 +305,517 @@ class FaqDir:
__okprog = re.compile(OKFILENAME)
def __init__(self, dir=os.curdir):
- self.__dir = dir
- self.__files = None
+ 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()
+ 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)
+ 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 string.atoi(sec), string.atoi(num)
+ m = self.good(file)
+ if not m:
+ return None
+ sec, num = m.group(1, 2)
+ return string.atoi(sec), string.atoi(num)
def list(self):
- # XXX Caller shouldn't modify result
- self.__fill()
- return self.__files
+ # 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()
+ 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)
+ 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)
+ 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()
+ 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 %s." % `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()
+ 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 %s." % `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)
+ self.prologue(T_ERROR)
+ emit(message, kw)
def prologue(self, title, entry=None, **kw):
- emit(PROLOGUE, entry, kwdict=kw, title=escape(title))
+ emit(PROLOGUE, entry, kwdict=kw, title=escape(title))
def epilogue(self):
- emit(EPILOGUE)
+ emit(EPILOGUE)
def do_home(self):
- self.prologue(T_HOME)
- emit(HOME)
+ self.prologue(T_HOME)
+ emit(HOME)
def do_debug(self):
- self.prologue("FAQ Wizard Debugging")
- form = cgi.FieldStorage()
- cgi.print_form(form)
+ self.prologue("FAQ Wizard Debugging")
+ form = cgi.FieldStorage()
+ cgi.print_form(form)
cgi.print_environ(os.environ)
- cgi.print_directory()
- cgi.print_arguments()
+ 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 = [string.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)
+ 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 = [string.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)
+ 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
+ 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)
+ 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)
+ 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)
+ 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)
+ 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 = string.atof(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)
+ if not self.ui.days:
+ days = 1
+ else:
+ days = string.atof(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 whrandom
- files = self.dir.list()
- if not files:
- self.error("No entries.")
- return
- file = whrandom.choice(files)
- self.prologue(T_ROULETTE)
- emit(ROULETTE)
- self.dir.show(file)
+ import whrandom
+ files = self.dir.list()
+ if not files:
+ self.error("No entries.")
+ return
+ file = whrandom.choice(files)
+ self.prologue(T_ROULETTE)
+ emit(ROULETTE)
+ self.dir.show(file)
def do_help(self):
- self.prologue(T_HELP)
- emit(HELP)
+ self.prologue(T_HELP)
+ emit(HELP)
def do_show(self):
- entry = self.dir.open(self.ui.file)
- self.prologue(T_SHOW)
- entry.show()
+ 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)
+ 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)
+ 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)
+ 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 = string.split(output, '\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 = string.strip(line[9:])
- 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>'
+ output = os.popen(command).read()
+ sys.stdout.write('<PRE>')
+ athead = 0
+ lines = string.split(output, '\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 = string.strip(line[9:])
+ 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: %s." % `rev`)
- self.prologue(T_REVISION, entry)
- self.shell(interpolate(SH_REVISION, entry, rev=rev))
+ entry = self.dir.open(self.ui.file)
+ rev = self.ui.rev
+ mami = revparse(rev)
+ if not mami:
+ self.error("Invalid revision number: %s." % `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: %s." % `rev`)
- if prev:
- if not revparse(prev):
- self.error("Invalid previous revision number: %s." % `prev`)
- else:
- prev = '%d.%d' % (mami[0], mami[1])
- self.prologue(T_DIFF, entry)
- self.shell(interpolate(SH_RDIFF, entry, rev=rev, prev=prev))
+ 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: %s." % `rev`)
+ if prev:
+ if not revparse(prev):
+ self.error("Invalid previous revision number: %s." % `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>'
+ output = os.popen(command).read()
+ sys.stdout.write('<PRE>')
+ print escape(output)
+ print '</PRE>'
def do_new(self):
- entry = self.dir.new(section=string.atoi(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)
+ entry = self.dir.new(section=string.atoi(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)
+ 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 string.split(self.ui.title)[:1] != string.split(entry.title)[: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)
- emit(EDITFORM2, self.ui, entry, load_my_cookie())
- emit(EDITFORM3)
+ 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 string.split(self.ui.title)[:1] != string.split(entry.title)[: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)
+ emit(EDITFORM2, self.ui, entry, load_my_cookie())
+ emit(EDITFORM3)
def cantcommit(self):
- self.prologue(T_CANTCOMMIT)
- print CANTCOMMIT_HEAD
- if not self.ui.passwd:
- 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)
- print CANTCOMMIT_TAIL
+ self.prologue(T_CANTCOMMIT)
+ print CANTCOMMIT_HEAD
+ if not self.ui.passwd:
+ 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)
+ print CANTCOMMIT_TAIL
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 = string.join(string.split(self.ui.title))
- # 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
- # XXX Should lock here
- 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
- tfn = tempfile.mktemp()
- f = open(tfn, 'w')
- emit(LOGHEADER, self.ui, os.environ, date=date, _file=f)
- f.close()
-
- command = interpolate(
- SH_LOCK + '\n' + SH_CHECKIN,
- file=file, tfn=tfn)
-
- p = os.popen(command)
- output = p.read()
- sts = p.close()
- # XXX Should unlock here
- 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(tfn)
- except os.error:
- pass
-
- entry = self.dir.open(file)
- entry.show()
+ 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 = string.join(string.split(self.ui.title))
+ # 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
+ # XXX Should lock here
+ 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
+ tfn = tempfile.mktemp()
+ f = open(tfn, 'w')
+ emit(LOGHEADER, self.ui, os.environ, date=date, _file=f)
+ f.close()
+
+ command = interpolate(
+ SH_LOCK + '\n' + SH_CHECKIN,
+ file=file, tfn=tfn)
+
+ p = os.popen(command)
+ output = p.read()
+ sts = p.close()
+ # XXX Should unlock here
+ 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(tfn)
+ except os.error:
+ pass
+
+ entry = self.dir.open(file)
+ entry.show()
wiz = FaqWizard()
wiz.go()