aboutsummaryrefslogtreecommitdiffstats
path: root/libbe/bugdir.py
diff options
context:
space:
mode:
authorW. Trevor King <wking@drexel.edu>2008-11-14 19:25:44 -0500
committerW. Trevor King <wking@drexel.edu>2008-11-14 19:25:44 -0500
commit87e356c9208e955fcf6c20c0b271db87bdd48014 (patch)
tree8a9ef32cd7bd9798077824fb26e73c1358599d6a /libbe/bugdir.py
parent91b284cde8c4443cf0997798f4f847ce95409cd3 (diff)
downloadbugseverywhere-87e356c9208e955fcf6c20c0b271db87bdd48014.tar.gz
Split Bug and Comment class out to bug.py from bugdir.py
Comment should probably have it's own file too... I also tried to clean up the interface for setting status and severity. Both attributes involve selecting strings from predefined lists. The lists of valid strings (and descriptions of each string) are now defined in bug.py. The bug.py lists are then used to generate appropriate help strings in becommands/status.py and severity.py. This should make it easier to keep the help strings in synch with the validation information. The original status strings weren't documented, and I didn't know what they all ment, so I elimanted some of them. 'in-progress' and 'disabled' are no longer with us. Of course, it would be simple to add them back in if people don't agree with me on that. Due to the loss of 'disabled' I had to change the status of two bugs (11e and 597) to 'closed'. I removed becommands/inprogress.py as well. It's functionality was replaced by the more general status.py command, which mimics the severity.py command.
Diffstat (limited to 'libbe/bugdir.py')
-rw-r--r--libbe/bugdir.py262
1 files changed, 8 insertions, 254 deletions
diff --git a/libbe/bugdir.py b/libbe/bugdir.py
index bcc163c..7570bb3 100644
--- a/libbe/bugdir.py
+++ b/libbe/bugdir.py
@@ -23,6 +23,7 @@ import mapfile
import time
import utility
from rcs import rcs_by_name
+from bug import Bug
class NoBugDir(Exception):
def __init__(self, path):
@@ -108,7 +109,8 @@ def create_bug_dir(path, rcs):
raise
rcs.mkdir(os.path.join(root, "bugs"))
set_version(root, rcs)
- map_save(rcs, os.path.join(root, "settings"), {"rcs_name": rcs.name})
+ mapfile.map_save(rcs,
+ os.path.join(root, "settings"), {"rcs_name": rcs.name})
return BugDir(os.path.join(path, ".be"))
@@ -137,8 +139,8 @@ class BugDir:
self.dir = dir
self.bugs_path = os.path.join(self.dir, "bugs")
try:
- self.settings = map_load(os.path.join(self.dir, "settings"))
- except NoSuchFile:
+ self.settings = mapfile.map_load(os.path.join(self.dir, "settings"))
+ except mapfile.NoSuchFile:
self.settings = {"rcs_name": "None"}
rcs_name = setting_property("rcs_name", ("None", "bzr", "git", "Arch", "hg"))
@@ -147,7 +149,8 @@ class BugDir:
target = setting_property("target")
def save_settings(self):
- map_save(self.rcs, os.path.join(self.dir, "settings"), self.settings)
+ mapfile.map_save(self.rcs,
+ os.path.join(self.dir, "settings"), self.settings)
def get_rcs(self):
if self._rcs is not None and self.rcs_name == self._rcs.name:
@@ -188,258 +191,9 @@ class BugDir:
bug.uuid = uuid
return bug
-class InvalidValue(Exception):
+class InvalidValue(ValueError):
def __init__(self, name, value):
msg = "Cannot assign value %s to %s" % (value, name)
Exception.__init__(self, msg)
self.name = name
self.value = value
-
-
-def checked_property(name, valid):
- def getter(self):
- value = getattr(self, "_"+name)
- if value not in valid:
- raise InvalidValue(name, value)
- return value
-
- def setter(self, value):
- if value not in valid:
- raise InvalidValue(name, value)
- return setattr(self, "_"+name, value)
- return property(getter, setter)
-
-severity_levels = ("wishlist", "minor", "serious", "critical", "fatal")
-active_status = ("open", "in-progress", "waiting", "new", "verified")
-inactive_status = ("closed", "disabled", "fixed", "wontfix", "waiting")
-
-severity_value = {}
-for i in range(len(severity_levels)):
- severity_value[severity_levels[i]] = i
-
-class Bug(object):
- status = checked_property("status", (None,)+active_status+inactive_status)
- severity = checked_property("severity", (None, "wishlist", "minor",
- "serious", "critical", "fatal"))
-
- def __init__(self, path, uuid, rcs_name):
- self.path = path
- self.uuid = uuid
- if uuid is not None:
- dict = map_load(self.get_path("values"))
- else:
- dict = {}
-
- self.rcs_name = rcs_name
-
- self.summary = dict.get("summary")
- self.creator = dict.get("creator")
- self.target = dict.get("target")
- self.status = dict.get("status")
- self.severity = dict.get("severity")
- self.assigned = dict.get("assigned")
- self.time = dict.get("time")
- if self.time is not None:
- self.time = utility.str_to_time(self.time)
-
- def __repr__(self):
- return "Bug(uuid=%r)" % self.uuid
-
- def get_path(self, file):
- return os.path.join(self.path, self.uuid, file)
-
- def _get_active(self):
- return self.status in active_status
-
- active = property(_get_active)
-
- def add_attr(self, map, name):
- value = getattr(self, name)
- if value is not None:
- map[name] = value
-
- def save(self):
- map = {}
- self.add_attr(map, "assigned")
- self.add_attr(map, "summary")
- self.add_attr(map, "creator")
- self.add_attr(map, "target")
- self.add_attr(map, "status")
- self.add_attr(map, "severity")
- if self.time is not None:
- map["time"] = utility.time_to_str(self.time)
- path = self.get_path("values")
- map_save(rcs_by_name(self.rcs_name), path, map)
-
- def _get_rcs(self):
- return rcs_by_name(self.rcs_name)
-
- rcs = property(_get_rcs)
-
- def new_comment(self):
- if not os.path.exists(self.get_path("comments")):
- self.rcs.mkdir(self.get_path("comments"))
- comm = Comment(None, self)
- comm.uuid = names.uuid()
- return comm
-
- def get_comment(self, uuid):
- 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(path):
- if (uuid.startswith('.')):
- continue
- yield uuid
- except OSError, e:
- if e.errno != errno.ENOENT:
- raise
- return
-
- def list_comments(self):
- comments = [Comment(id, self) for id in self.iter_comment_ids()]
- comments.sort(cmp_date)
- return comments
-
-def cmp_date(comm1, comm2):
- return cmp(comm1.date, comm2.date)
-
-def new_bug(dir, uuid=None):
- bug = dir.new_bug(uuid)
- bug.creator = names.creator()
- bug.severity = "minor"
- bug.status = "open"
- bug.time = time.time()
- return bug
-
-def new_comment(bug, body=None):
- comm = bug.new_comment()
- comm.From = names.creator()
- comm.date = time.time()
- comm.body = body
- return comm
-
-def add_headers(obj, map, names):
- map_names = {}
- for name in names:
- map_names[name] = pyname_to_header(name)
- add_attrs(obj, map, names, map_names)
-
-def add_attrs(obj, map, names, map_names=None):
- if map_names is None:
- map_names = {}
- for name in names:
- map_names[name] = name
-
- for name in names:
- value = getattr(obj, name)
- if value is not None:
- map[map_names[name]] = value
-
-
-class Comment(object):
- def __init__(self, uuid, bug):
- object.__init__(self)
- self.uuid = uuid
- self.bug = bug
- if self.uuid is not None and self.bug is not None:
- mapfile = map_load(self.get_path("values"))
- self.date = utility.str_to_time(mapfile["Date"])
- self.From = mapfile["From"]
- self.in_reply_to = mapfile.get("In-reply-to")
- self.content_type = mapfile.get("Content-type", "text/plain")
- self.body = file(self.get_path("body")).read().decode("utf-8")
- else:
- self.date = None
- self.From = None
- self.in_reply_to = None
- self.content_type = "text/plain"
- self.body = None
-
- def save(self):
- map_file = {"Date": utility.time_to_str(self.date)}
- add_headers(self, map_file, ("From", "in_reply_to", "content_type"))
- if not os.path.exists(self.get_path(None)):
- self.bug.rcs.mkdir(self.get_path(None))
- map_save(self.bug.rcs, self.get_path("values"), map_file)
- self.bug.rcs.set_file_contents(self.get_path("body"),
- self.body.encode('utf-8'))
-
-
- def get_path(self, name):
- my_dir = os.path.join(self.bug.get_path("comments"), self.uuid)
- if name is None:
- return my_dir
- return os.path.join(my_dir, name)
-
-
-def thread_comments(comments):
- child_map = {}
- top_comments = []
- for comment in comments:
- child_map[comment.uuid] = []
- for comment in comments:
- if comment.in_reply_to is None or comment.in_reply_to not in child_map:
- top_comments.append(comment)
- continue
- child_map[comment.in_reply_to].append(comment)
-
- def recurse_children(comment):
- child_list = []
- for child in child_map[comment.uuid]:
- child_list.append(recurse_children(child))
- return (comment, child_list)
- return [recurse_children(c) for c in top_comments]
-
-
-def pyname_to_header(name):
- return name.capitalize().replace('_', '-')
-
-
-def map_save(rcs, path, map):
- """Save the map as a mapfile to the specified path"""
- add = not os.path.exists(path)
- output = file(path, "wb")
- mapfile.generate(output, map)
- if add:
- rcs.add_id(path)
-
-class NoSuchFile(Exception):
- def __init__(self, pathname):
- Exception.__init__(self, "No such file: %s" % pathname)
-
-
-def map_load(path):
- try:
- return mapfile.parse(file(path, "rb"))
- except IOError, e:
- if e.errno != errno.ENOENT:
- raise e
- raise NoSuchFile(path)
-
-
-class MockBug:
- def __init__(self, severity):
- self.severity = severity
-
-def cmp_severity(bug_1, bug_2):
- """
- Compare the severity levels of two bugs, with more sever bugs comparing
- as less.
-
- >>> cmp_severity(MockBug(None), MockBug(None))
- 0
- >>> cmp_severity(MockBug("wishlist"), MockBug(None)) < 0
- True
- >>> cmp_severity(MockBug(None), MockBug("wishlist")) > 0
- True
- >>> cmp_severity(MockBug("critical"), MockBug("wishlist")) < 0
- True
- """
- val_1 = severity_value.get(bug_1.severity)
- val_2 = severity_value.get(bug_2.severity)
- return -cmp(val_1, val_2)