示例#1
0
文件: log.py 项目: miracle2k/stgit
def func(parser, options, args):
    if options.branch:
        stack = directory.repository.get_stack(options.branch)
    else:
        stack = directory.repository.current_stack
    patches = common.parse_patches(args, list(stack.patchorder.all))
    logref = log.log_ref(stack.name)
    try:
        logcommit = stack.repository.refs.get(logref)
    except KeyError:
        out.info('Log is empty')
        return

    if options.clear:
        log.delete_log(stack.repository, stack.name)
        return

    stacklog = log.get_log_entry(stack.repository, logref, logcommit)
    pathlim = [os.path.join('patches', pn) for pn in patches]

    if options.graphical:
        for o in ['diff', 'number', 'full']:
            if getattr(options, o):
                parser.error('cannot combine --graphical and --%s' % o)
        # Discard the exit codes generated by SIGINT, SIGKILL, and SIGTERM.
        run.Run(*(['gitk', stacklog.simplified.sha1, '--'] + pathlim)
                 ).returns([0, -2, -9, -15]).run()
    else:
        show_log(stacklog.simplified, pathlim,
                 options.number, options.full, options.diff)
示例#2
0
文件: commit.py 项目: snits/stgit
def func(parser, options, args):
    """Commit a number of patches."""
    stack = directory.repository.current_stack
    args = common.parse_patches(args, list(stack.patchorder.all_visible))
    if len([x for x in [args, options.number is not None, options.all] if x]) > 1:
        parser.error('too many options')
    if args:
        patches = [pn for pn in stack.patchorder.all_visible if pn in args]
        bad = set(args) - set(patches)
        if bad:
            raise common.CmdException('Nonexistent or hidden patch names: %s'
                                      % ', '.join(sorted(bad)))
    elif options.number is not None:
        if options.number <= len(stack.patchorder.applied):
            patches = stack.patchorder.applied[:options.number]
        else:
            raise common.CmdException('There are not that many applied patches')
    elif options.all:
        patches = stack.patchorder.applied
    else:
        patches = stack.patchorder.applied[:1]
    if not patches:
        raise common.CmdException('No patches to commit')

    iw = stack.repository.default_iw
    def allow_conflicts(trans):
        # As long as the topmost patch stays where it is, it's OK to
        # run "stg commit" with conflicts in the index.
        return len(trans.applied) >= 1
    trans = transaction.StackTransaction(stack, 'commit',
                                         allow_conflicts = allow_conflicts)
    try:
        common_prefix = 0
        for i in range(min(len(stack.patchorder.applied), len(patches))):
            if stack.patchorder.applied[i] == patches[i]:
                common_prefix += 1
            else:
                break
        if common_prefix < len(patches):
            to_push = [pn for pn in stack.patchorder.applied[common_prefix:]
                       if pn not in patches[common_prefix:]]
            # this pops all the applied patches from common_prefix
            trans.pop_patches(lambda pn: pn in to_push)
            for pn in patches[common_prefix:]:
                trans.push_patch(pn, iw)
        else:
            to_push = []
        new_base = trans.patches[patches[-1]]
        for pn in patches:
            trans.patches[pn] = None
        trans.applied = [pn for pn in trans.applied if pn not in patches]
        trans.base = new_base
        out.info('Committed %d patch%s' % (len(patches),
                                           ['es', ''][len(patches) == 1]))
        for pn in to_push:
            trans.push_patch(pn, iw)
    except transaction.TransactionHalted:
        pass
    return trans.run(iw)
示例#3
0
文件: common.py 项目: snits/stgit
def get_patch_from_list(part_name, patch_list):
    candidates = [full for full in patch_list if part_name in full]
    if len(candidates) >= 2:
        out.info('Possible patches:\n  %s' % '\n  '.join(candidates))
        raise CmdException('Ambiguous patch name "%s"' % part_name)
    elif len(candidates) == 1:
        return candidates[0]
    else:
        return None
示例#4
0
文件: git.py 项目: snits/stgit
def mergetool(files = ()):
    """Invoke 'git mergetool' to resolve any outstanding conflicts. If 'not
    files', all the files in an unmerged state will be processed."""
    GRun('mergetool', *list(files)).returns([0, 1]).run()
    # check for unmerged entries (prepend 'CONFLICT ' for consistency with
    # merge_recursive())
    conflicts = ['CONFLICT ' + f for f in get_conflicts()]
    if conflicts:
        out.info(*conflicts)
        raise GitException("%d conflict(s)" % len(conflicts))
示例#5
0
文件: common.py 项目: snits/stgit
def print_crt_patch(crt_series, branch = None):
    if not branch:
        patch = crt_series.get_current()
    else:
        patch = stack.Series(branch).get_current()

    if patch:
        out.info('Now at patch "%s"' % patch)
    else:
        out.info('No patches applied')
示例#6
0
文件: stack.py 项目: snits/stgit
    def clone(self, target_series):
        """Clones a series
        """
        try:
            # allow cloning of branches not under StGIT control
            base = self.get_base()
        except:
            base = git.get_head()
        Series(target_series).init(create_at = base)
        new_series = Series(target_series)

        # generate an artificial description file
        new_series.set_description('clone of "%s"' % self.get_name())

        # clone self's entire series as unapplied patches
        try:
            # allow cloning of branches not under StGIT control
            applied = self.get_applied()
            unapplied = self.get_unapplied()
            patches = applied + unapplied
            patches.reverse()
        except:
            patches = applied = unapplied = []
        for p in patches:
            patch = self.get_patch(p)
            newpatch = new_series.new_patch(p, message = patch.get_description(),
                                            can_edit = False, unapplied = True,
                                            bottom = patch.get_bottom(),
                                            top = patch.get_top(),
                                            author_name = patch.get_authname(),
                                            author_email = patch.get_authemail(),
                                            author_date = patch.get_authdate())
            if patch.get_log():
                out.info('Setting log to %s' %  patch.get_log())
                newpatch.set_log(patch.get_log())
            else:
                out.info('No log for %s' % p)

        # fast forward the cloned series to self's top
        new_series.forward_patches(applied)

        # Clone parent informations
        value = config.get('branch.%s.remote' % self.get_name())
        if value:
            config.set('branch.%s.remote' % target_series, value)

        value = config.get('branch.%s.merge' % self.get_name())
        if value:
            config.set('branch.%s.merge' % target_series, value)

        value = config.get('branch.%s.stgit.parentbranch' % self.get_name())
        if value:
            config.set('branch.%s.stgit.parentbranch' % target_series, value)
