def func(parser, options, args): """Repair inconsistencies in StGit metadata.""" if args: parser.error('incorrect number of arguments') repository = directory.repository stack = repository.get_stack() if stack.protected: raise CmdException( 'This branch is protected. Modification is not permitted.') patchorder = stack.patchorder patches = [stack.patches.get(pn) for pn in patchorder.all] # Find commits that aren't patches, and applied patches. patchify = [] # commits to definitely patchify maybe_patchify = [] # commits to patchify if we find a patch below them applied = [] c = stack.head while len(c.data.parents) == 1: for p in patches: if p.commit == c: applied.append(p) patchify.extend(maybe_patchify) maybe_patchify = [] break else: maybe_patchify.append(c) c = c.data.parent applied.reverse() patchify.reverse() # Find patches unreachable behind a merge. merge = c todo = set([c]) seen = set() unreachable = set() while todo: c = todo.pop() seen.add(c) todo |= set(c.data.parents) - seen if any(p.commit == c for p in patches): unreachable.add(c) if unreachable: out.warn(('%d patch%s are hidden below the merge commit' % (len(unreachable), ['es', ''][len(unreachable) == 1])), '%s,' % merge.sha1, 'and will be considered unapplied.') # Make patches of any linear sequence of commits on top of a patch. if applied and patchify: out.start('Creating %d new patch%s' % (len(patchify), ['es', ''][len(patchify) == 1])) for c in patchify: pn = make_patch_name( c.data.message, unacceptable=lambda name: any(p.name == name for p in patches), ) out.info('Creating patch %s from commit %s' % (pn, c.sha1)) applied.append(stack.patches.new(pn, c, 'repair')) out.done() # Figure out hidden hidden = [p for p in patches if p.name in patchorder.hidden] # Write the applied/unapplied files. out.start('Checking patch appliedness') unapplied = [p for p in patches if p not in applied and p not in hidden] for pn in patchorder.all: if all(pn != p.name for p in patches): out.info('%s is gone' % pn) for p in applied: if p.name not in patchorder.applied: out.info('%s is now applied' % p.name) for p in unapplied: if p.name not in patchorder.unapplied: out.info('%s is now unapplied' % p.name) for p in hidden: if p.name not in patchorder.hidden: out.info('%s is now hidden' % p.name) out.done() orig_order = dict((pn, i) for i, pn in enumerate(patchorder.all)) def patchname_key(p): i = orig_order.get(p, len(orig_order)) return i, p trans = StackTransaction(stack, 'repair', check_clean_iw=False, allow_bad_head=True) try: trans.applied = [p.name for p in applied] trans.unapplied = sorted((p.name for p in unapplied), key=patchname_key) trans.hidden = sorted((p.name for p in hidden), key=patchname_key) except TransactionHalted: pass return trans.run()
def func(parser, options, args): """Repair inconsistencies in StGit metadata.""" if args: parser.error('incorrect number of arguments') repository = directory.repository stack = repository.get_stack() if stack.protected: raise CmdException( 'This branch is protected. Modification is not permitted.') patchorder = stack.patchorder patches = list(patchorder.all) # Find commits that aren't patches, and applied patches. patchify = [] # commits to definitely patchify maybe_patchify = [] # commits to patchify if we find a patch below them applied = [] c = stack.head while len(c.data.parents) == 1: for pn in patchorder.all: if stack.patches[pn] == c: applied.append(pn) patchify.extend(maybe_patchify) maybe_patchify = [] break else: maybe_patchify.append(c) c = c.data.parent if stack.base == c: # Reaching the original stack base can happen if, for example, the first # applied patch is amended. In this case, any commits descending from the # stack base should be patchified. patchify.extend(maybe_patchify) maybe_patchify = [] # Once the base commit has been found, we know that no existing patches # can be found be searching further. break applied.reverse() patchify.reverse() # Find patches unreachable behind a merge. if c != stack.base: merge = c todo = set([c]) seen = set() unreachable = set() while todo: c = todo.pop() seen.add(c) todo |= set(c.data.parents) - seen if any(stack.patches[pn] == c for pn in patches): unreachable.add(c) if unreachable: out.warn( ('%d patch%s are hidden below the merge commit' % (len(unreachable), ['es', ''][len(unreachable) == 1])), '%s,' % merge.sha1, 'and will be considered unapplied.', ) # Make patches of any linear sequence of commits on top of a patch. if patchify: out.start('Creating %d new patch%s' % (len(patchify), ['es', ''][len(patchify) == 1])) for c in patchify: pn = stack.patches.make_name(c.data.message_str) out.info('Creating patch %s from commit %s' % (pn, c.sha1)) stack.patches.new(pn, c, 'repair') applied.append(pn) out.done() # Figure out hidden hidden = [pn for pn in patches if pn in patchorder.hidden] # Write the applied/unapplied files. out.start('Checking patch appliedness') unapplied = [ pn for pn in patches if pn not in applied and pn not in hidden ] for pn in patchorder.all: if pn not in patches: out.info('%s is gone' % pn) for pn in applied: if pn not in patchorder.applied: out.info('%s is now applied' % pn) for pn in unapplied: if pn not in patchorder.unapplied: out.info('%s is now unapplied' % pn) for pn in hidden: if pn not in patchorder.hidden: out.info('%s is now hidden' % pn) out.done() orig_order = {pn: i for i, pn in enumerate(patchorder.all)} def patchname_key(p): i = orig_order.get(p, len(orig_order)) return i, p trans = StackTransaction(stack) try: trans.applied = applied trans.unapplied = sorted(unapplied, key=patchname_key) trans.hidden = sorted(hidden, key=patchname_key) except TransactionHalted: pass return trans.execute('repair')