X-Git-Url: https://git.distorted.org.uk/~mdw/stgit/blobdiff_plain/99c529152847b7e20e48dc477925e315918eed5d..8fe7e9f08ae6fe49cec66a8034e8495cbf77c6f3:/stgit/stack.py diff --git a/stgit/stack.py b/stgit/stack.py index a477e7d..69fa03b 100644 --- a/stgit/stack.py +++ b/stgit/stack.py @@ -119,27 +119,57 @@ def edit_file(series, line, comment, show_patch = True): # Classes # -class Patch: +class StgitObject: + """An object with stgit-like properties stored as files in a directory + """ + def _set_dir(self, dir): + self.__dir = dir + def _dir(self): + return self.__dir + + def create_empty_field(self, name): + create_empty_file(os.path.join(self.__dir, name)) + + def _get_field(self, name, multiline = False): + id_file = os.path.join(self.__dir, name) + if os.path.isfile(id_file): + line = read_string(id_file, multiline) + if line == '': + return None + else: + return line + else: + return None + + def _set_field(self, name, value, multiline = False): + fname = os.path.join(self.__dir, name) + if value and value != '': + write_string(fname, value, multiline) + elif os.path.isfile(fname): + os.remove(fname) + + +class Patch(StgitObject): """Basic patch implementation """ def __init__(self, name, series_dir, refs_dir): self.__series_dir = series_dir self.__name = name - self.__dir = os.path.join(self.__series_dir, self.__name) + self._set_dir(os.path.join(self.__series_dir, self.__name)) self.__refs_dir = refs_dir self.__top_ref_file = os.path.join(self.__refs_dir, self.__name) self.__log_ref_file = os.path.join(self.__refs_dir, self.__name + '.log') def create(self): - os.mkdir(self.__dir) - create_empty_file(os.path.join(self.__dir, 'bottom')) - create_empty_file(os.path.join(self.__dir, 'top')) + os.mkdir(self._dir()) + self.create_empty_field('bottom') + self.create_empty_field('top') def delete(self): - for f in os.listdir(self.__dir): - os.remove(os.path.join(self.__dir, f)) - os.rmdir(self.__dir) + for f in os.listdir(self._dir()): + os.remove(os.path.join(self._dir(), f)) + os.rmdir(self._dir()) os.remove(self.__top_ref_file) if os.path.exists(self.__log_ref_file): os.remove(self.__log_ref_file) @@ -148,16 +178,16 @@ class Patch: return self.__name def rename(self, newname): - olddir = self.__dir + olddir = self._dir() old_top_ref_file = self.__top_ref_file old_log_ref_file = self.__log_ref_file self.__name = newname - self.__dir = os.path.join(self.__series_dir, self.__name) + self._set_dir(os.path.join(self.__series_dir, self.__name)) self.__top_ref_file = os.path.join(self.__refs_dir, self.__name) self.__log_ref_file = os.path.join(self.__refs_dir, self.__name + '.log') - os.rename(olddir, self.__dir) + os.rename(olddir, self._dir()) os.rename(old_top_ref_file, self.__top_ref_file) if os.path.exists(old_log_ref_file): os.rename(old_log_ref_file, self.__log_ref_file) @@ -173,128 +203,88 @@ class Patch: if top: self.__update_top_ref(top) - def __get_field(self, name, multiline = False): - id_file = os.path.join(self.__dir, name) - if os.path.isfile(id_file): - line = read_string(id_file, multiline) - if line == '': - return None - else: - return line - else: - return None - - def __set_field(self, name, value, multiline = False): - fname = os.path.join(self.__dir, name) - if value and value != '': - write_string(fname, value, multiline) - elif os.path.isfile(fname): - os.remove(fname) - def get_old_bottom(self): - return self.__get_field('bottom.old') + return self._get_field('bottom.old') def get_bottom(self): - return self.__get_field('bottom') + return self._get_field('bottom') def set_bottom(self, value, backup = False): if backup: - curr = self.__get_field('bottom') - self.__set_field('bottom.old', curr) - self.__set_field('bottom', value) + curr = self._get_field('bottom') + self._set_field('bottom.old', curr) + self._set_field('bottom', value) def get_old_top(self): - return self.__get_field('top.old') + return self._get_field('top.old') def get_top(self): - return self.__get_field('top') + return self._get_field('top') def set_top(self, value, backup = False): if backup: - curr = self.__get_field('top') - self.__set_field('top.old', curr) - self.__set_field('top', value) + curr = self._get_field('top') + self._set_field('top.old', curr) + self._set_field('top', value) self.__update_top_ref(value) def restore_old_boundaries(self): - bottom = self.__get_field('bottom.old') - top = self.__get_field('top.old') + bottom = self._get_field('bottom.old') + top = self._get_field('top.old') if top and bottom: - self.__set_field('bottom', bottom) - self.__set_field('top', top) + self._set_field('bottom', bottom) + self._set_field('top', top) self.__update_top_ref(top) return True else: return False def get_description(self): - return self.__get_field('description', True) + return self._get_field('description', True) def set_description(self, line): - self.__set_field('description', line, True) + self._set_field('description', line, True) def get_authname(self): - return self.__get_field('authname') + return self._get_field('authname') def set_authname(self, name): - if not name: - if config.has_option('stgit', 'authname'): - name = config.get('stgit', 'authname') - elif 'GIT_AUTHOR_NAME' in os.environ: - name = os.environ['GIT_AUTHOR_NAME'] - self.__set_field('authname', name) + self._set_field('authname', name or git.author().name) def get_authemail(self): - return self.__get_field('authemail') + return self._get_field('authemail') - def set_authemail(self, address): - if not address: - if config.has_option('stgit', 'authemail'): - address = config.get('stgit', 'authemail') - elif 'GIT_AUTHOR_EMAIL' in os.environ: - address = os.environ['GIT_AUTHOR_EMAIL'] - self.__set_field('authemail', address) + def set_authemail(self, email): + self._set_field('authemail', email or git.author().email) def get_authdate(self): - return self.__get_field('authdate') + return self._get_field('authdate') def set_authdate(self, date): - if not date and 'GIT_AUTHOR_DATE' in os.environ: - date = os.environ['GIT_AUTHOR_DATE'] - self.__set_field('authdate', date) + self._set_field('authdate', date or git.author().date) def get_commname(self): - return self.__get_field('commname') + return self._get_field('commname') def set_commname(self, name): - if not name: - if config.has_option('stgit', 'commname'): - name = config.get('stgit', 'commname') - elif 'GIT_COMMITTER_NAME' in os.environ: - name = os.environ['GIT_COMMITTER_NAME'] - self.__set_field('commname', name) + self._set_field('commname', name or git.committer().name) def get_commemail(self): - return self.__get_field('commemail') + return self._get_field('commemail') - def set_commemail(self, address): - if not address: - if config.has_option('stgit', 'commemail'): - address = config.get('stgit', 'commemail') - elif 'GIT_COMMITTER_EMAIL' in os.environ: - address = os.environ['GIT_COMMITTER_EMAIL'] - self.__set_field('commemail', address) + def set_commemail(self, email): + self._set_field('commemail', email or git.committer().email) def get_log(self): - return self.__get_field('log') + return self._get_field('log') def set_log(self, value, backup = False): - self.__set_field('log', value) + self._set_field('log', value) self.__update_log_ref(value) -class Series: +class Series(StgitObject): """Class including the operations on series """ def __init__(self, name = None): @@ -309,22 +299,21 @@ class Series: except git.GitException, ex: raise StackException, 'GIT tree not initialised: %s' % ex - self.__series_dir = os.path.join(self.__base_dir, 'patches', - self.__name) + self._set_dir(os.path.join(self.__base_dir, 'patches', self.__name)) self.__refs_dir = os.path.join(self.__base_dir, 'refs', 'patches', self.__name) self.__base_file = os.path.join(self.__base_dir, 'refs', 'bases', self.__name) - self.__applied_file = os.path.join(self.__series_dir, 'applied') - self.__unapplied_file = os.path.join(self.__series_dir, 'unapplied') - self.__current_file = os.path.join(self.__series_dir, 'current') - self.__descr_file = os.path.join(self.__series_dir, 'description') + self.__applied_file = os.path.join(self._dir(), 'applied') + self.__unapplied_file = os.path.join(self._dir(), 'unapplied') + self.__current_file = os.path.join(self._dir(), 'current') + self.__descr_file = os.path.join(self._dir(), 'description') # where this series keeps its patches - self.__patch_dir = os.path.join(self.__series_dir, 'patches') + self.__patch_dir = os.path.join(self._dir(), 'patches') if not os.path.isdir(self.__patch_dir): - self.__patch_dir = self.__series_dir + self.__patch_dir = self._dir() # if no __refs_dir, create and populate it (upgrade old repositories) if self.is_initialised() and not os.path.isdir(self.__refs_dir): @@ -333,7 +322,7 @@ class Series: self.get_patch(patch).update_top_ref() # trash directory - self.__trash_dir = os.path.join(self.__series_dir, 'trash') + self.__trash_dir = os.path.join(self._dir(), 'trash') if self.is_initialised() and not os.path.isdir(self.__trash_dir): os.makedirs(self.__trash_dir) @@ -345,10 +334,7 @@ class Series: def __set_current(self, name): """Sets the topmost patch """ - if name: - write_string(self.__current_file, name) - else: - create_empty_file(self.__current_file) + self._set_field('current', name) def get_patch(self, name): """Return a Patch object for the given name @@ -366,10 +352,7 @@ class Series: def get_current(self): """Return the name of the topmost patch, or None if there is no such patch.""" - if os.path.isfile(self.__current_file): - name = read_string(self.__current_file) - else: - return None + name = self._get_field('current') if name == '': return None else: @@ -396,33 +379,33 @@ class Series: return self.__base_file def get_protected(self): - return os.path.isfile(os.path.join(self.__series_dir, 'protected')) + return os.path.isfile(os.path.join(self._dir(), 'protected')) def protect(self): - protect_file = os.path.join(self.__series_dir, 'protected') + protect_file = os.path.join(self._dir(), 'protected') if not os.path.isfile(protect_file): create_empty_file(protect_file) def unprotect(self): - protect_file = os.path.join(self.__series_dir, 'protected') + protect_file = os.path.join(self._dir(), 'protected') if os.path.isfile(protect_file): os.remove(protect_file) def get_description(self): - if os.path.isfile(self.__descr_file): - return read_string(self.__descr_file) - else: - return '' + return self._get_field('description') + + def set_description(self, line): + self._set_field('description', line) def __patch_is_current(self, patch): - return patch.get_name() == read_string(self.__current_file) + return patch.get_name() == self.get_current() - def __patch_applied(self, name): + def patch_applied(self, name): """Return true if the patch exists in the applied list """ return name in self.get_applied() - def __patch_unapplied(self, name): + def patch_unapplied(self, name): """Return true if the patch exists in the unapplied list """ return name in self.get_unapplied() @@ -430,7 +413,7 @@ class Series: def patch_exists(self, name): """Return true if there is a patch with the given name, false otherwise.""" - return self.__patch_applied(name) or self.__patch_unapplied(name) + return self.patch_applied(name) or self.patch_unapplied(name) def __begin_stack_check(self): """Save the current HEAD into .git/refs/heads/base if the stack @@ -481,10 +464,10 @@ class Series: create_dirs(bases_dir) - create_empty_file(self.__applied_file) - create_empty_file(self.__unapplied_file) - create_empty_file(self.__descr_file) - os.makedirs(os.path.join(self.__series_dir, 'patches')) + self.create_empty_field('applied') + self.create_empty_field('unapplied') + self.create_empty_field('description') + os.makedirs(os.path.join(self._dir(), 'patches')) os.makedirs(self.__refs_dir) self.__begin_stack_check() @@ -493,15 +476,15 @@ class Series: unconvert to place the patches in the same directory with series control files """ - if self.__patch_dir == self.__series_dir: + if self.__patch_dir == self._dir(): print 'Converting old-style to new-style...', sys.stdout.flush() - self.__patch_dir = os.path.join(self.__series_dir, 'patches') + self.__patch_dir = os.path.join(self._dir(), 'patches') os.makedirs(self.__patch_dir) for p in self.get_applied() + self.get_unapplied(): - src = os.path.join(self.__series_dir, p) + src = os.path.join(self._dir(), p) dest = os.path.join(self.__patch_dir, p) os.rename(src, dest) @@ -513,7 +496,7 @@ class Series: for p in self.get_applied() + self.get_unapplied(): src = os.path.join(self.__patch_dir, p) - dest = os.path.join(self.__series_dir, p) + dest = os.path.join(self._dir(), p) os.rename(src, dest) if not os.listdir(self.__patch_dir): @@ -522,7 +505,7 @@ class Series: else: print 'Patch directory %s is not empty.' % self.__name - self.__patch_dir = self.__series_dir + self.__patch_dir = self._dir() def rename(self, to_name): """Renames a series @@ -536,7 +519,7 @@ class Series: git.rename_branch(self.__name, to_name) - if os.path.isdir(self.__series_dir): + if os.path.isdir(self._dir()): rename(os.path.join(self.__base_dir, 'patches'), self.__name, to_stack.__name) if os.path.exists(self.__base_file): @@ -556,7 +539,7 @@ class Series: new_series = Series(target_series) # generate an artificial description file - write_string(new_series.__descr_file, 'clone of "%s"' % self.__name) + new_series.set_description('clone of "%s"' % self.__name) # clone self's entire series as unapplied patches patches = self.get_applied() + self.get_unapplied() @@ -590,6 +573,8 @@ class Series: os.remove(fname) os.rmdir(self.__trash_dir) + # FIXME: find a way to get rid of those manual removals + # (move functionnality to StgitObject ?) if os.path.exists(self.__applied_file): os.remove(self.__applied_file) if os.path.exists(self.__unapplied_file): @@ -602,7 +587,7 @@ class Series: os.rmdir(self.__patch_dir) else: print 'Patch directory %s is not empty.' % self.__name - if not os.listdir(self.__series_dir): + if not os.listdir(self._dir()): remove_dirs(os.path.join(self.__base_dir, 'patches'), self.__name) else: @@ -713,7 +698,7 @@ class Series: before_existing = False, refresh = True): """Creates a new patch """ - if self.__patch_applied(name) or self.__patch_unapplied(name): + if self.patch_applied(name) or self.patch_unapplied(name): raise StackException, 'Patch "%s" already exists' % name if not message and can_edit: @@ -773,7 +758,7 @@ class Series: if self.__patch_is_current(patch): self.pop_patch(name) - elif self.__patch_applied(name): + elif self.patch_applied(name): raise StackException, 'Cannot remove an applied patch, "%s", ' \ 'which is not current' % name elif not name in self.get_unapplied():