示例#7
0
文件: common.py 项目: snits/stgit
def pop_patches(crt_series, patches, keep = False):
    """Pop the patches in the list from the stack. It is assumed that
    the patches are listed in the stack reverse order.
    """
    if len(patches) == 0:
        out.info('Nothing to push/pop')
    else:
        p = patches[-1]
        if len(patches) == 1:
            out.start('Popping patch "%s"' % p)
        else:
            out.start('Popping patches "%s" - "%s"' % (patches[0], p))
        crt_series.pop_patch(p, keep)
        out.done()
示例#8
0
def reset_stack_partially(trans, iw, state, only_patches):
    """Reset the stack to a given previous state -- but only the given
    patches, not anything else.

    @param only_patches: Touch only these patches
    @type only_patches: iterable"""
    only_patches = set(only_patches)
    patches_to_reset = set(state.all_patches) & only_patches
    existing_patches = set(trans.all_patches)
    original_applied_order = list(trans.applied)
    to_delete = (existing_patches - patches_to_reset) & only_patches

    # In one go, do all the popping we have to in order to pop the
    # patches we're going to delete or modify.
    def mod(pn):
        if not pn in only_patches:
            return False
        if pn in to_delete:
            return True
        if trans.patches[pn] != state.patches.get(pn, None):
            return True
        return False
    trans.pop_patches(mod)

    # Delete and modify/create patches. We've previously popped all
    # patches that we touch in this step.
    trans.delete_patches(lambda pn: pn in to_delete)
    for pn in patches_to_reset:
        if pn in existing_patches:
            if trans.patches[pn] == state.patches[pn]:
                continue
            else:
                out.info('Resetting %s' % pn)
        else:
            if pn in state.hidden:
                trans.hidden.append(pn)
            else:
                trans.unapplied.append(pn)
            out.info('Resurrecting %s' % pn)
        trans.patches[pn] = state.patches[pn]

    # Push all the patches that we've popped, if they still
    # exist.
    pushable = set(trans.unapplied + trans.hidden)
    for pn in original_applied_order:
        if pn in pushable:
            trans.push_patch(pn, iw)
示例#9
0
文件: git.py 项目: snits/stgit
def merge_recursive(base, head1, head2):
    """Perform a 3-way merge between base, head1 and head2 into the
    local tree
    """
    refresh_index()
    p = GRun('merge-recursive', base, '--', head1, head2).env(
        { 'GITHEAD_%s' % base: 'ancestor',
          'GITHEAD_%s' % head1: 'current',
          'GITHEAD_%s' % head2: 'patched'}).returns([0, 1])
    output = p.output_lines()
    if p.exitcode:
        # There were conflicts
        if config.get('stgit.autoimerge') == 'yes':
            mergetool()
        else:
            conflicts = [l for l in output if l.startswith('CONFLICT')]
            out.info(*conflicts)
            raise GitException("%d conflict(s)" % len(conflicts))
示例#10
0
文件: common.py 项目: snits/stgit
def push_patches(crt_series, patches, check_merged = False):
    """Push multiple patches onto the stack. This function is shared
    between the push and pull commands
    """
    forwarded = crt_series.forward_patches(patches)
    if forwarded > 1:
        out.info('Fast-forwarded patches "%s" - "%s"'
                 % (patches[0], patches[forwarded - 1]))
    elif forwarded == 1:
        out.info('Fast-forwarded patch "%s"' % patches[0])

    names = patches[forwarded:]

    # check for patches merged upstream
    if names and check_merged:
        out.start('Checking for patches merged upstream')

        merged = crt_series.merged_patches(names)

        out.done('%d found' % len(merged))
    else:
        merged = []

    for p in names:
        out.start('Pushing patch "%s"' % p)

        if p in merged:
            crt_series.push_empty_patch(p)
            out.done('merged upstream')
        else:
            modified = crt_series.push_patch(p)

            if crt_series.empty_patch(p):
                out.done('empty patch')
            elif modified:
                out.done('modified')
            else:
                out.done()
