aboutsummaryrefslogtreecommitdiffstats
path: root/interfaces
diff options
context:
space:
mode:
authorGianluca Montecchi <gian@grys.it>2010-02-10 00:03:38 +0100
committerGianluca Montecchi <gian@grys.it>2010-02-10 00:03:38 +0100
commitc67a5863826771001f009e1ee90262ccb7a2e172 (patch)
tree64c7f83238685959bf40a13c876168071a085556 /interfaces
parenta60e599798d43ba930efc1f8e2f184d3e8262189 (diff)
parent50444209eee408dde7d240fdf59bfc9e82b714ce (diff)
downloadbugseverywhere-c67a5863826771001f009e1ee90262ccb7a2e172.tar.gz
Merged Trevor's tree
Diffstat (limited to 'interfaces')
-rw-r--r--interfaces/README34
-rwxr-xr-xinterfaces/email/catmutt59
-rw-r--r--interfaces/email/interactive/README105
-rwxr-xr-xinterfaces/email/interactive/be-handle-mail541
l---------interfaces/email/interactive/becommands1
-rw-r--r--interfaces/email/interactive/examples/email_bugs37
-rw-r--r--interfaces/email/interactive/send_pgp_mime.py2
-rwxr-xr-xinterfaces/gui/beg/beg12
-rw-r--r--interfaces/gui/beg/table.py97
-rwxr-xr-xinterfaces/gui/wxbe/wxbe87
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/SOURCES.txt36
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/not-zip-safe0
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/requires.txt1
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/sqlobject.txt2
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/Bugs-Everywhere-Web.egg-info/top_level.txt2
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/PKG-INFO15
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/SOURCES.txt44
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/dependency_links.txt1
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/not-zip-safe1
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/paster_plugins.txt2
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/requires.txt1
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/sqlobject.txt2
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/top_level.txt1
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/README.txt42
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/__init__.py0
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/app.cfg120
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/config.py.example10
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/config/app.cfg92
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/config/log.cfg29
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/controllers.py240
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/formatting.py76
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/json.py13
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/model.py107
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/prest.py168
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/release.py14
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/css/style.css116
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-b.pngbin213 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-bl.pngbin327 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-br.pngbin365 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-l.pngbin197 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-r.pngbin214 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-t.pngbin200 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-tl.pngbin240 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-tr.pngbin311 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds2-b.pngbin206 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds2-r.pngbin204 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.icobin318 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.pngbin267 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/half-spiral.pngbin1112 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/header_inner.pngbin37537 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/info.pngbin2889 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-b.pngbin200 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-bl.pngbin408 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-br.pngbin304 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-l.pngbin214 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-r.pngbin197 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-t.pngbin213 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-tl.pngbin413 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-tr.pngbin414 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ok.pngbin25753 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/shadows.pngbin3960 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/spiral.pngbin2120 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/tg_under_the_hood.pngbin4010 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/static/images/under_the_hood_blue.pngbin2667 -> 0 bytes
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/templates/__init__.py0
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/templates/about.kid21
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/templates/bugs.kid52
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/templates/edit_bug.kid52
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/templates/edit_comment.kid26
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/templates/error.kid14
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/templates/login.kid113
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/templates/master.kid71
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/templates/projects.kid32
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/templates/welcome.kid50
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/tests/__init__.py0
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/tests/test_controllers.py16
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/beweb/tests/test_model.py23
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/dev.cfg71
l---------interfaces/web/Bugs-Everywhere-Web/libbe1
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/prod.cfg41
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/sample-prod.cfg71
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/server.log26
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/setup-tables.py34
-rw-r--r--interfaces/web/Bugs-Everywhere-Web/setup.py62
-rwxr-xr-xinterfaces/web/Bugs-Everywhere-Web/start-beweb.py28
-rwxr-xr-xinterfaces/xml/be-mbox-to-xml151
-rwxr-xr-xinterfaces/xml/be-xml-to-mbox205
87 files changed, 348 insertions, 2922 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/README b/interfaces/email/interactive/README
index 79ef9a9..48bccdd 100644
--- a/interfaces/email/interactive/README
+++ b/interfaces/email/interactive/README
@@ -1,16 +1,19 @@
+***************
+Email Interface
+***************
+
Overview
========
The interactive email interface to Bugs Everywhere (BE) attempts to
-provide a Debian-bug-tracking-system-style interface to a BE
+provide a `Debian-bug-tracking-system-style`_ interface to a BE
repository. Users can mail in bug reports, comments, or control
requests, which will be committed to the served repository.
Developers can then pull the changes they approve of from the served
repository into their other repositories and push updates back onto
the served repository.
-For details about the Debian bug tracking system that inspired this
-interface, see http://www.debian.org/Bugs .
+.. _Debian-bug-tracking-system-style: http://www.debian.org/Bugs
Architecture
============
@@ -18,27 +21,34 @@ Architecture
In order to reduce setup costs, the entire interface can piggyback on
an existing email address, although from a security standpoint it's
probably best to create a dedicated user. Incoming email is filtered
-by procmail, with matching emails being piped into be-handle-mail for
-execution.
-
-Once be-handle-mail receives the email, the parsing method is selected
-according to the subject tag that procmail used grab the email in the
-first place. There are three parsing styles:
- Style Subject
- creating bugs [be-bug:submit] new bug summary
- commenting on bugs [be-bug:<bug-id>] commit message
- control [be-bug] commit message
-These are analogous to submit@bugs.debian.org, nnn@bugs.debian.org,
-and control@bugs.debian.org respectively.
+by procmail, with matching emails being piped into ``be-handle-mail``
+for execution.
+
+Once ``be-handle-mail`` receives the email, the parsing method is
+selected according to the subject tag that procmail used grab the
+email in the first place. There are four parsing styles:
+
+ +--------------------+----------------------------------+
+ | Style | Subject |
+ +====================+==================================+
+ | creating bugs | [be-bug:submit] new bug summary |
+ +--------------------+----------------------------------+
+ | commenting on bugs | [be-bug:<bug-id>] commit message |
+ +--------------------+----------------------------------+
+ | control | [be-bug] commit message |
+ +--------------------+----------------------------------+
+
+These are analogous to ``submit@bugs.debian.org``,
+``nnn@bugs.debian.org``, and ``control@bugs.debian.org`` respectively.
Creating bugs
=============
This interface creates a bug whose summary is given by the email's
post-tag subject. The body of the email must begin with a
-pseudo-header containing at least the "Version" field. Anything after
-the pseudo-header and before a line starting with '--' is, if present,
-attached as the bug's first comment.
+pseudo-header containing at least the ``Version`` field. Anything after
+the pseudo-header and before a line starting with ``--`` is, if present,
+attached as the bug's first comment.::
From jdoe@example.com Fri Apr 18 12:00:00 2008
From: John Doe <jdoe@example.com>
@@ -51,22 +61,22 @@ attached as the bug's first comment.
Severity: minor
Someone should write up a series of test emails to send into
- be-handle mail so we can test changes quickly without having to
+ be-handle-mail so we can test changes quickly without having to
use procmail.
--
Goofy tagline not included.
-Available pseudo-headers are Version, Reporter, Assign, Depend,
-Severity, Status, Tag, and Target.
+Available pseudo-headers are ``Version``, ``Reporter``, ``Assign``,
+``Depend``, ``Severity``, ``Status``, ``Tag``, and ``Target``.
Commenting on bugs
==================
This interface appends a comment to the bug specified in the subject
tag. The the first non-multipart body is attached with the
-appropriate content-type. In the case of "text/plain" contents,
-anything following a line starting with '--' is stripped.
+appropriate content-type. In the case of ``text/plain`` contents,
+anything following a line starting with ``--`` is stripped.::
From jdoe@example.com Fri Apr 18 12:00:00 2008
From: John Doe <jdoe@example.com>
@@ -85,11 +95,11 @@ Controlling bugs
================
This interface consists of a list of allowed be commands, with one
-command per line. Blank lines and lines beginning with '#' are
-ignored, as well anything following a line starting with '--'. All
+command per line. Blank lines and lines beginning with ``#`` are
+ignored, as well anything following a line starting with ``--``. All
the listed commands are executed in order and their output returned.
The commands are split into arguments with the POSIX-compliant
-shlex.split().
+shlex.split().::
From jdoe@example.com Fri Apr 18 12:00:00 2008
From: John Doe <jdoe@example.com>
@@ -109,37 +119,42 @@ shlex.split().
Example emails
==============
-Take a look at my interfaces/email/interactive/examples for some
+Take a look at ``interfaces/email/interactive/examples`` for some
more examples.
Procmail rules
==============
-The file _procmailrc as it stands is fairly appropriate for as a
-dedicated user's ~/.procmailrc. It forwards matching mail to
-be-handle-mail, which should be installed somewhere in the user's
-path. All non-matching mail is dumped into /dev/null. Everything
-procmail does will be logged to ~/be-mail/procmail.log.
+The file ``_procmailrc`` as it stands is fairly appropriate for as a
+dedicated user's ``~/.procmailrc``. It forwards matching mail to
+``be-handle-mail``, which should be installed somewhere in the user's
+path. All non-matching mail is dumped into ``/dev/null``. Everything
+procmail does will be logged to ``~/be-mail/procmail.log``.
If you're piggybacking the interface on top of an existing account,
-you probably only need to add the be-handle-mail stanza to your
-existing ~/.procmailrc, since you will still want to receive non-bug
-emails.
+you probably only need to add the ``be-handle-mail`` stanza to your
+existing ``~/.procmailrc``, since you will still want to receive
+non-bug emails.
+
+Note that you will probably have to add a::
+
+ --repo /path/to/served/repository
-Note that you will probably have to add a
- --be-dir /path/to/served/repository
-option to the be-handle-mail invocation so it knows what repository to
+option to the ``be-handle-mail`` invocation so it knows what repository to
serve.
Multiple repositories may be served by the same email address by adding
-multiple be-handle-mail stanzas, each matching a different tag, for
-example the "[be-bug" portion of the stanza could be "[projectX-bug",
-"[projectY-bug", etc. If you change the base tag, be sure to add a
- --tag-base "projectX-bug"
-or equivalent to your be-handle-mail invocation.
+multiple ``be-handle-mail`` stanzas, each matching a different tag, for
+example the ``[be-bug`` portion of the stanza could be ``[projectX-bug``,
+``[projectY-bug``, etc. If you change the base tag, be sure to add a::
+
+ --tag-base "projectX-bug"
+
+or equivalent to your ``be-handle-mail`` invocation.
Testing
=======
-Send test emails in to be-handle-mail with something like
- cat examples/blank | ./be-handle-mail -o -l - -a
+Send test emails in to ``be-handle-mail`` with something like::
+
+ cat examples/blank | ./be-handle-mail -o -l - -a
diff --git a/interfaces/email/interactive/be-handle-mail b/interfaces/email/interactive/be-handle-mail
index fa80698..c8343fc 100755
--- a/interfaces/email/interactive/be-handle-mail
+++ b/interfaces/email/interactive/be-handle-mail
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright (C) 2009 W. Trevor King <wking@drexel.edu>
+# Copyright (C) 2009-2010 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
@@ -58,44 +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
-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"]
+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):
@@ -103,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)
@@ -114,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
@@ -165,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)
@@ -178,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)
@@ -196,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.
@@ -221,60 +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)
- 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):
@@ -304,6 +274,8 @@ class DiffTree (libbe.diff.DiffTree):
"""
def report_or_none(self):
report = self.report()
+ if report == None:
+ return None
payload = report.get_payload()
if payload == None or len(payload) == 0:
return None
@@ -311,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(self.report(), to_unicode=True)
+ 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)
@@ -353,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
@@ -380,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):
"""
@@ -410,13 +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"
+ 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):
@@ -426,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
@@ -445,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,
@@ -465,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:
@@ -481,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()
@@ -491,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
@@ -500,22 +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()
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 = \
@@ -523,49 +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, u"--alt-id", alt_id,
- u"--content-type", content_type, bug_id, u"-"]
+ 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'-'])
commands = [Command(self, command, args, stdin=body)]
return commands
def parse_control(self):
@@ -577,39 +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 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)
@@ -625,86 +609,54 @@ 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)
- if bd.vcs.versioned == False: # no way to tell what's changed
- raise NotificationFailed("Not versioned")
+ bd = UI.storage_callbacks.get_bugdir()
+ writeable = bd.storage.writeable
+ bd.storage.writeable = False
+ if bd.storage.versioned == False: # no way to tell what's changed
+ bd.storage.writeable = writeable
+ raise NotificationFailed('Not versioned')
bd.load_all_bugs()
subscribers = subscribe.get_bugdir_subscribers(bd, THIS_SERVER)
-
if len(subscribers) == 0:
- return []
+ bd.storage.writeable = writeable
+ return []
+ for subscriber,subscriptions in subscribers.items():
+ subscribers[subscriber] = []
+ for id,types in subscriptions.items():
+ for type in types:
+ subscribers[subscriber].append(
+ libbe.diff.Subscription(id,type))
before_bd, after_bd = self._get_before_and_after_bugdirs(bd, previous_revision)
diff = Diff(before_bd, after_bd)
- diff_tree = diff.report_tree(diff_tree=DiffTree)
- bug_index = {}
- for child in diff_tree.child_by_path("/bugs/new"):
- bug_index[child.name] = ("added", child)
- for child in diff_tree.child_by_path("/bugs/mod"):
- bug_index[child.name] = ("modified", child)
- for child in diff_tree.child_by_path("/bugs/rem"):
- bug_index[child.name] = ("removed", child)
+ diff.full_report(diff_tree=DiffTree)
header = self._subscriber_header(bd, previous_revision)
emails = []
for subscriber,subscriptions in subscribers.items():
- header.replace_header("to", subscriber)
- parts = []
- if "DIR" in subscriptions: # make sure we check the DIR level first
- ordered_subscriptions = [("DIR", subscriptions.pop("DIR"))]
- else:
- ordered_subscriptions = []
- ordered_subscriptions.extend(subscriptions.items())
- for id,types in ordered_subscriptions:
- if id == "DIR":
- if subscribe.BUGDIR_TYPE_ALL in types:
- parts.append(diff_tree.report_or_none())
- break # we've attached everything, so stop checking.
- if subscribe.BUGDIR_TYPE_NEW in types:
- new = diff_tree.child_by_path("/bugs/new")
- parts.append(new.report_or_none())
- continue # move on to next id
- # if we get this far, id refers to a bug.
- assert types == [subscribe.BUG_TYPE_ALL], types
- if id not in bug_index:
- continue # no changes here, move on to next id
- type,bug_root = bug_index[id]
- if type == "added" \
- and "DIR" in subscriptions \
- and subscriptions["DIR"] == subscribe.BUGDIR_TYPE_NEW:
- # this info already attached at the DIR level
- continue # move on to next id
- parts.append(bug_root.report_or_none())
- parts = [p for p in parts if p != None]
- if len(parts) == 0:
- continue # no email to this subscriber
- elif len(parts) == 1:
- root = parts[0]
- else: # join subscription parts into a single body
- root = MIMEMultipart()
- root[u"Content-Description"] = u"Multiple subscription trees."
- for part in parts:
- root.attach(part)
- emails.append(send_pgp_mime.attach_root(header, root))
- if LOGFILE != None:
- LOGFILE.write(u"Preparing to notify %s of changes\n" % 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)
+ 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 "):]
- before_revision = bd.vcs.revision_id(-2)
+ assert commit_msg.startswith('Committed '), commit_msg
+ after_revision = commit_msg[len('Committed '):]
+ before_revision = bd.storage.revision_id(-2)
else:
before_revision = previous_revision
if before_revision == None:
@@ -712,36 +664,36 @@ class Message (object):
before_bd = libbe.bugdir.BugDir(from_disk=False,
manipulate_encodings=False)
else:
- before_bd = bd.duplicate_bugdir(before_revision)
+ before_bd = libbe.bugdir.RevisionedBugDir(bd, before_revision)
#after_bd = bd.duplicate_bugdir(after_revision)
after_bd = bd # assume no changes since commit a few cycles ago
return (before_bd, after_bd)
def _subscriber_header(self, bd, previous_revision=None):
- root_dir = os.path.basename(bd.root)
+ root_dir = os.path.basename(bd.storage.repo)
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_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
def open_logfile(logpath=None):
@@ -754,27 +706,25 @@ 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.util.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()
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)
@@ -783,15 +733,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.")
@@ -817,27 +767,28 @@ 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:
@@ -845,12 +796,14 @@ def main(args):
else:
send_pgp_mime.mail(msg, send_pgp_mime.sendmail)
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)
@@ -859,9 +812,11 @@ 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()
+ m.commit_command.cleanup()
+ UI.cleanup()
sys.exit(1)
else:
response = m.response_email()
@@ -869,21 +824,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:
@@ -892,7 +847,8 @@ def main(args):
send_pgp_mime.mail(msg, send_pgp_mime.sendmail)
close_logfile()
-
+ m.commit_command.cleanup()
+ UI.cleanup()
class GenerateGlobalTagsTestCase (unittest.TestCase):
def setUp(self):
@@ -914,37 +870,40 @@ 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:abc/xyz-123]')
self.failUnlessEqual(len(m.groups()), 1)
- self.failUnlessEqual(m.group(1), u"xyz-123")
+ self.failUnlessEqual(m.group(1), u'abc/xyz-123')
+
+unitsuite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
+suite = unittest.TestSuite([unitsuite, doctest.DocTestSuite()])
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/email/interactive/examples/email_bugs b/interfaces/email/interactive/examples/email_bugs
new file mode 100644
index 0000000..949e1c1
--- /dev/null
+++ b/interfaces/email/interactive/examples/email_bugs
@@ -0,0 +1,37 @@
+From jdoe@example.com Fri Apr 18 12:00:00 2008
+Content-Type: text/xml; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: quoted-printable
+From: jdoe@example.com
+To: a@b.com
+Date: Fri, 18 Apr 2008 12:00:00 +0000
+Subject: [be-bug:xml] Updates to a, b
+
+<?xml version="1.0" encoding="utf-8" ?>
+<be-xml>
+ <version>
+ <tag>1.0.0</tag>
+ <branch-nick>be</branch-nick>
+ <revno>446</revno>
+ <revision-id>wking@drexel.edu-20091119214553-iqyw2cpqluww3zna</revision-id>
+ </version>
+ <bug>
+ <uuid>a</uuid>
+ <short-name>a</short-name>
+ <severity>minor</severity>
+ <status>open</status>
+ <creator>John Doe &lt;jdoe@example.com&gt;</creator>
+ <created>Thu, 01 Jan 1970 00:00:00 +0000</created>
+ <summary>Bug A</summary>
+ </bug>
+ <bug>
+ <uuid>b</uuid>
+ <short-name>b</short-name>
+ <severity>minor</severity>
+ <status>closed</status>
+ <creator>Jane Doe &lt;jdoe@example.com&gt;</creator>
+ <created>Thu, 01 Jan 1970 00:00:00 +0000</created>
+ <summary>Bug B</summary>
+ </bug>
+</be-xml>
+
diff --git a/interfaces/email/interactive/send_pgp_mime.py b/interfaces/email/interactive/send_pgp_mime.py
index c19483e..517b1f0 100644
--- a/interfaces/email/interactive/send_pgp_mime.py
+++ b/interfaces/email/interactive/send_pgp_mime.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
#
-# Copyright (C) 2009 W. Trevor King <wking@drexel.edu>
+# Copyright (C) 2009-2010 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
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.txt b/interfaces/web/Bugs-Everywhere-Web/README.txt
deleted file mode 100644
index 10774df..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/README.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-Bugs-Everywhere-Web
-
-This is a TurboGears (http://www.turbogears.org) project. It can be
-started by running the start-beweb.py script.
-
-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.
-
-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
-
-
-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', '&': '&amp;', '\x3c': '&lt;',
- '\x3e': '&gt;'}
- for ch in to_unix(text):
- if ch == ' ' and first_space is True:
- yield '&#160;'
- 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
deleted file mode 100644
index 790e438..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-b.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 5b43259..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-bl.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 6cfd62c..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-br.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index a6ce3ce..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-l.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 1ffd6f8..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-r.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 0129b0c..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-t.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index d616b77..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-tl.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 18e542e..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds-tr.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 05a190e..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds2-b.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 0c3ea4c..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ds2-r.png
+++ /dev/null
Binary files differ
diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.ico b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.ico
deleted file mode 100644
index 339d09c..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.png
deleted file mode 100644
index 6dc53ee..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/favicon.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index cb4b56c..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/half-spiral.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 2b2d87d..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/header_inner.png
+++ /dev/null
Binary files differ
diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/info.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/info.png
deleted file mode 100644
index 329c523..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/info.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 25d3cfa..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-b.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index f496223..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-bl.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 74cbd91..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-br.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index dd567fa..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-l.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 9ac4486..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-r.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index fbb06c8..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-t.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 9336290..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-tl.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index de74808..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/is-tr.png
+++ /dev/null
Binary files differ
diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ok.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ok.png
deleted file mode 100644
index fee6751..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/ok.png
+++ /dev/null
Binary files differ
diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/shadows.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/shadows.png
deleted file mode 100644
index 9ddc676..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/shadows.png
+++ /dev/null
Binary files differ
diff --git a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/spiral.png b/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/spiral.png
deleted file mode 100644
index b4bcb1e..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/spiral.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index bc9c79c..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/tg_under_the_hood.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 90e84b7..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/beweb/static/images/under_the_hood_blue.png
+++ /dev/null
Binary files differ
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>&#160;</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">&nbsp;</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/server.log b/interfaces/web/Bugs-Everywhere-Web/server.log
deleted file mode 100644
index fe02ade..0000000
--- a/interfaces/web/Bugs-Everywhere-Web/server.log
+++ /dev/null
@@ -1,26 +0,0 @@
-2005/12/01 15:44:05 CONFIG INFO Server parameters:
-2005/12/01 15:44:05 CONFIG INFO server.environment: production
-2005/12/01 15:44:05 CONFIG INFO server.logToScreen: False
-2005/12/01 15:44:05 CONFIG INFO server.logFile: server.log
-2005/12/01 15:44:05 CONFIG INFO server.protocolVersion: HTTP/1.0
-2005/12/01 15:44:05 CONFIG INFO server.socketHost:
-2005/12/01 15:44:05 CONFIG INFO server.socketPort: 8080
-2005/12/01 15:44:05 CONFIG INFO server.socketFile:
-2005/12/01 15:44:05 CONFIG INFO server.reverseDNS: False
-2005/12/01 15:44:05 CONFIG INFO server.socketQueueSize: 5
-2005/12/01 15:44:05 CONFIG INFO server.threadPool: 0
-2005/12/01 15:44:05 HTTP INFO Serving HTTP on http://localhost:8080/
-2005/12/01 15:44:17 HTTP INFO 127.0.0.1 - GET / HTTP/1.1
-2005/12/01 15:44:37 HTTP INFO 192.168.2.12 - GET / HTTP/1.1
-2005/12/01 15:44:42 HTTP INFO 192.168.2.12 - GET /be HTTP/1.1
-2005/12/01 15:44:43 HTTP INFO 192.168.2.12 - GET /be/301724b1-3853-4aff-8f23-44373df7cf1c HTTP/1.1
-2005/12/01 15:44:48 HTTP INFO 192.168.2.12 - GET /be/ HTTP/1.1
-2005/12/01 15:44:50 HTTP INFO 192.168.2.12 - GET / HTTP/1.1
-2005/12/01 15:44:53 HTTP INFO 192.168.2.12 - GET /devel/ HTTP/1.1
-2005/12/01 15:44:58 HTTP INFO 192.168.2.12 - GET / HTTP/1.1
-2005/12/01 15:52:57 HTTP INFO 127.0.0.1 - GET /devel HTTP/1.1
-2005/12/01 15:52:59 HTTP INFO 127.0.0.1 - GET /devel HTTP/1.1
-2005/12/01 15:53:25 HTTP INFO 127.0.0.1 - GET /devel HTTP/1.1
-2005/12/01 15:53:29 HTTP INFO <Ctrl-C> hit: shutting down server
-2005/12/01 15:53:29 HTTP INFO HTTP Server shut down
-2005/12/01 15:53:29 HTTP INFO CherryPy shut down
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 a740117..0000000
--- a/interfaces/xml/be-mbox-to-xml
+++ /dev/null
@@ -1,151 +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 imput into be.
- $ cat mbox | be-mbox-to-xml | be comment --xml <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.
- """
- return email.utils.formataddr(email.utils.parseaddr(address))
-
-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"<comment-list>"
- for message in mb:
- print comment_message_to_xml(message)
- print u"</comment-list>"
-
-
-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 c630447..0000000
--- a/interfaces/xml/be-xml-to-mbox
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2009 Chris Ball <cjb@laptop.org>
-# 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"target",
- u"reporter",
- u"creator",
- u"created",
- u"summary",
- u"comments",
- u"extra-strings"]
- def print_to_mbox(self):
- 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"])
- print ""
- print self["summary"]
- print ""
- if "extra-strings" in self:
- print "extra strings:\n ",
- print '\n '.join(self["extra_strings"])
- 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"]
- 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 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 == "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 ["bugs", "bug-list"]:
- for b_elt in element.getchildren():
- b = Bug()
- b.init_from_etree(b_elt)
- b.print_to_mbox()
- elif element.tag in ["comments", "comment-list"]:
- for c_elt in element.getchildren():
- c = Comment()
- c.init_from_etree(c_elt)
- c.print_to_mbox()
-
-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)