aboutsummaryrefslogtreecommitdiffstats
path: root/libbe
diff options
context:
space:
mode:
authorW. Trevor King <wking@drexel.edu>2009-07-21 07:28:26 -0400
committerW. Trevor King <wking@drexel.edu>2009-07-21 07:28:26 -0400
commit4c7a9d837a268480e61124bba84b5fb01ec3728f (patch)
treeeb20c2f424a0b334316e25fa179d2307befba66d /libbe
parent9ef6ad576c01444e35b91dfee8d05b39ec911d45 (diff)
downloadbugseverywhere-4c7a9d837a268480e61124bba84b5fb01ec3728f.tar.gz
Cleaned up saving/sync_with_disk.
Got rid of a whole bunch of redundant .save() calls when sync_with_disk==True. Fixed up the "File-system access" portion of the BugDir docstring so we can all remember how things are supposed to work ;). Note that some .save() calls are still required. For example in becommands/merge.py, the copied comments have their .bug changed, but that is not a versioned property, so it doesn't trigger an automatic save, and we have to force the .save() by hand. libbe.rcs.RCS.mkdir() is now recursive by default, but you can set check_parents==False if you want it to fail in the case of missing parents. Because of the recursion, we removed the .update() call on preexisting directories, since there will be at least one of these occurrences for every .mkdir(check_parents=True) call, and I don't know of any VCS that actually needs them... Also stripped trailing whitespace from some files...
Diffstat (limited to 'libbe')
-rw-r--r--libbe/bug.py16
-rw-r--r--libbe/bugdir.py92
-rw-r--r--libbe/comment.py20
-rw-r--r--libbe/rcs.py10
4 files changed, 101 insertions, 37 deletions
diff --git a/libbe/bug.py b/libbe/bug.py
index 8be6010..e3dc1e0 100644
--- a/libbe/bug.py
+++ b/libbe/bug.py
@@ -252,6 +252,11 @@ class Bug(settings_object.SavedSettingsObject):
def __repr__(self):
return "Bug(uuid=%r)" % self.uuid
+ def set_sync_with_disk(self, value):
+ self.sync_with_disk = value
+ for comment in self.comments():
+ comment.set_sync_with_disk(value)
+
def _setting_attr_string(self, setting):
value = getattr(self, setting)
if value == None:
@@ -371,10 +376,17 @@ class Bug(settings_object.SavedSettingsObject):
mapfile.map_save(self.rcs, path, self._get_saved_settings())
def save(self):
+ """
+ Save any loaded contents to disk. Because of lazy loading of
+ comments, this is actually not too inefficient.
+
+ However, if self.sync_with_disk = True, then any changes are
+ automatically written to disk as soon as they happen, so
+ calling this method will just waste time (unless something
+ else has been messing with your on-disk files).
+ """
self.save_settings()
-
if len(self.comment_root) > 0:
- self.rcs.mkdir(self.get_path("comments"))
comment.saveComments(self)
def remove(self):
diff --git a/libbe/bugdir.py b/libbe/bugdir.py
index e37db81..9802502 100644
--- a/libbe/bugdir.py
+++ b/libbe/bugdir.py
@@ -51,7 +51,7 @@ class NoRootEntry(Exception):
class AlreadyInitialized(Exception):
def __init__(self, path):
self.path = path
- Exception.__init__(self,
+ Exception.__init__(self,
"Specified root is already initialized: %s" % path)
class MultipleBugMatches(ValueError):
@@ -70,7 +70,7 @@ class BugDir (list, settings_object.SavedSettingsObject):
"""
Sink to existing root
======================
-
+
Consider the following usage case:
You have a bug directory rooted in
/path/to/source
@@ -85,23 +85,35 @@ class BugDir (list, settings_object.SavedSettingsObject):
/path/to/source/GUI/.be miss
/path/to/source/.be hit!
So it still roots itself appropriately without much work for you.
-
+
File-system access
==================
-
- When rooted in non-bugdir directory, BugDirs live completely in
- memory until the first call to .save(). This creates a '.be'
- sub-directory containing configurations options, bugs, comments,
- etc. Once this sub-directory has been created (possibly by
- another BugDir instance) any changes to the BugDir in memory will
- be flushed to the file system automatically. However, the BugDir
- will only load information from the file system when it loads new
- bugs/comments that it doesn't already have in memory, or when it
- explicitly asked to do so (e.g. .load() or __init__(from_disk=True)).
-
+
+ BugDirs live completely in memory when .sync_with_disk is False.
+ This is the default configuration setup by BugDir(from_disk=False).
+ If .sync_with_disk == True (e.g. BugDir(from_disk=True)), then
+ any changes to the BugDir will be immediately written to disk.
+
+ If you want to change .sync_with_disk, we suggest you use
+ .set_sync_with_disk(), which propogates the new setting through to
+ all bugs/comments/etc. that have been loaded into memory. If
+ you've been living in memory and want to move to
+ .sync_with_disk==True, but you're not sure if anything has been
+ changed in memoryy, a call to save() is a safe move.
+
+ Regardless of .sync_with_disk, a call to .save() will write out
+ all the contents that the BugDir instance has loaded into memory.
+ If sync_with_disk has been True over the course of all interesting
+ changes, this .save() call will be a waste of time.
+
+ The BugDir will only load information from the file system when it
+ loads new bugs/comments that it doesn't already have in memory, or
+ when it explicitly asked to do so (e.g. .load() or
+ __init__(from_disk=True)).
+
Allow RCS initialization
========================
-
+
This one is for testing purposes. Setting it to True allows the
BugDir to search for an installed RCS backend and initialize it in
the root directory. This is a convenience option for supporting
@@ -109,7 +121,7 @@ class BugDir (list, settings_object.SavedSettingsObject):
Disable encoding manipulation
=============================
-
+
This one is for testing purposed. You might have non-ASCII
Unicode in your bugs, comments, files, etc. BugDir instances try
and support your preferred encoding scheme (e.g. "utf-8") when
@@ -160,7 +172,7 @@ class BugDir (list, settings_object.SavedSettingsObject):
def encoding(): return {}
def _setup_user_id(self, user_id):
- self.rcs.user_id = user_id
+ self.rcs.user_id = user_id
def _guess_user_id(self):
return self.rcs.get_user_id()
def _set_user_id(self, old_user_id, new_user_id):
@@ -215,7 +227,7 @@ settings easy. Don't set this attribute. Set .rcs instead, and
if uuid not in map:
map[uuid] = None
self._bug_map_value = map # ._bug_map_value used by @local_property
-
+
@Property
@primed_property(primer=_bug_map_gen)
@local_property("bug_map")
@@ -270,7 +282,7 @@ settings easy. Don't set this attribute. Set .rcs instead, and
# get a temporary rcs until we've loaded settings
self.sync_with_disk = False
self.rcs = self._guess_rcs()
-
+
if from_disk == True:
self.sync_with_disk = True
self.load()
@@ -284,6 +296,11 @@ settings easy. Don't set this attribute. Set .rcs instead, and
self.rcs = rcs
self._setup_user_id(self.user_id)
+ def set_sync_with_disk(self, value):
+ self.sync_with_disk = value
+ for bug in self:
+ bug.set_sync_with_disk(value)
+
def _find_root(self, path):
"""
Search for an existing bug database dir and it's ancestors and
@@ -302,7 +319,7 @@ settings easy. Don't set this attribute. Set .rcs instead, and
if beroot == None:
raise NoBugDir(path)
return beroot
-
+
def get_version(self, path=None, use_none_rcs=False):
if use_none_rcs == True:
RCS = rcs.rcs_by_name("None")
@@ -317,6 +334,7 @@ settings easy. Don't set this attribute. Set .rcs instead, and
return tree_version
def set_version(self):
+ self.rcs.mkdir(self.get_path())
self.rcs.set_file_contents(self.get_path("version"),
TREE_VERSION_STRING)
@@ -348,7 +366,7 @@ settings easy. Don't set this attribute. Set .rcs instead, and
if not os.path.exists(self.get_path()):
raise NoBugDir(self.get_path())
self.load_settings()
-
+
self.rcs = rcs.rcs_by_name(self.rcs_name)
self._setup_user_id(self.user_id)
@@ -359,10 +377,17 @@ settings easy. Don't set this attribute. Set .rcs instead, and
self._load_bug(uuid)
def save(self):
- self.rcs.mkdir(self.get_path())
+ """
+ Save any loaded contents to disk. Because of lazy loading of
+ bugs and comments, this is actually not too inefficient.
+
+ However, if self.sync_with_disk = True, then any changes are
+ automatically written to disk as soon as they happen, so
+ calling this method will just waste time (unless something
+ else has been messing with your on-disk files).
+ """
self.set_version()
self.save_settings()
- self.rcs.mkdir(self.get_path("bugs"))
for bug in self:
bug.save()
@@ -378,7 +403,7 @@ settings easy. Don't set this attribute. Set .rcs instead, and
allow_no_rcs = not self.rcs.path_in_root(settings_path)
# allow_no_rcs=True should only be for the special case of
# configuring duplicate bugdir settings
-
+
try:
settings = mapfile.map_load(self.rcs, settings_path, allow_no_rcs)
except rcs.NoSuchFile:
@@ -393,6 +418,7 @@ settings easy. Don't set this attribute. Set .rcs instead, and
allow_no_rcs = not self.rcs.path_in_root(settings_path)
# allow_no_rcs=True should only be for the special case of
# configuring duplicate bugdir settings
+ self.rcs.mkdir(self.get_path(), allow_no_rcs)
mapfile.map_save(self.rcs, settings_path, settings, allow_no_rcs)
def duplicate_bugdir(self, revision):
@@ -443,6 +469,9 @@ settings easy. Don't set this attribute. Set .rcs instead, and
def new_bug(self, uuid=None, summary=None):
bg = bug.Bug(bugdir=self, uuid=uuid, summary=summary)
+ bg.set_sync_with_disk(self.sync_with_disk)
+ if bg.sync_with_disk == True:
+ bg.save()
self.append(bg)
self._bug_map_gen()
return bg
@@ -456,7 +485,7 @@ settings easy. Don't set this attribute. Set .rcs instead, and
Generate short names from uuids. Picks the minimum number of
characters (>=3) from the beginning of the uuid such that the
short names are unique.
-
+
Obviously, as the number of bugs in the database grows, these
short names will cease to be unique. The complete uuid should be
used for long term reference.
@@ -503,7 +532,7 @@ settings easy. Don't set this attribute. Set .rcs instead, and
if bug_uuid not in self._bug_map:
return False
return True
-
+
def simple_bug_dir():
"""
@@ -592,14 +621,17 @@ class BugDirTestCase(unittest.TestCase):
self.failUnless(bugA == bugAprime, "%s != %s" % (bugA, bugAprime))
self.bugdir.save()
self.versionTest()
- def testComments(self):
+ def testComments(self, sync_with_disk=False):
+ if sync_with_disk == True:
+ self.bugdir.set_sync_with_disk(True)
self.bugdir.new_bug(uuid="a", summary="Ant")
bug = self.bugdir.bug_from_uuid("a")
comm = bug.comment_root
rep = comm.new_reply("Ants are small.")
rep.new_reply("And they have six legs.")
- self.bugdir.save()
- self.bugdir._clear_bugs()
+ if sync_with_disk == False:
+ self.bugdir.save()
+ self.bugdir._clear_bugs()
bug = self.bugdir.bug_from_uuid("a")
bug.load_comments()
self.failUnless(len(bug.comment_root)==1, len(bug.comment_root))
@@ -623,6 +655,8 @@ class BugDirTestCase(unittest.TestCase):
comment.body)
else:
self.failIf(True, "Invalid comment: %d\n%s" % (index, comment))
+ def testSyncedComments(self):
+ self.testComments(sync_with_disk=True)
unitsuite = unittest.TestLoader().loadTestsFromTestCase(BugDirTestCase)
suite = unittest.TestSuite([unitsuite])#, doctest.DocTestSuite()])
diff --git a/libbe/comment.py b/libbe/comment.py
index 60cccff..d19953b 100644
--- a/libbe/comment.py
+++ b/libbe/comment.py
@@ -123,6 +123,7 @@ def loadComments(bug, load_full=False):
if uuid.startswith('.'):
continue
comm = Comment(bug, uuid, from_disk=True)
+ comm.set_sync_with_disk(bug.sync_with_disk)
if load_full == True:
comm.load_settings()
dummy = comm.body # force the body to load
@@ -130,8 +131,6 @@ def loadComments(bug, load_full=False):
return list_to_root(comments, bug)
def saveComments(bug):
- path = bug.get_path("comments")
- bug.rcs.mkdir(path)
for comment in bug.comment_root.traverse():
comment.save()
@@ -249,6 +248,9 @@ class Comment(Tree, settings_object.SavedSettingsObject):
self.in_reply_to = in_reply_to
self.body = body
+ def set_sync_with_disk(self, value):
+ self.sync_with_disk = True
+
def traverse(self, *args, **kwargs):
"""Avoid working with the possible dummy root comment"""
for comment in Tree.traverse(self, *args, **kwargs):
@@ -429,13 +431,19 @@ class Comment(Tree, settings_object.SavedSettingsObject):
self._setup_saved_settings()
def save_settings(self):
- parent_dir = os.path.dirname(self.get_path())
- self.rcs.mkdir(parent_dir)
self.rcs.mkdir(self.get_path())
path = self.get_path("values")
mapfile.map_save(self.rcs, path, self._get_saved_settings())
def save(self):
+ """
+ Save any loaded contents to disk.
+
+ However, if self.sync_with_disk = True, then any changes are
+ automatically written to disk as soon as they happen, so
+ calling this method will just waste time (unless something
+ else has been messing with your on-disk files).
+ """
assert self.body != None, "Can't save blank comment"
self.save_settings()
self._set_comment_body(new=self.body, force=True)
@@ -460,6 +468,10 @@ class Comment(Tree, settings_object.SavedSettingsObject):
True
"""
reply = Comment(self.bug, body=body)
+ if self.bug != None:
+ reply.set_sync_with_disk(self.bug.sync_with_disk)
+ if reply.sync_with_disk == True:
+ reply.save()
self.add_reply(reply)
return reply
diff --git a/libbe/rcs.py b/libbe/rcs.py
index 3bf8c9d..1e1cfa7 100644
--- a/libbe/rcs.py
+++ b/libbe/rcs.py
@@ -339,11 +339,15 @@ class RCS(object):
self.add(path)
else:
self.update(path)
- def mkdir(self, path, allow_no_rcs=False):
+ def mkdir(self, path, allow_no_rcs=False, check_parents=True):
"""
Create (if neccessary) a directory at path under version
control.
"""
+ if check_parents == True:
+ parent = os.path.dirname(path)
+ if not os.path.exists(parent): # recurse through parents
+ self.mkdir(parent, allow_no_rcs, check_parents)
if not os.path.exists(path):
os.mkdir(path)
if self._use_rcs(path, allow_no_rcs):
@@ -351,7 +355,9 @@ class RCS(object):
else:
assert os.path.isdir(path)
if self._use_rcs(path, allow_no_rcs):
- self.update(path)
+ #self.update(path)# Don't update directories. Changing files
+ pass # underneath them should be sufficient.
+
def duplicate_repo(self, revision=None):
"""
Get the repository as it was in a given revision.