示例#11
0
文件: branch.py 项目: snits/stgit
def func(parser, options, args):

    if options.create:

        if len(args) == 0 or len(args) > 2:
            parser.error('incorrect number of arguments')

        check_local_changes()
        check_conflicts()
        check_head_top_equal(crt_series)

        tree_id = None
        if len(args) >= 2:
            parentbranch = None
            try:
                branchpoint = git.rev_parse(args[1])

                # parent branch?
                head_re = re.compile('refs/(heads|remotes)/')
                ref_re = re.compile(args[1] + '$')
                for ref in git.all_refs():
                    if head_re.match(ref) and ref_re.search(ref):
                        # args[1] is a valid ref from the branchpoint
                        # setting above
                        parentbranch = args[1]
                        break
            except git.GitException:
                # should use a more specific exception to catch only
                # non-git refs ?
                out.info('Don\'t know how to determine parent branch'
                         ' from "%s"' % args[1])
                # exception in branch = rev_parse() leaves branchpoint unbound
                branchpoint = None

            tree_id = git_id(crt_series, branchpoint or args[1])

            if parentbranch:
                out.info('Recording "%s" as parent branch' % parentbranch)
            else:
                out.info('Don\'t know how to determine parent branch'
                         ' from "%s"' % args[1])                
        else:
            # branch stack off current branch
            parentbranch = git.get_head_file()

        if parentbranch:
            parentremote = git.identify_remote(parentbranch)
            if parentremote:
                out.info('Using remote "%s" to pull parent from'
                         % parentremote)
            else:
                out.info('Recording as a local branch')
        else:
            # no known parent branch, can't guess the remote
            parentremote = None

        stack.Series(args[0]).init(create_at = tree_id,
                                   parent_remote = parentremote,
                                   parent_branch = parentbranch)

        out.info('Branch "%s" created' % args[0])
        log.compat_log_entry('branch --create')
        return

    elif options.clone:

        if len(args) == 0:
            clone = crt_series.get_name() + \
                    time.strftime('-%C%y%m%d-%H%M%S')
        elif len(args) == 1:
            clone = args[0]
        else:
            parser.error('incorrect number of arguments')

        check_local_changes()
        check_conflicts()
        check_head_top_equal(crt_series)

        out.start('Cloning current branch to "%s"' % clone)
        crt_series.clone(clone)
        out.done()

        log.copy_log(log.default_repo(), crt_series.get_name(), clone,
                     'branch --clone')
        return

    elif options.delete:

        if len(args) != 1:
            parser.error('incorrect number of arguments')
        __delete_branch(args[0], options.force)
        log.delete_log(log.default_repo(), args[0])
        return

    elif options.cleanup:

        if not args:
            name = crt_series.get_name()
        elif len(args) == 1:
            name = args[0]
        else:
            parser.error('incorrect number of arguments')
        __cleanup_branch(name, options.force)
        log.delete_log(log.default_repo(), name)
        return

    elif options.list:

        if len(args) != 0:
            parser.error('incorrect number of arguments')

        branches = set(git.get_heads())
        for br in set(branches):
            m = re.match(r'^(.*)\.stgit$', br)
            if m and m.group(1) in branches:
                branches.remove(br)

        if branches:
            out.info('Available branches:')
            max_len = max([len(i) for i in branches])
            for i in sorted(branches):
                __print_branch(i, max_len)
        else:
            out.info('No branches')
        return

    elif options.protect:

        if len(args) == 0:
            branch_name = crt_series.get_name()
        elif len(args) == 1:
            branch_name = args[0]
        else:
            parser.error('incorrect number of arguments')
        branch = stack.Series(branch_name)

        if not branch.is_initialised():
            raise CmdException('Branch "%s" is not controlled by StGIT' %
                               branch_name)

        out.start('Protecting branch "%s"' % branch_name)
        branch.protect()
        out.done()

        return

    elif options.rename:

        if len(args) != 2:
            parser.error('incorrect number of arguments')

        if __is_current_branch(args[0]):
            raise CmdException('Renaming the current branch is not supported')

        stack.Series(args[0]).rename(args[1])

        out.info('Renamed branch "%s" to "%s"' % (args[0], args[1]))
        log.rename_log(log.default_repo(), args[0], args[1], 'branch --rename')
        return

    elif options.unprotect:

        if len(args) == 0:
            branch_name = crt_series.get_name()
        elif len(args) == 1:
            branch_name = args[0]
        else:
            parser.error('incorrect number of arguments')
        branch = stack.Series(branch_name)

        if not branch.is_initialised():
            raise CmdException('Branch "%s" is not controlled by StGIT' %
                               branch_name)

        out.info('Unprotecting branch "%s"' % branch_name)
        branch.unprotect()
        out.done()

        return

    elif options.description is not None:

        if len(args) == 0:
            branch_name = crt_series.get_name()
        elif len(args) == 1:
            branch_name = args[0]
        else:
            parser.error('incorrect number of arguments')
        branch = stack.Series(branch_name)

        if not branch.is_initialised():
            raise CmdException('Branch "%s" is not controlled by StGIT' %
                               branch_name)

        branch.set_description(options.description)

        return

    elif len(args) == 1:

        if __is_current_branch(args[0]):
            raise CmdException('Branch "%s" is already the current branch' %
                               args[0])

        if not options.merge:
            check_local_changes()
        check_conflicts()
        check_head_top_equal(crt_series)

        out.start('Switching to branch "%s"' % args[0])
        git.switch_branch(args[0])
        out.done()
        return

    # default action: print the current branch
    if len(args) != 0:
        parser.error('incorrect number of arguments')

    print(crt_series.get_name())
示例#12
0
def func(parser, options, args):
    """Publish the stack changes."""
    repository = directory.repository
    stack = repository.get_stack(options.branch)

    if not args:
        public_ref = common.get_public_ref(stack.name)
    elif len(args) == 1:
        public_ref = args[0]
    else:
        parser.error('incorrect number of arguments')

    if not public_ref.startswith('refs/heads/'):
        public_ref = 'refs/heads/' + public_ref

    # just clone the stack if the public ref does not exist
    if not repository.refs.exists(public_ref):
        if options.unpublished or options.last:
            raise common.CmdException('"%s" does not exist' % public_ref)
        repository.refs.set(public_ref, stack.head, 'publish')
        out.info('Created "%s"' % public_ref)
        return

    public_head = repository.refs.get(public_ref)
    public_tree = public_head.data.tree

    # find the last published patch
    if options.last:
        last = __get_last(stack, public_tree)
        if not last:
            raise common.CmdException('Unable to find the last published patch '
                                      '(possibly rebased stack)')
        out.info('%s' % last)
        return

    # check for same tree (already up to date)
    if public_tree.sha1 == stack.head.data.tree.sha1:
        out.info('"%s" already up to date' % public_ref)
        return

    # check for unpublished patches
    if options.unpublished:
        published = set(__get_published(stack, public_tree))
        for p in stack.patchorder.applied:
            if p not in published:
                print p
        return

    # check for rebased stack. In this case we emulate a merge with the stack
    # base by setting two parents.
    merge_bases = set(repository.get_merge_bases(public_head, stack.base))
    if public_head in merge_bases:
        # fast-forward the public ref
        repository.refs.set(public_ref, stack.head, 'publish')
        out.info('Fast-forwarded "%s"' % public_ref)
        return
    if not stack.base in merge_bases:
        message = 'Merge %s into %s' % (repository.describe(stack.base).strip(),
                                        utils.strip_prefix('refs/heads/',
                                                           public_ref))
        public_head = __create_commit(repository, stack.head.data.tree,
                                      [public_head, stack.base], options,
                                      message)
        repository.refs.set(public_ref, public_head, 'publish')
        out.info('Merged the stack base into "%s"' % public_ref)
        return

    # check for new patches from the last publishing. This is done by checking
    # whether the public tree is the same as the bottom of the checked patch.
    # If older patches were modified, new patches cannot be detected. The new
    # patches and their metadata are pushed directly to the published head.
    for p in stack.patchorder.applied:
        pc = stack.patches.get(p).commit
        if public_tree.sha1 == pc.data.parent.data.tree.sha1:
            if pc.data.is_nochange():
                out.info('Ignored new empty patch "%s"' % p)
                continue
            cd = pc.data.set_parent(public_head)
            public_head = repository.commit(cd)
            public_tree = public_head.data.tree
            out.info('Published new patch "%s"' % p)

    # create a new commit (only happens if no new patches are detected)
    if public_tree.sha1 != stack.head.data.tree.sha1:
        public_head = __create_commit(repository, stack.head.data.tree,
                                      [public_head], options)

    # update the public head
    repository.refs.set(public_ref, public_head, 'publish')
    out.info('Updated "%s"' % public_ref)
