aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Bentley <aaron.bentley@utoronto.ca>2007-07-15 12:43:30 -0400
committerAaron Bentley <aaron.bentley@utoronto.ca>2007-07-15 12:43:30 -0400
commit7969f5ec12c0107b7c799a7bf26d8c43c1615b15 (patch)
tree1d7f3f22fceabe46752fe85907bd24c40175abe2
parent9703aefca39996f954a91f5426f193c06661e69c (diff)
parentb14962ab20d38c2a8fdaba8ecde55174141891a5 (diff)
downloadbugseverywhere-7969f5ec12c0107b7c799a7bf26d8c43c1615b15.tar.gz
Merge from panometrics
-rw-r--r--.be/bugs/9ce2f015-8ea0-43a5-a03d-fc36f6d202fe/values35
-rw-r--r--.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/bcd6e5d4-8d03-43ad-a10d-17619735d077/body5
-rw-r--r--.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/bcd6e5d4-8d03-43ad-a10d-17619735d077/values28
-rw-r--r--.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/e5decfc6-050b-4283-8776-977bf85b2c99/body3
-rw-r--r--.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/e5decfc6-050b-4283-8776-977bf85b2c99/values21
-rw-r--r--.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/values35
-rw-r--r--.bzrignore6
-rw-r--r--Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/SOURCES.txt44
-rw-r--r--Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/dependency_links.txt1
-rw-r--r--Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/not-zip-safe1
-rw-r--r--Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/requires.txt2
-rw-r--r--Bugs-Everywhere-Web/beweb/config/app.cfg42
-rw-r--r--Bugs-Everywhere-Web/beweb/config/log.cfg29
-rw-r--r--Bugs-Everywhere-Web/beweb/controllers.py18
-rw-r--r--Bugs-Everywhere-Web/beweb/formatting.py2
-rw-r--r--Bugs-Everywhere-Web/beweb/json.py13
-rw-r--r--Bugs-Everywhere-Web/beweb/model.py106
-rw-r--r--Bugs-Everywhere-Web/beweb/release.py1
-rw-r--r--Bugs-Everywhere-Web/beweb/static/css/style.css232
-rw-r--r--Bugs-Everywhere-Web/beweb/static/images/header_inner.pngbin0 -> 37537 bytes
-rw-r--r--Bugs-Everywhere-Web/beweb/static/images/info.pngbin0 -> 2889 bytes
-rw-r--r--Bugs-Everywhere-Web/beweb/static/images/ok.pngbin0 -> 25753 bytes
-rw-r--r--Bugs-Everywhere-Web/beweb/static/images/tg_under_the_hood.pngbin0 -> 4010 bytes
-rw-r--r--Bugs-Everywhere-Web/beweb/static/images/under_the_hood_blue.pngbin0 -> 2667 bytes
-rw-r--r--Bugs-Everywhere-Web/beweb/templates/login.kid4
-rw-r--r--Bugs-Everywhere-Web/beweb/templates/master.kid142
-rw-r--r--Bugs-Everywhere-Web/beweb/templates/welcome.kid83
-rw-r--r--Bugs-Everywhere-Web/beweb/tests/test_model.py17
-rw-r--r--Bugs-Everywhere-Web/dev.cfg42
-rw-r--r--Bugs-Everywhere-Web/sample-prod.cfg71
-rw-r--r--Bugs-Everywhere-Web/setup.py4
-rwxr-xr-xBugs-Everywhere-Web/start-beweb.py9
-rw-r--r--libbe/bugdir.py7
-rw-r--r--libbe/bzr.py9
-rw-r--r--libbe/hg.py115
-rw-r--r--libbe/names.py12
-rw-r--r--libbe/rcs.py20
37 files changed, 888 insertions, 271 deletions
diff --git a/.be/bugs/9ce2f015-8ea0-43a5-a03d-fc36f6d202fe/values b/.be/bugs/9ce2f015-8ea0-43a5-a03d-fc36f6d202fe/values
new file mode 100644
index 0000000..0292ab5
--- /dev/null
+++ b/.be/bugs/9ce2f015-8ea0-43a5-a03d-fc36f6d202fe/values
@@ -0,0 +1,35 @@
+
+
+
+creator=abentley
+
+
+
+
+
+
+severity=minor
+
+
+
+
+
+
+status=open
+
+
+
+
+
+
+summary=Add last-modified field to bugs
+
+
+
+
+
+
+time=Thu, 14 Sep 2006 18:08:53 +0000
+
+
+
diff --git a/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/bcd6e5d4-8d03-43ad-a10d-17619735d077/body b/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/bcd6e5d4-8d03-43ad-a10d-17619735d077/body
new file mode 100644
index 0000000..c3b0f20
--- /dev/null
+++ b/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/bcd6e5d4-8d03-43ad-a10d-17619735d077/body
@@ -0,0 +1,5 @@
+There is definitely a difference between the person who reports a bug and the
+person who enters it in the system. For example, you are reporting bugs to me,
+and I am entering them in the Bugs Everywhere bug list.
+
+Perhaps there should be two fields.
diff --git a/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/bcd6e5d4-8d03-43ad-a10d-17619735d077/values b/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/bcd6e5d4-8d03-43ad-a10d-17619735d077/values
new file mode 100644
index 0000000..b2bedbb
--- /dev/null
+++ b/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/bcd6e5d4-8d03-43ad-a10d-17619735d077/values
@@ -0,0 +1,28 @@
+
+
+
+Content-type=text/plain
+
+
+
+
+
+
+Date=Thu, 14 Sep 2006 18:05:48 +0000
+
+
+
+
+
+
+From=abentley
+
+
+
+
+
+
+In-reply-to=e5decfc6-050b-4283-8776-977bf85b2c99
+
+
+
diff --git a/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/e5decfc6-050b-4283-8776-977bf85b2c99/body b/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/e5decfc6-050b-4283-8776-977bf85b2c99/body
new file mode 100644
index 0000000..23cb999
--- /dev/null
+++ b/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/e5decfc6-050b-4283-8776-977bf85b2c99/body
@@ -0,0 +1,3 @@
+Jens Mueller:
+Referring to the fields describing a bug, I suggest the following:
+The field 'Creator' should be named 'Reporter' (minor issue).
diff --git a/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/e5decfc6-050b-4283-8776-977bf85b2c99/values b/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/e5decfc6-050b-4283-8776-977bf85b2c99/values
new file mode 100644
index 0000000..9e82a6e
--- /dev/null
+++ b/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/comments/e5decfc6-050b-4283-8776-977bf85b2c99/values
@@ -0,0 +1,21 @@
+
+
+
+Content-type=text/plain
+
+
+
+
+
+
+Date=Thu, 14 Sep 2006 18:03:41 +0000
+
+
+
+
+
+
+From=abentley
+
+
+
diff --git a/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/values b/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/values
new file mode 100644
index 0000000..ac013c5
--- /dev/null
+++ b/.be/bugs/e2f6514c-5f9f-4734-a537-daf3fbe7e9a0/values
@@ -0,0 +1,35 @@
+
+
+
+creator=abentley
+
+
+
+
+
+
+severity=minor
+
+
+
+
+
+
+status=open
+
+
+
+
+
+
+summary=Add a reporter field
+
+
+
+
+
+
+time=Thu, 14 Sep 2006 16:47:57 +0000
+
+
+
diff --git a/.bzrignore b/.bzrignore
index 5ddfb0e..a051550 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -2,3 +2,9 @@ Bugs-Everywhere-Web/beweb/config.py
./build
Bugs-Everywhere-Web/beweb/database.sqlite
Bugs-Everywhere-Web/beweb/catwalk-session
+*.pyc
+*.sw[pon]
+fte.dsk
+*~
+./.shelf
+Bugs-Everywhere-Web/devdata.sqlite
diff --git a/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/SOURCES.txt b/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/SOURCES.txt
new file mode 100644
index 0000000..ab62ee4
--- /dev/null
+++ b/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/SOURCES.txt
@@ -0,0 +1,44 @@
+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/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/dependency_links.txt b/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/not-zip-safe b/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/not-zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/not-zip-safe
@@ -0,0 +1 @@
+
diff --git a/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/requires.txt b/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/requires.txt
index b4e1d25..5fd6f71 100644
--- a/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/requires.txt
+++ b/Bugs-Everywhere-Web/Bugs_Everywhere_Web.egg-info/requires.txt
@@ -1 +1 @@
-TurboGears >= 0.8a4 \ No newline at end of file
+TurboGears >= 1.0b1 \ No newline at end of file
diff --git a/Bugs-Everywhere-Web/beweb/config/app.cfg b/Bugs-Everywhere-Web/beweb/config/app.cfg
new file mode 100644
index 0000000..d37cf67
--- /dev/null
+++ b/Bugs-Everywhere-Web/beweb/config/app.cfg
@@ -0,0 +1,42 @@
+[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
+
+[/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/Bugs-Everywhere-Web/beweb/config/log.cfg b/Bugs-Everywhere-Web/beweb/config/log.cfg
new file mode 100644
index 0000000..ce776f8
--- /dev/null
+++ b/Bugs-Everywhere-Web/beweb/config/log.cfg
@@ -0,0 +1,29 @@
+# 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/Bugs-Everywhere-Web/beweb/controllers.py b/Bugs-Everywhere-Web/beweb/controllers.py
index 4417a63..358e74a 100644
--- a/Bugs-Everywhere-Web/beweb/controllers.py
+++ b/Bugs-Everywhere-Web/beweb/controllers.py
@@ -1,12 +1,20 @@
-import turbogears
-from turbogears import controllers, expose, redirect, identity
+import logging
+
import cherrypy
+import turbogears
+from turbogears import controllers, expose, validate, redirect, identity
+
from libbe.bugdir import (tree_root, cmp_severity, new_bug, new_comment,
NoRootEntry)
from libbe import names
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])
@@ -112,9 +120,9 @@ class Bug(PrestHandler):
assigned = None
bug.assigned = assigned
bug.save()
- bug.rcs.precommit(bug.path)
- bug.rcs.commit(bug.path, "Auto-commit")
- bug.rcs.postcommit(bug.path)
+# bug.rcs.precommit(bug.path)
+# bug.rcs.commit(bug.path, "Auto-commit")
+# bug.rcs.postcommit(bug.path)
raise cherrypy.HTTPRedirect(bug_list_url(bug_data["project"]))
def instantiate(self, project, bug):
diff --git a/Bugs-Everywhere-Web/beweb/formatting.py b/Bugs-Everywhere-Web/beweb/formatting.py
index 44ed849..b68d328 100644
--- a/Bugs-Everywhere-Web/beweb/formatting.py
+++ b/Bugs-Everywhere-Web/beweb/formatting.py
@@ -33,7 +33,7 @@ def soft_text(text):
def soft_pre(text):
return XML('<div style="font-family: monospace">'+
- ''.join(soft_text(text))+'</div>')
+ ''.join(soft_text(text)).encode('utf-8')+'</div>')
def get_rest_body(rest):
diff --git a/Bugs-Everywhere-Web/beweb/json.py b/Bugs-Everywhere-Web/beweb/json.py
new file mode 100644
index 0000000..6e100c3
--- /dev/null
+++ b/Bugs-Everywhere-Web/beweb/json.py
@@ -0,0 +1,13 @@
+# 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/Bugs-Everywhere-Web/beweb/model.py b/Bugs-Everywhere-Web/beweb/model.py
index 6a603bb..aa4b6b6 100644
--- a/Bugs-Everywhere-Web/beweb/model.py
+++ b/Bugs-Everywhere-Web/beweb/model.py
@@ -1,15 +1,107 @@
+from datetime import datetime
+
from sqlobject import *
from turbogears.database import PackageHub
-# Uncomment the following line if you wish to use Identity and SO_Provider
-from turbogears.identity.soprovider import TG_User, TG_Group, TG_Permission
from turbogears import identity
hub = PackageHub("beweb")
__connection__ = hub
-def people_map():
- return dict([(u.userId, u.displayName) for u in TG_User.select() if
- "fixbugs" in identity.current.permissions])
+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 YourDataClass(SQLObject):
-# pass
+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/Bugs-Everywhere-Web/beweb/release.py b/Bugs-Everywhere-Web/beweb/release.py
index 0232912..9d64bf7 100644
--- a/Bugs-Everywhere-Web/beweb/release.py
+++ b/Bugs-Everywhere-Web/beweb/release.py
@@ -3,6 +3,7 @@
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"
diff --git a/Bugs-Everywhere-Web/beweb/static/css/style.css b/Bugs-Everywhere-Web/beweb/static/css/style.css
index ada46f3..6fe197f 100644
--- a/Bugs-Everywhere-Web/beweb/static/css/style.css
+++ b/Bugs-Everywhere-Web/beweb/static/css/style.css
@@ -1,116 +1,116 @@
-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;
-}
+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/Bugs-Everywhere-Web/beweb/static/images/header_inner.png b/Bugs-Everywhere-Web/beweb/static/images/header_inner.png
new file mode 100644
index 0000000..2b2d87d
--- /dev/null
+++ b/Bugs-Everywhere-Web/beweb/static/images/header_inner.png
Binary files differ
diff --git a/Bugs-Everywhere-Web/beweb/static/images/info.png b/Bugs-Everywhere-Web/beweb/static/images/info.png
new file mode 100644
index 0000000..329c523
--- /dev/null
+++ b/Bugs-Everywhere-Web/beweb/static/images/info.png
Binary files differ
diff --git a/Bugs-Everywhere-Web/beweb/static/images/ok.png b/Bugs-Everywhere-Web/beweb/static/images/ok.png
new file mode 100644
index 0000000..fee6751
--- /dev/null
+++ b/Bugs-Everywhere-Web/beweb/static/images/ok.png
Binary files differ
diff --git a/Bugs-Everywhere-Web/beweb/static/images/tg_under_the_hood.png b/Bugs-Everywhere-Web/beweb/static/images/tg_under_the_hood.png
new file mode 100644
index 0000000..bc9c79c
--- /dev/null
+++ b/Bugs-Everywhere-Web/beweb/static/images/tg_under_the_hood.png
Binary files differ
diff --git a/Bugs-Everywhere-Web/beweb/static/images/under_the_hood_blue.png b/Bugs-Everywhere-Web/beweb/static/images/under_the_hood_blue.png
new file mode 100644
index 0000000..90e84b7
--- /dev/null
+++ b/Bugs-Everywhere-Web/beweb/static/images/under_the_hood_blue.png
Binary files differ
diff --git a/Bugs-Everywhere-Web/beweb/templates/login.kid b/Bugs-Everywhere-Web/beweb/templates/login.kid
index 2c150db..e7ad852 100644
--- a/Bugs-Everywhere-Web/beweb/templates/login.kid
+++ b/Bugs-Everywhere-Web/beweb/templates/login.kid
@@ -8,7 +8,7 @@
<meta content="text/html; charset=UTF-8"
http-equiv="content-type" py:replace="''"/>
<title>Login</title>
- <style>
+ <style type="text/css">
#loginBox
{
width: 30%;
@@ -97,7 +97,7 @@
</tr>
<tr>
<td colspan="2" class="buttons">
- <input type="submit" value="Login"/>
+ <input type="submit" name="login" value="Login"/>
</td>
</tr>
</table>
diff --git a/Bugs-Everywhere-Web/beweb/templates/master.kid b/Bugs-Everywhere-Web/beweb/templates/master.kid
index 54f6bad..0772524 100644
--- a/Bugs-Everywhere-Web/beweb/templates/master.kid
+++ b/Bugs-Everywhere-Web/beweb/templates/master.kid
@@ -1,71 +1,71 @@
-<!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>
- #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.displayName}.
- <a href="/logout">Logout</a>
- </span>
- </div>
-
- <div py:if="tg_flash" class="flash" py:content="tg_flash"></div>
-
- <div py:replace="item[:]"/>
-
-</body>
-<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>
-
-</html>
+<!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/Bugs-Everywhere-Web/beweb/templates/welcome.kid b/Bugs-Everywhere-Web/beweb/templates/welcome.kid
index 0d3cf3e..08abd21 100644
--- a/Bugs-Everywhere-Web/beweb/templates/welcome.kid
+++ b/Bugs-Everywhere-Web/beweb/templates/welcome.kid
@@ -1,33 +1,50 @@
-<!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>
- <p>Congratulations, your TurboGears application is running as of <span py:replace="now">now</span>.</p>
-
- <h2>Are you ready to Gear Up?</h2>
-
- <p>Take the following steps to dive right in:</p>
-
- <ol>
- <li>Edit your project's model.py to create SQLObjects representing the data you're working with</li>
- <li>Edit your dev.cfg file to point to the database you'll be using</li>
- <li>Run "<code>tg-admin sql create</code>" to create the tables in the database</li>
- <li>Edit controllers.py to add the functionality to your webapp</li>
- <li>Change the master.kid template to have the headers and footers for your application.</li>
- <li>Change welcome.kid (this template) or create a new one to display your data</li>
- <li>Repeat steps 4-6 until done.</li>
- <li><b>Profit!</b></li>
- </ol>
-
- <p>If you haven't already, you might check out some of the <a href="http://www.turbogears.org/docs/" >documentation</a>.</p>
-
- <p>Thanks for using TurboGears! See you on the <a href="http://groups.google.com/group/turbogears" >mailing list</a> and the "turbogears" channel on irc.freenode.org!</p>
-
-</body>
-</html>
+<!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/Bugs-Everywhere-Web/beweb/tests/test_model.py b/Bugs-Everywhere-Web/beweb/tests/test_model.py
index 5346f8b..74c4e83 100644
--- a/Bugs-Everywhere-Web/beweb/tests/test_model.py
+++ b/Bugs-Everywhere-Web/beweb/tests/test_model.py
@@ -4,21 +4,20 @@
# choice for testing, because you can use an in-memory database
# which is very fast.
-from turbogears import testutil
-#from beweb.model import YourDataClass
-#from turbogears.identity.soprovider import TG_User
+from turbogears import testutil, database
+# from beweb.model import YourDataClass, User
# database.set_db_uri("sqlite:///:memory:")
-# class testTG_User(testutil.DBTest):
+# class TestUser(testutil.DBTest):
# def get_model(self):
-# return TG_User
+# return User
#
# def test_creation(self):
# "Object creation should set the name"
-# obj = TG_User(userId = "creosote",
-# emailAddress = "spam@python.not",
-# displayName = "Mr Creosote",
+# obj = User(user_name = "creosote",
+# email_address = "spam@python.not",
+# display_name = "Mr Creosote",
# password = "Wafer-thin Mint")
-# assert obj.displayName == "Mr Creosote"
+# assert obj.display_name == "Mr Creosote"
diff --git a/Bugs-Everywhere-Web/dev.cfg b/Bugs-Everywhere-Web/dev.cfg
index c8e1658..eda9e6c 100644
--- a/Bugs-Everywhere-Web/dev.cfg
+++ b/Bugs-Everywhere-Web/dev.cfg
@@ -2,14 +2,19 @@
# 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
-# yourpackage/config/app.cfg
+# 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"
+# 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
@@ -17,8 +22,7 @@ sqlobject.dburi="sqlite://%(package_dir)s/database.sqlite"
# sqlobject.dburi="notrans_mysql://username:password@hostname:port/databasename"
# for Windows users, sqlite URIs look like:
-# sqlobject.dburi="sqlite:///drive_letter|/path/to/file"
-
+# sqlobject.dburi="sqlite:///drive_letter:/path/to/file"
# SERVER
@@ -31,7 +35,37 @@ sqlobject.dburi="sqlite://%(package_dir)s/database.sqlite"
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/Bugs-Everywhere-Web/sample-prod.cfg b/Bugs-Everywhere-Web/sample-prod.cfg
new file mode 100644
index 0000000..d1052f8
--- /dev/null
+++ b/Bugs-Everywhere-Web/sample-prod.cfg
@@ -0,0 +1,71 @@
+[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/Bugs-Everywhere-Web/setup.py b/Bugs-Everywhere-Web/setup.py
index 29f1d6f..8ba3da2 100644
--- a/Bugs-Everywhere-Web/setup.py
+++ b/Bugs-Everywhere-Web/setup.py
@@ -16,7 +16,9 @@ setup(
#download_url=download_url,
#license=license,
- install_requires = ["TurboGears >= 0.9a4"],
+ install_requires = [
+ "TurboGears >= 1.0b1",
+ ],
scripts = ["start-beweb.py"],
zip_safe=False,
packages=find_packages(),
diff --git a/Bugs-Everywhere-Web/start-beweb.py b/Bugs-Everywhere-Web/start-beweb.py
index 6eba527..39100e7 100755
--- a/Bugs-Everywhere-Web/start-beweb.py
+++ b/Bugs-Everywhere-Web/start-beweb.py
@@ -15,15 +15,14 @@ import sys
# probably installed
if len(sys.argv) > 1:
turbogears.update_config(configfile=sys.argv[1],
- modulename="beweb.config.app")
+ modulename="beweb.config")
elif exists(join(dirname(__file__), "setup.py")):
turbogears.update_config(configfile="dev.cfg",
- modulename="beweb.config.app")
+ modulename="beweb.config")
else:
turbogears.update_config(configfile="prod.cfg",
- modulename="beweb.config.app")
+ modulename="beweb.config")
from beweb.controllers import Root
-cherrypy.root = Root()
-cherrypy.server.start()
+turbogears.start_server(Root())
diff --git a/libbe/bugdir.py b/libbe/bugdir.py
index 414b47e..bfe9a27 100644
--- a/libbe/bugdir.py
+++ b/libbe/bugdir.py
@@ -141,7 +141,7 @@ class BugDir:
except NoSuchFile:
self.settings = {"rcs_name": "None"}
- rcs_name = setting_property("rcs_name", ("None", "bzr", "Arch"))
+ rcs_name = setting_property("rcs_name", ("None", "bzr", "Arch", "hg"))
_rcs = None
target = setting_property("target")
@@ -287,8 +287,11 @@ class Bug(object):
return Comment(uuid, self)
def iter_comment_ids(self):
+ path = self.get_path("comments")
+ if not os.path.isdir(path):
+ return
try:
- for uuid in os.listdir(self.get_path("comments")):
+ for uuid in os.listdir(path):
if (uuid.startswith('.')):
continue
yield uuid
diff --git a/libbe/bzr.py b/libbe/bzr.py
index b53429c..ddda334 100644
--- a/libbe/bzr.py
+++ b/libbe/bzr.py
@@ -25,14 +25,7 @@ def invoke_client(*args, **kwargs):
expect = kwargs.get('expect', (0, 1))
cl_args = ["bzr"]
cl_args.extend(args)
- if directory:
- old_dir = os.getcwd()
- os.chdir(directory)
- try:
- status,output,error = invoke(cl_args, expect)
- finally:
- if directory:
- os.chdir(old_dir)
+ status,output,error = invoke(cl_args, expect, cwd=directory)
return status, output
def add_id(filename, paranoid=False):
diff --git a/libbe/hg.py b/libbe/hg.py
new file mode 100644
index 0000000..35de8e0
--- /dev/null
+++ b/libbe/hg.py
@@ -0,0 +1,115 @@
+# Copyright (C) 2007 Steve Borho <steve@borho.org>
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+import os
+import tempfile
+
+import config
+from rcs import invoke, CommandError
+
+def invoke_client(*args, **kwargs):
+ directory = kwargs['directory']
+ expect = kwargs.get('expect', (0, 1))
+ cl_args = ["hg"]
+ cl_args.extend(args)
+ status,output,error = invoke(cl_args, expect, cwd=directory)
+ return status, output
+
+def add_id(filename, paranoid=False):
+ invoke_client("add", filename, directory='.')
+
+def delete_id(filename):
+ invoke_client("rm", filename, directory='.')
+
+def mkdir(path, paranoid=False):
+ os.mkdir(path)
+
+def set_file_contents(path, contents):
+ add = not os.path.exists(path)
+ file(path, "wb").write(contents)
+ if add:
+ add_id(path)
+
+def lookup_revision(revno, directory):
+ return invoke_client('log', '--rev', str(revno), '--template={node}',
+ directory=directory)[1].rstrip('\n')
+
+def export(revno, directory, revision_dir):
+ invoke_client("archive", "--rev", str(revno), revision_dir,
+ directory=directory)
+
+def find_or_make_export(revno, directory):
+ revision_id = lookup_revision(revno, directory)
+ home = os.path.expanduser("~")
+ revision_root = os.path.join(home, ".be_revs")
+ if not os.path.exists(revision_root):
+ os.mkdir(revision_root)
+ revision_dir = os.path.join(revision_root, revision_id)
+ if not os.path.exists(revision_dir):
+ export(revno, directory, revision_dir)
+ return revision_dir
+
+def hg_root(path):
+ return invoke_client("root", "-R", path, directory=None)[1].rstrip('\r')
+
+def path_in_reference(bug_dir, spec):
+ if spec is None:
+ spec = int(invoke_client('tip', '--template="{rev}"',
+ directory=bug_dir)[1])
+ rel_bug_dir = bug_dir[len(hg_root(bug_dir)):]
+ export_root = find_or_make_export(spec, directory=bug_dir)
+ return os.path.join(export_root, rel_bug_dir)
+
+
+def unlink(path):
+ try:
+ os.unlink(path)
+ delete_id(path)
+ except OSError, e:
+ if e.errno != 2:
+ raise
+
+
+def detect(path):
+ """Detect whether a directory is revision-controlled using Mercurial"""
+ path = os.path.realpath(path)
+ old_path = None
+ while True:
+ if os.path.exists(os.path.join(path, ".hg")):
+ return True
+ if path == old_path:
+ return False
+ old_path = path
+ path = os.path.dirname(path)
+
+def precommit(directory):
+ pass
+
+def commit(directory, summary, body=None):
+ if body is not None:
+ summary += '\n' + body
+ descriptor, filename = tempfile.mkstemp()
+ try:
+ temp_file = os.fdopen(descriptor, 'wb')
+ temp_file.write(summary)
+ temp_file.close()
+ invoke_client('commit', '--logfile', filename, directory=directory)
+ finally:
+ os.unlink(filename)
+
+def postcommit(directory):
+ pass
+
+name = "hg"
diff --git a/libbe/names.py b/libbe/names.py
index cbcfbf8..d2e077a 100644
--- a/libbe/names.py
+++ b/libbe/names.py
@@ -14,13 +14,21 @@
# 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
-import commands
+
import os
import sys
def uuid():
- return commands.getoutput('uuidgen')
+ # this code borrowed from standard commands module
+ # but adapted to win32
+ pipe = os.popen('uuidgen', 'r')
+ text = pipe.read()
+ sts = pipe.close()
+ if sts not in (0, None):
+ raise "Failed to run uuidgen"
+ if text[-1:] == '\n': text = text[:-1]
+ return text
def creator():
if sys.platform != "win32":
diff --git a/libbe/rcs.py b/libbe/rcs.py
index ac96734..64503db 100644
--- a/libbe/rcs.py
+++ b/libbe/rcs.py
@@ -15,6 +15,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
from subprocess import Popen, PIPE
+import sys
+
def rcs_by_name(rcs_name):
"""Return the module for the RCS with the given name"""
if rcs_name == "Arch":
@@ -23,6 +25,9 @@ def rcs_by_name(rcs_name):
elif rcs_name == "bzr":
import bzr
return bzr
+ elif rcs_name == "hg":
+ import hg
+ return hg
elif rcs_name == "None":
import no_rcs
return no_rcs
@@ -31,10 +36,13 @@ def detect(dir):
"""Return the module for the rcs being used in this directory"""
import arch
import bzr
+ import hg
if arch.detect(dir):
return arch
elif bzr.detect(dir):
return bzr
+ elif hg.detect(dir):
+ return hg
import no_rcs
return no_rcs
@@ -44,10 +52,14 @@ class CommandError(Exception):
self.err_str = err_str
self.status = status
-def invoke(args, expect=(0,)):
- q = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE)
- output = q.stdout.read()
- error = q.stderr.read()
+def invoke(args, expect=(0,), cwd=None):
+ if sys.platform != "win32":
+ q = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=cwd)
+ else:
+ # win32 don't have os.execvp() so have to run command in a shell
+ q = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True,
+ cwd=cwd)
+ output, error = q.communicate()
status = q.wait()
if status not in expect:
raise CommandError(error, status)