diff options
Diffstat (limited to 'libbe')
-rw-r--r-- | libbe/bug.py | 12 | ||||
-rw-r--r-- | libbe/bugdir.py | 41 | ||||
-rw-r--r-- | libbe/comment.py | 15 | ||||
-rw-r--r-- | libbe/mapfile.py | 18 | ||||
-rw-r--r-- | libbe/upgrade.py | 171 |
5 files changed, 207 insertions, 50 deletions
diff --git a/libbe/bug.py b/libbe/bug.py index 7554318..f7a1a06 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -341,12 +341,12 @@ class Bug(settings_object.SavedSettingsObject): # methods for saving/loading/acessing settings and properties. - def get_path(self, name=None): - my_dir = os.path.join(self.bugdir.get_path("bugs"), self.uuid) - if name is None: - return my_dir - assert name in ["values", "comments"] - return os.path.join(my_dir, name) + def get_path(self, *args): + dir = os.path.join(self.bugdir.get_path("bugs"), self.uuid) + if len(args) == 0: + return dir + assert args[0] in ["values", "comments"], str(args) + return os.path.join(dir, *args) def set_sync_with_disk(self, value): self.sync_with_disk = value diff --git a/libbe/bugdir.py b/libbe/bugdir.py index ee6c943..5946c04 100644 --- a/libbe/bugdir.py +++ b/libbe/bugdir.py @@ -26,18 +26,18 @@ import time import unittest import doctest +import bug +import encoding from properties import Property, doc_property, local_property, \ defaulting_property, checked_property, fn_checked_property, \ cached_property, primed_property, change_hook_property, \ settings_property -import settings_object import mapfile -import bug import rcs -import encoding +import settings_object +import upgrade import utility - class NoBugDir(Exception): def __init__(self, path): msg = "The directory \"%s\" has no bug directory." % path @@ -75,9 +75,6 @@ class DiskAccessRequired (Exception): Exception.__init__(self, msg) -TREE_VERSION_STRING = "Bugs Everywhere Tree 1 0\n" - - class BugDir (list, settings_object.SavedSettingsObject): """ Sink to existing root @@ -370,11 +367,11 @@ settings easy. Don't set this attribute. Set .rcs instead, and """ Return a path relative to .root. """ - my_dir = os.path.join(self.root, ".be") + dir = os.path.join(self.root, ".be") if len(args) == 0: - return my_dir + return dir assert args[0] in ["version", "settings", "bugs"], str(args) - return os.path.join(my_dir, *args) + return os.path.join(dir, *args) def _get_settings(self, settings_path, for_duplicate_bugdir=False): allow_no_rcs = not self.rcs.path_in_root(settings_path) @@ -414,7 +411,8 @@ settings easy. Don't set this attribute. Set .rcs instead, and settings = self._get_saved_settings() self._save_settings(self.get_path("settings"), settings) - def get_version(self, path=None, use_none_rcs=False): + def get_version(self, path=None, use_none_rcs=False, + for_duplicate_bugdir=False): """ Requires disk access. """ @@ -429,8 +427,12 @@ settings easy. Don't set this attribute. Set .rcs instead, and if path == None: path = self.get_path("version") - tree_version = RCS.get_file_contents(path) - return tree_version + allow_no_rcs = not RCS.path_in_root(path) + if allow_no_rcs == True: + assert for_duplicate_bugdir == True + version = RCS.get_file_contents( + path, allow_no_rcs=allow_no_rcs).rstrip("\n") + return version def set_version(self): """ @@ -440,7 +442,7 @@ settings easy. Don't set this attribute. Set .rcs instead, and raise DiskAccessRequired("set version") self.rcs.mkdir(self.get_path()) self.rcs.set_file_contents(self.get_path("version"), - TREE_VERSION_STRING) + upgrade.BUGDIR_DISK_VERSION+"\n") # methods controlling disk access @@ -459,9 +461,8 @@ settings easy. Don't set this attribute. Set .rcs instead, and Reqires disk access """ version = self.get_version(use_none_rcs=True) - if version != TREE_VERSION_STRING: - raise NotImplementedError, \ - "BugDir cannot handle version '%s' yet." % version + if version != upgrade.BUGDIR_DISK_VERSION: + upgrade.upgrade(self.root, version) else: if not os.path.exists(self.get_path()): raise NoBugDir(self.get_path()) @@ -508,6 +509,12 @@ settings easy. Don't set this attribute. Set .rcs instead, and def duplicate_bugdir(self, revision): duplicate_path = self.rcs.duplicate_repo(revision) + duplicate_version_path = os.path.join(duplicate_path, ".be", "version") + version = self.get_version(duplicate_version_path, + for_duplicate_bugdir=True) + if version != upgrade.BUGDIR_DISK_VERSION: + upgrade.upgrade(duplicate_path, version) + # setup revision RCS as None, since the duplicate may not be # initialized for versioning duplicate_settings_path = os.path.join(duplicate_path, diff --git a/libbe/comment.py b/libbe/comment.py index b2fc556..bcb8045 100644 --- a/libbe/comment.py +++ b/libbe/comment.py @@ -546,12 +546,12 @@ class Comment(Tree, settings_object.SavedSettingsObject): # methods for saving/loading/acessing settings and properties. - def get_path(self, name=None): - my_dir = os.path.join(self.bug.get_path("comments"), self.uuid) - if name is None: - return my_dir - assert name in ["values", "body"] - return os.path.join(my_dir, name) + def get_path(self, *args): + dir = os.path.join(self.bug.get_path("comments"), self.uuid) + if len(args) == 0: + return dir + assert args[0] in ["values", "body"], str(args) + return os.path.join(dir, *args) def set_sync_with_disk(self, value): self.sync_with_disk = value @@ -560,9 +560,6 @@ class Comment(Tree, settings_object.SavedSettingsObject): if self.sync_with_disk == False: raise DiskAccessRequired("load settings") self.settings = mapfile.map_load(self.rcs, self.get_path("values")) - # hack to deal with old BE comments: - if "From" in self.settings: - self.settings["Author"] = self.settings.pop("From") self._setup_saved_settings() def save_settings(self): diff --git a/libbe/mapfile.py b/libbe/mapfile.py index b959d76..74d2b1a 100644 --- a/libbe/mapfile.py +++ b/libbe/mapfile.py @@ -95,24 +95,6 @@ def parse(contents): >>> dict["e"] 'f' """ - old_format = False - for line in contents.splitlines(): - if len(line.split("=")) == 2: - old_format = True - break - if old_format: # translate to YAML. Hack to deal with old BE bugs. - newlines = [] - for line in contents.splitlines(): - line = line.rstrip('\n') - if len(line) == 0: - continue - fields = line.split("=") - if len(fields) == 2: - key,value = fields - newlines.append('%s: "%s"' % (key, value.replace('"','\\"'))) - else: - newlines.append(line) - contents = '\n'.join(newlines) return yaml.load(contents) or {} def map_save(rcs, path, map, allow_no_rcs=False): diff --git a/libbe/upgrade.py b/libbe/upgrade.py new file mode 100644 index 0000000..6f14cd8 --- /dev/null +++ b/libbe/upgrade.py @@ -0,0 +1,171 @@ +# 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. + +""" +Handle conversion between the various on-disk images. +""" + +import os, os.path +import sys +import doctest + +import encoding +import mapfile +import rcs + +# a list of all past versions +BUGDIR_DISK_VERSIONS = ["Bugs Everywhere Tree 1 0", + "Bugs Everywhere Directory v1.1"] + +# the current version +BUGDIR_DISK_VERSION = BUGDIR_DISK_VERSIONS[-1] + +class Upgrader (object): + "Class for converting " + initial_version = None + final_version = None + def __init__(self, root): + self.root = root + # use the "None" RCS to ensure proper encoding/decoding and + # simplify path construction. + self.rcs = rcs.rcs_by_name("None") + self.rcs.root(self.root) + self.rcs.encoding = encoding.get_encoding() + + def get_path(self, *args): + """ + Return a path relative to .root. + """ + dir = os.path.join(self.root, ".be") + if len(args) == 0: + return dir + assert args[0] in ["version", "settings", "bugs"], str(args) + return os.path.join(dir, *args) + + def check_initial_version(self): + path = self.get_path("version") + version = self.rcs.get_file_contents(path).rstrip("\n") + assert version == self.initial_version, version + + def set_version(self): + path = self.get_path("version") + self.rcs.set_file_contents(path, self.final_version+"\n") + + def upgrade(self): + print >> sys.stderr, "upgrading bugdir from '%s' to '%s'" \ + % (self.initial_version, self.final_version) + self.check_initial_version() + self.set_version() + self._upgrade() + + def _upgrade(self): + raise NotImplementedError + + +class Upgrade_1_0_to_2 (Upgrader): + initial_version = "Bugs Everywhere Tree 1 0" + final_version = "Bugs Everywhere Directory v2" + def _upgrade_mapfile(self, path): + contents = self.rcs.get_file_contents(path) + old_format = False + for line in contents.splitlines(): + if len(line.split("=")) == 2: + old_format = True + break + if old_format == True: + # translate to YAML. + newlines = [] + for line in contents.splitlines(): + line = line.rstrip('\n') + if len(line) == 0: + continue + fields = line.split("=") + if len(fields) == 2: + key,value = fields + newlines.append('%s: "%s"' % (key, value.replace('"','\\"'))) + else: + newlines.append(line) + contents = '\n'.join(newlines) + # load the YAML and save + map = mapfile.parse(contents) + mapfile.map_save(self.rcs, path, map) + + def _upgrade(self): + """ + Comment value field "From" -> "Author". + Homegrown mapfile -> YAML. + """ + path = self.get_path("settings") + self._upgrade_mapfile(path) + for bug_uuid in os.listdir(self.get_path("bugs")): + path = self.get_path("bugs", bug_uuid, "values") + self._upgrade_mapfile(path) + c_path = ["bugs", bug_uuid, "comments"] + if not os.path.exists(self.get_path(*c_path)): + continue # no comments for this bug + for comment_uuid in os.listdir(self.get_path(*c_path)): + path_list = c_path + [comment_uuid, "values"] + path = self.get_path(*path_list) + self._upgrade_mapfile(path) + settings = mapfile.map_load(self.rcs, path) + if "From" in settings: + settings["Author"] = settings.pop("From") + mapfile.map_save(self.rcs, path, settings) + + +upgraders = [Upgrade_1_0_to_2] +upgrade_classes = {} +for upgrader in upgraders: + upgrade_classes[(upgrader.initial_version,upgrader.final_version)]=upgrader + +def upgrade(path, current_version, + target_version=BUGDIR_DISK_VERSION): + """ + Call the appropriate upgrade function to convert current_version + to target_version. If a direct conversion function does not exist, + use consecutive conversion functions. + """ + if current_version not in BUGDIR_DISK_VERSIONS: + raise NotImplementedError, \ + "Cannot handle version '%s' yet." % version + if target_version not in BUGDIR_DISK_VERSIONS: + raise NotImplementedError, \ + "Cannot handle version '%s' yet." % version + + if (current_version, target_version) in upgrade_classes: + # direct conversion + upgrade_class = upgrade_classes[(current_version, target_version)] + u = upgrade_class(path) + u.upgrade() + else: + # consecutive single-step conversion + i = BUGDIR_DISK_VERSIONS.index(current_version) + while True: + version_a = BUGDIR_DISK_VERSIONS[i] + version_b = BUGDIR_DISK_VERSIONS[i+1] + try: + upgrade_class = upgrade_classes[(version_a, version_b)] + except KeyError: + raise NotImplementedError, \ + "Cannot convert version '%s' to '%s' yet." \ + % (version_a, version_b) + u = upgrade_class(path) + u.upgrade() + if version_b == target_version: + break + i += 1 + +suite = doctest.DocTestSuite() |