示例#13
0
文件: pull.py 项目: snits/stgit
def func(parser, options, args):
    """Pull the changes from a remote repository
    """
    policy = config.get('branch.%s.stgit.pull-policy' % crt_series.get_name()) or \
             config.get('stgit.pull-policy')

    if policy == 'rebase':
        # parent is local
        if len(args) == 1:
            parser.error('specifying a repository is meaningless for policy="%s"' % policy)
        if len(args) > 0:
            parser.error('incorrect number of arguments')

    else:
        # parent is remote
        if len(args) > 1:
            parser.error('incorrect number of arguments')

        if len(args) >= 1:
            repository = args[0]
        else:
            repository = crt_series.get_parent_remote()

    if crt_series.get_protected():
        raise CmdException('This branch is protected. Pulls are not permitted')

    check_local_changes()
    check_conflicts()
    check_head_top_equal(crt_series)

    if policy not in ['pull', 'fetch-rebase', 'rebase']:
        raise GitConfigException('Unsupported pull-policy "%s"' % policy)

    applied = prepare_rebase(crt_series)

    # pull the remote changes
    if policy == 'pull':
        out.info('Pulling from "%s"' % repository)
        git.pull(repository)
    elif policy == 'fetch-rebase':
        out.info('Fetching from "%s"' % repository)
        git.fetch(repository)
        try:
            target = git.fetch_head()
        except git.GitException:
            out.error('Could not find the remote head to rebase onto - fix branch.%s.merge in .git/config' % crt_series.get_name())
            out.error('Pushing any patches back...')
            post_rebase(crt_series, applied, False, False)
            raise

        rebase(crt_series, target)
    elif policy == 'rebase':
        rebase(crt_series, crt_series.get_parent_branch())

    post_rebase(crt_series, applied, options.nopush, options.merged)

    # maybe tidy up
    if config.get('stgit.keepoptimized') == 'yes':
        git.repack()

    print_crt_patch(crt_series)
示例#14
0
文件: pick.py 项目: snits/stgit
def __pick_commit(commit_id, patchname, options):
    """Pick a commit id.
    """
    commit = git.Commit(commit_id)

    if options.name:
        patchname = options.name
    elif patchname and options.revert:
        patchname = 'revert-' + patchname
    if patchname:
        patchname = find_patch_name(patchname, crt_series.patch_exists)

    if options.parent:
        parent = git_id(crt_series, options.parent)
    else:
        parent = commit.get_parent()

    if not options.revert:
        bottom = parent
        top = commit_id
    else:
        bottom = commit_id
        top = parent

    if options.fold:
        out.start('Folding commit %s' % commit_id)

        # try a direct git apply first
        if not git.apply_diff(bottom, top, files = options.file):
            if options.file:
                raise CmdException('Patch folding failed')
            else:
                git.merge_recursive(bottom, git.get_head(), top)

        out.done()
    elif options.update:
        rev1 = git_id(crt_series, 'HEAD^')
        rev2 = git_id(crt_series, 'HEAD')
        files = git.barefiles(rev1, rev2).split('\n')

        out.start('Updating with commit %s' % commit_id)

        if not git.apply_diff(bottom, top, files = files):
            raise CmdException('Patch updating failed')

        out.done()
    else:
        message = commit.get_log()
        if options.revert:
            if message:
                lines = message.splitlines()
                subject = lines[0]
                body = '\n'.join(lines[2:])
            else:
                subject = commit.get_id_hash()
                body = ''
            message = 'Revert "%s"\n\nThis reverts commit %s.\n\n%s\n' \
                    % (subject, commit.get_id_hash(), body)
        elif options.expose:
            if not message.endswith('\n'):
                message += '\n'
            message += '(imported from commit %s)\n' % commit.get_id_hash()
        author_name, author_email, author_date = \
                     name_email_date(commit.get_author())
        if options.revert:
            author_name = author_email = None

        out.start('Importing commit %s' % commit_id)

        newpatch = crt_series.new_patch(patchname, message = message, can_edit = False,
                                        unapplied = True, bottom = bottom, top = top,
                                        author_name = author_name,
                                        author_email = author_email,
                                        author_date = author_date)
        # in case the patch name was automatically generated
        patchname = newpatch.get_name()

        # find a patchlog to fork from
        refbranchname, refpatchname = parse_rev(patchname)
        if refpatchname:
            if refbranchname:
                # assume the refseries is OK, since we already resolved
                # commit_str to a git_id
                refseries = Series(refbranchname)
            else:
                refseries = crt_series
            patch = refseries.get_patch(refpatchname)
            if patch.get_log():
                out.info("Log was %s" % newpatch.get_log())
                out.info("Setting log to %s\n" %  patch.get_log())
                newpatch.set_log(patch.get_log())
                out.info("Log is now %s" % newpatch.get_log())
            else:
                out.info("No log for %s\n" % patchname)

        if not options.unapplied:
            modified = crt_series.push_patch(patchname)
        else:
            modified = False

        if crt_series.empty_patch(patchname):
            out.done('empty patch')
        elif modified:
            out.done('modified')
        else:
            out.done()
