diff options
author | W. Trevor King <wking@drexel.edu> | 2009-12-31 15:54:12 -0500 |
---|---|---|
committer | W. Trevor King <wking@drexel.edu> | 2009-12-31 15:54:12 -0500 |
commit | b0b5341c4045dd27cfbb3e2585cb2614ed9ad903 (patch) | |
tree | 37c7c2d011617ccd7a6f28a24ea77bb1b3cddfe7 /interfaces | |
parent | a06030436d3940dddfba37b344f90651366d67e1 (diff) | |
parent | 2d1562d951e763fed71fe60e77cc9921be9abdc9 (diff) | |
download | bugseverywhere-b0b5341c4045dd27cfbb3e2585cb2614ed9ad903.tar.gz |
Merged be.restructure, major internal reorganization.
Added a bunch of classes to make the commands, user interfaces, and
storage backends more abstract and distinct. This should make it much
easier to extend and maintain BE.
Features:
* Directory restructured:
becommands/ -> libbe/commands
submods sorted by functionality.
* Lots of new classes:
Option, Argument, Command
InputOutput, StorageCallbacks, UserInterface
Storage
* Consolidated ID handling in libbe.util.id
* Transitioned VCS backends for Python-based VCSs from subprocess
calss to internal python calls.
Plus the user-visible changes:
* New bugdir/bug/comment ID format replaces old bug:comment format.
* Deprecated support for `be diff` on Arch and Darcs <= 2.3.1. A new
backend abstraction (Storage) makes the former implementation
ungainly.
* Improved command completion.
* Removed commands close, open, email_bugs,
* Flipped some arguments
`be assign BUG-ID [ASSIGNEE]` -> `be status ASSIGNED BUG-ID ...`
`be severity BUG-ID SEVERITY` -> `be severity SEVERITY BUG-ID ...`
`be status BUG-ID STATUS` -> `be status STATUS BUG-ID ...`
In the merge:
* Added 'commit' to list of pagerless commands.
* Updated doc/README.dev
See
#bea86499-824e-4e77-b085-2d581fa9ccab/1100c966-9671-4bc6-8b68-6d408a910da1#
for a discussion of why the changes were made and some of the
difficulties en-route.
Diffstat (limited to 'interfaces')
83 files changed, 229 insertions, 2845 deletions
diff --git a/interfaces/README b/interfaces/README deleted file mode 100644 index 4d74580..0000000 --- a/interfaces/README +++ /dev/null @@ -1,34 +0,0 @@ -Removing spam commits from the history -====================================== - -arch bzr darcs git hg none - -In the case that some spam or inappropriate comment makes its way -through you interface, you can remove the offending commit XYZ with: - - If the offending commit is the last commit: - - arch: - bzr: bzr uncommit && bzr revert - darcs: darcs obliterate --last=1 - git: git reset --hard HEAD^ - hg: hg rollback && hg revert - - If the offending commit is not the last commit: - - arch: - bzr: bzr rebase -r <XYZ+1>..-1 --onto before:XYZ . - (requires bzr-rebase plugin, note, you have to increment XYZ by - hand for <XYZ+1>, because bzr does not support "after:XYZ".) - darcs: darcs obliterate --matches 'name XYZ' - git: git rebase --onto XYZ~1 XYZ - hg: -not-supported- - (From http://hgbook.red-bean.com/read/finding-and-fixing-mistakes.html#id394667 - "Mercurial also does not provide a way to make a file or - changeset completely disappear from history, because there is no - way to enforce its disappearance") - -Note that all of these _change_the_repo_history_, so only do this on -your interface-specific repo before it interacts with any other repo. -Otherwise, you'll have to survive by cherry-picking only the good -commits. diff --git a/interfaces/email/catmutt b/interfaces/email/catmutt deleted file mode 100755 index 601f14f..0000000 --- a/interfaces/email/catmutt +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/sh - -# catmutt - wrap mutt allowing mboxes read from stdin. -# -# Copyright (C) 1998-1999 Moritz Barsnick <barsnick (at) gmx (dot) net>, -# 2009 William Trevor King <wking (at) drexel (dot) edu> -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# version 2 as published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# developed from grepm-0.6 -# http://www.barsnick.net/sw/grepm.html - -PROGNAME=`basename "$0"` -export TMPDIR="${TMPDIR-/tmp}" # used by mktemp -umask 077 - -if [ $# -gt 0 ] && [ "$1" = "--help" ]; then - echo 1>&2 "Usage: ${PROGNAME} [--help] mutt-arguments" - echo 1>&2 "" - echo 1>&2 "Read a mailbox file from stdin and opens it with mutt." - echo 1>&2 "For example: cat somefile.mbox | ${PROGNAME}" - exit 0 -fi - -# Note: the -t/-p options to mktemp are deprecated for mktemp (GNU -# coreutils) 7.1 in favor of --tmpdir but the --tmpdir option does not -# exist yet for my 6.10-3ubuntu2 coreutils -TMPFILE=`mktemp -t catmutt.XXXXXX` || exit 1 - -trap "rm -f ${TMPFILE}; exit 1" 1 2 3 13 15 - -cat > "${TMPFILE}" || exit 1 - -# Now that we've read in the mailbox file, reopen stdin for mutt/user -# interaction. When in a pipe we're not technically in a tty, so use -# a little hack from "greno" at -# http://www.linuxforums.org/forum/linux-programming-scripting/98607-bash-stdin-problem.html -tty="/dev/`ps -p$$ --no-heading | awk '{print $2}'`" -exec < ${tty} - -if [ `wc -c "${TMPFILE}" | awk '{print $1}'` -gt 0 ]; then - echo 1>&2 "Calling mutt on temporary mailbox file (${TMPFILE})." - mutt -R -f "${TMPFILE}" "$@" -else - echo 1>&2 "Empty mailbox input." -fi - -rm -f "${TMPFILE}" && echo 1>&2 "Deleted temporary mailbox file (${TMPFILE})." diff --git a/interfaces/email/interactive/be-handle-mail b/interfaces/email/interactive/be-handle-mail index 10f6884..f8792f1 100755 --- a/interfaces/email/interactive/be-handle-mail +++ b/interfaces/email/interactive/be-handle-mail @@ -58,45 +58,51 @@ import shlex import sys import time import traceback +import types import doctest import unittest -from becommands import subscribe -import libbe.cmdutil, libbe.encoding, libbe.utility, libbe.diff, \ - libbe.bugdir, libbe.bug, libbe.comment +import libbe.bugdir +import libbe.bug +import libbe.comment +import libbe.diff +import libbe.command +import libbe.command.subscribe as subscribe +import libbe.storage +import libbe.ui.command_line +import libbe.util.encoding +import libbe.util.utility import send_pgp_mime -THIS_SERVER = u"thor.physics.drexel.edu" -THIS_ADDRESS = u"BE Bugs <wking@thor.physics.drexel.edu>" - +THIS_SERVER = u'thor.physics.drexel.edu' +THIS_ADDRESS = u'BE Bugs <wking@thor.physics.drexel.edu>' +UI = None _THIS_DIR = os.path.abspath(os.path.dirname(__file__)) -BE_DIR = _THIS_DIR -LOGPATH = os.path.join(_THIS_DIR, u"be-handle-mail.log") +LOGPATH = os.path.join(_THIS_DIR, u'be-handle-mail.log') LOGFILE = None # Tag strings generated by generate_global_tags() -SUBJECT_TAG_BASE = u"be-bug" +SUBJECT_TAG_BASE = u'be-bug' SUBJECT_TAG_RESPONSE = None SUBJECT_TAG_START = None SUBJECT_TAG_NEW = None SUBJECT_TAG_COMMENT = None SUBJECT_TAG_CONTROL = None -SUBJECT_TAG_XML = None - -BREAK = u"--" -NEW_REQUIRED_PSEUDOHEADERS = [u"Version"] -NEW_OPTIONAL_PSEUDOHEADERS = [u"Reporter", u"Assign", u"Depend", u"Severity", - u"Status", u"Tag", u"Target", - u"Confirm", u"Subscribe"] -CONTROL_COMMENT = u"#" -ALLOWED_COMMANDS = [u"assign", u"comment", u"commit", u"depend", u"help", - u"list", u"merge", u"new", u"open", u"severity", u"show", - u"status", u"subscribe", u"tag", u"target", u"import-xml"] + +BREAK = u'--' +NEW_REQUIRED_PSEUDOHEADERS = [u'Version'] +NEW_OPTIONAL_PSEUDOHEADERS = [u'Reporter', u'Assign', u'Depend', u'Severity', + u'Status', u'Tag', u'Target', + u'Confirm', u'Subscribe'] +CONTROL_COMMENT = u'#' +ALLOWED_COMMANDS = [u'assign', u'comment', u'commit', u'depend', u'diff', + u'due', u'help', u'list', u'merge', u'new', u'severity', + u'show', u'status', u'subscribe', u'tag', u'target'] AUTOCOMMIT = True -libbe.encoding.ENCODING = u"utf-8" # force default encoding -ENCODING = libbe.encoding.get_encoding() +ENCODING = u'utf-8' +libbe.util.encoding.ENCODING = ENCODING # force default encoding class InvalidEmail (ValueError): def __init__(self, msg, message): @@ -104,10 +110,10 @@ class InvalidEmail (ValueError): self.msg = msg def response(self): header = self.msg.response_header - body = [u"Error processing email:\n", - self.response_body(), u""] + body = [u'Error processing email:\n', + self.response_body(), u''] response_generator = \ - send_pgp_mime.PGPMimeMessageFactory(u"\n".join(body)) + send_pgp_mime.PGPMimeMessageFactory(u'\n'.join(body)) response = MIMEMultipart() response.attach(response_generator.plain()) response.attach(self.msg.msg) @@ -115,44 +121,44 @@ class InvalidEmail (ValueError): return ret def response_body(self): err_text = [unicode(self)] - return u"\n".join(err_text) + return u'\n'.join(err_text) class InvalidSubject (InvalidEmail): def __init__(self, msg, message=None): if message == None: - message = u"Invalid subject" + message = u'Invalid subject' InvalidEmail.__init__(self, msg, message) def response_body(self): - err_text = u"\n".join([unicode(self), u"", - u"full subject was:", + err_text = u'\n'.join([unicode(self), u'', + u'full subject was:', self.msg.subject()]) return err_text class InvalidPseudoHeader (InvalidEmail): def response_body(self): - err_text = [u"Invalid pseudo-header:\n", + err_text = [u'Invalid pseudo-header:\n', unicode(self)] - return u"\n".join(err_text) + return u'\n'.join(err_text) class InvalidCommand (InvalidEmail): def __init__(self, msg, command, message=None): - bigmessage = u"Invalid execution command '%s'" % command + bigmessage = u'Invalid execution command "%s"' % command if message != None: - bigmessage += u"\n%s" % message + bigmessage += u'\n%s' % message InvalidEmail.__init__(self, msg, bigmessage) self.command = command class InvalidOption (InvalidCommand): def __init__(self, msg, option, message=None): - bigmessage = u"Invalid option '%s'" % (option) + bigmessage = u'Invalid option "%s"' % (option) if message != None: - bigmessage += u"\n%s" % message + bigmessage += u'\n%s' % message InvalidCommand.__init__(self, msg, info, command, bigmessage) self.option = option class NotificationFailed (Exception): def __init__(self, msg): - bigmessage = "Notification failed: %s" % msg + bigmessage = 'Notification failed: %s' % msg Exception.__init__(self, bigmessage) self.short_msg = msg @@ -166,11 +172,11 @@ class ID (object): def __init__(self, command): self.command = command def extract_id(self): - if hasattr(self, "cached_id"): + if hasattr(self, 'cached_id'): return self._cached_id assert self.command.ret == 0, self.command.ret - if self.command.command == u"new": - regexp = re.compile(u"Created bug with ID (.*)") + if self.command.command.name == u'new': + regexp = re.compile(u'Created bug with ID (.*)') else: raise NotImplementedError, self.command.command match = regexp.match(self.command.stdout) @@ -179,13 +185,12 @@ class ID (object): return self._cached_id def __str__(self): if self.command.ret != 0: - return "<id for %s>" % repr(self.command) - return "<id %s>" % self.extract_id() + return '<id for %s>' % repr(self.command) + return '<id %s>' % self.extract_id() class Command (object): """ - A becommands command wrapper. - Doesn't validate input, so do that before initializing. + A libbe.command.Command handler. Initialize with Command(msg, command, args=None, stdin=None) @@ -197,18 +202,17 @@ class Command (object): """ def __init__(self, msg, command, args=None, stdin=None): self.msg = msg - self.command = command if args == None: self.args = [] else: self.args = args - self.stdin = stdin + self.command = libbe.command.get_command_class(command_name=command)() + self.command._setup_io = lambda i_enc,o_enc : None self.ret = None + self.stdin = stdin self.stdout = None - self.stderr = None - self.err = None def __str__(self): - return "<command: %s %s>" % (self.command, " ".join([str(s) for s in self.args])) + return '<command: %s %s>' % (self.command, ' '.join([str(s) for s in self.args])) def normalize_args(self): """ Expand any ID placeholders in self.args. @@ -222,61 +226,25 @@ class Command (object): info. Returns the exit code, stdout, and stderr produced by the command. """ - if self.command in [None, u""]: # don't accept blank commands - raise InvalidCommand(self.msg, self, "Blank") - elif self.command not in ALLOWED_COMMANDS: - raise InvalidCommand(self.msg, self, "Not allowed") - assert self.ret == None, u"running %s twice!" % unicode(self) + if self.command.name in [None, u'']: # don't accept blank commands + raise InvalidCommand(self.msg, self, 'Blank') + elif self.command.name not in ALLOWED_COMMANDS: + raise InvalidCommand(self.msg, self, 'Not allowed') + assert self.ret == None, u'running %s twice!' % unicode(self) self.normalize_args() - # set stdin and catch stdout and stderr - if self.stdin != None: - orig_stdin = sys.stdin - sys.stdin = StringIO.StringIO(self.stdin) - new_stdout = codecs.getwriter(ENCODING)(StringIO.StringIO()) - new_stderr = codecs.getwriter(ENCODING)(StringIO.StringIO()) - orig_stdout = sys.stdout - orig_stderr = sys.stderr - sys.stdout = new_stdout - sys.stderr = new_stderr - # run the command - os.chdir(BE_DIR) - try: - self.ret = libbe.cmdutil.execute(self.command, self.args, - manipulate_encodings=False, - restrict_file_access=True) - except libbe.cmdutil.GetHelp: - print libbe.cmdutil.help(command) - except libbe.cmdutil.GetCompletions: - self.err = InvalidOption(self.msg, self.command, u"--complete") - except libbe.cmdutil.UsageError, e: - self.err = InvalidCommand(self.msg, self, - "%s\n%s" % (type(e), unicode(e))) - except libbe.cmdutil.UserError, e: - self.err = InvalidCommand(self.msg, self, - "%s\n%s" % (type(e), unicode(e))) - # restore stdin, stdout, and stderr - if self.stdin != None: - sys.stdin = orig_stdin - sys.stdout.flush() - sys.stderr.flush() - sys.stdout = orig_stdout - sys.stderr = orig_stderr - self.stdout = codecs.decode(new_stdout.getvalue(), ENCODING) - self.stderr = codecs.decode(new_stderr.getvalue(), ENCODING) - if self.err != None: - raise self.err - return (self.ret, self.stdout, self.stderr) + UI.io.set_stdin(self.stdin) + self.ret = libbe.ui.command_line.dispatch(UI, self.command, self.args) + self.stdout = UI.io.get_stdout() + return (self.ret, self.stdout) def response_msg(self): if self.ret == None: self.ret = -1 - response_body = [u"Results of running: (exit code %d)" % self.ret, - u" %s %s" % (self.command, u" ".join(self.args))] + response_body = [u'Results of running: (exit code %d)' % self.ret, + u' %s %s' % (self.command.name,u' '.join(self.args))] if self.stdout != None and len(self.stdout) > 0: - response_body.extend([u"", u"stdout:", u"", self.stdout]) - if self.stderr != None and len(self.stderr) > 0: - response_body.extend([u"", u"stderr:", u"", self.stderr]) - response_body.append(u"") # trailing endline + response_body.extend([u'', u'output:', u'', self.stdout]) + response_body.append(u'') # trailing endline response_generator = \ - send_pgp_mime.PGPMimeMessageFactory(u"\n".join(response_body)) + send_pgp_mime.PGPMimeMessageFactory(u'\n'.join(response_body)) return response_generator.plain() class DiffTree (libbe.diff.DiffTree): @@ -315,27 +283,27 @@ class DiffTree (libbe.diff.DiffTree): def report_string(self): report = self.report_or_none() if report == None: - return "No changes" + return 'No changes' else: return send_pgp_mime.flatten(report, to_unicode=True) def make_root(self): return MIMEMultipart() def join(self, root, parent, data_part): - if hasattr(parent, "attach_child_text"): + if hasattr(parent, 'attach_child_text'): self.attach_child_text = True if data_part != None: - send_pgp_mime.append_text(parent.data_mime_part, u"\n\n%s" % (data_part)) + send_pgp_mime.append_text(parent.data_mime_part, u'\n\n%s' % (data_part)) self.data_mime_part = parent.data_mime_part else: self.data_mime_part = None if data_part != None: self.data_mime_part = send_pgp_mime.encodedMIMEText(data_part) - if parent != None and parent.name in [u"new", u"rem", u"mod"]: + if parent != None and parent.name in [u'new', u'rem', u'mod']: self.attach_child_text = True if data_part == None: # make blank data_mime_part for children's appends - self.data_mime_part = send_pgp_mime.encodedMIMEText(u"") + self.data_mime_part = send_pgp_mime.encodedMIMEText(u'') if self.data_mime_part != None: - self.data_mime_part[u"Content-Description"] = self.name + self.data_mime_part[u'Content-Description'] = self.name root.attach(self.data_mime_part) def data_part(self, depth, indent=False): return libbe.diff.DiffTree.data_part(self, depth, indent=indent) @@ -357,19 +325,19 @@ class Message (object): p=email.Parser.Parser() self.msg=p.parsestr(self.text) if LOGFILE != None: - LOGFILE.write(u"handling %s\n" % self.author_addr()) - LOGFILE.write(u"\n%s\n\n" % self.text) + LOGFILE.write(u'handling %s\n' % self.author_addr()) + LOGFILE.write(u'\n%s\n\n' % self.text) self.confirm = True # enable/disable confirmation email def _yes_no(self, boolean): if boolean == True: - return "yes" - return "no" + return 'yes' + return 'no' def author_tuple(self): """ Extract and normalize the sender's email address. Returns a (name, email) tuple. """ - if not hasattr(self, "author_tuple_cache"): + if not hasattr(self, 'author_tuple_cache'): self._author_tuple_cache = \ send_pgp_mime.source_email(self.msg, return_realname=True) return self._author_tuple_cache @@ -384,24 +352,24 @@ class Message (object): return self.msg[attr_name] return default def message_id(self, default=None): - return self.default_msg_attribute_access("message-id", default=default) + return self.default_msg_attribute_access('message-id', default=default) def subject(self): - if "subject" not in self.msg: - raise InvalidSubject(self, u"Email must contain a subject") - return self.msg["subject"] + if 'subject' not in self.msg: + raise InvalidSubject(self, u'Email must contain a subject') + return self.msg['subject'] def _split_subject(self): """ Returns (tag, subject), with missing values replaced by None. """ - if hasattr(self, "_split_subject_cache"): + if hasattr(self, '_split_subject_cache'): return self._split_subject_cache - args = self.subject().split(u"]",1) + args = self.subject().split(u']',1) if len(args) < 1: self._split_subject_cache = (None, None) elif len(args) < 2: - self._split_subject_cache = (args[0]+u"]", None) + self._split_subject_cache = (args[0]+u']', None) else: - self._split_subject_cache = (args[0]+u"]", args[1].strip()) + self._split_subject_cache = (args[0]+u']', args[1].strip()) return self._split_subject_cache def _subject_tag_type(self): """ @@ -414,15 +382,13 @@ class Message (object): type = None value = None if tag == SUBJECT_TAG_NEW: - type = u"new" + type = u'new' elif tag == SUBJECT_TAG_CONTROL: - type = u"control" - elif tag == SUBJECT_TAG_XML: - type = u"xml" + type = u'control' else: match = SUBJECT_TAG_COMMENT.match(tag) if len(match.groups()) == 1: - type = u"comment" + type = u'comment' value = match.group(1) return (type, value) def validate_subject(self): @@ -432,14 +398,14 @@ class Message (object): tag,subject = self._split_subject() if not tag.startswith(SUBJECT_TAG_START): raise InvalidSubject( - self, u"Subject must start with '%s'" % SUBJECT_TAG_START) + self, u'Subject must start with "%s"' % SUBJECT_TAG_START) tag_type,value = self._subject_tag_type() if tag_type == None: - raise InvalidSubject(self, u"Invalid tag '%s'" % tag) - elif tag_type == u"new" and len(subject) == 0: - raise InvalidSubject(self, u"Cannot create a bug with blank title") - elif tag_type == u"comment" and len(value) == 0: - raise InvalidSubject(self, u"Must specify a bug ID to comment") + raise InvalidSubject(self, u'Invalid tag "%s"' % tag) + elif tag_type == u'new' and len(subject) == 0: + raise InvalidSubject(self, u'Cannot create a bug with blank title') + elif tag_type == u'comment' and len(value) == 0: + raise InvalidSubject(self, u'Must specify a bug ID to comment') def _get_bodies_and_mime_types(self): """ Traverse the email message returning (body, mime_type) for @@ -451,7 +417,7 @@ class Message (object): continue body,mime_type=(part.get_payload(decode=True),part.get_content_type()) charset = part.get_content_charset(msg_charset).lower() - if mime_type.startswith("text/"): + if mime_type.startswith('text/'): body = unicode(body, charset) # convert text types to unicode yield (body, mime_type) def _parse_body_pseudoheaders(self, body, required, optional, @@ -471,15 +437,15 @@ class Message (object): line = line.strip() if len(line) == 0: break - if ":" not in line: + if ':' not in line: raise InvalidPseudoheader(self, line) - key,value = line.split(":", 1) + key,value = line.split(':', 1) value = value.strip() if key not in all: raise InvalidPseudoHeader(self, key) if len(value) == 0: raise InvalidEmail( - self, u"Blank value for: %s" % key) + self, u'Blank value for: %s' % key) dictionary[key] = value missing = [] for key in required: @@ -487,9 +453,9 @@ class Message (object): missing.append(key) if len(missing) > 0: raise InvalidPseudoHeader(self, - u"Missing required pseudo-headers:\n%s" - % u", ".join(missing)) - remaining_body = u"\n".join(body_lines[i:]).strip() + u'Missing required pseudo-headers:\n%s' + % u', '.join(missing)) + remaining_body = u'\n'.join(body_lines[i:]).strip() return (remaining_body, dictionary) def _strip_footer(self, body): body_lines = body.splitlines() @@ -497,7 +463,7 @@ class Message (object): if line.startswith(BREAK): break i += 1 # increment past the current valid line. - return u"\n".join(body_lines[:i]).strip() + return u'\n'.join(body_lines[:i]).strip() def parse(self): """ Parse the commands given in the email. Raises assorted @@ -506,24 +472,22 @@ class Message (object): """ self.validate_subject() tag_type,value = self._subject_tag_type() - if tag_type == u"new": + if tag_type == u'new': commands = self.parse_new() - elif tag_type == u"comment": + elif tag_type == u'comment': commands = self.parse_comment(value) - elif tag_type == u"control": + elif tag_type == u'control': commands = self.parse_control() - elif tag_type == u"xml": - commands = self.parse_xml() else: - raise Exception, u"Unrecognized tag type '%s'" % tag_type + raise Exception, u'Unrecognized tag type "%s"' % tag_type return commands def parse_new(self): - command = u"new" + command = u'new' tag,subject = self._split_subject() summary = subject - options = {u"Reporter": self.author_addr(), - u"Confirm": self._yes_no(self.confirm), - u"Subscribe": "no", + options = {u'Reporter': self.author_addr(), + u'Confirm': self._yes_no(self.confirm), + u'Subscribe': 'no', } body,mime_type = list(self._get_bodies_and_mime_types())[0] comment_body,options = \ @@ -531,51 +495,54 @@ class Message (object): NEW_REQUIRED_PSEUDOHEADERS, NEW_OPTIONAL_PSEUDOHEADERS, options) - if options[u"Confirm"].lower() == "no": + if options[u'Confirm'].lower() == 'no': self.confirm = False - if options[u"Subscribe"].lower() == "yes" and self.confirm == True: + if options[u'Subscribe'].lower() == 'yes' and self.confirm == True: # respond with the subscription format rather than the # normal command-output format, because the subscription # format is more user-friendly. self.confirm = False - args = [u"--reporter", options[u"Reporter"]] + args = [u'--reporter', options[u'Reporter']] args.append(summary) commands = [Command(self, command, args)] id = ID(commands[0]) comment_body = self._strip_footer(comment_body) if len(comment_body) > 0: - command = u"comment" - comment = u"Version: %s\n\n"%options[u"Version"] + comment_body - args = [u"--author", self.author_addr(), - u"--alt-id", self.message_id(), - u"--content-type", mime_type] + command = u'comment' + comment = u'Version: %s\n\n'%options[u'Version'] + comment_body + args = [u'--author', self.author_addr(), + u'--alt-id', self.message_id(), + u'--content-type', mime_type] args.append(id) - args.append(u"-") - commands.append(Command(self, u"comment", args, stdin=comment)) + args.append(u'-') + commands.append(Command(self, u'comment', args, stdin=comment)) for key,value in options.items(): - if key in [u"Version", u"Reporter", u"Confirm"]: + if key in [u'Version', u'Reporter', u'Confirm']: continue # we've already handled these options command = key.lower() - args = [id, value] - if key == u"Subscribe": - if value.lower() != "yes": + if key in [u'Depend', u'Tag', u'Target', u'Subscribe']: + args = [id, value] + else: + args = [value, id] + if key == u'Subscribe': + if value.lower() != 'yes': continue - args = ["--subscriber", self.author_addr(), id] + args = ['--subscriber', self.author_addr(), id] commands.append(Command(self, command, args)) return commands def parse_comment(self, bug_uuid): - command = u"comment" + command = u'comment' bug_id = bug_uuid author = self.author_addr() alt_id = self.message_id() body,mime_type = list(self._get_bodies_and_mime_types())[0] - if mime_type == "text/plain": + if mime_type == 'text/plain': body = self._strip_footer(body) content_type = mime_type - args = [u"--author", author] + args = [u'--author', author] if alt_id != None: - args.extend([u"--alt-id", alt_id]) - args.extend([u"--content-type", content_type, bug_id, u"-"]) + args.extend([u'--alt-id', alt_id]) + args.extend([u'--content-type', content_type, bug_id, u'-']) commands = [Command(self, command, args, stdin=body)] return commands def parse_control(self): @@ -587,49 +554,46 @@ class Message (object): continue if line.startswith(BREAK): break + if type(line) == types.UnicodeType: + # work around http://bugs.python.org/issue1170 + line = line.encode('unicode escape') fields = shlex.split(line) + if type(line) == types.UnicodeType: + # work around http://bugs.python.org/issue1170 + for field in fields: + field = unicode(field, 'unicode escape') command,args = (fields[0], fields[1:]) commands.append(Command(self, command, args)) if len(commands) == 0: - raise InvalidEmail(self, u"No commands in control email.") + raise InvalidEmail(self, u'No commands in control email.') return commands - def parse_xml(self): - command = u"import-xml" - body,mime_type = list(self._get_bodies_and_mime_types())[0] - if mime_type != "text/xml": - raise InvalidEmail(self, - u"Emails to %s must have MIME type 'text/xml', not '%s'." - % (SUBJECT_TAG_XML, mime_type)) - args = [u"--add-only", u"-"] - commands = [Command(self, command, args, stdin=body)] - return commands - def run(self): + def run(self, repo='.'): self._begin_response() commands = self.parse() try: - for command in commands: + for i,command in enumerate(commands): command.run() self._add_response(command.response_msg()) finally: if AUTOCOMMIT == True: tag,subject = self._split_subject() - self.commit_command = Command(self, "commit", [subject]) + self.commit_command = Command(self, 'commit', [subject]) self.commit_command.run() if LOGFILE != None: - LOGFILE.write(u"Autocommit:\n%s\n\n" % + LOGFILE.write(u'Autocommit:\n%s\n\n' % send_pgp_mime.flatten(self.commit_command.response_msg(), to_unicode=True)) def _begin_response(self): tag,subject = self._split_subject() - response_header = [u"From: %s" % THIS_ADDRESS, - u"To: %s" % self.author_addr(), - u"Date: %s" % libbe.utility.time_to_str(time.time()), - u"Subject: %s Re: %s"%(SUBJECT_TAG_RESPONSE,subject) + response_header = [u'From: %s' % THIS_ADDRESS, + u'To: %s' % self.author_addr(), + u'Date: %s' % libbe.util.utility.time_to_str(time.time()), + u'Subject: %s Re: %s'%(SUBJECT_TAG_RESPONSE,subject) ] if self.message_id() != None: - response_header.append(u"In-reply-to: %s" % self.message_id()) + response_header.append(u'In-reply-to: %s' % self.message_id()) self.response_header = \ - send_pgp_mime.header_from_text(text=u"\n".join(response_header)) + send_pgp_mime.header_from_text(text=u'\n'.join(response_header)) self._response_messages = [] def _add_response(self, response_message): self._response_messages.append(response_message) @@ -645,22 +609,24 @@ class Message (object): def subscriber_emails(self, previous_revision=None): if previous_revision == None: if AUTOCOMMIT != True: # no way to tell what's changed - raise NotificationFailed("Autocommit dissabled") + raise NotificationFailed('Autocommit dissabled') if len(self._response_messages) == 0: - raise NotificationFailed("Initial email failed.") + raise NotificationFailed('Initial email failed.') if self.commit_command.ret != 0: # commit failed. Error already logged. - raise NotificationFailed("Commit failed") + raise NotificationFailed('Commit failed') - # read only bugdir. - bd = libbe.bugdir.BugDir(from_disk=True, - manipulate_encodings=False) + bd = UI.storage_callbacks.get_bugdir() + writeable = bd.storage.writeable + bd.storage.writeable = False if bd.vcs.versioned == False: # no way to tell what's changed - raise NotificationFailed("Not versioned") + bd.storage.writeable = writeable + raise NotificationFailed('Not versioned') bd.load_all_bugs() subscribers = subscribe.get_bugdir_subscribers(bd, THIS_SERVER) if len(subscribers) == 0: + bd.storage.writeable = writeable return [] for subscriber,subscriptions in subscribers.items(): subscribers[subscriber] = [] @@ -676,19 +642,20 @@ class Message (object): emails = [] for subscriber,subscriptions in subscribers.items(): - header.replace_header("to", subscriber) + header.replace_header('to', subscriber) report = diff.report_tree(subscriptions, diff_tree=DiffTree) root = report.report_or_none() if root != None: emails.append(send_pgp_mime.attach_root(header, root)) if LOGFILE != None: - LOGFILE.write(u"Preparing to notify %s of changes\n" % subscriber) + LOGFILE.write(u'Preparing to notify %s of changes\n' % subscriber) + bd.storage.writeable = writeable return emails def _get_before_and_after_bugdirs(self, bd, previous_revision=None): if previous_revision == None: commit_msg = self.commit_command.stdout - assert commit_msg.startswith("Committed "), commit_msg - after_revision = commit_msg[len("Committed "):] + assert commit_msg.startswith('Committed '), commit_msg + after_revision = commit_msg[len('Committed '):] before_revision = bd.vcs.revision_id(-2) else: before_revision = previous_revision @@ -704,32 +671,30 @@ class Message (object): def _subscriber_header(self, bd, previous_revision=None): root_dir = os.path.basename(bd.root) if previous_revision == None: - subject = "Changes to %s on %s by %s" \ + subject = 'Changes to %s on %s by %s' \ % (root_dir, THIS_SERVER, self.author_addr()) else: - subject = "Changes to %s on %s since revision %s" \ + subject = 'Changes to %s on %s since revision %s' \ % (root_dir, THIS_SERVER, previous_revision) - header = [u"From: %s" % THIS_ADDRESS, - u"To: %s" % u"DUMMY-AUTHOR", - u"Date: %s" % libbe.utility.time_to_str(time.time()), - u"Subject: %s Re: %s" % (SUBJECT_TAG_RESPONSE, subject) + header = [u'From: %s' % THIS_ADDRESS, + u'To: %s' % u'DUMMY-AUTHOR', + u'Date: %s' % libbe.util.utility.time_to_str(time.time()), + u'Subject: %s Re: %s' % (SUBJECT_TAG_RESPONSE, subject) ] - return send_pgp_mime.header_from_text(text=u"\n".join(header)) + return send_pgp_mime.header_from_text(text=u'\n'.join(header)) -def generate_global_tags(tag_base=u"be-bug"): +def generate_global_tags(tag_base=u'be-bug'): """ Generate a series of tags from a base tag string. """ global SUBJECT_TAG_BASE, SUBJECT_TAG_START, SUBJECT_TAG_RESPONSE, \ - SUBJECT_TAG_NEW, SUBJECT_TAG_COMMENT, SUBJECT_TAG_CONTROL, \ - SUBJECT_TAG_XML + SUBJECT_TAG_NEW, SUBJECT_TAG_COMMENT, SUBJECT_TAG_CONTROL SUBJECT_TAG_BASE = tag_base - SUBJECT_TAG_START = u"[%s" % tag_base - SUBJECT_TAG_RESPONSE = u"[%s]" % tag_base - SUBJECT_TAG_NEW = u"[%s:submit]" % tag_base - SUBJECT_TAG_COMMENT = re.compile(u"\[%s:([\-0-9a-z]*)]" % tag_base) + SUBJECT_TAG_START = u'[%s' % tag_base + SUBJECT_TAG_RESPONSE = u'[%s]' % tag_base + SUBJECT_TAG_NEW = u'[%s:submit]' % tag_base + SUBJECT_TAG_COMMENT = re.compile(u'\[%s:([\-0-9a-z]*)]' % tag_base) SUBJECT_TAG_CONTROL = SUBJECT_TAG_RESPONSE - SUBJECT_TAG_XML = u"[%s:xml]" % tag_base def open_logfile(logpath=None): """ @@ -741,27 +706,28 @@ def open_logfile(logpath=None): """ global LOGPATH, LOGFILE if logpath != None: - if logpath == u"-": - LOGPATH = u"stderr" + if logpath == u'-': + LOGPATH = u'stderr' LOGFILE = sys.stderr - elif logpath == u"none": - LOGPATH = u"none" + elif logpath == u'none': + LOGPATH = u'none' LOGFILE = None elif os.path.isabs(logpath): LOGPATH = logpath else: LOGPATH = os.path.join(_THIS_DIR, logpath) - if LOGFILE == None and LOGPATH != u"none": - LOGFILE = codecs.open(LOGPATH, u"a+", ENCODING) - LOGFILE.write(u"Default encoding: %s\n" % ENCODING) + if LOGFILE == None and LOGPATH != u'none': + LOGFILE = codecs.open(LOGPATH, u'a+', + libbe.utuil.encoding.get_filesystem_encoding()) def close_logfile(): - if LOGFILE != None and LOGPATH not in [u"stderr", u"none"]: + if LOGFILE != None and LOGPATH not in [u'stderr', u'none']: LOGFILE.close() +unitsuite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) +suite = unittest.TestSuite([unitsuite, doctest.DocTestSuite()]) + def test(): - unitsuite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) - suite = unittest.TestSuite([unitsuite, doctest.DocTestSuite()]) result = unittest.TextTestRunner(verbosity=2).run(suite) num_errors = len(result.errors) num_failures = len(result.failures) @@ -770,15 +736,15 @@ def test(): def main(args): from optparse import OptionParser - global AUTOCOMMIT, BE_DIR + global AUTOCOMMIT, UI - usage="be-handle-mail [options]\n\n%s" % (__doc__) + usage='be-handle-mail [options]\n\n%s' % (__doc__) parser = OptionParser(usage=usage) - parser.add_option('-b', '--be-dir', dest='be_dir', default=BE_DIR, - metavar="DIR", - help='Select the BE directory to serve (%default).') + parser.add_option('-r', '--repo', dest='repo', default=_THIS_DIR, + metavar='REPO', + help='Select the BE repository to serve (%default).') parser.add_option('-t', '--tag-base', dest='tag_base', - default=SUBJECT_TAG_BASE, metavar="TAG", + default=SUBJECT_TAG_BASE, metavar='TAG', help='Set the subject tag base (%default).') parser.add_option('-o', '--output', dest='output', action='store_true', help="Don't mail the generated message, print it to stdout instead. Useful for testing be-handle-mail functionality without the whole mail transfer agent and procmail setup.") @@ -804,40 +770,44 @@ def main(args): num_bad = 1 sys.exit(num_bad) - BE_DIR = options.be_dir AUTOCOMMIT = options.autocommit if options.notify_since == None: msg_text = sys.stdin.read() - libbe.encoding.set_IO_stream_encodings(ENCODING) # _after_ reading message open_logfile(options.logfile) generate_global_tags(options.tag_base) + io = libbe.command.StringInputOutput() + UI = libbe.command.UserInterface(io, location=options.repo) + if options.notify_since != None: if options.subscribers == True: if LOGFILE != None: - LOGFILE.write(u"Checking for subscribers to notify since revision %s\n" + LOGFILE.write(u'Checking for subscribers to notify since revision %s\n' % options.notify_since) try: m = Message(disable_parsing=True) emails = m.subscriber_emails(options.notify_since) except NotificationFailed, e: if LOGFILE != None: - LOGFILE.write(unicode(e) + u"\n") + LOGFILE.write(unicode(e) + u'\n') else: for msg in emails: if options.output == True: print send_pgp_mime.flatten(msg, to_unicode=True) else: send_pgp_mime.mail(msg, send_pgp_mime.sendmail) + self.commit_command.cleanup() close_logfile() + UI.cleanup() sys.exit(0) if len(msg_text.strip()) == 0: # blank email!? if LOGFILE != None: - LOGFILE.write(u"Blank email!\n") + LOGFILE.write(u'Blank email!\n') close_logfile() + UI.cleanup() sys.exit(1) try: m = Message(msg_text) @@ -846,9 +816,10 @@ def main(args): response = e.response() except Exception, e: if LOGFILE != None: - LOGFILE.write(u"Uncaught exception:\n%s\n" % (e,)) + LOGFILE.write(u'Uncaught exception:\n%s\n' % (e,)) traceback.print_tb(sys.exc_traceback, file=LOGFILE) close_logfile() + UI.cleanup() sys.exit(1) else: response = m.response_email() @@ -856,21 +827,21 @@ def main(args): print send_pgp_mime.flatten(response, to_unicode=True) elif m.confirm == True: if LOGFILE != None: - LOGFILE.write(u"Sending response to %s\n" % m.author_addr()) - LOGFILE.write(u"\n%s\n\n" % send_pgp_mime.flatten(response, + LOGFILE.write(u'Sending response to %s\n' % m.author_addr()) + LOGFILE.write(u'\n%s\n\n' % send_pgp_mime.flatten(response, to_unicode=True)) send_pgp_mime.mail(response, send_pgp_mime.sendmail) else: if LOGFILE != None: - LOGFILE.write(u"Response declined by %s\n" % m.author_addr()) + LOGFILE.write(u'Response declined by %s\n' % m.author_addr()) if options.subscribers == True: if LOGFILE != None: - LOGFILE.write(u"Checking for subscribers\n") + LOGFILE.write(u'Checking for subscribers\n') try: emails = m.subscriber_emails() except NotificationFailed, e: if LOGFILE != None: - LOGFILE.write(unicode(e) + u"\n") + LOGFILE.write(unicode(e) + u'\n') else: for msg in emails: if options.output == True: @@ -879,7 +850,7 @@ def main(args): send_pgp_mime.mail(msg, send_pgp_mime.sendmail) close_logfile() - + UI.cleanup() class GenerateGlobalTagsTestCase (unittest.TestCase): def setUp(self): @@ -901,41 +872,37 @@ class GenerateGlobalTagsTestCase (unittest.TestCase): def test_restore_global_tags(self): "Test global tag restoration by teardown function." global SUBJECT_TAG_BASE - self.failUnlessEqual(SUBJECT_TAG_BASE, u"be-bug") - SUBJECT_TAG_BASE = "projectX-bug" - self.failUnlessEqual(SUBJECT_TAG_BASE, u"projectX-bug") + self.failUnlessEqual(SUBJECT_TAG_BASE, u'be-bug') + SUBJECT_TAG_BASE = 'projectX-bug' + self.failUnlessEqual(SUBJECT_TAG_BASE, u'projectX-bug') self.restore_global_tags() - self.failUnlessEqual(SUBJECT_TAG_BASE, u"be-bug") + self.failUnlessEqual(SUBJECT_TAG_BASE, u'be-bug') def test_subject_tag_base(self): "Should set SUBJECT_TAG_BASE global correctly" - generate_global_tags(u"projectX-bug") - self.failUnlessEqual(SUBJECT_TAG_BASE, u"projectX-bug") + generate_global_tags(u'projectX-bug') + self.failUnlessEqual(SUBJECT_TAG_BASE, u'projectX-bug') def test_subject_tag_start(self): "Should set SUBJECT_TAG_START global correctly" - generate_global_tags(u"projectX-bug") - self.failUnlessEqual(SUBJECT_TAG_START, u"[projectX-bug") + generate_global_tags(u'projectX-bug') + self.failUnlessEqual(SUBJECT_TAG_START, u'[projectX-bug') def test_subject_tag_response(self): "Should set SUBJECT_TAG_RESPONSE global correctly" - generate_global_tags(u"projectX-bug") - self.failUnlessEqual(SUBJECT_TAG_RESPONSE, u"[projectX-bug]") + generate_global_tags(u'projectX-bug') + self.failUnlessEqual(SUBJECT_TAG_RESPONSE, u'[projectX-bug]') def test_subject_tag_new(self): "Should set SUBJECT_TAG_NEW global correctly" - generate_global_tags(u"projectX-bug") - self.failUnlessEqual(SUBJECT_TAG_NEW, u"[projectX-bug:submit]") + generate_global_tags(u'projectX-bug') + self.failUnlessEqual(SUBJECT_TAG_NEW, u'[projectX-bug:submit]') def test_subject_tag_control(self): "Should set SUBJECT_TAG_CONTROL global correctly" - generate_global_tags(u"projectX-bug") - self.failUnlessEqual(SUBJECT_TAG_CONTROL, u"[projectX-bug]") + generate_global_tags(u'projectX-bug') + self.failUnlessEqual(SUBJECT_TAG_CONTROL, u'[projectX-bug]') def test_subject_tag_comment(self): "Should set SUBJECT_TAG_COMMENT global correctly" - generate_global_tags(u"projectX-bug") - m = SUBJECT_TAG_COMMENT.match("[projectX-bug:xyz-123]") + generate_global_tags(u'projectX-bug') + m = SUBJECT_TAG_COMMENT.match('[projectX-bug:xyz-123]') self.failUnlessEqual(len(m.groups()), 1) - self.failUnlessEqual(m.group(1), u"xyz-123") - def test_subject_tag_xml(self): - "Should set SUBJECT_TAG_XML global correctly" - generate_global_tags(u"projectX-bug") - self.failUnlessEqual(SUBJECT_TAG_XML, u"[projectX-bug:xml]") + self.failUnlessEqual(m.group(1), u'xyz-123') if __name__ == "__main__": main(sys.argv) diff --git a/interfaces/email/interactive/becommands b/interfaces/email/interactive/becommands deleted file mode 120000 index 8af773c..0000000 --- a/interfaces/email/interactive/becommands +++ /dev/null @@ -1 +0,0 @@ -../../../becommands
\ No newline at end of file diff --git a/interfaces/gui/beg/beg b/interfaces/gui/beg/beg deleted file mode 100755 index 55e537d..0000000 --- a/interfaces/gui/beg/beg +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -import table -from Tkinter import * -from libbe import bugdir - -tk = Tk() -Label(tk, text="Bug list").pack() -mlb = table.MultiListbox(tk, (('Severity', 4), ('Creator', 8), ('Summary', 40))) -for bug in [b for b in bugdir.tree_root(".").list() if b.active]: - mlb.insert(END, (bug.severity, bug.creator, bug.summary)) -mlb.pack(expand=YES,fill=BOTH) -tk.mainloop() diff --git a/interfaces/gui/beg/table.py b/interfaces/gui/beg/table.py deleted file mode 100644 index 2865f28..0000000 --- a/interfaces/gui/beg/table.py +++ /dev/null @@ -1,97 +0,0 @@ -from Tkinter import * - -class MultiListbox(Frame): - def __init__(self, master, lists): - Frame.__init__(self, master) - self.lists = [] - for l,w in lists: - frame = Frame(self); frame.pack(side=LEFT, expand=YES, fill=BOTH) - Label(frame, text=l, borderwidth=1, relief=RAISED).pack(fill=X) - lb = Listbox(frame, width=w, borderwidth=0, selectborderwidth=0, - relief=FLAT, exportselection=FALSE) - lb.pack(expand=YES, fill=BOTH) - self.lists.append(lb) - lb.bind('<B1-Motion>', lambda e, s=self: s._select(e.y)) - lb.bind('<Button-1>', lambda e, s=self: s._select(e.y)) - lb.bind('<Leave>', lambda e: 'break') - lb.bind('<B2-Motion>', lambda e, s=self: s._b2motion(e.x, e.y)) - lb.bind('<Button-2>', lambda e, s=self: s._button2(e.x, e.y)) - frame = Frame(self); frame.pack(side=LEFT, fill=Y) - Label(frame, borderwidth=1, relief=RAISED).pack(fill=X) - sb = Scrollbar(frame, orient=VERTICAL, command=self._scroll) - sb.pack(expand=YES, fill=Y) - self.lists[0]['yscrollcommand']=sb.set - - def _select(self, y): - row = self.lists[0].nearest(y) - self.selection_clear(0, END) - self.selection_set(row) - return 'break' - - def _button2(self, x, y): - for l in self.lists: l.scan_mark(x, y) - return 'break' - - def _b2motion(self, x, y): - for l in self.lists: l.scan_dragto(x, y) - return 'break' - - def _scroll(self, *args): - for l in self.lists: - apply(l.yview, args) - - def curselection(self): - return self.lists[0].curselection() - - def delete(self, first, last=None): - for l in self.lists: - l.delete(first, last) - - def get(self, first, last=None): - result = [] - for l in self.lists: - result.append(l.get(first,last)) - if last: return apply(map, [None] + result) - return result - - def index(self, index): - self.lists[0].index(index) - - def insert(self, index, *elements): - for e in elements: - i = 0 - for l in self.lists: - l.insert(index, e[i]) - i = i + 1 - - def size(self): - return self.lists[0].size() - - def see(self, index): - for l in self.lists: - l.see(index) - - def selection_anchor(self, index): - for l in self.lists: - l.selection_anchor(index) - - def selection_clear(self, first, last=None): - for l in self.lists: - l.selection_clear(first, last) - - def selection_includes(self, index): - return self.lists[0].selection_includes(index) - - def selection_set(self, first, last=None): - for l in self.lists: - l.selection_set(first, last) - -if __name__ == '__main__': - tk = Tk() - Label(tk, text='MultiListbox').pack() - mlb = MultiListbox(tk, (('Subject', 40), ('Sender', 20), ('Date', 10))) - for i in range(1000): - mlb.insert(END, ('Important Message: %d' % i, 'John Doe', '10/10/%04d' % (1900+i))) - mlb.pack(expand=YES,fill=BOTH) - tk.mainloop() - diff --git a/interfaces/gui/wxbe/wxbe b/interfaces/gui/wxbe/wxbe deleted file mode 100755 index e71ae0c..0000000 --- a/interfaces/gui/wxbe/wxbe +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env python -import wx -from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin -import sys, os.path -from libbe import bugdir, names -from libbe.bug import cmp_status, cmp_severity, cmp_time, cmp_full - -class MyApp(wx.App): - def OnInit(self): - frame = BugListFrame(None, title="Bug List") - frame.Show(True) - self.SetTopWindow(frame) - return True - -class BugListFrame(wx.Frame): - def __init__(self, *args, **kwargs): - wx.Frame.__init__(self, *args, **kwargs) - bugs = BugList(self) - - # Widgets to display/sort/edit will go in this panel - # for now it is just a placeholder - panel = wx.Panel(self) - panel.SetBackgroundColour("RED") - - vbox = wx.BoxSizer(wx.VERTICAL) - vbox.Add(panel, 0, wx.EXPAND) - vbox.Add(bugs, 1, wx.EXPAND) - - self.SetAutoLayout(True) - self.SetSizer(vbox) - self.Layout() - -class BugList(wx.ListCtrl, ListCtrlAutoWidthMixin): - def __init__(self, parent): - wx.ListCtrl.__init__(self, parent, - style=wx.LC_REPORT) - ListCtrlAutoWidthMixin.__init__(self) - - self.bugdir = bugdir.tree_root(".") - self.buglist = list(self.bugdir.list()) - self.buglist.sort() - self.columns = ("id", "status", "severity", "summary") - - dataIndex = 0 - for x in range(len(self.columns)): - self.InsertColumn(x, self.columns[x].capitalize()) - self.SetColumnWidth(x, wx.LIST_AUTOSIZE_USEHEADER) - for bug in [b for b in self.buglist if b.active]: - name = names.unique_name(bug, self.buglist) - id = self.InsertStringItem(self.GetItemCount(), name) - self.SetStringItem(id, 1, bug.status) - self.SetStringItem(id, 2, bug.severity) - self.SetStringItem(id, 3, bug.summary) - self.SetItemData(id, dataIndex) # set keys for each line - dataIndex += 1 - self.EnsureVisible(id) - for x in range(len(self.columns)): - self.SetColumnWidth(x, wx.LIST_AUTOSIZE) - conts_width = self.GetColumnWidth(x) - self.SetColumnWidth(x, wx.LIST_AUTOSIZE_USEHEADER) - if conts_width > self.GetColumnWidth(x): - self.SetColumnWidth(x, conts_width) - - self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColumnClick) - self.bugcmp_fn = cmp_full - # For reasons I don't understant, sorting is broken... - #self.SortItems(self.Sorter) - #self.Refresh() - def Sorter(self, key1, key2): - """Get bug info from the keys and pass to self.bugcmp_fn""" - bug1 = self.buglist[key1-1] - bug2 = self.buglist[key2-1] - # Another way of getting bug information - #bug1uuid = self.GetItem(key1, 0).GetText() - #bug2uuid = self.GetItem(key2, 0).GetText() - #print bug1uuid, bug2uuid - #bug1 = self.bugdir.get_bug(bug1uuid) - #bug2 = self.bugdir.get_bug(bug1uuid) - print self.bugcmp_fn(bug1,bug2) - return self.bugcmp_fn(bug1,bug2) - def OnColumnClick(self, event): - """Resort bug list depending on which column was clicked""" - print "TODO: sort by column %d" % event.Column - # change self.bugcmp_fn and resort, but I can't get it working - -app = MyApp() -app.MainLoop() diff --git a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/SOURCES.txt b/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/SOURCES.txt deleted file mode 100644 index def18b1..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/SOURCES.txt +++ /dev/null @@ -1,36 +0,0 @@ -README.txt -setup.py -start-beweb.py -Bugs-Everywhere-Web.egg-info/PKG-INFO -Bugs-Everywhere-Web.egg-info/SOURCES.txt -Bugs-Everywhere-Web.egg-info/not-zip-safe -Bugs-Everywhere-Web.egg-info/requires.txt -Bugs-Everywhere-Web.egg-info/sqlobject.txt -Bugs-Everywhere-Web.egg-info/top_level.txt -beweb/__init__.py -beweb/config.py -beweb/controllers.py -beweb/formatting.py -beweb/model.py -beweb/prest.py -beweb/release.py -beweb/config/__init__.py -beweb/templates/__init__.py -beweb/tests/__init__.py -beweb/tests/test_controllers.py -beweb/tests/test_model.py -libbe/__init__.py -libbe/arch.py -libbe/bugdir.py -libbe/bzr.py -libbe/cmdutil.py -libbe/config.py -libbe/diff.py -libbe/mapfile.py -libbe/names.py -libbe/no_rcs.py -libbe/plugin.py -libbe/rcs.py -libbe/restconvert.py -libbe/tests.py -libbe/utility.py diff --git a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/not-zip-safe b/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/not-zip-safe deleted file mode 100644 index e69de29..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/not-zip-safe +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/requires.txt b/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/requires.txt deleted file mode 100644 index 88b15cb..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/requires.txt +++ /dev/null @@ -1 +0,0 @@ -TurboGears >= 0.9a4
\ No newline at end of file diff --git a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/sqlobject.txt b/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/sqlobject.txt deleted file mode 100644 index 7f7cbad..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/sqlobject.txt +++ /dev/null @@ -1,2 +0,0 @@ -db_module=beweb.model -history_dir=$base/beweb/sqlobject-history diff --git a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/top_level.txt b/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/top_level.txt deleted file mode 100644 index 6455be9..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/top_level.txt +++ /dev/null @@ -1,2 +0,0 @@ -beweb -libbe diff --git a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/PKG-INFO b/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/PKG-INFO deleted file mode 100644 index 6cb6ad2..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/PKG-INFO +++ /dev/null @@ -1,15 +0,0 @@ -Metadata-Version: 1.0 -Name: Bugs-Everywhere-Web -Version: 1.0 -Summary: UNKNOWN -Home-page: UNKNOWN -Author: UNKNOWN -Author-email: UNKNOWN -License: UNKNOWN -Description: UNKNOWN -Platform: UNKNOWN -Classifier: Development Status :: 3 - Alpha -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Framework :: TurboGears diff --git a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/SOURCES.txt b/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/SOURCES.txt deleted file mode 100644 index ab62ee4..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/SOURCES.txt +++ /dev/null @@ -1,44 +0,0 @@ -README.txt -setup.py -start-beweb.py -Bugs_Everywhere_Web.egg-info/PKG-INFO -Bugs_Everywhere_Web.egg-info/SOURCES.txt -Bugs_Everywhere_Web.egg-info/dependency_links.txt -Bugs_Everywhere_Web.egg-info/not-zip-safe -Bugs_Everywhere_Web.egg-info/paster_plugins.txt -Bugs_Everywhere_Web.egg-info/requires.txt -Bugs_Everywhere_Web.egg-info/sqlobject.txt -Bugs_Everywhere_Web.egg-info/top_level.txt -Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/SOURCES.txt -Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/not-zip-safe -Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/requires.txt -Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/sqlobject.txt -Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/top_level.txt -beweb/__init__.py -beweb/config.py -beweb/controllers.py -beweb/formatting.py -beweb/json.py -beweb/model.py -beweb/prest.py -beweb/release.py -beweb/config/__init__.py -beweb/templates/__init__.py -beweb/tests/__init__.py -beweb/tests/test_controllers.py -beweb/tests/test_model.py -libbe/__init__.py -libbe/arch.py -libbe/bugdir.py -libbe/bzr.py -libbe/cmdutil.py -libbe/config.py -libbe/diff.py -libbe/mapfile.py -libbe/names.py -libbe/no_rcs.py -libbe/plugin.py -libbe/rcs.py -libbe/restconvert.py -libbe/tests.py -libbe/utility.py diff --git a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/dependency_links.txt b/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/not-zip-safe b/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/not-zip-safe deleted file mode 100644 index 8b13789..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/not-zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/paster_plugins.txt b/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/paster_plugins.txt deleted file mode 100644 index 14fec70..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/paster_plugins.txt +++ /dev/null @@ -1,2 +0,0 @@ -TurboGears -PasteScript diff --git a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/requires.txt b/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/requires.txt deleted file mode 100644 index 5fd6f71..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/requires.txt +++ /dev/null @@ -1 +0,0 @@ -TurboGears >= 1.0b1
\ No newline at end of file diff --git a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/sqlobject.txt b/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/sqlobject.txt deleted file mode 100644 index 7f7cbad..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/sqlobject.txt +++ /dev/null @@ -1,2 +0,0 @@ -db_module=beweb.model -history_dir=$base/beweb/sqlobject-history diff --git a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/top_level.txt b/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/top_level.txt deleted file mode 100644 index 74a8358..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -beweb diff --git a/interfaces/web/Bugs-Everywhere-Web/README b/interfaces/web/Bugs-Everywhere-Web/README deleted file mode 100644 index c152757..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/README +++ /dev/null @@ -1,60 +0,0 @@ -Using BeWeb, the web UI -======================= -BeWeb uses the Turbogears framework: http://www.turbogears.org/ -Please ensure you have Turbogears 0.8a5 or a compatible release installed. -Because it uses BE data, the web UI does not require a database. - -To use BeWeb, first create a configuration file, telling it which projects -to track, and what to call them. An example configuration file -(beweb/beweb/config.py.example) is provided. - -Next, cd to this directory, and run ./start-beweb.py - -BeWeb allows you to create, view and edit bugs, but it is in an early stage of -development, so some features are missing. - -Configuration file ------------------- - -Configure by creating an appropriate beweb/config.py from -beweb/config.py.example. The server will edit the repositories that -it manages, so you should probably have it running on a seperate -branch than your working repository. You can then merge/push -as you require to keep the branches in sync. - -See - http://docs.turbogears.org/1.0/Configuration -For standard turbogears configuration information. - -Actions -------- - -Currently, you need to login for any methods with a -@identity.require() decorator. The only group in the current -implementation is 'editbugs'. Basically, anyone can browse around, -but only registered 'editbugs' members can change things. - -Anonymous actions: - * See project tree - * See buglist - * See comments -Editbugs required actions: - * Create new comments - * Reply to comments - * Update comment info - -Users ------ - -All login attempts will fail unless you have added some valid users. See - http://docs.turbogears.org/1.0/GettingStartedWithIdentity -For a good intro. For the impatient, try something like - Bugs-Everywhere-Web$ tg-admin toolbox - browse to 'CatWalk' -> 'User' -> 'Add User+' -or - Bugs-Everywhere-Web$ tg-admin sholl - >>> u = User(user_name=u'jdoe', email_address=u'jdoe@example.com', - display_name=u'Jane Doe', password=u'xxx') - >>> g = Group(group_name=u'editbugs', display_name=u'Edit Bugs') - >>> g.addUser(u) # BE-Web uses SQLObject -Exit the tg-admin shell with Ctrl-Z on MS Windows, Ctrl-D on other systems. diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/__init__.py b/interfaces/web/Bugs-Everywhere-Web/beweb/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/__init__.py +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/app.cfg b/interfaces/web/Bugs-Everywhere-Web/beweb/app.cfg deleted file mode 100644 index 024fa8a..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/app.cfg +++ /dev/null @@ -1,120 +0,0 @@ -[global] -# The settings in this file should not vary depending on the deployment -# environment. devcfg.py and prodcfg.py are the locations for -# the different deployment settings. Settings in this file will -# be overridden by settings in those other files. - -# The commented out values below are the defaults - -# VIEW - -# which view (template engine) to use if one is not specified in the -# template name -# tg.defaultview = "kid" - -# kid.outputformat="html" -# kid.encoding="utf-8" - -# The sitetemplate is used for overall styling of a site that -# includes multiple TurboGears applications -# tg.sitetemplate="<packagename.templates.templatename>" - -# Allow every exposed function to be called as json, -# tg.allow_json = False - -# Set to True if you'd like all of your pages to include MochiKit -# tg.mochikit_all = False - -# VISIT TRACKING -# Each visit to your application will be assigned a unique visit ID tracked via -# a cookie sent to the visitor's browser. -# -------------- - -# Enable Visit tracking -visit.on=True - -# Number of minutes a visit may be idle before it expires. -# visit.timeout=20 - -# The name of the cookie to transmit to the visitor's browser. -# visit.cookie.name="tg-visit" - -# Domain name to specify when setting the cookie (must begin with . according to -# RFC 2109). The default (None) should work for most cases and will default to -# the machine to which the request was made. NOTE: localhost is NEVER a valid -# value and will NOT WORK. -# visit.cookie.domain=None - -# Specific path for the cookie -# visit.cookie.path="/" - -# The name of the VisitManager plugin to use for visitor tracking. -# visit.manager="sqlobject" - - -# IDENTITY -# General configuration of the TurboGears Identity management module -# -------- - -# Switch to turn on or off the Identity management module -identity.on=True - -# [REQUIRED] URL to which CherryPy will internally redirect when an access -# control check fails. If Identity management is turned on, a value for this -# option must be specified. -identity.failure_url="/login" - -# The IdentityProvider to use -- defaults to the SqlObjectIdentityProvider which -# pulls User, Group, and Permission data out of your model database. -identity.provider="sqlobject" - -# The names of the fields on the login form containing the visitor's user ID -# and password. In addition, the submit button is specified simply so its -# existence may be stripped out prior to passing the form data to the target -# controller. -identity.form.user_name="user_name" -identity.form.password="password" -identity.form.submit="login" - -# What sources should the identity provider consider when determining the -# identity associated with a request? Comma separated list of identity sources. -# Valid sources: form, visit, http_auth -identity.source="form,http_auth,visit" - - -# SqlObjectIdentityProvider -# Configuration options for the default IdentityProvider -# ------------------------- - -# The classes you wish to use for your Identity model. Leave these commented out -# to use the default classes for SqlObjectIdentityProvider. Or set them to the -# classes in your model. NOTE: These aren't TG_* because the TG prefix is -# reserved for classes created by TurboGears. -# identity.soprovider.model.user="beweb.model.User" -# identity.soprovider.model.group="beweb.model.Group" -# identity.soprovider.model.permission="beweb.model.Permission" - -# The password encryption algorithm used when comparing passwords against what's -# stored in the database. Valid values are 'md5' or 'sha1'. If you do not -# specify an encryption algorithm, passwords are expected to be clear text. -# -# The SqlObjectProvider *will* encrypt passwords supplied as part of your login -# form. If you set the password through the password property, like: -# my_user.password = 'secret' -# the password will be encrypted in the database, provided identity is up and -# running, or you have loaded the configuration specifying what encryption to -# use (in situations where identity may not yet be running, like tests). - -# identity.soprovider.encryption_algorithm=None - -[/static] -static_filter.on = True -static_filter.dir = "." - -[/favicon.ico] -static_filter.on = True -static_filter.file = "images/favicon.ico" - -[/] -decodingFilter.on = True -static_filter.root = '%(package_dir)s/static' diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/config.py.example b/interfaces/web/Bugs-Everywhere-Web/beweb/config.py.example deleted file mode 100644 index 8745c6d..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/config.py.example +++ /dev/null @@ -1,10 +0,0 @@ -# This is an example beweb configuration file. - -# One thing we need is a map of projects. Projects have a beweb ID, a path, -# and a display name. - -# In this example, the 'be' beweb ID is assigned the display name "Bugs -# Everywhere" and the path "/home/abentley/be" - -projects = {"be": ("Bugs Everywhere","/home/abentley/be"), - } diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/config/app.cfg b/interfaces/web/Bugs-Everywhere-Web/beweb/config/app.cfg deleted file mode 100644 index 15555b7..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/config/app.cfg +++ /dev/null @@ -1,92 +0,0 @@ -[global] -# The settings in this file should not vary depending on the deployment -# environment. dev.cfg and prod.cfg are the locations for -# the different deployment settings. Settings in this file will -# be overridden by settings in those other files. - -# The commented out values below are the defaults - -# VIEW - -# which view (template engine) to use if one is not specified in the -# template name -# tg.defaultview = "kid" - -# The following kid settings determine the settings used by the kid serializer. - -# One of (html|xml|json) -# kid.outputformat="html" - -# kid.encoding="utf-8" - -# The sitetemplate is used for overall styling of a site that -# includes multiple TurboGears applications -# tg.sitetemplate="<packagename.templates.templatename>" - -# Allow every exposed function to be called as json, -# tg.allow_json = False - -# List of Widgets to include on every page. -# for exemple ['turbogears.mochikit'] -# tg.include_widgets = [] - -# Set to True if the scheduler should be started -# tg.scheduler = False - -# IDENTITY -# General configuration of the TurboGears Identity management module -# -------- - -# Switch to turn on or off the Identity management module -identity.on=True - -# [REQUIRED] URL to which CherryPy will internally redirect when an access -# control check fails. If Identity management is turned on, a value for this -# option must be specified. -identity.failure_url="/login" - -# identity.provider='sqlobject' - -# The names of the fields on the login form containing the visitor's user ID -# and password. In addition, the submit button is specified simply so its -# existence may be stripped out prior to passing the form data to the target -# controller. -# identity.form.user_name="user_name" -# identity.form.password="password" -# identity.form.submit="login" - -# What sources should the identity provider consider when determining the -# identity associated with a request? Comma separated list of identity sources. -# Valid sources: form, visit, http_auth -# identity.source="form,http_auth,visit" - -# SqlObjectIdentityProvider -# Configuration options for the default IdentityProvider -# ------------------------- - -# The classes you wish to use for your Identity model. Remember to not use reserved -# SQL keywords for class names (at least unless you specify a different table -# name using sqlmeta). -identity.soprovider.model.user="stfa.model.User" -identity.soprovider.model.group="stfa.model.Group" -identity.soprovider.model.permission="stfa.model.Permission" - -# The password encryption algorithm used when comparing passwords against what's -# stored in the database. Valid values are 'md5' or 'sha1'. If you do not -# specify an encryption algorithm, passwords are expected to be clear text. -# The SqlObjectProvider *will* encrypt passwords supplied as part of your login -# form. If you set the password through the password property, like: -# my_user.password = 'secret' -# the password will be encrypted in the database, provided identity is up and -# running, or you have loaded the configuration specifying what encryption to -# use (in situations where identity may not yet be running, like tests). - -# identity.soprovider.encryption_algorithm=None - -[/static] -static_filter.on = True -static_filter.dir = "%(top_level_dir)s/static" - -[/favicon.ico] -static_filter.on = True -static_filter.file = "%(top_level_dir)s/static/images/favicon.ico" diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/config/log.cfg b/interfaces/web/Bugs-Everywhere-Web/beweb/config/log.cfg deleted file mode 100644 index ce776f8..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/config/log.cfg +++ /dev/null @@ -1,29 +0,0 @@ -# LOGGING -# Logging is often deployment specific, but some handlers and -# formatters can be defined here. - -[logging] -[[formatters]] -[[[message_only]]] -format='*(message)s' - -[[[full_content]]] -format='*(asctime)s *(name)s *(levelname)s *(message)s' - -[[handlers]] -[[[debug_out]]] -class='StreamHandler' -level='DEBUG' -args='(sys.stdout,)' -formatter='full_content' - -[[[access_out]]] -class='StreamHandler' -level='INFO' -args='(sys.stdout,)' -formatter='message_only' - -[[[error_out]]] -class='StreamHandler' -level='ERROR' -args='(sys.stdout,)' diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/controllers.py b/interfaces/web/Bugs-Everywhere-Web/beweb/controllers.py deleted file mode 100644 index 50cc754..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/controllers.py +++ /dev/null @@ -1,240 +0,0 @@ -import logging - -import cherrypy -import turbogears -from turbogears import controllers, expose, validate, redirect, identity - -from libbe.bugdir import tree_root, NoRootEntry -from config import projects -from prest import PrestHandler, provide_action - - -from beweb import json - -log = logging.getLogger("beweb.controllers") - -def project_tree(project): - try: - return tree_root(projects[project][1]) - except KeyError: - raise Exception("Unknown project %s" % project) - -def comment_url(project, bug, comment, **kwargs): - return turbogears.url("/project/%s/bug/%s/comment/%s" % - (project, bug, comment), kwargs) - -class Comment(PrestHandler): - @identity.require( identity.has_permission("editbugs")) - @provide_action("action", "New comment") - def new_comment(self, comment_data, comment, *args, **kwargs): - bug_tree = project_tree(comment_data['project']) - bug = bug_tree.get_bug(comment_data['bug']) - comment = new_comment(bug, "") - comment.From = identity.current.user.userId - comment.content_type = "text/restructured" - comment.save() - raise cherrypy.HTTPRedirect(comment_url(comment=comment.uuid, - **comment_data)) - - @identity.require( identity.has_permission("editbugs")) - @provide_action("action", "Reply") - def reply_comment(self, comment_data, comment, *args, **kwargs): - bug_tree = project_tree(comment_data['project']) - bug = bug_tree.get_bug(comment_data['bug']) - reply_comment = new_comment(bug, "") - reply_comment.From = identity.current.user.userId - reply_comment.in_reply_to = comment.uuid - reply_comment.save() - reply_data = dict(comment_data) - del reply_data["comment"] - raise cherrypy.HTTPRedirect(comment_url(comment=reply_comment.uuid, - **reply_data)) - - @identity.require( identity.has_permission("editbugs")) - @provide_action("action", "Update") - def update(self, comment_data, comment, comment_body, *args, **kwargs): - comment.body = comment_body - comment.save() - raise cherrypy.HTTPRedirect(bug_url(comment_data['project'], - comment_data['bug'])) - - def instantiate(self, project, bug, comment): - bug_tree = project_tree(project) - bug = bug_tree.get_bug(bug) - return bug.get_comment(comment) - - def dispatch(self, comment_data, comment, *args, **kwargs): - return self.edit_comment(comment_data['project'], comment) - - @turbogears.expose(html="beweb.templates.edit_comment") - def edit_comment(self, project, comment): - return {"comment": comment, "project_id": project} - -class Bug(PrestHandler): - comment = Comment() - @turbogears.expose(html="beweb.templates.edit_bug") - def index(self, project, bug): - return {"bug": bug, "project_id": project} - - def dispatch(self, bug_data, bug, *args, **kwargs): - if bug is None: - return self.list(bug_data['project'], **kwargs) - else: - return self.index(bug_data['project'], bug) - - @turbogears.expose(html="beweb.templates.bugs") - def list(self, project, sort_by=None, show_closed=False, action=None, - search=None): - if action == "New bug": - self.new_bug() - if show_closed == "False": - show_closed = False - bug_tree = project_tree(project) - bugs = list(bug_tree.list()) - if sort_by is None: - bugs.sort() - return {"project_id" : project, - "project_name" : projects[project][0], - "bugs" : bugs, - "show_closed" : show_closed, - "search" : search, - } - - @identity.require( identity.has_permission("editbugs")) - @provide_action("action", "New bug") - def new_bug(self, bug_data, bug, **kwargs): - bug = project_tree(bug_data['project']).new_bug() - bug.creator = identity.current.user.userId - bug.save() - raise cherrypy.HTTPRedirect(bug_url(bug_data['project'], bug.uuid)) - - @identity.require( identity.has_permission("editbugs")) - @provide_action("action", "Update") - def update(self, bug_data, bug, status, severity, summary, assigned, - action): - bug.status = status - bug.severity = severity - bug.summary = summary - if assigned == "": - assigned = None - bug.assigned = assigned - bug.save() -# bug.vcs.precommit(bug.path) -# bug.vcs.commit(bug.path, "Auto-commit") -# bug.vcs.postcommit(bug.path) - raise cherrypy.HTTPRedirect(bug_list_url(bug_data["project"])) - - def instantiate(self, project, bug): - return project_tree(project).get_bug(bug) - - @provide_action("action", "New comment") - def new_comment(self, bug_data, bug, *args, **kwargs): - try: - self.update(bug_data, bug, *args, **kwargs) - except cherrypy.HTTPRedirect: - pass - return self.comment.new_comment(bug_data, comment=None, *args, - **kwargs) - - -def project_url(project_id=None): - project_url = "/project/" - if project_id is not None: - project_url += "%s/" % project_id - return turbogears.url(project_url) - -def bug_url(project_id, bug_uuid=None): - bug_url = "/project/%s/bug/" % project_id - if bug_uuid is not None: - bug_url += "%s/" % bug_uuid - return turbogears.url(bug_url) - -def bug_list_url(project_id, show_closed=False, search=None): - bug_url = "/project/%s/bug/?show_closed=%s" % (project_id, - str(show_closed)) - if search is not None: - bug_url = "%s&search=%s" % (bug_url, search) - return turbogears.url(str(bug_url)) - - -class Project(PrestHandler): - bug = Bug() - @turbogears.expose(html="beweb.templates.projects") - def dispatch(self, project_data, project, *args, **kwargs): - if project is not None: - raise cherrypy.HTTPRedirect(bug_url(project)) - else: - return {"projects": projects} - - def instantiate(self, project): - return project - - -class Root(controllers.Root): - prest = PrestHandler() - prest.project = Project() - @turbogears.expose() - def index(self): - raise cherrypy.HTTPRedirect(project_url()) - - @expose(template="beweb.templates.login") - def login(self, forward_url=None, previous_url=None, *args, **kw): - - if not identity.current.anonymous and identity.was_login_attempted(): - raise redirect(forward_url) - - forward_url=None - previous_url= cherrypy.request.path - - if identity.was_login_attempted(): - msg=_("The credentials you supplied were not correct or "\ - "did not grant access to this resource.") - elif identity.get_identity_errors(): - msg=_("You must provide your credentials before accessing "\ - "this resource.") - else: - msg=_("Please log in.") - forward_url= cherrypy.request.headers.get("Referer", "/") - cherrypy.response.status=403 - return dict(message=msg, previous_url=previous_url, logging_in=True, - original_parameters=cherrypy.request.params, - forward_url=forward_url) - - @expose() - def logout(self): - identity.current.logout() - raise redirect("/") - - @turbogears.expose('beweb.templates.about') - def about(self, *paths, **kwargs): - return {} - - @turbogears.expose() - def default(self, *args, **kwargs): - return self.prest.default(*args, **kwargs) - - def _cp_on_error(self): - import traceback, StringIO - bodyFile = StringIO.StringIO() - traceback.print_exc(file = bodyFile) - trace_text = bodyFile.getvalue() - try: - raise - except cherrypy.NotFound: - self.handle_error('Not Found', str(e), trace_text, '404 Not Found') - - except NoRootEntry, e: - self.handle_error('Project Misconfiguration', str(e), trace_text) - - except Exception, e: - self.handle_error('Internal server error', str(e), trace_text) - - def handle_error(self, heading, body, traceback=None, - status='500 Internal Server Error'): - cherrypy.response.headerMap['Status'] = status - cherrypy.response.body = [self.errorpage(heading, body, traceback)] - - - @turbogears.expose(html='beweb.templates.error') - def errorpage(self, heading, body, traceback): - return {'heading': heading, 'body': body, 'traceback': traceback} diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/formatting.py b/interfaces/web/Bugs-Everywhere-Web/beweb/formatting.py deleted file mode 100644 index 1278414..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/formatting.py +++ /dev/null @@ -1,76 +0,0 @@ -from StringIO import StringIO - -try : - from xml.etree.ElementTree import XML # Python 2.5 (and greater?) -except ImportError : - from elementtree.ElementTree import XML -from libbe.restconvert import rest_xml - -def to_unix(text): - skip_newline = False - for ch in text: - if ch not in ('\r', '\n'): - yield ch - else: - if ch == '\n': - if skip_newline: - continue - else: - skip_newline = True - yield '\n' - - -def soft_text(text): - first_space = False - translations = {'\n': '<br />\n', '&': '&', '\x3c': '<', - '\x3e': '>'} - for ch in to_unix(text): - if ch == ' ' and first_space is True: - yield ' ' - first_space = ch in (' ') - try: - yield translations[ch] - except KeyError: - yield ch - - -def soft_pre(text): - return XML('<div style="font-family: monospace">'+ - ''.join(soft_text(text)).encode('utf-8')+'</div>') - - -def get_rest_body(rest): - xml, warnings = rest_xml(StringIO(rest)) - return xml.find('{http://www.w3.org/1999/xhtml}body'), warnings - - -def comment_body_xhtml(comment): - if comment.content_type == "text/restructured": - return get_rest_body(comment.body)[0] - else: - return soft_pre(comment.body) - - -def select_among(name, options, default, display_names=None): - output = ['<select name="%s">' % name] - for option in options: - if option == default: - selected = ' selected="selected"' - else: - selected = "" - if display_names is None: - display_name = None - else: - display_name = display_names.get(option) - - if option is None: - option = "" - if display_name is None: - display_name = option - value = "" - else: - value = ' value="%s"' % option - output.append("<option%s%s>%s</option>" % (selected, value, - display_name)) - output.append("</select>") - return XML("".join(output)) diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/json.py b/interfaces/web/Bugs-Everywhere-Web/beweb/json.py deleted file mode 100644 index 6e100c3..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/json.py +++ /dev/null @@ -1,13 +0,0 @@ -# This module provides helper functions for the JSON part of your -# view, if you are providing a JSON-based API for your app. - -# Here's what most rules would look like: -# @jsonify.when("isinstance(obj, YourClass)") -# def jsonify_yourclass(obj): -# return [obj.val1, obj.val2] -# -# The goal is to break your objects down into simple values: -# lists, dicts, numbers and strings - -from turbojson.jsonify import jsonify - diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/model.py b/interfaces/web/Bugs-Everywhere-Web/beweb/model.py deleted file mode 100644 index aa4b6b6..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/model.py +++ /dev/null @@ -1,107 +0,0 @@ -from datetime import datetime - -from sqlobject import * -from turbogears.database import PackageHub -from turbogears import identity - -hub = PackageHub("beweb") -__connection__ = hub - -class Visit(SQLObject): - class sqlmeta: - table = "visit" - - visit_key = StringCol(length=40, alternateID=True, - alternateMethodName="by_visit_key") - created = DateTimeCol(default=datetime.now) - expiry = DateTimeCol() - - def lookup_visit(cls, visit_key): - try: - return cls.by_visit_key(visit_key) - except SQLObjectNotFound: - return None - lookup_visit = classmethod(lookup_visit) - -class VisitIdentity(SQLObject): - visit_key = StringCol(length=40, alternateID=True, - alternateMethodName="by_visit_key") - user_id = IntCol() - - -class Group(SQLObject): - """ - An ultra-simple group definition. - """ - - # names like "Group", "Order" and "User" are reserved words in SQL - # so we set the name to something safe for SQL - class sqlmeta: - table = "tg_group" - - group_name = UnicodeCol(length=16, alternateID=True, - alternateMethodName="by_group_name") - display_name = UnicodeCol(length=255) - created = DateTimeCol(default=datetime.now) - - # collection of all users belonging to this group - users = RelatedJoin("User", intermediateTable="user_group", - joinColumn="group_id", otherColumn="user_id") - - # collection of all permissions for this group - permissions = RelatedJoin("Permission", joinColumn="group_id", - intermediateTable="group_permission", - otherColumn="permission_id") - - -class User(SQLObject): - """ - Reasonably basic User definition. Probably would want additional attributes. - """ - # names like "Group", "Order" and "User" are reserved words in SQL - # so we set the name to something safe for SQL - class sqlmeta: - table = "tg_user" - - child_name = UnicodeCol(length=255) - user_name = UnicodeCol(length=16, alternateID=True, - alternateMethodName="by_user_name") - email_address = UnicodeCol(length=255, alternateID=True, - alternateMethodName="by_email_address") - display_name = UnicodeCol(length=255) - password = UnicodeCol(length=40) - created = DateTimeCol(default=datetime.now) - - # groups this user belongs to - groups = RelatedJoin("Group", intermediateTable="user_group", - joinColumn="user_id", otherColumn="group_id") - - def _get_permissions(self): - perms = set() - for g in self.groups: - perms = perms | set(g.permissions) - return perms - - def _set_password(self, cleartext_password): - "Runs cleartext_password through the hash algorithm before saving." - hash = identity.encrypt_password(cleartext_password) - self._SO_set_password(hash) - - def set_password_raw(self, password): - "Saves the password as-is to the database." - self._SO_set_password(password) - - - -class Permission(SQLObject): - permission_name = UnicodeCol(length=16, alternateID=True, - alternateMethodName="by_permission_name") - description = UnicodeCol(length=255) - - groups = RelatedJoin("Group", - intermediateTable="group_permission", - joinColumn="permission_id", - otherColumn="group_id") - -def people_map(): - return dict((u.user_name, u.display_name) for u in User.select()) diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/prest.py b/interfaces/web/Bugs-Everywhere-Web/beweb/prest.py deleted file mode 100644 index 9a6505d..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/prest.py +++ /dev/null @@ -1,168 +0,0 @@ -from unittest import TestCase -import unittest -from cherrypy import NotFound -"""A pseudo-REST dispatching method in which only the noun comes from the path. -The action performed will depend on kwargs. -""" - -class AmbiguousAction(Exception): - def __init__(self, actions): - Exception.__init__(self, "Supplied action is ambiguous.") - self.actions = actions - - -def provide_action(name, value): - def provider(func): - func._action_desc = (name, value) - return func - return provider - -class PrestHandler(object): - def __init__(self): - object.__init__(self) - self.actions = {} - for member in (getattr(self, m) for m in dir(self)): - if not hasattr(member, '_action_desc'): - continue - name, value = member._action_desc - if name not in self.actions: - self.actions[name] = {} - self.actions[name][value] = member - - @classmethod - def add_action(klass, name, value, function): - if name not in klass.actions: - klass.actions[name] = {} - klass.actions[name][value] = function - - - def decode(self, path, data=None): - """Convert the path into a handler, a resource, data, and extra_path""" - if data is None: - data = {} - if len(path) < 2 or not (hasattr(self, path[1])): - if len(path) == 0: - resource = None - else: - try: - resource = self.instantiate(**data) - except NotImplementedError, e: - if e.args[0] is not PrestHandler.instantiate: - raise NotFound() - - return self, resource, data, path[1:] - if len(path) > 2: - data[path[1]] = path[2] - return getattr(self, path[1]).decode(path[2:], data) - - def instantiate(self, **date): - raise NotImplementedError(PrestHandler.instantiate) - - def default(self, *args, **kwargs): - child, resource, data, extra = self.decode([None,] + list(args)) - action = child.get_action(**kwargs) - new_args = ([data, resource]+extra) - if action is not None: - return action(*new_args, **kwargs) - else: - return child.dispatch(*new_args, **kwargs) - - def get_action(self, **kwargs): - """Return the action requested by kwargs, if any. - - Raises AmbiguousAction if more than one action matches. - """ - actions = [] - for key in kwargs: - if key in self.actions: - if kwargs[key] in self.actions[key]: - actions.append(self.actions[key][kwargs[key]]) - if len(actions) == 0: - return None - elif len(actions) == 1: - return actions[0] - else: - raise AmbiguousAction(actions) - - -class PrestTester(TestCase): - def test_decode(self): - class ProjectHandler(PrestHandler): - actions = {} - def dispatch(self, project_data, project, *args, **kwargs): - self.project_id = project_data['project'] - self.project_data = project_data - self.resource = project - self.args = args - self.kwargs = kwargs - - def instantiate(self, project): - return [project] - - @provide_action('action', 'Save') - def save(self, project_data, project, *args, **kwargs): - self.action = "save" - - @provide_action('behavior', 'Update') - def update(self, project_data, project, *args, **kwargs): - self.action = "update" - - foo = PrestHandler() - foo.project = ProjectHandler() - handler, resource, data, extra = foo.decode([None, 'project', '83', - 'bloop', 'yeah']) - assert handler is foo.project - self.assertEqual({'project': '83'}, data) - self.assertEqual(['bloop', 'yeah'], extra) - foo.default(*['project', '27', 'extra'], **{'a':'b', 'b':'97'}) - self.assertEqual(foo.project.args, ('extra',)) - self.assertEqual(foo.project.kwargs, {'a':'b', 'b':'97'}) - self.assertEqual(foo.project.project_data, {'project': '27'}) - self.assertEqual(foo.project.resource, ['27']) - foo.default(*['project', '27', 'extra'], **{'action':'Save', 'b':'97'}) - self.assertEqual(foo.project.action, 'save') - foo.default(*['project', '27', 'extra'], - **{'behavior':'Update', 'b':'97'}) - self.assertEqual(foo.project.action, 'update') - self.assertRaises(AmbiguousAction, foo.default, - *['project', '27', 'extra'], - **{'behavior':'Update', 'action':'Save', 'b':'97'}) - - class BugHandler(PrestHandler): - actions = {} - def dispatch(self, bug_data, bug, *args, **kwargs): - self.project_id = project_data['project'] - self.project_data = project_data - self.resource = project - self.args = args - self.kwargs = kwargs - - def instantiate(self, project, bug): - return [project, bug] - - @provide_action('action', 'Save') - def save(self, project_data, project, *args, **kwargs): - self.action = "save" - - @provide_action('behavior', 'Update') - def update(self, project_data, project, *args, **kwargs): - self.action = "update" - - foo.project.bug = BugHandler() - handler, resource, data, extra = foo.decode([None, 'project', '83', - 'bug', '92']) - assert handler is foo.project.bug - self.assertEqual(resource[0], '83') - self.assertEqual(resource[1], '92') - self.assertEqual([], extra) - self.assertEqual(data['project'], '83') - self.assertEqual(data['bug'], '92') - -def test(): - patchesTestSuite = unittest.makeSuite(PrestTester,'test') - runner = unittest.TextTestRunner(verbosity=0) - return runner.run(patchesTestSuite) - - -if __name__ == "__main__": - test() diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/release.py b/interfaces/web/Bugs-Everywhere-Web/beweb/release.py deleted file mode 100644 index 9d64bf7..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/release.py +++ /dev/null @@ -1,14 +0,0 @@ -# Release information about Bugs-Everywhere-Web - -version = "1.0" - -# description = "Your plan to rule the world" -# long_description = "More description about your plan" -# author = "Your Name Here" -# email = "YourEmail@YourDomain" -# copyright = "Vintage 2006 - a good year indeed" - -# if it's open source, you might want to specify these -# url = "http://yourcool.site/" -# download_url = "http://yourcool.site/download" -# license = "MIT" diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/css/style.css b/interfaces/web/Bugs-Everywhere-Web/beweb/static/css/style.css deleted file mode 100644 index 6fe197f..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/css/style.css +++ /dev/null @@ -1,116 +0,0 @@ -table
-{
- background-color: black;
-}
-td
-{
- background-color: white;
-}
-h1
-{
- font-family: "Verdana";
- font-weight: bold;
- font-size: 120%;
- margin-bottom:0;
- color: #990;
-}
-
-tr.closed td
-{
- background-color: #ccc;
-}
-tr.closedeven td
-{
- background-color: #ccc;
-}
-tr.closedodd td
-{
- background-color: #dda;
-}
-
-a:visited, a:link
-{
- color: #990;
- text-decoration: None;
-}
-td a:visited, td a:link
-{
- display: block;
-}
-a:visited:hover, a:link:hover
-{
- text-decoration: underline;
-}
-td a:visited:hover, td a:link:hover
-{
- color:black;
- background-color:#dda;
- text-decoration: None;
- display: block;
-}
-
-body
-{
- font-family: "Verdana";
- font-size:11pt;
- background-color: white;
-}
-.comment
-{
-}
-.comment table
-{
- background-color: transparent;
-}
-.comment td
-{
- background-color: transparent;
-}
-.comment pre
-{
- font-family: "Verdana";
-}
-#header
-{
- color: black;
- font-weight: bold;
- background-image: url(/static/images/half-spiral.png);
- background-position: right center;
- background-repeat: no-repeat;
- background-color: #ff0;
-}
-#header ul.navoption
-{
- display: block;
- float: right;
- margin: 0;
- padding-right: 30px;
-}
-#header li
-{
- display: inline;
- margin:0;
- padding:0;
-}
-table.insetbox
-{
- margin-top: 0.5em;
- margin-bottom: 0.5em;
-}
-.insetbox tr, .insetbox td
-{
- margin: 0;
- padding: 0;
-}
-pre.traceback
-{
- font-family: Verdana, Ariel, Helvetica, sanserif;
-}
-tr.even td
-{
- background-color: #eee;
-}
-tr.odd td
-{
- background-color: #ffe;
-}
diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-b.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-b.png Binary files differdeleted file mode 100644 index 790e438..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-b.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-bl.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-bl.png Binary files differdeleted file mode 100644 index 5b43259..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-bl.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-br.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-br.png Binary files differdeleted file mode 100644 index 6cfd62c..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-br.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-l.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-l.png Binary files differdeleted file mode 100644 index a6ce3ce..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-l.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-r.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-r.png Binary files differdeleted file mode 100644 index 1ffd6f8..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-r.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-t.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-t.png Binary files differdeleted file mode 100644 index 0129b0c..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-t.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-tl.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-tl.png Binary files differdeleted file mode 100644 index d616b77..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-tl.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-tr.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-tr.png Binary files differdeleted file mode 100644 index 18e542e..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-tr.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds2-b.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds2-b.png Binary files differdeleted file mode 100644 index 05a190e..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds2-b.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds2-r.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds2-r.png Binary files differdeleted file mode 100644 index 0c3ea4c..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds2-r.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.ico b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.ico Binary files differdeleted file mode 100644 index 339d09c..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.ico +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.png Binary files differdeleted file mode 100644 index 6dc53ee..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/half-spiral.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/half-spiral.png Binary files differdeleted file mode 100644 index cb4b56c..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/half-spiral.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/header_inner.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/header_inner.png Binary files differdeleted file mode 100644 index 2b2d87d..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/header_inner.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/info.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/info.png Binary files differdeleted file mode 100644 index 329c523..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/info.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-b.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-b.png Binary files differdeleted file mode 100644 index 25d3cfa..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-b.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-bl.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-bl.png Binary files differdeleted file mode 100644 index f496223..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-bl.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-br.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-br.png Binary files differdeleted file mode 100644 index 74cbd91..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-br.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-l.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-l.png Binary files differdeleted file mode 100644 index dd567fa..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-l.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-r.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-r.png Binary files differdeleted file mode 100644 index 9ac4486..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-r.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-t.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-t.png Binary files differdeleted file mode 100644 index fbb06c8..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-t.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-tl.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-tl.png Binary files differdeleted file mode 100644 index 9336290..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-tl.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-tr.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-tr.png Binary files differdeleted file mode 100644 index de74808..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-tr.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ok.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ok.png Binary files differdeleted file mode 100644 index fee6751..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ok.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/shadows.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/shadows.png Binary files differdeleted file mode 100644 index 9ddc676..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/shadows.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/spiral.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/spiral.png Binary files differdeleted file mode 100644 index b4bcb1e..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/spiral.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/tg_under_the_hood.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/tg_under_the_hood.png Binary files differdeleted file mode 100644 index bc9c79c..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/tg_under_the_hood.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/under_the_hood_blue.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/under_the_hood_blue.png Binary files differdeleted file mode 100644 index 90e84b7..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/under_the_hood_blue.png +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/__init__.py b/interfaces/web/Bugs-Everywhere-Web/beweb/templates/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/__init__.py +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/about.kid b/interfaces/web/Bugs-Everywhere-Web/beweb/templates/about.kid deleted file mode 100644 index fa3548a..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/about.kid +++ /dev/null @@ -1,21 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" - py:extends="'master.kid'"> -<head> - <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/> - <title>About Bugs Everywhere</title> -</head> - -<body> -<h1>About Bugs Everywhere</h1> -<p>Bugs Everywhere is a "distributed bugtracker", designed to complement distributed revision control systems. -</p> -<p> -Bugs Everywhere was conceived and written by developers at <a href="http://panoramicfeedback.com/">Panoramic Feedback</a>, primarily Aaron Bentley. <a href="http://panoramicfeedback.com/">Panoramic Feedback</a> is no longer developing BE, and the current maintainer is <a href="http://bugseverywhere.org/be/show/ChrisBall">Chris Ball</a>. -</p> -<p> - Bugs Everywhere <a href="http://bugseverywhere.org/">web site</a> -</p> -<a href="/">Project List</a> -</body> -</html> diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/bugs.kid b/interfaces/web/Bugs-Everywhere-Web/beweb/templates/bugs.kid deleted file mode 100644 index 198aa94..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/bugs.kid +++ /dev/null @@ -1,52 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<?python -from libbe.names import unique_name -from beweb.controllers import bug_url, project_url, bug_list_url -from beweb.model import people_map -people = people_map() -def row_class(bug, num): - if not bug.active is True: - extra = "closed" - else: - extra = "" - if num % 2 == 0: - return extra+"even" - else: - return extra+"odd" - - -def match(bug, show_closed, search): - if not show_closed and not bug.active: - return False - elif search is None: - return True - else: - return search.lower() in bug.summary.lower() -?> -<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" - py:extends="'master.kid'"> - -<head> - <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/> - <title>Bugs for $project_name</title> -</head> - -<body> -<h1>Bug list for ${project_name}</h1> -<table> -<tr><td>ID</td><td>Status</td><td>Severity</td><td>Assigned To</td><td>Comments</td><td>Summary</td></tr> -<div py:for="num, bug in enumerate([b for b in bugs if match(b, show_closed, search)])" py:strip="True"><tr class="${row_class(bug, num)}"><td><a href="${bug_url(project_id, bug.uuid)}">${unique_name(bug, bugs[:])}</a></td><td>${bug.status}</td><td>${bug.severity}</td><td>${people.get(bug.assigned, bug.assigned)}</td><td>${len(list(bug.iter_comment_ids()))}</td><td>${bug.summary}</td></tr> -</div> -</table> -<a href="${project_url()}">Project list</a> -<a href="${bug_list_url(project_id, not show_closed, search)}">Toggle closed</a> -<form action="${bug_list_url(project_id)}" method="post"> -<input type="submit" name="action" value="New bug"/> -</form> -<form action="${bug_list_url(project_id)}" method="get"> -<input type="hidden" name="show_closed" value="False" /> -<input name="search" value="$search"/> -<input type="submit" name="action" value="Search" /> -</form> -</body> -</html> diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/edit_bug.kid b/interfaces/web/Bugs-Everywhere-Web/beweb/templates/edit_bug.kid deleted file mode 100644 index 276f610..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/edit_bug.kid +++ /dev/null @@ -1,52 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<?python -from libbe.bug import severity_values, status_values, thread_comments -from libbe.utility import time_to_str -from beweb.controllers import bug_list_url, comment_url -from beweb.formatting import comment_body_xhtml, select_among -from beweb.model import people_map -people = people_map() -?> -<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" - py:extends="'master.kid'"> - -<head> - <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/> - <title>Edit bug</title> -</head> - -<body> -<h1>Edit bug</h1> -<form method="post" action="."> -<table> -<tr><td>Status</td><td>Severity</td><td>Assigned To</td><td>Summary</td></tr> -<tr><td>${select_among("status", status_values, bug.status)}</td><td>${select_among("severity", severity_values, bug.severity)}</td> -<td>${select_among("assigned", people.keys()+[None], bug.assigned, people)}</td><td><input name="summary" value="${bug.summary}" size="80" /></td></tr> -</table> -<div py:def="show_comment(comment, children)" class="comment"> - <insetbox> - <table> - <tr><td>From</td><td>${comment.From}</td></tr> - <tr><td>Date</td><td>${time_to_str(comment.time)}</td></tr> - </table> - <div py:content="comment_body_xhtml(comment)" py:strip="True"></div> - <a href="${comment_url(project_id, bug.uuid, comment.uuid)}">Edit</a> - <a href="${comment_url(project_id, bug.uuid, comment.uuid, - action='Reply')}">Reply</a> - </insetbox> - <div style="margin-left:20px;"> - <div py:for="child, grandchildren in children" py:strip="True"> - ${show_comment(child, grandchildren)} - </div> - </div> -</div> -<div py:for="comment, children in thread_comments(bug.list_comments())" - py:strip="True"> - ${show_comment(comment, children)} -</div> -<p><input type="submit" name="action" value="Update"/></p> -<p><input type="submit" name="action" value="New comment"/></p> -</form> -<a href="${bug_list_url(project_id)}">Bug List</a> -</body> -</html> diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/edit_comment.kid b/interfaces/web/Bugs-Everywhere-Web/beweb/templates/edit_comment.kid deleted file mode 100644 index 2b522d4..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/edit_comment.kid +++ /dev/null @@ -1,26 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<?python -from libbe.utility import time_to_str -from beweb.controllers import bug_list_url, bug_url -?> -<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" - py:extends="'master.kid'"> - -<head> - <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/> - <title>Edit comment</title> -</head> - -<body> -<h1>Edit comment</h1> -<form method="post"> -<table> - <tr><td>From</td><td>${comment.From}</td></tr> - <tr><td>Date</td><td>${time_to_str(comment.time)}</td></tr> -</table> -<insetbox><textarea rows="15" cols="80" py:content="comment.body" name="comment_body" style="border-style: none"/></insetbox> -<p><input type="submit" name="action" value="Update"/></p> -</form> -<a href="${bug_url(project_id, comment.bug.uuid)}">Up to Bug</a> -</body> -</html> diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/error.kid b/interfaces/web/Bugs-Everywhere-Web/beweb/templates/error.kid deleted file mode 100644 index bc55615..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/error.kid +++ /dev/null @@ -1,14 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" - py:extends="'master.kid'"> -<head> - <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/> - <title>BE Error: ${heading}</title> -</head> - -<body> -<h1 py:content="heading">Error heading</h1> -<div py:replace="body" >Error Body</div> -<pre py:content="traceback" class="traceback">Traceback</pre> -</body> -</html> diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/login.kid b/interfaces/web/Bugs-Everywhere-Web/beweb/templates/login.kid deleted file mode 100644 index e7ad852..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/login.kid +++ /dev/null @@ -1,113 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" - xmlns:py="http://purl.org/kid/ns#" - py:extends="'master.kid'"> - -<head> - <meta content="text/html; charset=UTF-8" - http-equiv="content-type" py:replace="''"/> - <title>Login</title> - <style type="text/css"> - #loginBox - { - width: 30%; - margin: auto; - margin-top: 10%; - padding-left: 10%; - padding-right: 10%; - padding-top: 5%; - padding-bottom: 5%; - font-family: verdana; - font-size: 10px; - background-color: #eee; - border: 2px solid #ccc; - } - - #loginBox h1 - { - font-size: 42px; - font-family: "Trebuchet MS"; - margin: 0; - color: #ddd; - } - - #loginBox p - { - position: relative; - top: -1.5em; - padding-left: 4em; - font-size: 12px; - margin: 0; - color: #666; - } - - #loginBox table - { - table-layout: fixed; - border-spacing: 0; - width: 100%; - } - - #loginBox td.label - { - width: 33%; - text-align: right; - } - - #loginBox td.field - { - width: 66%; - } - - #loginBox td.field input - { - width: 100%; - } - - #loginBox td.buttons - { - text-align: right; - } - - </style> -</head> - -<body> - <div id="loginBox"> - <h1>Login</h1> - <p>${message}</p> - <form action="${previous_url}" method="POST"> - <table> - <tr> - <td class="label"> - <label for="user_name">User Name:</label> - </td> - <td class="field"> - <input type="text" id="user_name" name="user_name"/> - </td> - </tr> - <tr> - <td class="label"> - <label for="password">Password:</label> - </td> - <td class="field"> - <input type="password" id="password" name="password"/> - </td> - </tr> - <tr> - <td colspan="2" class="buttons"> - <input type="submit" name="login" value="Login"/> - </td> - </tr> - </table> - - <input py:if="forward_url" type="hidden" name="forward_url" - value="${forward_url}"/> - - <input py:for="name,value in original_parameters.items()" - type="hidden" name="${name}" value="${value}"/> - </form> - </div> -</body> -</html> diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/master.kid b/interfaces/web/Bugs-Everywhere-Web/beweb/templates/master.kid deleted file mode 100644 index 0772524..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/master.kid +++ /dev/null @@ -1,71 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<?python import sitetemplate ?>
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="sitetemplate">
-
-<head py:match="item.tag=='{http://www.w3.org/1999/xhtml}head'" py:attrs="item.items()">
- <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
- <title py:if="False">Your title goes here</title>
- <link rel="stylesheet" type="text/css" href="/static/css/style.css"/>
- <meta py:replace="item[:]"/>
- <style type="text/css">
- #pageLogin
- {
- font-size: 10px;
- font-family: verdana;
- text-align: right;
- }
- </style>
-</head>
-
-<body py:match="item.tag=='{http://www.w3.org/1999/xhtml}body'" py:attrs="item.items()">
-<div id="header"><div style="float: left">b u g s e v r y w h e r e</div><ul class="navoption"><li><a href="/about/">About</a></li></ul> </div>
- <div py:if="tg.config('identity.on',False) and not 'logging_in' in locals()"
- id="pageLogin">
- <span py:if="tg.identity.anonymous">
- <a href="/login">Login</a>
- </span>
- <span py:if="not tg.identity.anonymous">
- Welcome ${tg.identity.user.display_name}.
- <a href="/logout">Logout</a>
- </span>
- </div>
-
- <div py:if="tg_flash" class="flash" py:content="tg_flash"></div>
-
- <div py:replace="[item.text]+item[:]"/>
-
-<table py:match="item.tag=='{http://www.w3.org/1999/xhtml}insetbox'" cellspacing="0" cellpadding="0" border="0" class="insetbox">
-<tr height="19"><td background="/static/images/is-tl.png" width="19"/>
- <td background="/static/images/is-t.png" />
- <td background="/static/images/is-tr.png" width="11"></td>
-</tr>
-<tr>
- <td background="/static/images/is-l.png"/>
- <td py:content="item[:]"> Hello, this is some random text</td>
- <td background="/static/images/is-r.png"/>
-</tr>
-<tr height="11">
- <td background="/static/images/is-bl.png"/>
- <td background="/static/images/is-b.png" />
- <td background="/static/images/is-br.png"/>
-</tr>
-</table>
-<table py:match="item.tag=='{http://www.w3.org/1999/xhtml}dsbox'" cellspacing="0" cellpadding="0" border="0" class="dsbox">
-<tr height="11"><td background="/static/images/ds-tl.png" width="11"/>
- <td background="/static/images/ds-t.png" />
- <td background="/static/images/ds-tr.png" width="19"></td>
-</tr>
-<tr>
- <td background="/static/images/ds-l.png"/>
- <td py:content="item[:]"> Hello, this is some random text</td>
- <td background="/static/images/ds2-r.png"/>
-</tr>
-<tr height="19">
- <td background="/static/images/ds-bl.png"/>
- <td background="/static/images/ds2-b.png" />
- <td background="/static/images/ds-br.png"/>
-</tr>
-</table>
-</body>
-
-</html>
diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/projects.kid b/interfaces/web/Bugs-Everywhere-Web/beweb/templates/projects.kid deleted file mode 100644 index d5f9fd3..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/projects.kid +++ /dev/null @@ -1,32 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<?python -from libbe.bug import severity_values -def select_among(name, options, default): - output = ['<select name="%s">' % name] - for option in options: - if option == default: - selected = ' selected="selected"' - else: - selected = "" - output.append("<option%s>%s</option>" % (selected, option)) - output.append("</select>") - return XML("".join(output)) -?> -<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" - py:extends="'master.kid'"> -<?python -project_triples = [(pn, pid, pl) for pid,(pn, pl) in projects.iteritems()] -project_triples.sort() -?> -<head> - <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/> - <title>Project List</title> -</head> - -<body> -<h1>Project List</h1> -<table> -<tr py:for="project_name, project_id, project_loc in project_triples"><td><a href="/project/${project_id}/">${project_name}</a></td></tr> -</table> -</body> -</html> diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/welcome.kid b/interfaces/web/Bugs-Everywhere-Web/beweb/templates/welcome.kid deleted file mode 100644 index 08abd21..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/templates/welcome.kid +++ /dev/null @@ -1,50 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
- py:extends="'master.kid'">
-<head>
-<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
-<title>Welcome to TurboGears</title>
-</head>
-<body>
-<div id="header"> </div>
-<div id="main_content">
- <div id="status_block">Your TurboGears application is now running.</div>
- <!--h1>Take steps to dive right in:</h1-->
- <div id="sidebar">
- <h2>Learn more</h2>
- Learn more about TurboGears and take part in its
- development
- <ul class="links">
- <li><a href="http://www.turbogears.org">Official website</a></li>
- <li><a href="http://docs.turbogears.org">Documentation</a></li>
- <li><a href="http://trac.turbogears.org/turbogears/">Trac
- (bugs/suggestions)</a></li>
- <li><a href="http://groups.google.com/group/turbogears"> Mailing list</a> </li>
- </ul>
- </div>
- <div id="getting_started">
- <ol id="getting_started_steps">
- <li class="getting_started">
- <h3>Model</h3>
- <p> <a href="http://docs.turbogears.org/1.0/GettingStarted/DefineDatabase">Design models</a> in the <span class="code">model.py</span>.<br/>
- Edit <span class="code">dev.cfg</span> to <a href="http://docs.turbogears.org/1.0/GettingStarted/UseDatabase">use a different backend</a>, or start with a pre-configured SQLite database. <br/>
- Use script <span class="code">tg-admin sql create</span> to create the database tables.</p>
- </li>
- <li class="getting_started">
- <h3>View</h3>
- <p> Edit <a href="http://docs.turbogears.org/1.0/GettingStarted/Kid">html-like templates</a> in the <span class="code">/templates</span> folder;<br/>
- Put all <a href="http://docs.turbogears.org/1.0/StaticFiles">static contents</a> in the <span class="code">/static</span> folder. </p>
- </li>
- <li class="getting_started">
- <h3>Controller</h3>
- <p> Edit <span class="code"> controllers.py</span> and <a href="http://docs.turbogears.org/1.0/GettingStarted/CherryPy">build your
- website structure</a> with the simplicity of Python objects. <br/>
- TurboGears will automatically reload itself when you modify your project. </p>
- </li>
- </ol>
- <div class="notice"> If you create something cool, please <a href="http://groups.google.com/group/turbogears">let people know</a>, and consider contributing something back to the <a href="http://groups.google.com/group/turbogears">community</a>.</div>
- </div>
- <!-- End of getting_started -->
-</div>
-</body>
-</html>
diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/tests/__init__.py b/interfaces/web/Bugs-Everywhere-Web/beweb/tests/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/tests/__init__.py +++ /dev/null diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/tests/test_controllers.py b/interfaces/web/Bugs-Everywhere-Web/beweb/tests/test_controllers.py deleted file mode 100644 index 0c77afe..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/tests/test_controllers.py +++ /dev/null @@ -1,16 +0,0 @@ -from turbogears import testutil -from beweb.controllers import Root -import cherrypy - -cherrypy.root = Root() - -def test_method(): - "the index method should return a string called now" - import types - result = testutil.call(cherrypy.root.index) - assert type(result["now"]) == types.StringType - -def test_indextitle(): - "The mainpage should have the right title" - testutil.createRequest("/") - assert "<TITLE>Welcome to TurboGears</TITLE>" in cherrypy.response.body[0] diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/tests/test_model.py b/interfaces/web/Bugs-Everywhere-Web/beweb/tests/test_model.py deleted file mode 100644 index 74c4e83..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/beweb/tests/test_model.py +++ /dev/null @@ -1,23 +0,0 @@ -# If your project uses a database, you can set up database tests -# similar to what you see below. Be sure to set the db_uri to -# an appropriate uri for your testing database. sqlite is a good -# choice for testing, because you can use an in-memory database -# which is very fast. - -from turbogears import testutil, database -# from beweb.model import YourDataClass, User - -# database.set_db_uri("sqlite:///:memory:") - -# class TestUser(testutil.DBTest): -# def get_model(self): -# return User -# -# def test_creation(self): -# "Object creation should set the name" -# obj = User(user_name = "creosote", -# email_address = "spam@python.not", -# display_name = "Mr Creosote", -# password = "Wafer-thin Mint") -# assert obj.display_name == "Mr Creosote" - diff --git a/interfaces/web/Bugs-Everywhere-Web/dev.cfg b/interfaces/web/Bugs-Everywhere-Web/dev.cfg deleted file mode 100644 index eda9e6c..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/dev.cfg +++ /dev/null @@ -1,71 +0,0 @@ -[global] -# This is where all of your settings go for your development environment -# Settings that are the same for both development and production -# (such as template engine, encodings, etc.) all go in -# beweb/config/app.cfg - -# DATABASE - -# pick the form for your database -# sqlobject.dburi="postgres://username@hostname/databasename" -# sqlobject.dburi="mysql://username:password@hostname:port/databasename" -# sqlobject.dburi="sqlite://%(package_dir)s/database.sqlite" - -# If you have sqlite, here's a simple default to get you started -# in development -sqlobject.dburi="sqlite://%(current_dir_uri)s/devdata.sqlite" - - -# if you are using a database or table type without transactions -# (MySQL default, for example), you should turn off transactions -# by prepending notrans_ on the uri -# sqlobject.dburi="notrans_mysql://username:password@hostname:port/databasename" - -# for Windows users, sqlite URIs look like: -# sqlobject.dburi="sqlite:///drive_letter:/path/to/file" - -# SERVER - -# Some server parameters that you may want to tweak -# server.socket_port=8080 - -# Enable the debug output at the end on pages. -# log_debug_info_filter.on = False - -server.environment="development" -autoreload.package="beweb" - -# session_filter.on = True - -# Set to True if you'd like to abort execution if a controller gets an -# unexpected parameter. False by default -tg.strict_parameters = True -identity.on = True -visit.on = True -identity.soprovider.model.user="beweb.model.User" -identity.soprovider.model.group="beweb.model.Group" -identity.soprovider.model.permission="beweb.model.Permission" - - -# LOGGING -# Logging configuration generally follows the style of the standard -# Python logging module configuration. Note that when specifying -# log format messages, you need to use *() for formatting variables. -# Deployment independent log configuration is in beweb/config/log.cfg -[logging] - -[[loggers]] -[[[beweb]]] -level='DEBUG' -qualname='beweb' -handlers=['debug_out'] - -[[[allinfo]]] -level='INFO' -handlers=['debug_out'] - -[[[access]]] -level='INFO' -qualname='turbogears.access' -handlers=['access_out'] -propagate=0 diff --git a/interfaces/web/Bugs-Everywhere-Web/libbe b/interfaces/web/Bugs-Everywhere-Web/libbe deleted file mode 120000 index 7d18612..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/libbe +++ /dev/null @@ -1 +0,0 @@ -../../../libbe
\ No newline at end of file diff --git a/interfaces/web/Bugs-Everywhere-Web/prod.cfg b/interfaces/web/Bugs-Everywhere-Web/prod.cfg deleted file mode 100644 index c0d4aca..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/prod.cfg +++ /dev/null @@ -1,41 +0,0 @@ -[global] -# This is where all of your settings go for your production environment. -# You'll copy this file over to your production server and provide it -# as a command-line option to your start script. -# Settings that are the same for both development and production -# (such as template engine, encodings, etc.) all go in -# yourpackage/config/app.cfg - -# DATABASE - -# pick the form for your database -# sqlobject.dburi="postgres://username@hostname/databasename" -# sqlobject.dburi="mysql://username:password@hostname:port/databasename" -# sqlobject.dburi="sqlite:///file_name_and_path" - -# if you are using a database or table type without transactions -# (MySQL default, for example), you should turn off transactions -# by prepending notrans_ on the uri -# sqlobject.dburi="notrans_mysql://username:password@hostname:port/databasename" - -# for Windows users, sqlite URIs look like: -# sqlobject.dburi="sqlite:///drive_letter|/path/to/file" - - -# SERVER - -server.environment="production" -server.log_file="server.log" -server.log_to_screen=False - -# Sets the number of threads the server uses -# server.thread_pool = 1 - -# if this is part of a larger site, you can set the path -# to the TurboGears instance here -# server.webpath="" - -# Set to True if you'd like to abort execution if a controller gets an -# unexpected parameter. False by default -# tg.strict_parameters = False - diff --git a/interfaces/web/Bugs-Everywhere-Web/sample-prod.cfg b/interfaces/web/Bugs-Everywhere-Web/sample-prod.cfg deleted file mode 100644 index d1052f8..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/sample-prod.cfg +++ /dev/null @@ -1,71 +0,0 @@ -[global] -# This is where all of your settings go for your production environment. -# You'll copy this file over to your production server and provide it -# as a command-line option to your start script. -# Settings that are the same for both development and production -# (such as template engine, encodings, etc.) all go in -# beweb/config/app.cfg - -# pick the form for your database -# sqlobject.dburi="postgres://username@hostname/databasename" -# sqlobject.dburi="mysql://username:password@hostname:port/databasename" -# sqlobject.dburi="sqlite:///file_name_and_path" - -# If you have sqlite, here's a simple default to get you started -# in development -sqlobject.dburi="sqlite://%(current_dir_uri)s/devdata.sqlite" - - -# if you are using a database or table type without transactions -# (MySQL default, for example), you should turn off transactions -# by prepending notrans_ on the uri -# sqlobject.dburi="notrans_mysql://username:password@hostname:port/databasename" - -# for Windows users, sqlite URIs look like: -# sqlobject.dburi="sqlite:///drive_letter:/path/to/file" - - -# SERVER - -server.environment="production" - -# Sets the number of threads the server uses -# server.thread_pool = 1 - -# if this is part of a larger site, you can set the path -# to the TurboGears instance here -# server.webpath="" - -# session_filter.on = True - -# Set to True if you'd like to abort execution if a controller gets an -# unexpected parameter. False by default -# tg.strict_parameters = False - -# LOGGING -# Logging configuration generally follows the style of the standard -# Python logging module configuration. Note that when specifying -# log format messages, you need to use *() for formatting variables. -# Deployment independent log configuration is in beweb/config/log.cfg -[logging] - -[[handlers]] - -[[[access_out]]] -# set the filename as the first argument below -args="('server.log',)" -class='FileHandler' -level='INFO' -formatter='message_only' - -[[loggers]] -[[[beweb]]] -level='ERROR' -qualname='beweb' -handlers=['error_out'] - -[[[access]]] -level='INFO' -qualname='turbogears.access' -handlers=['access_out'] -propagate=0 diff --git a/interfaces/web/Bugs-Everywhere-Web/setup-tables.py b/interfaces/web/Bugs-Everywhere-Web/setup-tables.py deleted file mode 100644 index 161d7c7..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/setup-tables.py +++ /dev/null @@ -1,34 +0,0 @@ -import pkg_resources -pkg_resources.require("TurboGears") - -import turbogears -import cherrypy -cherrypy.lowercase_api = True - -from os.path import * -import sys - -# first look on the command line for a desired config file, -# if it's not on the command line, then -# look for setup.py in this directory. If it's not there, this script is -# probably installed -if len(sys.argv) > 1: - turbogears.update_config(configfile=sys.argv[1], - modulename="beweb.config.app") -elif exists(join(dirname(__file__), "setup.py")): - turbogears.update_config(configfile="dev.cfg", - modulename="beweb.config.app") -else: - turbogears.update_config(configfile="prod.cfg", - modulename="beweb.config.app") - -from beweb.controllers import Root - -cherrypy.root = Root() - - -from beweb.model import TG_Group, TG_Permission -g = TG_Group(groupId="editors", displayName="Editors") -p = TG_Permission(permissionId="editbugs", - description="Ability to create and edit bugs") -g.addTG_Permission(p) diff --git a/interfaces/web/Bugs-Everywhere-Web/setup.py b/interfaces/web/Bugs-Everywhere-Web/setup.py deleted file mode 100644 index 8ba3da2..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/setup.py +++ /dev/null @@ -1,62 +0,0 @@ -from setuptools import setup, find_packages -from turbogears.finddata import find_package_data - -import os -execfile(os.path.join("beweb", "release.py")) - -setup( - name="Bugs-Everywhere-Web", - version=version, - - # uncomment the following lines if you fill them out in release.py - #description=description, - #author=author, - #author_email=email, - #url=url, - #download_url=download_url, - #license=license, - - install_requires = [ - "TurboGears >= 1.0b1", - ], - scripts = ["start-beweb.py"], - zip_safe=False, - packages=find_packages(), - package_data = find_package_data(where='beweb', - package='beweb'), - keywords = [ - # Use keywords if you'll be adding your package to the - # Python Cheeseshop - - # if this has widgets, uncomment the next line - # 'turbogears.widgets', - - # if this has a tg-admin command, uncomment the next line - # 'turbogears.command', - - # if this has identity providers, uncomment the next line - # 'turbogears.identity.provider', - - # If this is a template plugin, uncomment the next line - # 'python.templating.engines', - - # If this is a full application, uncomment the next line - # 'turbogears.app', - ], - classifiers = [ - 'Development Status :: 3 - Alpha', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'Framework :: TurboGears', - # if this is an application that you'll distribute through - # the Cheeseshop, uncomment the next line - # 'Framework :: TurboGears :: Applications', - - # if this is a package that includes widgets that you'll distribute - # through the Cheeseshop, uncomment the next line - # 'Framework :: TurboGears :: Widgets', - ], - test_suite = 'nose.collector', - ) - diff --git a/interfaces/web/Bugs-Everywhere-Web/start-beweb.py b/interfaces/web/Bugs-Everywhere-Web/start-beweb.py deleted file mode 100755 index 4070abd..0000000 --- a/interfaces/web/Bugs-Everywhere-Web/start-beweb.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python -import pkg_resources -pkg_resources.require("TurboGears") - -import turbogears -import cherrypy -cherrypy.lowercase_api = True - -from os.path import * -import sys - -# first look on the command line for a desired config file, -# if it's not on the command line, then -# look for setup.py in this directory. If it's not there, this script is -# probably installed -if len(sys.argv) > 1: - turbogears.update_config(configfile=sys.argv[1], - modulename="beweb.config") -elif exists(join(dirname(__file__), "setup.py")): - turbogears.update_config(configfile="dev.cfg", - modulename="beweb.config") -else: - turbogears.update_config(configfile="prod.cfg", - modulename="beweb.config") - -from beweb.controllers import Root - -turbogears.start_server(Root()) diff --git a/interfaces/xml/be-mbox-to-xml b/interfaces/xml/be-mbox-to-xml deleted file mode 100755 index eda6d6e..0000000 --- a/interfaces/xml/be-mbox-to-xml +++ /dev/null @@ -1,154 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2009 W. Trevor King <wking@drexel.edu> -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -""" -Convert an mbox into xml suitable for input into be. - $ be-mbox-to-xml file.mbox | be import-xml -c <ID> - -mbox is a flat-file format, consisting of a series of messages. -Messages begin with a a From_ line, followed by RFC 822 email, -followed by a blank line. -""" - -import base64 -import email.utils -from libbe.encoding import get_encoding, set_IO_stream_encodings -from libbe.utility import time_to_str -from mailbox import mbox, Message # the mailbox people really want an on-disk copy -from time import asctime, gmtime, mktime -import types -from xml.sax.saxutils import escape - -DEFAULT_ENCODING = get_encoding() -set_IO_stream_encodings(DEFAULT_ENCODING) - -KNOWN_IDS = [] - -def normalize_email_address(address): - """ - Standardize whitespace, etc. - """ - addr = email.utils.formataddr(email.utils.parseaddr(address)) - if len(addr) == 0: - return None - return addr - -def normalize_RFC_2822_date(date): - """ - Some email clients write non-RFC 2822-compliant date tags like: - Fri, 18 Sep 2009 08:49:02 -0400 (EDT) - with the non-standard (EDT) timezone name. This funtion attempts - to deal with such inconsistencies. - """ - time_tuple = email.utils.parsedate(date) - assert time_tuple != None, \ - 'unparsable date: "%s"' % date - return time_to_str(mktime(time_tuple)) - -def comment_message_to_xml(message, fields=None): - if fields == None: - fields = {} - new_fields = {} - new_fields[u'alt-id'] = message[u'message-id'] - new_fields[u'in-reply-to'] = message[u'in-reply-to'] - new_fields[u'author'] = normalize_email_address(message[u'from']) - new_fields[u'date'] = message[u'date'] - if new_fields[u'date'] != None: - new_fields[u'date'] = normalize_RFC_2822_date(new_fields[u'date']) - new_fields[u'content-type'] = message.get_content_type() - for k,v in new_fields.items(): - if v != None and type(v) != types.UnicodeType: - fields[k] = unicode(v, encoding=DEFAULT_ENCODING) - elif v == None and k in fields: - new_fields[k] = fields[k] - for k,v in fields.items(): - if k not in new_fields: - new_fields.k = fields[k] - fields = new_fields - - if fields[u'in-reply-to'] == None: - if message[u'references'] != None: - refs = message[u'references'].split() - for ref in refs: # search for a known reference id. - if ref in KNOWN_IDS: - fields[u'in-reply-to'] = ref - break - if fields[u'in-reply-to'] == None and len(refs) > 0: - fields[u'in-reply-to'] = refs[0] # default to the first - else: # check for mutliple in-reply-to references. - refs = fields[u'in-reply-to'].split() - found_ref = False - for ref in refs: # search for a known reference id. - if ref in KNOWN_IDS: - fields[u'in-reply-to'] = ref - found_ref = True - break - if found_ref == False and len(refs) > 0: - fields[u'in-reply-to'] = refs[0] # default to the first - - if fields[u'alt-id'] != None: - KNOWN_IDS.append(fields[u'alt-id']) - - if message.is_multipart(): - ret = [] - alt_id = fields[u'alt-id'] - from_str = fields[u'author'] - date = fields[u'date'] - for m in message.walk(): - if m == message: - continue - fields[u'author'] = from_str - fields[u'date'] = date - if len(ret) > 0: # we've added one part already - fields.pop(u'alt-id') # don't pass alt-id to other parts - fields[u'in-reply-to'] = alt_id # others respond to first - ret.append(comment_message_to_xml(m, fields)) - return u'\n'.join(ret) - - charset = message.get_content_charset(DEFAULT_ENCODING).lower() - #assert charset == DEFAULT_ENCODING.lower(), \ - # u"Unknown charset: %s" % charset - - if message[u'content-transfer-encoding'] == None: - encoding = DEFAULT_ENCODING - else: - encoding = message[u'content-transfer-encoding'].lower() - body = message.get_payload(decode=True) # attempt to decode - assert body != None, "Unable to decode?" - if fields[u'content-type'].startswith(u"text/"): - body = unicode(body, encoding=charset).rstrip(u'\n') - else: - body = base64.encode(body) - fields[u'body'] = body - lines = [u"<comment>"] - for tag,body in fields.items(): - if body != None: - ebody = escape(body) - lines.append(u" <%s>%s</%s>" % (tag, ebody, tag)) - lines.append(u"</comment>") - return u'\n'.join(lines) - -def main(mbox_filename): - mb = mbox(mbox_filename) - print u'<?xml version="1.0" encoding="%s" ?>' % DEFAULT_ENCODING - print u"<be-xml>" - for message in mb: - print comment_message_to_xml(message) - print u"</be-xml>" - - -if __name__ == "__main__": - import sys - main(sys.argv[1]) diff --git a/interfaces/xml/be-xml-to-mbox b/interfaces/xml/be-xml-to-mbox deleted file mode 100755 index ef7b714..0000000 --- a/interfaces/xml/be-xml-to-mbox +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2009 W. Trevor King <wking@drexel.edu> -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -""" -Convert xml output of `be list --xml` into mbox format for browsing -with a mail reader. For example - $ be list --xml --status=all | be-xml-to-mbox | catmutt - -mbox is a flat-file format, consisting of a series of messages. -Messages begin with a a From_ line, followed by RFC 822 email, -followed by a blank line. -""" - -#from mailbox import mbox, Message # the mailbox people really want an on-disk copy -import codecs -import email.utils -from libbe.encoding import get_encoding, set_IO_stream_encodings -from libbe.utility import str_to_time as rfc2822_to_gmtime_integer -from time import asctime, gmtime -import types -try: # import core module, Python >= 2.5 - from xml.etree import ElementTree -except ImportError: # look for non-core module - from elementtree import ElementTree -from xml.sax.saxutils import unescape - - -DEFAULT_DOMAIN = "invalid.com" -DEFAULT_EMAIL = "dummy@" + DEFAULT_DOMAIN -DEFAULT_ENCODING = get_encoding() -set_IO_stream_encodings(DEFAULT_ENCODING) - -def rfc2822_to_asctime(rfc2822_string): - """Convert an RFC 2822-fomatted string into a asctime string. - >>> rfc2822_to_asctime("Thu, 01 Jan 1970 00:00:00 +0000") - "Thu Jan 01 00:00:00 1970" - """ - if rfc2822_string == "": - return asctime(gmtime(0)) - return asctime(gmtime(rfc2822_to_gmtime_integer(rfc2822_string))) - -class LimitedAttrDict (dict): - """ - Dict with error checking, to avoid invalid bug/comment fields. - """ - _attrs = [] # override with list of valid attribute names - def __init__(self, **kwargs): - dict.__init__(self) - for key,value in kwargs.items(): - self[key] = value - def __setitem__(self, key, item): - self._validate_key(key) - dict.__setitem__(self, key, item) - def _validate_key(self, key): - if key in self._attrs: - return - elif type(key) not in types.StringTypes: - raise TypeError, "Invalid attribute type %s for '%s'" % (type(key), key) - else: - raise ValueError, "Invalid attribute name '%s'" % key - -class Bug (LimitedAttrDict): - _attrs = [u"uuid", - u"short-name", - u"severity", - u"status", - u"assigned", - u"reporter", - u"creator", - u"created", - u"summary", - u"comments", - u"extra-strings"] - def print_to_mbox(self): - if "creator" in self: - # otherwise, probably a `be show` uuid-only bug to avoid - # root comments. - name,addr = email.utils.parseaddr(self["creator"]) - print "From %s %s" % (addr, rfc2822_to_asctime(self["created"])) - print "Message-id: <%s@%s>" % (self["uuid"], DEFAULT_DOMAIN) - print "Date: %s" % self["created"] - print "From: %s" % self["creator"] - print "Content-Type: %s; charset=%s" % ("text/plain", DEFAULT_ENCODING) - print "Content-Transfer-Encoding: 8bit" - print "Subject: %s: %s" % (self["short-name"], self["summary"]) - if "extra-strings" in self: - for estr in self["extra_strings"]: - print "X-Extra-String: %s" % estr - print "" - print self["summary"] - print "" - if "comments" in self: - for comment in self["comments"]: - comment.print_to_mbox(self) - def init_from_etree(self, element): - assert element.tag == "bug", element.tag - for field in element.getchildren(): - text = unescape(unicode(field.text).decode("unicode_escape").strip()) - if field.tag == "comment": - comm = Comment() - comm.init_from_etree(field) - if "comments" in self: - self["comments"].append(comm) - else: - self["comments"] = [comm] - elif field.tag == "extra-string": - if "extra-strings" in self: - self["extra-strings"].append(text) - else: - self["extra-strings"] = [text] - else: - self[field.tag] = text - -class Comment (LimitedAttrDict): - _attrs = [u"uuid", - u"alt-id", - u"short-name", - u"in-reply-to", - u"author", - u"date", - u"content-type", - u"body", - u"extra-strings"] - def print_to_mbox(self, bug=None): - if bug == None: - bug = Bug() - bug[u"uuid"] = u"no-uuid" - name,addr = email.utils.parseaddr(self["author"]) - print "From %s %s" % (addr, rfc2822_to_asctime(self["date"])) - if "uuid" in self: id = self["uuid"] - elif "alt-id" in self: id = self["alt-id"] - else: id = None - if id != None: - print "Message-id: <%s@%s>" % (id, DEFAULT_DOMAIN) - print "Date: %s" % self["date"] - print "From: %s" % self["author"] - subject = "" - if "short-name" in self: - subject += self["short-name"]+u": " - if "summary" in bug: - subject += bug["summary"] - else: - subject += u"no-subject" - print "Subject: %s" % subject - if "in-reply-to" not in self.keys(): - self["in-reply-to"] = bug["uuid"] - print "In-Reply-To: <%s@%s>" % (self["in-reply-to"], DEFAULT_DOMAIN) - if "extra-strings" in self: - for estr in self["extra_strings"]: - print "X-Extra-String: %s" % estr - if self["content-type"].startswith("text/"): - print "Content-Transfer-Encoding: 8bit" - print "Content-Type: %s; charset=%s" % (self["content-type"], DEFAULT_ENCODING) - print "" - print self["body"] - else: # content type and transfer encoding already in XML MIME output - print self["body"] - print "" - def init_from_etree(self, element): - assert element.tag == "comment", element.tag - for field in element.getchildren(): - text = unescape(unicode(field.text).decode("unicode_escape").strip()) - if field.tag == "extra-string": - if "extra-strings" in self: - self["extra-strings"].append(text) - else: - self["extra-strings"] = [text] - else: - if field.tag == "body": - text+="\n" - self[field.tag] = text - -def print_to_mbox(element): - if element.tag == "bug": - b = Bug() - b.init_from_etree(element) - b.print_to_mbox() - elif element.tag == "comment": - c = Comment() - c.init_from_etree(element) - c.print_to_mbox() - elif element.tag in ["be-xml"]: - for elt in element.getchildren(): - print_to_mbox(elt) - -if __name__ == "__main__": - import sys - - if len(sys.argv) == 1: # no filename given, use stdin - xml_unicode = sys.stdin.read() - else: - xml_unicode = codecs.open(sys.argv[1], "r", DEFAULT_ENCODING).read() - xml_str = xml_unicode.encode("unicode_escape").replace(r"\n", "\n") - elist = ElementTree.XML(xml_str) - print_to_mbox(elist) |