f.writelines(lines)
def edit_file(series, line, comment, show_patch = True):
- fname = '.stgit.msg'
+ fname = '.stgitmsg.txt'
tmpl = templates.get_template('patchdescr.tmpl')
f = file(fname, 'w+')
self.__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)
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)
def get_name(self):
return self.__name
def rename(self, newname):
olddir = self.__dir
- old_ref_file = self.__top_ref_file
+ 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.__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(old_ref_file, self.__top_ref_file)
+ 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)
def __update_top_ref(self, ref):
write_string(self.__top_ref_file, ref)
+ def __update_log_ref(self, ref):
+ write_string(self.__log_ref_file, ref)
+
def update_top_ref(self):
top = self.get_top()
if top:
address = os.environ['GIT_COMMITTER_EMAIL']
self.__set_field('commemail', address)
+ def get_log(self):
+ return self.__get_field('log')
+
+ def set_log(self, value, backup = False):
+ self.__set_field('log', value)
+ self.__update_log_ref(value)
+
class Series:
"""Class including the operations on series
"""
return Patch(name, self.__patch_dir, self.__refs_dir)
+ def get_current_patch(self):
+ """Return a Patch object representing the topmost patch, or
+ None if there is no such patch."""
+ crt = self.get_current()
+ if not crt:
+ return None
+ return Patch(crt, self.__patch_dir, self.__refs_dir)
+
def get_current(self):
- """Return a Patch object representing the topmost patch
- """
+ """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 name in self.get_unapplied()
+ 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_applied(name)
+
def __begin_stack_check(self):
"""Save the current HEAD into .git/refs/heads/base if the stack
is empty
def head_top_equal(self):
"""Return true if the head and the top are the same
"""
- crt = self.get_current()
+ crt = self.get_current_patch()
if not crt:
# we don't care, no patches applied
return True
- return git.get_head() == Patch(crt, self.__patch_dir,
- self.__refs_dir).get_top()
+ return git.get_head() == crt.get_top()
def is_initialised(self):
"""Checks if series is already initialised
author_name = None, author_email = None,
author_date = None,
committer_name = None, committer_email = None,
- backup = False):
+ backup = False, sign_str = None, log = 'refresh'):
"""Generates a new commit for the given patch
"""
name = self.get_current()
if not committer_email:
committer_email = patch.get_commemail()
+ if sign_str:
+ descr = '%s\n%s: %s <%s>\n' % (descr.rstrip(), sign_str,
+ committer_name, committer_email)
+
bottom = patch.get_bottom()
commit_id = git.commit(files = files,
patch.set_commname(committer_name)
patch.set_commemail(committer_email)
+ if log:
+ self.log_patch(patch, log)
+
return commit_id
def undo_refresh(self):
raise StackException, 'No refresh undo information available'
git.reset(tree_id = old_top, check_out = False)
- patch.restore_old_boundaries()
+ if patch.restore_old_boundaries():
+ self.log_patch(patch, 'undo')
def new_patch(self, name, message = None, can_edit = True,
unapplied = False, show_patch = False,
top = None, bottom = None,
author_name = None, author_email = None, author_date = None,
committer_name = None, committer_email = None,
- before_existing = False):
+ before_existing = False, refresh = True):
"""Creates a new patch
"""
if self.__patch_applied(name) or self.__patch_unapplied(name):
patch.set_commemail(committer_email)
if unapplied:
+ self.log_patch(patch, 'new')
+
patches = [patch.get_name()] + self.get_unapplied()
f = file(self.__unapplied_file, 'w+')
f.writelines([line + '\n' for line in patches])
f.close()
- else:
- if before_existing:
- insert_string(self.__applied_file, patch.get_name())
- if not self.get_current():
- self.__set_current(name)
- else:
- append_string(self.__applied_file, patch.get_name())
- self.__set_current(name)
+ elif before_existing:
+ self.log_patch(patch, 'new')
- self.refresh_patch(cache_update = False)
+ insert_string(self.__applied_file, patch.get_name())
+ if not self.get_current():
+ self.__set_current(name)
+ else:
+ append_string(self.__applied_file, patch.get_name())
+ self.__set_current(name)
+ if refresh:
+ self.refresh_patch(cache_update = False, log = 'new')
def delete_patch(self, name):
"""Deletes a patch
# top != bottom always since we have a commit for each patch
if head == bottom:
- # reset the backup information
+ # reset the backup information. No logging since the
+ # patch hasn't changed
patch.set_bottom(head, backup = True)
patch.set_top(top, backup = True)
patch.set_bottom(head, backup = True)
patch.set_top(top, backup = True)
+
+ self.log_patch(patch, 'push(f)')
else:
top = head
# stop the fast-forwarding, must do a real merge
patch.set_top(head, backup = True)
modified = True
elif head == bottom:
- # reset the backup information
+ # reset the backup information. No need for logging
patch.set_bottom(bottom, backup = True)
patch.set_top(top, backup = True)
if not ex:
# if the merge was OK and no conflicts, just refresh the patch
# The GIT cache was already updated by the merge operation
- self.refresh_patch(cache_update = False)
+ if modified:
+ log = 'push(m)'
+ else:
+ log = 'push'
+ self.refresh_patch(cache_update = False, log = log)
else:
raise StackException, str(ex)
git.reset()
self.pop_patch(name)
- return patch.restore_old_boundaries()
+ ret = patch.restore_old_boundaries()
+ if ret:
+ self.log_patch(patch, 'undo')
+
+ return ret
- def pop_patch(self, name):
+ def pop_patch(self, name, keep = False):
"""Pops the top patch from the stack
"""
applied = self.get_applied()
patch = Patch(name, self.__patch_dir, self.__refs_dir)
- git.switch(patch.get_bottom())
+ # only keep the local changes
+ if keep and not git.apply_diff(git.get_head(), patch.get_bottom()):
+ raise StackException, \
+ 'Failed to pop patches while preserving the local changes'
+
+ git.switch(patch.get_bottom(), keep)
# save the new applied list
idx = applied.index(name) + 1
f.close()
else:
raise StackException, 'Unknown patch "%s"' % oldname
+
+ def log_patch(self, patch, message):
+ """Generate a log commit for a patch
+ """
+ top = git.get_commit(patch.get_top())
+ msg = '%s\t%s' % (message, top.get_id_hash())
+
+ old_log = patch.get_log()
+ if old_log:
+ parents = [old_log]
+ else:
+ parents = []
+
+ log = git.commit(message = msg, parents = parents,
+ cache_update = False, tree_id = top.get_tree(),
+ allowempty = True)
+ patch.set_log(log)