示例#15
0
文件: publish.py 项目: gwd/stgit
def func(parser, options, args):
    """Publish the stack changes."""
    repository = directory.repository
    stack = repository.get_stack(options.branch)

    if not args:
        public_ref = get_public_ref(stack.name)
    elif len(args) == 1:
        public_ref = args[0]
    else:
        parser.error('incorrect number of arguments')

    if not public_ref.startswith('refs/heads/'):
        public_ref = 'refs/heads/' + public_ref

    # just clone the stack if the public ref does not exist
    if not repository.refs.exists(public_ref):
        if options.unpublished or options.last:
            raise CmdException('"%s" does not exist' % public_ref)
        repository.refs.set(public_ref, stack.head, 'publish')
        out.info('Created "%s"' % public_ref)
        return

    public_head = repository.refs.get(public_ref)
    public_tree = public_head.data.tree

    # find the last published patch
    if options.last:
        last = __get_last(stack, public_tree)
        if not last:
            raise CmdException('Unable to find the last published patch '
                               '(possibly rebased stack)')
        out.info('%s' % last)
        return

    # check for same tree (already up to date)
    if public_tree.sha1 == stack.head.data.tree.sha1:
        out.info('"%s" already up to date' % public_ref)
        return

    # check for unpublished patches
    if options.unpublished:
        published = set(__get_published(stack, public_tree))
        for p in stack.patchorder.applied:
            if p not in published:
                out.stdout(p)
        return

    if options.overwrite:
        repository.refs.set(public_ref, stack.head, 'publish')
        out.info('Overwrote "%s"' % public_ref)
        return

    # check for rebased stack. In this case we emulate a merge with the stack
    # base by setting two parents.
    merge_bases = set(repository.get_merge_bases(public_head, stack.base))
    if public_head in merge_bases:
        # fast-forward the public ref
        repository.refs.set(public_ref, stack.head, 'publish')
        out.info('Fast-forwarded "%s"' % public_ref)
        return
    if stack.base not in merge_bases:
        message = 'Merge %s into %s' % (
            repository.describe(stack.base).strip(),
            utils.strip_prefix('refs/heads/', public_ref),
        )
        public_head = __create_commit(
            repository,
            stack.head.data.tree,
            [public_head, stack.base],
            options,
            message,
        )
        repository.refs.set(public_ref, public_head, 'publish')
        out.info('Merged the stack base into "%s"' % public_ref)
        return

    # check for new patches from the last publishing. This is done by checking
    # whether the public tree is the same as the bottom of the checked patch.
    # If older patches were modified, new patches cannot be detected. The new
    # patches and their metadata are pushed directly to the published head.
    for p in stack.patchorder.applied:
        pc = stack.patches.get(p).commit
        if public_tree.sha1 == pc.data.parent.data.tree.sha1:
            if pc.data.is_nochange():
                out.info('Ignored new empty patch "%s"' % p)
                continue
            cd = pc.data.set_parent(public_head)
            public_head = repository.commit(cd)
            public_tree = public_head.data.tree
            out.info('Published new patch "%s"' % p)

    # create a new commit (only happens if no new patches are detected)
    if public_tree.sha1 != stack.head.data.tree.sha1:
        public_head = __create_commit(repository, stack.head.data.tree,
                                      [public_head], options)

    # update the public head
    repository.refs.set(public_ref, public_head, 'publish')
    out.info('Updated "%s"' % public_ref)
示例#16
0
 def set_format_version(v):
     out.info('Upgraded branch %s to format version %d' % (branch, v))
     config.set(key, '%d' % v)
示例#17
0
 def now_at(pn):
     out.info('Now at patch "%s"' % pn)
