X-Git-Url: https://git.distorted.org.uk/~mdw/stgit/blobdiff_plain/d1368d811f20d4957d9fca7a8fe016e764f77d1b..f72ad3d613850b9cb831d98e2eff96e0a0fa3402:/stgit/stack.py diff --git a/stgit/stack.py b/stgit/stack.py index 2200d33..3960729 100644 --- a/stgit/stack.py +++ b/stgit/stack.py @@ -18,7 +18,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -import sys, os +import sys, os, re from stgit.utils import * from stgit import git, basedir, templates @@ -92,8 +92,9 @@ def edit_file(series, line, comment, show_patch = True): f.close() # the editor - if config.has_option('stgit', 'editor'): - editor = config.get('stgit', 'editor') + editor = config.get('stgit.editor') + if editor: + pass elif 'EDITOR' in os.environ: editor = os.environ['EDITOR'] else: @@ -307,6 +308,7 @@ class Series(StgitObject): self.__applied_file = os.path.join(self._dir(), 'applied') self.__unapplied_file = os.path.join(self._dir(), 'unapplied') + self.__hidden_file = os.path.join(self._dir(), 'hidden') self.__current_file = os.path.join(self._dir(), 'current') self.__descr_file = os.path.join(self._dir(), 'description') @@ -326,6 +328,12 @@ class Series(StgitObject): if self.is_initialised() and not os.path.isdir(self.__trash_dir): os.makedirs(self.__trash_dir) + def __patch_name_valid(self, name): + """Raise an exception if the patch name is not valid. + """ + if not name or re.search('[^\w.-]', name): + raise StackException, 'Invalid patch name: "%s"' % name + def get_branch(self): """Return the branch name for the Series object """ @@ -374,6 +382,14 @@ class Series(StgitObject): f.close() return names + def get_hidden(self): + if not os.path.isfile(self.__hidden_file): + return [] + f = file(self.__hidden_file) + names = [line.strip() for line in f.readlines()] + f.close() + return names + def get_base_file(self): self.__begin_stack_check() return self.__base_file @@ -397,6 +413,42 @@ class Series(StgitObject): def set_description(self, line): self._set_field('description', line) + def get_parent_remote(self): + value = config.get('branch.%s.remote' % self.__name) + if value: + return value + elif 'origin' in git.remotes_list(): + # FIXME: this is for compatibility only. Should be + # dropped when all relevant commands record this info. + return 'origin' + else: + raise StackException, 'Cannot find a parent remote for "%s"' % self.__name + + def __set_parent_remote(self, remote): + value = config.set('branch.%s.remote' % self.__name, remote) + + def get_parent_branch(self): + value = config.get('branch.%s.merge' % self.__name) + if value: + return value + elif git.rev_parse('heads/origin'): + # FIXME: this is for compatibility only. Should be + # dropped when all relevant commands record this info. + return 'heads/origin' + else: + raise StackException, 'Cannot find a parent branch for "%s"' % self.__name + + def __set_parent_branch(self, name): + config.set('branch.%s.merge' % self.__name, name) + + def set_parent(self, remote, localbranch): + if localbranch: + self.__set_parent_branch(localbranch) + if remote: + self.__set_parent_remote(remote) + elif remote: + raise StackException, 'Remote "%s" without a branch cannot be used as parent' % remote + def __patch_is_current(self, patch): return patch.get_name() == self.get_current() @@ -410,6 +462,11 @@ class Series(StgitObject): """ return name in self.get_unapplied() + def patch_hidden(self, name): + """Return true if the patch is hidden. + """ + return name in self.get_hidden() + def patch_exists(self, name): """Return true if there is a patch with the given name, false otherwise.""" @@ -445,7 +502,7 @@ class Series(StgitObject): """ return os.path.isdir(self.__patch_dir) - def init(self, create_at=False): + def init(self, create_at=False, parent_remote=None, parent_branch=None): """Initialises the stgit series """ bases_dir = os.path.join(self.__base_dir, 'refs', 'bases') @@ -462,6 +519,8 @@ class Series(StgitObject): os.makedirs(self.__patch_dir) + self.set_parent(parent_remote, parent_branch) + create_dirs(bases_dir) self.create_empty_field('applied') @@ -589,6 +648,8 @@ class Series(StgitObject): os.remove(self.__applied_file) if os.path.exists(self.__unapplied_file): os.remove(self.__unapplied_file) + if os.path.exists(self.__hidden_file): + os.remove(self.__hidden_file) if os.path.exists(self.__current_file): os.remove(self.__current_file) if os.path.exists(self.__descr_file): @@ -694,7 +755,7 @@ class Series(StgitObject): # old_bottom is different, there wasn't any previous 'refresh' # command (probably only a 'push') if old_bottom != patch.get_bottom() or old_top == patch.get_top(): - raise StackException, 'No refresh undo information available' + raise StackException, 'No undo information available' git.reset(tree_id = old_top, check_out = False) if patch.restore_old_boundaries(): @@ -708,6 +769,8 @@ class Series(StgitObject): before_existing = False, refresh = True): """Creates a new patch """ + self.__patch_name_valid(name) + if self.patch_applied(name) or self.patch_unapplied(name): raise StackException, 'Patch "%s" already exists' % name @@ -764,6 +827,7 @@ class Series(StgitObject): def delete_patch(self, name): """Deletes a patch """ + self.__patch_name_valid(name) patch = Patch(name, self.__patch_dir, self.__refs_dir) if self.__patch_is_current(patch): @@ -784,6 +848,10 @@ class Series(StgitObject): f = file(self.__unapplied_file, 'w+') f.writelines([line + '\n' for line in unapplied]) f.close() + + if self.patch_hidden(name): + self.unhide_patch(name) + self.__begin_stack_check() def forward_patches(self, names): @@ -933,7 +1001,7 @@ class Series(StgitObject): # merge can fail but the patch needs to be pushed try: - git.merge(bottom, head, top) + git.merge(bottom, head, top, recursive = True) except git.GitException, ex: print >> sys.stderr, \ 'The merge failed during "push". ' \ @@ -959,6 +1027,11 @@ class Series(StgitObject): log = 'push' self.refresh_patch(cache_update = False, log = log) else: + # we store the correctly merged files only for + # tracking the conflict history. Note that the + # git.merge() operations shouls always leave the index + # in a valid state (i.e. only stage 0 files) + self.refresh_patch(cache_update = False, log = 'push(c)') raise StackException, str(ex) return modified @@ -976,7 +1049,7 @@ class Series(StgitObject): # modified by 'refresh'). If they are both unchanged, there # was a fast forward if old_bottom == patch.get_bottom() and old_top != patch.get_top(): - raise StackException, 'No push undo information available' + raise StackException, 'No undo information available' git.reset() self.pop_patch(name) @@ -1030,6 +1103,7 @@ class Series(StgitObject): def empty_patch(self, name): """Returns True if the patch is empty """ + self.__patch_name_valid(name) patch = Patch(name, self.__patch_dir, self.__refs_dir) bottom = patch.get_bottom() top = patch.get_top() @@ -1043,6 +1117,8 @@ class Series(StgitObject): return False def rename_patch(self, oldname, newname): + self.__patch_name_valid(newname) + applied = self.get_applied() unapplied = self.get_unapplied() @@ -1052,6 +1128,10 @@ class Series(StgitObject): if newname in applied or newname in unapplied: raise StackException, 'Patch "%s" already exists' % newname + if self.patch_hidden(oldname): + self.unhide_patch(oldname) + self.hide_patch(newname) + if oldname in unapplied: Patch(oldname, self.__patch_dir, self.__refs_dir).rename(newname) unapplied[unapplied.index(oldname)] = newname @@ -1088,3 +1168,28 @@ class Series(StgitObject): cache_update = False, tree_id = top.get_tree(), allowempty = True) patch.set_log(log) + + def hide_patch(self, name): + """Add the patch to the hidden list. + """ + if not self.patch_exists(name): + raise StackException, 'Unknown patch "%s"' % name + elif self.patch_hidden(name): + raise StackException, 'Patch "%s" already hidden' % name + + append_string(self.__hidden_file, name) + + def unhide_patch(self, name): + """Add the patch to the hidden list. + """ + if not self.patch_exists(name): + raise StackException, 'Unknown patch "%s"' % name + hidden = self.get_hidden() + if not name in hidden: + raise StackException, 'Patch "%s" not hidden' % name + + hidden.remove(name) + + f = file(self.__hidden_file, 'w+') + f.writelines([line + '\n' for line in hidden]) + f.close()