def write_commit(self): metadata = self.__metadata_string() tree = self.__tree(metadata) self.__simplified = self.__repo.commit( CommitData(tree=tree, message=self.message, parents=[ prev.simplified for prev in [self.prev] if prev is not None ])) parents = list(self.__parents()) while len(parents) >= self.__max_parents: g = self.__repo.commit( CommitData( tree=tree, parents=parents[-self.__max_parents:], message='Stack log parent grouping', )) parents[-self.__max_parents:] = [g] self.commit = self.__repo.commit( CommitData( tree=tree, message=self.message, parents=[self.simplified] + parents, ))
def commit_state(self, repo, message): """Commit stack state to stack metadata branch.""" prev_state = self.get_prev_state(repo) tree = self._tree(repo, prev_state) simplified_parent = repo.commit( CommitData( tree=tree, message=message, parents=[] if prev_state is None else [prev_state.simplified_parent], ) ) parents = list(self._parents(prev_state)) while len(parents) >= self._max_parents: g = repo.commit( CommitData( tree=tree, parents=parents[-self._max_parents :], message='Stack log parent grouping', ) ) parents[-self._max_parents :] = [g] self.commit = repo.commit( CommitData( tree=tree, message=message, parents=[simplified_parent] + parents, ) ) return self.commit
def _squash_patches(trans, patches, msg, save_template, no_verify=False): cd = trans.patches[patches[0]].data cd = CommitData(tree=cd.tree, parents=cd.parents) for pn in patches[1:]: c = trans.patches[pn] tree = trans.stack.repository.simple_merge( base=c.data.parent.data.tree, ours=cd.tree, theirs=c.data.tree, ) if not tree: return None cd = cd.set_tree(tree) if msg is None: msg = utils.append_comment( trans.patches[patches[0]].data.message, '\n\n'.join('%s\n\n%s' % (pn.ljust(70, '-'), trans.patches[pn].data.message) for pn in patches[1:])) if save_template: save_template(msg.encode('utf-8')) raise SaveTemplateDone() else: msg = utils.edit_string(msg, '.stgit-squash.txt') msg = utils.strip_comment(msg).strip() cd = cd.set_message(msg) if not no_verify: cd = common.run_commit_msg_hook(trans.stack.repository, cd) return cd
def commit_state(self): """Commit stack state to stack metadata branch.""" tree = self._tree() self._simplified = self._repo.commit( CommitData( tree=tree, message=self.message, parents=[ prev.simplified for prev in [self.prev] if prev is not None ], )) parents = list(self._parents()) while len(parents) >= self._max_parents: g = self._repo.commit( CommitData( tree=tree, parents=parents[-self._max_parents:], message='Stack log parent grouping', )) parents[-self._max_parents:] = [g] self.commit = self._repo.commit( CommitData( tree=tree, message=self.message, parents=[self.simplified] + parents, )) return self.commit
def apply_patch(stack, diff, base=None, reject=False, strip=None): iw = stack.repository.default_iw iw.refresh_index() if base: orig_head = stack.head iw.checkout(orig_head.data.tree, base.data.tree) stack.set_head(base, msg='apply patch') try: iw.apply(diff, quiet=False, reject=reject, strip=strip) except MergeException: if base: iw.checkout_hard(orig_head.data.tree) raise if base: iw.update_index(iw.changed_files(base.data.tree)) top = stack.repository.commit( CommitData( tree=stack.repository.default_index.write_tree(), message='temporary commit used for applying a patch', parents=[base], )) iw.checkout(top.data.tree, orig_head.data.tree) stack.set_head(orig_head, msg='post apply') iw.merge(base.data.tree, orig_head.data.tree, top.data.tree)
def __series_merge_patch(patchdir, stack, commit, pname): """Merge a patch file with the given StGIT patch. """ with io.open(os.path.join(patchdir, pname), 'rb') as f: diff = f.read() base = commit.data.parent orig_head = stack.head iw = stack.repository.default_iw iw.refresh_index() iw.checkout(new_tree=base.data.tree, old_tree=orig_head.data.tree) stack.set_head(base, msg='apply patch') iw.apply(diff, quiet=False) iw.update_index(iw.changed_files(base.data.tree)) new_tree = iw.index.write_tree() stack.repository.commit( CommitData( tree=new_tree, message='temp commit for applying patch', parents=[base], )) iw.checkout(new_tree=orig_head.data.tree, old_tree=new_tree) stack.set_head(orig_head, msg='post apply') iw.merge(base=base.data.tree, ours=orig_head.data.tree, theirs=new_tree) if iw.index.is_clean(orig_head.data.tree): return None else: return new_tree
def func(parser, options, args): """Create a new patch.""" stack = directory.repository.current_stack if stack.repository.default_index.conflicts(): raise CmdException( 'Cannot create a new patch -- resolve conflicts first') # Choose a name for the new patch -- or None, which means make one # up later when we've gotten hold of the commit message. if len(args) == 0: name = None elif len(args) == 1: name = args[0] if not stack.patches.is_name_valid(name): raise CmdException('Invalid patch name: "%s"' % name) elif name in stack.patches: raise CmdException('%s: patch already exists' % name) else: parser.error('incorrect number of arguments') if options.verbose: verbose = options.verbose else: verbose = config.getbool('stgit.new.verbose') or False cd = CommitData( tree=stack.head.data.tree, parents=[stack.head], message='', author=Person.author(), committer=Person.committer(), ) cd = update_commit_data( stack.repository, cd, message=options.message, author=options.author(cd.author), trailers=options.trailers, edit=(not options.save_template and options.message is None), verbose=verbose, ) if options.save_template: options.save_template(cd.message) return utils.STGIT_SUCCESS if not options.no_verify: cd = run_commit_msg_hook(stack.repository, cd) if name is None: name = stack.patches.make_name(cd.message_str) # Write the new patch. check_head_top_equal(stack) trans = StackTransaction(stack) trans.patches[name] = stack.repository.commit(cd) trans.applied.append(name) return trans.execute('new: %s' % name)
def __create_commit(repository, tree, parents, options, message=''): """Return a new Commit object.""" cd = CommitData( tree=tree, parents=parents, message=message, author=Person.author(), committer=Person.committer(), ) cd = common.update_commit_data(cd, options) return repository.commit(cd)
def write_patchlog(): try: old_log = [self._stack.repository.refs.get(self._log_ref)] except KeyError: old_log = [] cd = CommitData( tree=new_commit.data.tree, parents=old_log, message='%s\t%s' % (msg, new_commit.sha1), ) c = self._stack.repository.commit(cd) self._stack.repository.refs.set(self._log_ref, c, msg) return c
def make_temp_patch(stack, patch_name, tree): """Commit tree to temp patch, in a complete transaction.""" commit = stack.repository.commit( CommitData( tree=tree, parents=[stack.head], message='Refresh of %s' % patch_name, )) temp_name = utils.make_patch_name('refresh-temp', stack.patches.exists) trans = StackTransaction(stack, 'refresh (create temporary patch)') trans.patches[temp_name] = commit trans.applied.append(temp_name) return ( trans.run(stack.repository.default_iw, print_current_patch=False), temp_name, )
def make_temp_patch(stack, patch_name, paths, temp_index): """Commit index to temp patch, in a complete transaction. If any path limiting is in effect, use a temp index.""" tree = write_tree(stack, paths, temp_index) commit = stack.repository.commit( CommitData( tree=tree, parents=[stack.head], message='Refresh of %s' % patch_name, )) temp_name = utils.make_patch_name('refresh-temp', stack.patches.exists) trans = transaction.StackTransaction(stack, 'refresh (create temporary patch)') trans.patches[temp_name] = commit trans.applied.append(temp_name) return (trans.run(stack.repository.default_iw, print_current_patch=False), temp_name)
def func(parser, options, args): """Create a new patch.""" stack = directory.repository.current_stack if stack.repository.default_index.conflicts(): raise CmdException( 'Cannot create a new patch -- resolve conflicts first') # Choose a name for the new patch -- or None, which means make one # up later when we've gotten hold of the commit message. if len(args) == 0: name = None elif len(args) == 1: name = args[0] if stack.patches.exists(name): raise CmdException('%s: patch already exists' % name) elif not stack.patches.is_name_valid(name): raise CmdException('Invalid patch name: "%s"' % name) else: parser.error('incorrect number of arguments') cd = CommitData( tree=stack.head.data.tree, parents=[stack.head], message='', author=Person.author(), committer=Person.committer(), ) cd = update_commit_data(cd, options) if options.save_template: options.save_template(cd.message.encode('utf-8')) return utils.STGIT_SUCCESS if not options.no_verify: cd = run_commit_msg_hook(stack.repository, cd) if name is None: name = utils.make_patch_name(cd.message, stack.patches.exists) assert stack.patches.is_name_valid(name) # Write the new patch. stack.repository.default_iw trans = StackTransaction(stack, 'new: %s' % name) trans.patches[name] = stack.repository.commit(cd) trans.applied.append(name) return trans.run()
def __create_commit(repository, tree, parents, options, message=''): """Return a new Commit object.""" cd = CommitData( tree=tree, parents=parents, message=message, author=Person.author(), committer=Person.committer(), ) cd = update_commit_data( cd, message=options.message, author=options.author(cd.author), sign_str=options.sign_str, edit=options.message is None, ) return repository.commit(cd)
def __pick_commit(stack, ref_stack, iw, commit, patchname, options): """Pick a commit.""" repository = stack.repository if options.name: patchname = options.name elif patchname and options.revert: patchname = 'revert-' + patchname if patchname: patchname = find_patch_name(patchname, stack.patches.exists) else: patchname = make_patch_name(commit.data.message_str, stack.patches.exists) if options.parent: parent = git_commit(options.parent, repository, ref_stack.name) else: parent = commit.data.parent if not options.revert: bottom = parent top = commit else: bottom = commit top = parent if options.fold: out.start('Folding commit %s' % commit.sha1) diff = repository.diff_tree(bottom.data.tree, top.data.tree, pathlimits=options.file) if diff: try: # try a direct git apply first iw.apply(diff, quiet=True) except MergeException: if options.file: out.done('conflict(s)') out.error('%s does not apply cleanly' % patchname) return STGIT_CONFLICT else: try: iw.merge( bottom.data.tree, stack.head.data.tree, top.data.tree, ) except MergeConflictException as e: out.done('%s conflicts' % len(e.conflicts)) out.error('%s does not apply cleanly' % patchname, *e.conflicts) return STGIT_CONFLICT out.done() else: out.done('no changes') return STGIT_SUCCESS elif options.update: files = [ fn1 for _, _, _, _, _, fn1, fn2 in repository.diff_tree_files( stack.top.data.parent.data.tree, stack.top.data.tree) ] diff = repository.diff_tree(bottom.data.tree, top.data.tree, pathlimits=files) out.start('Updating with commit %s' % commit.sha1) try: iw.apply(diff, quiet=True) except MergeException: out.done('conflict(s)') out.error('%s does not apply cleanly' % patchname) return STGIT_CONFLICT else: out.done() return STGIT_SUCCESS else: author = commit.data.author message = commit.data.message_str if options.revert: author = Person.author() if message: lines = message.splitlines() subject = lines[0] body = '\n'.join(lines[2:]) else: subject = commit.sha1 body = '' message = 'Revert "%s"\n\nThis reverts commit %s.\n\n%s\n' % ( subject, commit.sha1, body, ) elif options.expose: fmt = config.get('stgit.pick.expose-format') message = Run('git', 'show', '--no-patch', '--pretty=' + fmt, commit.sha1).raw_output() message = message.rstrip() + '\n' out.start('Importing commit %s' % commit.sha1) new_commit = repository.commit( CommitData( tree=top.data.tree, parents=[bottom], message=message, author=author, )) trans = StackTransaction( stack, 'pick %s from %s' % (patchname, ref_stack.name)) trans.patches[patchname] = new_commit trans.unapplied.append(patchname) if not options.unapplied: try: trans.push_patch(patchname, iw, allow_interactive=True) except TransactionHalted: pass retval = trans.run(iw, print_current_patch=False) if retval == STGIT_CONFLICT: out.done('conflict(s)') elif stack.patches.get(patchname).is_empty(): out.done('empty patch') else: out.done() return retval
def __create_patch(filename, message, author_name, author_email, author_date, diff, options): """Create a new patch on the stack """ stack = directory.repository.current_stack if options.name: name = options.name if not stack.patches.is_name_valid(name): raise CmdException('Invalid patch name: %s' % name) elif filename: name = os.path.basename(filename) else: name = '' if options.stripname: name = __strip_patch_name(name) if not name: if options.ignore or options.replace: def unacceptable_name(name): return False else: unacceptable_name = stack.patches.exists name = make_patch_name(message, unacceptable_name) else: # fix possible invalid characters in the patch name name = re.sub(r'[^\w.]+', '-', name).strip('-') assert stack.patches.is_name_valid(name) if options.ignore and name in stack.patchorder.applied: out.info('Ignoring already applied patch "%s"' % name) return out.start('Importing patch "%s"' % name) author = Person( author_name, author_email, Date.maybe(author_date), ) author = options.author(author) try: if not diff: out.warn('No diff found, creating empty patch') tree = stack.head.data.tree else: iw = stack.repository.default_iw iw.apply( diff, quiet=False, reject=options.reject, strip=options.strip ) tree = iw.index.write_tree() cd = CommitData( tree=tree, parents=[stack.head], author=author, message=message, ) cd = update_commit_data( cd, message=None, author=None, sign_str=options.sign_str, edit=options.edit, ) commit = stack.repository.commit(cd) trans = StackTransaction(stack, 'import: %s' % name) try: if options.replace and name in stack.patchorder.unapplied: trans.delete_patches(lambda pn: pn == name, quiet=True) trans.patches[name] = commit trans.applied.append(name) except TransactionHalted: pass trans.run() finally: out.done()
def __create_patch(filename, message, patch_name, author_name, author_email, author_date, diff, options): """Create a new patch on the stack""" stack = directory.repository.current_stack if patch_name: name = patch_name elif options.name: name = options.name elif filename: name = os.path.basename(filename) else: name = '' if options.stripname: # Removing leading numbers and trailing extension name = re.sub( r'''^ (?:[0-9]+-)? # Optional leading patch number (.*?) # Patch name group (non-greedy) (?:\.(?:diff|patch))? # Optional .diff or .patch extension $ ''', r'\g<1>', name, flags=re.VERBOSE, ) need_unique = not (options.ignore or options.replace) if name: name = stack.patches.make_name(name, unique=need_unique, lower=False) else: name = stack.patches.make_name(message, unique=need_unique, lower=True) if options.ignore and name in stack.patchorder.applied: out.info('Ignoring already applied patch "%s"' % name) return out.start('Importing patch "%s"' % name) author = options.author( Person( author_name, author_email, Date.maybe(author_date), )) try: if not diff: out.warn('No diff found, creating empty patch') tree = stack.head.data.tree else: iw = stack.repository.default_iw iw.apply( diff, quiet=False, reject=options.reject, strip=options.strip, context_lines=options.context_lines, ) tree = iw.index.write_tree() cd = CommitData( tree=tree, parents=[stack.head], author=author, message=message, ) cd = update_commit_data( stack.repository, cd, message=None, author=None, trailers=options.trailers, edit=options.edit, ) commit = stack.repository.commit(cd) trans = StackTransaction(stack) try: if options.replace and name in stack.patchorder.unapplied: trans.delete_patches(lambda pn: pn == name, quiet=True) trans.patches[name] = commit trans.applied.append(name) except TransactionHalted: pass trans.execute('import: %s' % name) finally: out.done()