示例#18
0
def func(parser, options, args):
    repository = directory.repository

    if options.create:
        if len(args) == 0 or len(args) > 2:
            parser.error('incorrect number of arguments')

        branch_name = args[0]
        committish = None if len(args) < 2 else args[1]

        if committish:
            check_local_changes(repository)
        check_conflicts(repository.default_iw)
        try:
            stack = repository.get_stack()
        except (DetachedHeadException, StackException):
            pass
        else:
            check_head_top_equal(stack)

        stack = __create_branch(branch_name, committish)

        out.info('Branch "%s" created' % branch_name)
        return

    elif options.clone:

        cur_branch = Branch(repository, repository.current_branch_name)
        if len(args) == 0:
            clone_name = cur_branch.name + time.strftime('-%C%y%m%d-%H%M%S')
        elif len(args) == 1:
            clone_name = args[0]
        else:
            parser.error('incorrect number of arguments')

        check_local_changes(repository)
        check_conflicts(repository.default_iw)
        try:
            stack = repository.current_stack
        except StackException:
            stack = None
        else:
            check_head_top_equal(stack)

        out.start('Cloning current branch to "%s"' % clone_name)

        if stack:
            clone = stack.clone(clone_name,
                                'branch clone of %s' % cur_branch.name)
            trans = StackTransaction(clone, 'clone')
            try:
                for pn in stack.patchorder.applied:
                    trans.push_patch(pn)
            except TransactionHalted:
                pass
            trans.run()
        else:
            clone = Stack.create(
                repository,
                name=clone_name,
                msg='branch clone of %s' % cur_branch.name,
                create_at=repository.refs.get(repository.head_ref),
                parent_remote=cur_branch.parent_remote,
                parent_branch=cur_branch.name,
            )

        clone.set_description('clone of "%s"' % cur_branch.name)
        clone.switch_to()
        out.done()
        return

    elif options.delete:

        if len(args) != 1:
            parser.error('incorrect number of arguments')
        __delete_branch(args[0], options.force)
        return

    elif options.cleanup:

        if not args:
            name = repository.current_branch_name
        elif len(args) == 1:
            name = args[0]
        else:
            parser.error('incorrect number of arguments')
        __cleanup_branch(name, options.force)
        return

    elif options.list:

        if len(args) != 0:
            parser.error('incorrect number of arguments')

        branch_names = sorted(
            ref.replace('refs/heads/', '', 1) for ref in repository.refs
            if ref.startswith('refs/heads/') and not ref.endswith('.stgit'))

        if branch_names:
            out.info('Available branches:')
            max_len = max(len(name) for name in branch_names)
            for branch_name in branch_names:
                __print_branch(branch_name, max_len)
        else:
            out.info('No branches')
        return

    elif options.protect:

        if len(args) == 0:
            branch_name = repository.current_branch_name
        elif len(args) == 1:
            branch_name = args[0]
        else:
            parser.error('incorrect number of arguments')

        try:
            stack = repository.get_stack(branch_name)
        except StackException:
            raise CmdException('Branch "%s" is not controlled by StGIT' %
                               branch_name)

        out.start('Protecting branch "%s"' % branch_name)
        stack.protected = True
        out.done()

        return

    elif options.rename:

        if len(args) == 1:
            stack = repository.current_stack
            new_name = args[0]
        elif len(args) == 2:
            stack = repository.get_stack(args[0])
            new_name = args[1]
        else:
            parser.error('incorrect number of arguments')

        old_name = stack.name
        stack.rename(new_name)

        out.info('Renamed branch "%s" to "%s"' % (old_name, new_name))
        return

    elif options.unprotect:

        if len(args) == 0:
            branch_name = repository.current_branch_name
        elif len(args) == 1:
            branch_name = args[0]
        else:
            parser.error('incorrect number of arguments')

        try:
            stack = repository.get_stack(branch_name)
        except StackException:
            raise CmdException('Branch "%s" is not controlled by StGIT' %
                               branch_name)

        out.info('Unprotecting branch "%s"' % branch_name)
        stack.protected = False
        out.done()

        return

    elif options.description is not None:

        if len(args) == 0:
            branch_name = repository.current_branch_name
        elif len(args) == 1:
            branch_name = args[0]
        else:
            parser.error('incorrect number of arguments')

        Branch(repository, branch_name).set_description(options.description)
        return

    elif len(args) == 1:
        branch_name = args[0]
        if branch_name == repository.current_branch_name:
            raise CmdException('Branch "%s" is already the current branch' %
                               branch_name)

        if not options.merge:
            check_local_changes(repository)
        check_conflicts(repository.default_iw)
        try:
            stack = repository.get_stack()
        except StackException:
            pass
        else:
            check_head_top_equal(stack)

        out.start('Switching to branch "%s"' % branch_name)
        Branch(repository, branch_name).switch_to()
        out.done()
        return

    # default action: print the current branch
    if len(args) != 0:
        parser.error('incorrect number of arguments')

    out.stdout(directory.repository.current_branch_name)
示例#19
0
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()
示例#20
0
文件: repair.py 项目: snits/stgit
def func(parser, options, args):
    """Repair inconsistencies in StGit metadata."""

    orig_applied = crt_series.get_applied()
    orig_unapplied = crt_series.get_unapplied()
    orig_hidden = crt_series.get_hidden()

    if crt_series.get_protected():
        raise CmdException(
            'This branch is protected. Modification is not permitted.')

    # Find commits that aren't patches, and applied patches.
    head = git.get_commit(git.get_head()).get_id_hash()
    commits, patches = read_commit_dag(crt_series.get_name())
    c = commits[head]
    patchify = []       # commits to definitely patchify
    maybe_patchify = [] # commits to patchify if we find a patch below them
    applied = []
    while len(c.parents) == 1:
        parent, = c.parents
        if c.patch:
            applied.append(c)
            patchify.extend(maybe_patchify)
            maybe_patchify = []
        else:
            maybe_patchify.append(c)
        c = parent
    applied.reverse()
    patchify.reverse()

    # Find patches hidden behind a merge.
    merge = c
    todo = set([c])
    seen = set()
    hidden = set()
    while todo:
        c = todo.pop()
        seen.add(c)
        todo |= c.parents - seen
        if c.patch:
            hidden.add(c)
    if hidden:
        out.warn(('%d patch%s are hidden below the merge commit'
                  % (len(hidden), ['es', ''][len(hidden) == 1])),
                 '%s,' % merge.id, 'and will be considered unapplied.')

    # Make patches of any linear sequence of commits on top of a patch.
    names = set(p.patch for p in patches)
    def name_taken(name):
        return name in names
    if applied and patchify:
        out.start('Creating %d new patch%s'
                  % (len(patchify), ['es', ''][len(patchify) == 1]))
        for p in patchify:
            name = make_patch_name(p.commit.get_log(), name_taken)
            out.info('Creating patch %s from commit %s' % (name, p.id))
            aname, amail, adate = name_email_date(p.commit.get_author())
            cname, cmail, cdate = name_email_date(p.commit.get_committer())
            parent, = p.parents
            crt_series.new_patch(
                name, can_edit = False, commit = False,
                top = p.id, bottom = parent.id, message = p.commit.get_log(),
                author_name = aname, author_email = amail, author_date = adate,
                committer_name = cname, committer_email = cmail)
            p.patch = name
            applied.append(p)
            names.add(name)
        out.done()

    # Figure out hidden
    orig_patches = orig_applied + orig_unapplied + orig_hidden
    orig_applied_name_set = set(orig_applied)
    orig_unapplied_name_set = set(orig_unapplied)
    orig_hidden_name_set = set(orig_hidden)
    orig_patches_name_set = set(orig_patches)
    hidden = [p for p in patches if p.patch in orig_hidden_name_set]

    # Write the applied/unapplied files.
    out.start('Checking patch appliedness')
    unapplied = patches - set(applied) - set(hidden)
    applied_name_set = set(p.patch for p in applied)
    unapplied_name_set = set(p.patch for p in unapplied)
    hidden_name_set = set(p.patch for p in hidden)
    patches_name_set = set(p.patch for p in patches)
    for name in orig_patches_name_set - patches_name_set:
        out.info('%s is gone' % name)
    for name in applied_name_set - orig_applied_name_set:
        out.info('%s is now applied' % name)
    for name in unapplied_name_set - orig_unapplied_name_set:
        out.info('%s is now unapplied' % name)
    for name in hidden_name_set - orig_hidden_name_set:
        out.info('%s is now hidden' % name)
    orig_order = dict(zip(orig_patches, range(len(orig_patches))))

    def patchname_key(p):
        i = orig_order.get(p, len(orig_order))
        return i, p

    crt_series.set_applied(p.patch for p in applied)
    crt_series.set_unapplied(sorted(unapplied_name_set, key=patchname_key))
    crt_series.set_hidden(sorted(hidden_name_set, key=patchname_key))
    out.done()
