This is of course needed by the new infrastructure as well. So break it out into its own file, where it can be used by both new and old infrastructure. This has the added benefit of making it easy to see that the upgrade code doesn't depend on anything it shouldn't. Signed-off-by: Karl Hasselström <kha@xxxxxxxxxxx> --- stgit/lib/git.py | 7 +++ stgit/lib/stack.py | 3 + stgit/lib/stackupgrade.py | 96 +++++++++++++++++++++++++++++++++++++++++++ stgit/stack.py | 100 +++------------------------------------------ 4 files changed, 112 insertions(+), 94 deletions(-) create mode 100644 stgit/lib/stackupgrade.py diff --git a/stgit/lib/git.py b/stgit/lib/git.py index 120ea35..c4011f9 100644 --- a/stgit/lib/git.py +++ b/stgit/lib/git.py @@ -160,6 +160,13 @@ class Refs(object): if self.__refs == None: self.__cache_refs() return self.__repository.get_commit(self.__refs[ref]) + def exists(self, ref): + try: + self.get(ref) + except KeyError: + return False + else: + return True def set(self, ref, commit, msg): if self.__refs == None: self.__cache_refs() diff --git a/stgit/lib/stack.py b/stgit/lib/stack.py index 5a34592..8fc8b08 100644 --- a/stgit/lib/stack.py +++ b/stgit/lib/stack.py @@ -1,6 +1,6 @@ import os.path from stgit import exception, utils -from stgit.lib import git +from stgit.lib import git, stackupgrade class Patch(object): def __init__(self, stack, name): @@ -128,6 +128,7 @@ class Stack(object): raise exception.StgException('%s: no such branch' % name) self.__patchorder = PatchOrder(self) self.__patches = Patches(self) + stackupgrade.update_to_current_format_version(repository, name) name = property(lambda self: self.__name) repository = property(lambda self: self.__repository) patchorder = property(lambda self: self.__patchorder) diff --git a/stgit/lib/stackupgrade.py b/stgit/lib/stackupgrade.py new file mode 100644 index 0000000..00bfdf0 --- /dev/null +++ b/stgit/lib/stackupgrade.py @@ -0,0 +1,96 @@ +import os.path +from stgit import utils +from stgit.out import out +from stgit.config import config + +# The current StGit metadata format version. +FORMAT_VERSION = 2 + +def format_version_key(branch): + return 'branch.%s.stgit.stackformatversion' % branch + +def update_to_current_format_version(repository, branch): + """Update a potentially older StGit directory structure to the latest + version. Note: This function should depend as little as possible + on external functions that may change during a format version + bump, since it must remain able to process older formats.""" + + branch_dir = os.path.join(repository.directory, 'patches', branch) + key = format_version_key(branch) + old_key = 'branch.%s.stgitformatversion' % branch + def get_format_version(): + """Return the integer format version number, or None if the + branch doesn't have any StGit metadata at all, of any version.""" + fv = config.get(key) + ofv = config.get(old_key) + if fv: + # Great, there's an explicitly recorded format version + # number, which means that the branch is initialized and + # of that exact version. + return int(fv) + elif ofv: + # Old name for the version info: upgrade it. + config.set(key, ofv) + config.unset(old_key) + return int(ofv) + elif os.path.isdir(os.path.join(branch_dir, 'patches')): + # There's a .git/patches/<branch>/patches dirctory, which + # means this is an initialized version 1 branch. + return 1 + elif os.path.isdir(branch_dir): + # There's a .git/patches/<branch> directory, which means + # this is an initialized version 0 branch. + return 0 + else: + # The branch doesn't seem to be initialized at all. + return None + def set_format_version(v): + out.info('Upgraded branch %s to format version %d' % (branch, v)) + config.set(key, '%d' % v) + def mkdir(d): + if not os.path.isdir(d): + os.makedirs(d) + def rm(f): + if os.path.exists(f): + os.remove(f) + def rm_ref(ref): + if repository.refs.exists(ref): + repository.refs.delete(ref) + + # Update 0 -> 1. + if get_format_version() == 0: + mkdir(os.path.join(branch_dir, 'trash')) + patch_dir = os.path.join(branch_dir, 'patches') + mkdir(patch_dir) + refs_base = 'refs/patches/%s' % branch + for patch in (file(os.path.join(branch_dir, 'unapplied')).readlines() + + file(os.path.join(branch_dir, 'applied')).readlines()): + patch = patch.strip() + os.rename(os.path.join(branch_dir, patch), + os.path.join(patch_dir, patch)) + topfield = os.path.join(patch_dir, patch, 'top') + if os.path.isfile(topfield): + top = utils.read_string(topfield, False) + else: + top = None + if top: + repository.refs.set(refs_base + '/' + patch, + repository.get_commit(top), 'StGit upgrade') + set_format_version(1) + + # Update 1 -> 2. + if get_format_version() == 1: + desc_file = os.path.join(branch_dir, 'description') + if os.path.isfile(desc_file): + desc = utils.read_string(desc_file) + if desc: + config.set('branch.%s.description' % branch, desc) + rm(desc_file) + rm(os.path.join(branch_dir, 'current')) + rm_ref('refs/bases/%s' % branch) + set_format_version(2) + + # Make sure we're at the latest version. + if not get_format_version() in [None, FORMAT_VERSION]: + raise StackException('Branch %s is at format version %d, expected %d' + % (branch, get_format_version(), FORMAT_VERSION)) diff --git a/stgit/stack.py b/stgit/stack.py index f93d842..29e92c9 100644 --- a/stgit/stack.py +++ b/stgit/stack.py @@ -28,7 +28,7 @@ from stgit.run import * from stgit import git, basedir, templates from stgit.config import config from shutil import copyfile - +from stgit.lib import git as libgit, stackupgrade # stack exception class class StackException(StgException): @@ -279,9 +279,6 @@ class Patch(StgitObject): self._set_field('log', value) self.__update_log_ref(value) -# The current StGIT metadata format version. -FORMAT_VERSION = 2 - class PatchSet(StgitObject): def __init__(self, name = None): try: @@ -349,7 +346,8 @@ class PatchSet(StgitObject): def is_initialised(self): """Checks if series is already initialised """ - return bool(config.get(self.format_version_key())) + return config.get(stackupgrade.format_version_key(self.get_name()) + ) != None def shortlog(patches): @@ -368,7 +366,8 @@ class Series(PatchSet): # Update the branch to the latest format version if it is # initialized, but don't touch it if it isn't. - self.update_to_current_format_version() + stackupgrade.update_to_current_format_version( + libgit.Repository.default(), self.get_name()) self.__refs_base = 'refs/patches/%s' % self.get_name() @@ -382,92 +381,6 @@ class Series(PatchSet): # trash directory self.__trash_dir = os.path.join(self._dir(), 'trash') - def format_version_key(self): - return 'branch.%s.stgit.stackformatversion' % self.get_name() - - def update_to_current_format_version(self): - """Update a potentially older StGIT directory structure to the - latest version. Note: This function should depend as little as - possible on external functions that may change during a format - version bump, since it must remain able to process older formats.""" - - branch_dir = os.path.join(self._basedir(), 'patches', self.get_name()) - def get_format_version(): - """Return the integer format version number, or None if the - branch doesn't have any StGIT metadata at all, of any version.""" - fv = config.get(self.format_version_key()) - ofv = config.get('branch.%s.stgitformatversion' % self.get_name()) - if fv: - # Great, there's an explicitly recorded format version - # number, which means that the branch is initialized and - # of that exact version. - return int(fv) - elif ofv: - # Old name for the version info, upgrade it - config.set(self.format_version_key(), ofv) - config.unset('branch.%s.stgitformatversion' % self.get_name()) - return int(ofv) - elif os.path.isdir(os.path.join(branch_dir, 'patches')): - # There's a .git/patches/<branch>/patches dirctory, which - # means this is an initialized version 1 branch. - return 1 - elif os.path.isdir(branch_dir): - # There's a .git/patches/<branch> directory, which means - # this is an initialized version 0 branch. - return 0 - else: - # The branch doesn't seem to be initialized at all. - return None - def set_format_version(v): - out.info('Upgraded branch %s to format version %d' % (self.get_name(), v)) - config.set(self.format_version_key(), '%d' % v) - def mkdir(d): - if not os.path.isdir(d): - os.makedirs(d) - def rm(f): - if os.path.exists(f): - os.remove(f) - def rm_ref(ref): - if git.ref_exists(ref): - git.delete_ref(ref) - - # Update 0 -> 1. - if get_format_version() == 0: - mkdir(os.path.join(branch_dir, 'trash')) - patch_dir = os.path.join(branch_dir, 'patches') - mkdir(patch_dir) - refs_base = 'refs/patches/%s' % self.get_name() - for patch in (file(os.path.join(branch_dir, 'unapplied')).readlines() - + file(os.path.join(branch_dir, 'applied')).readlines()): - patch = patch.strip() - os.rename(os.path.join(branch_dir, patch), - os.path.join(patch_dir, patch)) - topfield = os.path.join(patch_dir, patch, 'top') - if os.path.isfile(topfield): - top = read_string(topfield, False) - else: - top = None - if top: - git.set_ref(refs_base + '/' + patch, top) - set_format_version(1) - - # Update 1 -> 2. - if get_format_version() == 1: - desc_file = os.path.join(branch_dir, 'description') - if os.path.isfile(desc_file): - desc = read_string(desc_file) - if desc: - config.set('branch.%s.description' % self.get_name(), desc) - rm(desc_file) - rm(os.path.join(branch_dir, 'current')) - rm_ref('refs/bases/%s' % self.get_name()) - set_format_version(2) - - # Make sure we're at the latest version. - if not get_format_version() in [None, FORMAT_VERSION]: - raise StackException('Branch %s is at format version %d, expected %d' - % (self.get_name(), get_format_version(), FORMAT_VERSION)) - def __patch_name_valid(self, name): """Raise an exception if the patch name is not valid. """ @@ -620,7 +533,8 @@ class Series(PatchSet): self.create_empty_field('applied') self.create_empty_field('unapplied') - config.set(self.format_version_key(), str(FORMAT_VERSION)) + config.set(stackupgrade.format_version_key(self.get_name()), + str(stackupgrade.FORMAT_VERSION)) def rename(self, to_name): """Renames a series - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html