class StackException(Exception):
pass
+class FilterUntil:
+ def __init__(self):
+ self.should_print = True
+ def __call__(self, x, until_test, prefix):
+ if until_test(x):
+ self.should_print = False
+ if self.should_print:
+ return x[0:len(prefix)] != prefix
+ return False
+
#
# Functions
#
__comment_prefix = 'STG:'
+__patch_prefix = 'STG_PATCH:'
def __clean_comments(f):
"""Removes lines marked for status in a commit file
f.seek(0)
# remove status-prefixed lines
- lines = filter(lambda x: x[0:len(__comment_prefix)] != __comment_prefix,
- f.readlines())
+ lines = f.readlines()
+
+ patch_filter = FilterUntil()
+ until_test = lambda t: t == (__patch_prefix + '\n')
+ lines = [l for l in lines if patch_filter(l, until_test, __comment_prefix)]
+
# remove empty lines at the end
while len(lines) != 0 and lines[-1] == '\n':
del lines[-1]
f.seek(0); f.truncate()
f.writelines(lines)
-def edit_file(string, comment):
+def edit_file(series, string, comment, show_patch = True):
fname = '.stgit.msg'
tmpl = os.path.join(git.base_dir, 'patchdescr.tmpl')
% __comment_prefix
print >> f, __comment_prefix, \
'Trailing empty lines will be automatically removed.'
+
+ if show_patch:
+ print >> f, __patch_prefix
+ # series.get_patch(series.get_current()).get_top()
+ git.diff([], series.get_patch(series.get_current()).get_bottom(), None, f)
+
+ #Vim modeline must be near the end.
+ print >> f, __comment_prefix, 'vi: set textwidth=75 filetype=diff:'
f.close()
# the editor
create_empty_file(self.__unapplied_file)
self.__begin_stack_check()
- def refresh_patch(self, message = None, edit = False,
+ def refresh_patch(self, message = None, edit = False, show_patch = False,
+ cache_update = True,
author_name = None, author_email = None,
author_date = None,
committer_name = None, committer_email = None,
descr = message
if not message and edit:
- descr = edit_file(descr.rstrip(), \
+ descr = edit_file(self, descr.rstrip(), \
'Please edit the description for patch "%s" ' \
- 'above.' % name)
+ 'above.' % name, show_patch)
if not author_name:
author_name = patch.get_authname()
committer_email = patch.get_commemail()
commit_id = git.commit(message = descr, parents = [patch.get_bottom()],
+ cache_update = cache_update,
allowempty = True,
author_name = author_name,
author_email = author_email,
return commit_id
- def new_patch(self, name, message = None, edit = False,
+ def new_patch(self, name, message = None, can_edit = True, show_patch = False,
author_name = None, author_email = None, author_date = None,
committer_name = None, committer_email = None):
"""Creates a new patch
if self.__patch_applied(name) or self.__patch_unapplied(name):
raise StackException, 'Patch "%s" already exists' % name
- if not message:
- descr = edit_file(None, \
+ if not message and can_edit:
+ descr = edit_file(self, None, \
'Please enter the description for patch "%s" ' \
- 'above.' % name)
+ 'above.' % name, show_patch)
else:
descr = message
f.writelines([line + '\n' for line in unapplied])
f.close()
+ def forward_patches(self, names):
+ """Try to fast-forward an array of patches.
+
+ On return, patches in names[0:returned_value] have been pushed on the
+ stack. Apply the rest with push_patch
+ """
+ unapplied = self.get_unapplied()
+ self.__begin_stack_check()
+
+ forwarded = 0
+ top = git.get_head()
+
+ for name in names:
+ assert(name in unapplied)
+
+ patch = Patch(name, self.__patch_dir)
+
+ head = top
+ bottom = patch.get_bottom()
+ top = patch.get_top()
+
+ # top != bottom always since we have a commit for each patch
+ if head == bottom:
+ # reset the backup information
+ patch.set_bottom(bottom, backup = True)
+ patch.set_top(top, backup = True)
+
+ else:
+ top = head
+ # stop the fast-forwarding, must do a real merge
+ break
+
+ forwarded+=1
+ unapplied.remove(name)
+
+ git.switch(top)
+
+ append_strings(self.__applied_file, names[0:forwarded])
+
+ f = file(self.__unapplied_file, 'w+')
+ f.writelines([line + '\n' for line in unapplied])
+ f.close()
+
+ self.__set_current(name)
+
+ return forwarded
+
def push_patch(self, name):
"""Pushes a patch on the stack
"""
if head != bottom:
if not ex:
# if the merge was OK and no conflicts, just refresh the patch
- self.refresh_patch()
+ # The GIT cache was already updated by the merge operation
+ self.refresh_patch(cache_update = False)
else:
raise StackException, str(ex)
assert(name)
patch = Patch(name, self.__patch_dir)
+ git.reset()
self.pop_patch(name)
patch.restore_old_boundaries()