示例#21
0
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()
示例#22
0
def func(parser, options, args):

    if options.create:

        if len(args) == 0 or len(args) > 2:
            parser.error('incorrect number of arguments')

        check_local_changes()
        check_conflicts()
        check_head_top_equal(crt_series)

        tree_id = None
        if len(args) >= 2:
            parentbranch = None
            try:
                branchpoint = git.rev_parse(args[1])

                # parent branch?
                head_re = re.compile('refs/(heads|remotes)/')
                ref_re = re.compile(args[1] + '$')
                for ref in git.all_refs():
                    if head_re.match(ref) and ref_re.search(ref):
                        # args[1] is a valid ref from the branchpoint
                        # setting above
                        parentbranch = args[1]
                        break
            except git.GitException:
                # should use a more specific exception to catch only
                # non-git refs ?
                out.info('Don\'t know how to determine parent branch'
                         ' from "%s"' % args[1])
                # exception in branch = rev_parse() leaves branchpoint unbound
                branchpoint = None

            tree_id = git_id(crt_series, branchpoint or args[1])

            if parentbranch:
                out.info('Recording "%s" as parent branch' % parentbranch)
            else:
                out.info('Don\'t know how to determine parent branch'
                         ' from "%s"' % args[1])
        else:
            # branch stack off current branch
            parentbranch = git.get_head_file()

        if parentbranch:
            parentremote = git.identify_remote(parentbranch)
            if parentremote:
                out.info('Using remote "%s" to pull parent from' %
                         parentremote)
            else:
                out.info('Recording as a local branch')
        else:
            # no known parent branch, can't guess the remote
            parentremote = None

        stack.Series(args[0]).init(
            create_at=tree_id,
            parent_remote=parentremote,
            parent_branch=parentbranch,
        )

        out.info('Branch "%s" created' % args[0])
        log.compat_log_entry('branch --create')
        return

    elif options.clone:

        if len(args) == 0:
            clone = crt_series.get_name() + time.strftime('-%C%y%m%d-%H%M%S')
        elif len(args) == 1:
            clone = args[0]
        else:
            parser.error('incorrect number of arguments')

        check_local_changes()
        check_conflicts()
        check_head_top_equal(crt_series)

        out.start('Cloning current branch to "%s"' % clone)
        crt_series.clone(clone)
        out.done()

        log.copy_log(log.default_repo(), crt_series.get_name(), clone,
                     'branch --clone')
        return

    elif options.delete:

        if len(args) != 1:
            parser.error('incorrect number of arguments')
        __delete_branch(args[0], options.force)
        log.delete_log(log.default_repo(), args[0])
        return

    elif options.cleanup:

        if not args:
            name = crt_series.get_name()
        elif len(args) == 1:
            name = args[0]
        else:
            parser.error('incorrect number of arguments')
        __cleanup_branch(name, options.force)
        log.delete_log(log.default_repo(), name)
        return

    elif options.list:

        if len(args) != 0:
            parser.error('incorrect number of arguments')

        branches = set(git.get_heads())
        for br in set(branches):
            m = re.match(r'^(.*)\.stgit$', br)
            if m and m.group(1) in branches:
                branches.remove(br)

        if branches:
            out.info('Available branches:')
            max_len = max([len(i) for i in branches])
            for i in sorted(branches):
                __print_branch(i, max_len)
        else:
            out.info('No branches')
        return

    elif options.protect:

        if len(args) == 0:
            branch_name = crt_series.get_name()
        elif len(args) == 1:
            branch_name = args[0]
        else:
            parser.error('incorrect number of arguments')
        branch = stack.Series(branch_name)

        if not branch.is_initialised():
            raise CmdException('Branch "%s" is not controlled by StGIT' %
                               branch_name)

        out.start('Protecting branch "%s"' % branch_name)
        branch.protect()
        out.done()

        return

    elif options.rename:

        if len(args) != 2:
            parser.error('incorrect number of arguments')

        if __is_current_branch(args[0]):
            raise CmdException('Renaming the current branch is not supported')

        stack.Series(args[0]).rename(args[1])

        out.info('Renamed branch "%s" to "%s"' % (args[0], args[1]))
        log.rename_log(log.default_repo(), args[0], args[1], 'branch --rename')
        return

    elif options.unprotect:

        if len(args) == 0:
            branch_name = crt_series.get_name()
        elif len(args) == 1:
            branch_name = args[0]
        else:
            parser.error('incorrect number of arguments')
        branch = stack.Series(branch_name)

        if not branch.is_initialised():
            raise CmdException('Branch "%s" is not controlled by StGIT' %
                               branch_name)

        out.info('Unprotecting branch "%s"' % branch_name)
        branch.unprotect()
        out.done()

        return

    elif options.description is not None:

        if len(args) == 0:
            branch_name = crt_series.get_name()
        elif len(args) == 1:
            branch_name = args[0]
        else:
            parser.error('incorrect number of arguments')
        branch = stack.Series(branch_name)

        if not branch.is_initialised():
            raise CmdException('Branch "%s" is not controlled by StGIT' %
                               branch_name)

        branch.set_description(options.description)

        return

    elif len(args) == 1:

        if __is_current_branch(args[0]):
            raise CmdException('Branch "%s" is already the current branch' %
                               args[0])

        if not options.merge:
            check_local_changes()
        check_conflicts()
        check_head_top_equal(crt_series)

        out.start('Switching to branch "%s"' % args[0])
        git.switch_branch(args[0])
        out.done()
        return

    # default action: print the current branch
    if len(args) != 0:
        parser.error('incorrect number of arguments')

    print(crt_series.get_name())
示例#23
0
 def set_format_version(v):
     out.info('Upgraded branch %s to format version %d' % (branch, v))
     config.set(key, '%d' % v)
示例#24
0
文件: imprt.py 项目: snits/stgit
def __create_patch(filename, message, author_name, author_email, author_date,
                   diff, options):
    """Create a new patch on the stack
    """
    if options.name:
        patch = options.name
    elif filename:
        patch = os.path.basename(filename)
    else:
        patch = ''
    if options.stripname:
        patch = __strip_patch_name(patch)

    if not patch:
        if options.ignore or options.replace:
            unacceptable_name = lambda name: False
        else:
            unacceptable_name = crt_series.patch_exists
        patch = make_patch_name(message, unacceptable_name)
    else:
        # fix possible invalid characters in the patch name
        patch = re.sub(r'[^\w.]+', '-', patch).strip('-')

    if options.ignore and patch in crt_series.get_applied():
        out.info('Ignoring already applied patch "%s"' % patch)
        return
    if options.replace and patch in crt_series.get_unapplied():
        crt_series.delete_patch(patch, keep_log=True)

    if options.author:
        options.authname, options.authemail = name_email(options.author)

    # override the automatically parsed settings
    if options.authname:
        author_name = options.authname
    if options.authemail:
        author_email = options.authemail
    if options.authdate:
        author_date = options.authdate

    sign_str = options.sign_str
    if not options.sign_str:
        sign_str = config.get('stgit.autosign')

    crt_series.new_patch(patch,
                         message=message,
                         can_edit=False,
                         author_name=author_name,
                         author_email=author_email,
                         author_date=author_date,
                         sign_str=sign_str)

    if not diff:
        out.warn('No diff found, creating empty patch')
    else:
        out.start('Importing patch "%s"' % patch)
        if options.base:
            base = git_id(crt_series, options.base)
        else:
            base = None
        try:
            git.apply_patch(diff=diff,
                            base=base,
                            reject=options.reject,
                            strip=options.strip)
        except git.GitException:
            if not options.reject:
                crt_series.delete_patch(patch)
            raise
        crt_series.refresh_patch(edit=options.edit,
                                 show_patch=options.showdiff,
                                 author_date=author_date,
                                 backup=False)
        out.done()
示例#25
0
def func(parser, options, args):
    """Commit a number of patches."""
    stack = directory.repository.current_stack
    args = parse_patches(args, list(stack.patchorder.all_visible))
    exclusive = [args, options.number is not None, options.all]
    if sum(map(bool, exclusive)) > 1:
        parser.error('too many options')
    if args:
        patches = [pn for pn in stack.patchorder.all_visible if pn in args]
        bad = set(args) - set(patches)
        if bad:
            raise CmdException('Nonexistent or hidden patch names: %s' %
                               (', '.join(sorted(bad)), ))
    elif options.number is not None:
        if options.number <= len(stack.patchorder.applied):
            patches = stack.patchorder.applied[:options.number]
        else:
            raise CmdException('There are not that many applied patches')
    elif options.all:
        patches = stack.patchorder.applied
    else:
        patches = stack.patchorder.applied[:1]
    if not patches:
        raise CmdException('No patches to commit')

    iw = stack.repository.default_iw

    def allow_conflicts(trans):
        # As long as the topmost patch stays where it is, it's OK to
        # run "stg commit" with conflicts in the index.
        return len(trans.applied) >= 1

    trans = transaction.StackTransaction(stack,
                                         'commit',
                                         allow_conflicts=allow_conflicts)
    try:
        common_prefix = 0
        for i in range(min(len(stack.patchorder.applied), len(patches))):
            if stack.patchorder.applied[i] == patches[i]:
                common_prefix += 1
            else:
                break
        if common_prefix < len(patches):
            to_push = [
                pn for pn in stack.patchorder.applied[common_prefix:]
                if pn not in patches[common_prefix:]
            ]
            # this pops all the applied patches from common_prefix
            trans.pop_patches(lambda pn: pn in to_push)
            for pn in patches[common_prefix:]:
                trans.push_patch(pn, iw)
        else:
            to_push = []
        new_base = trans.patches[patches[-1]]
        for pn in patches:
            trans.patches[pn] = None
        trans.applied = [pn for pn in trans.applied if pn not in patches]
        trans.base = new_base
        out.info('Committed %d patch%s' %
                 (len(patches), ['es', ''][len(patches) == 1]))
        for pn in to_push:
            trans.push_patch(pn, iw)
    except transaction.TransactionHalted:
        pass
    return trans.run(iw)
示例#26
0
文件: common.py 项目: gwd/stgit
def print_current_patch(stack):
    if stack.patchorder.applied:
        out.info('Now at patch "%s"' % stack.patchorder.applied[-1])
    else:
        out.info('No patches applied')
示例#27
0
文件: repair.py 项目: zaneb/stgit
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_str,
                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 = {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()