Example #1
0
def __print_patch(stack, patch, branch_str, prefix, length, options, effects):
    """Print a patch name, description and various markers.
    """
    if options.noprefix:
        prefix = ''
    elif options.empty:
        if stack.patches.get(patch).is_empty():
            prefix = '0' + prefix
        else:
            prefix = ' ' + prefix

    patch_str = branch_str + patch

    if options.description or options.author:
        patch_str = patch_str.ljust(length)

    if options.description:
        output = prefix + patch_str + ' # ' + __get_description(stack, patch)
    elif options.author:
        output = prefix + patch_str + ' # ' + __get_author(stack, patch)
    else:
        output = prefix + patch_str
    if not effects:
        out.stdout(output)
    else:
        out.stdout(__render_text(output, effects))
Example #2
0
def __print_patch(stack, patch, branch_str, prefix, length, options, effects):
    """Print a patch name, description and various markers.
    """
    if options.noprefix:
        prefix = ''
    elif options.empty:
        if stack.patches.get(patch).is_empty():
            prefix = '0' + prefix
        else:
            prefix = ' ' + prefix

    patch_str = branch_str + patch

    if options.description or options.author:
        patch_str = patch_str.ljust(length)

    if options.description:
        output = prefix + patch_str + ' # ' + __get_description(stack, patch)
    elif options.author:
        output = prefix + patch_str + ' # ' + __get_author(stack, patch)
    else:
        output = prefix + patch_str
    if not effects:
        out.stdout(output)
    else:
        out.stdout(__render_text(output, effects))
Example #3
0
def func(parser, options, args):
    """Show the patches modifying a file."""
    repository = directory.repository
    stack = repository.get_stack(options.branch)

    if not stack.patchorder.applied:
        raise CmdException('No patches applied')

    iw = repository.default_iw

    if not args:
        files = iw.changed_files(stack.head.data.tree)
    else:
        files = iw.ls_files(stack.head.data.tree, args)

    if not files:
        raise CmdException('No files specified or no local changes')

    directory.cd_to_topdir()

    # Find set of revisions that modify the selected files.
    revs = set(
        repository.run(
            ['git', 'rev-list', '--stdin', stack.base.sha1 + '..' + stack.top.sha1]
        )
        .raw_input('--\n' + '\n'.join(files))
        .output_lines()
    )

    diff_lines = []
    for pn in stack.patchorder.applied:
        commit = stack.patches[pn]
        if commit.sha1 not in revs:
            continue
        if options.diff:
            diff_lines.extend(
                [
                    b'-' * 79,
                    pn.encode('utf-8'),
                    b'-' * 79,
                    commit.data.message,
                    b'---',
                    b'',
                    repository.diff_tree(
                        commit.data.parent.data.tree,
                        commit.data.tree,
                        pathlimits=files,
                        diff_opts=options.diff_flags + color_diff_flags(),
                    ),
                ]
            )
        else:
            out.stdout(pn)

    if options.diff:
        pager(b'\n'.join(diff_lines))
def func(parser, options, args):
    """Show the applied patches"""
    if len(args) == 0:
        id_str = 'HEAD'
    elif len(args) == 1:
        id_str = args[0]
    else:
        parser.error('incorrect number of arguments')

    out.stdout(git_commit(id_str, directory.repository).sha1)
Example #5
0
def func(parser, options, args):
    """Show the applied patches
    """
    if len(args) == 0:
        id_str = 'HEAD'
    elif len(args) == 1:
        id_str = args[0]
    else:
        parser.error('incorrect number of arguments')

    out.stdout(common.git_commit(id_str, directory.repository).sha1)
def func(parser, options, args):
    """Show the name of the topmost patch"""
    if len(args) != 0:
        parser.error('incorrect number of arguments')

    stack = directory.repository.get_stack(options.branch)
    applied = stack.patchorder.applied

    if applied:
        out.stdout(applied[-1])
    else:
        raise CmdException('No patches applied')
Example #7
0
def func(parser, options, args):
    """Show the name of the previous patch"""
    if len(args) != 0:
        parser.error('incorrect number of arguments')

    stack = directory.repository.get_stack(options.branch)
    applied = stack.patchorder.applied

    if applied and len(applied) >= 2:
        out.stdout(applied[-2])
    else:
        raise CmdException('Not enough applied patches')
Example #8
0
def func(parser, options, args):
    """Show the name of the next patch
    """
    if len(args) != 0:
        parser.error('incorrect number of arguments')

    stack = directory.repository.get_stack(options.branch)
    unapplied = stack.patchorder.unapplied

    if unapplied:
        out.stdout(unapplied[0])
    else:
        raise common.CmdException('No unapplied patches')
Example #9
0
def func(parser, options, args):
    """Show the name of the topmost patch
    """
    if len(args) != 0:
        parser.error('incorrect number of arguments')

    stack = directory.repository.get_stack(options.branch)
    applied = stack.patchorder.applied

    if applied:
        out.stdout(applied[-1])
    else:
        raise common.CmdException, 'No patches applied'
Example #10
0
File: next.py Project: snits/stgit
def func(parser, options, args):
    """Show the name of the next patch
    """
    if len(args) != 0:
        parser.error('incorrect number of arguments')

    stack = directory.repository.get_stack(options.branch)
    unapplied = stack.patchorder.unapplied

    if unapplied:
        out.stdout(unapplied[0])
    else:
        raise common.CmdException('No unapplied patches')
Example #11
0
def func(parser, options, args):
    """Show the name of the previous patch
    """
    if len(args) != 0:
        parser.error('incorrect number of arguments')

    stack = directory.repository.get_stack(options.branch)
    applied = stack.patchorder.applied

    if applied and len(applied) >= 2:
        out.stdout(applied[-2])
    else:
        raise common.CmdException, 'Not enough applied patches'
Example #12
0
def __print_branch(branch_name, length):
    branch = Branch(directory.repository, branch_name)
    current = '>' if __is_current_branch(branch_name) else ' '
    try:
        stack = directory.repository.get_stack(branch_name)
    except StackException:
        initialised = protected = ' '
    else:
        initialised = 's'
        protected = 'p' if stack.protected else ' '

    out.stdout(current + ' ' + initialised + protected + '\t' +
               branch_name.ljust(length) + '  | ' +
               (branch.get_description() or ''))
Example #13
0
def __print_branch(branch_name, length):
    initialized = ' '
    current = ' '
    protected = ' '

    branch = stack.Series(branch_name)

    if branch.is_initialised():
        initialized = 's'
    if __is_current_branch(branch_name):
        current = '>'
    if branch.get_protected():
        protected = 'p'
    out.stdout(current + ' ' + initialized + protected + '\t'
               + branch_name.ljust(length) + '  | ' + branch.get_description())
Example #14
0
def __print_branch(branch_name, length):
    initialized = ' '
    current = ' '
    protected = ' '

    branch = stack.Series(branch_name)

    if branch.is_initialised():
        initialized = 's'
    if __is_current_branch(branch_name):
        current = '>'
    if branch.get_protected():
        protected = 'p'
    out.stdout(current + ' ' + initialized + protected + '\t' +
               branch_name.ljust(length) + '  | ' + branch.get_description())
Example #15
0
def func(parser, options, args):
    """Show the patches modifying a file
    """
    if not args:
        files = [path for (stat, path) in git.tree_status(verbose=True)]
        # git.tree_status returns absolute paths
    else:
        files = git.ls_files(args)
    directory.cd_to_topdir()

    if not files:
        raise CmdException('No files specified or no local changes')

    applied = crt_series.get_applied()
    if not applied:
        raise CmdException('No patches applied')

    revs = git.modifying_revs(files, crt_series.get_base(),
                              crt_series.get_head())
    revs.reverse()

    # build the patch/revision mapping
    rev_patch = dict()
    for name in applied:
        patch = crt_series.get_patch(name)
        rev_patch[patch.get_top()] = patch

    # print the patch names
    diff_lines = []
    for rev in revs:
        patch = rev_patch[rev]
        if options.diff:
            diff_lines.extend([
                b'-' * 79,
                patch.get_name().encode('utf-8'),
                b'-' * 79,
                patch.get_description().encode('utf-8'),
                b'---',
                b'',
                git.diff(files, patch.get_bottom(), patch.get_top()),
            ])
        else:
            out.stdout(patch.get_name())

    if options.diff:
        pager(b'\n'.join(diff_lines))
Example #16
0
def func(parser, options, args):
    """Show the patches modifying a file
    """
    if not args:
        files = [path for (stat,path) in git.tree_status(verbose = True)]
        # git.tree_status returns absolute paths
    else:
        files = git.ls_files(args)
    directory.cd_to_topdir()

    if not files:
        raise CmdException('No files specified or no local changes')

    applied = crt_series.get_applied()
    if not applied:
        raise CmdException('No patches applied')

    revs = git.modifying_revs(files, crt_series.get_base(),
                              crt_series.get_head())
    revs.reverse()

    # build the patch/revision mapping
    rev_patch = dict()
    for name in applied:
        patch = crt_series.get_patch(name)
        rev_patch[patch.get_top()] = patch

    # print the patch names
    diff_output = ''
    for rev in revs:
        if rev in rev_patch:
            patch = rev_patch[rev]
            if options.diff:
                diff_output += diff_tmpl \
                               % (patch.get_name(), patch.get_description(),
                                  git.diff(files, patch.get_bottom(),
                                           patch.get_top()))
            else:
                out.stdout(patch.get_name())

    if options.diff:
        pager(diff_output)
Example #17
0
def func(parser, options, args):
    """Show the files modified by a patch (or the current patch)
    """
    if options.bare and options.stat:
        raise CmdException('Cannot specify both --bare and --stat')
    repository = directory.repository
    if len(args) == 0:
        stack = repository.current_stack
        commit = stack.top
    elif len(args) == 1:
        branch, name = parse_rev(args[0])
        stack = repository.get_stack(branch)
        if not stack.patches.exists(name):
            raise CmdException('%s: Unknown patch name' % name)
        commit = stack.patches.get(name).commit
    else:
        parser.error('incorrect number of arguments')

    if options.stat:
        cmd = ['git', 'diff-tree', '--stat', '--summary', '--no-commit-id']
        cmd.extend(options.diff_flags)
        cmd.extend(color_diff_flags())
        cmd.append(commit.sha1)
        out.stdout_bytes(repository.run(cmd).decoding(None).raw_output())
    else:
        used = set()
        for dt in repository.diff_tree_files(
            commit.data.parent.data.tree, commit.data.tree
        ):
            _, _, _, _, status, oldname, newname = dt
            for filename in [oldname, newname]:
                if filename in used:
                    continue
                else:
                    used.add(filename)

                if options.bare:
                    out.stdout(filename)
                else:
                    out.stdout('%s %s' % (status, filename))
Example #18
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.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.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.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.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.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.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')

    out.stdout(crt_series.name)
Example #19
0
def func(parser, options, args):
    """Show the patch series
    """
    if options.all and options.short:
        raise common.CmdException('combining --all and --short is meaningless')

    stack = directory.repository.get_stack(options.branch)
    if options.missing:
        cmp_stack = stack
        stack = directory.repository.get_stack(options.missing)

    # current series patches
    applied = unapplied = hidden = ()
    if options.applied or options.unapplied or options.hidden:
        if options.all:
            raise common.CmdException('--all cannot be used with'
                                      ' --applied/unapplied/hidden')
        if options.applied:
            applied = stack.patchorder.applied
        if options.unapplied:
            unapplied = stack.patchorder.unapplied
        if options.hidden:
            hidden = stack.patchorder.hidden
    elif options.all:
        applied = stack.patchorder.applied
        unapplied = stack.patchorder.unapplied
        hidden = stack.patchorder.hidden
    else:
        applied = stack.patchorder.applied
        unapplied = stack.patchorder.unapplied

    if options.missing:
        cmp_patches = cmp_stack.patchorder.all
    else:
        cmp_patches = ()

    # the filtering range covers the whole series
    if args:
        show_patches = parse_patches(args, applied + unapplied + hidden,
                                     len(applied))
    else:
        show_patches = applied + unapplied + hidden

    # missing filtering
    show_patches = [p for p in show_patches if p not in cmp_patches]

    # filter the patches
    applied = [p for p in applied if p in show_patches]
    unapplied = [p for p in unapplied if p in show_patches]
    hidden = [p for p in hidden if p in show_patches]

    if options.short:
        nr = int(config.get('stgit.shortnr'))
        if len(applied) > nr:
            applied = applied[-(nr + 1):]
        n = len(unapplied)
        if n > nr:
            unapplied = unapplied[:nr]
        elif n < nr:
            hidden = hidden[:nr - n]

    patches = applied + unapplied + hidden

    if options.count:
        out.stdout(len(patches))
        return

    if not patches:
        return

    if options.showbranch:
        branch_str = stack.name + ':'
    else:
        branch_str = ''

    max_len = 0
    if len(patches) > 0:
        max_len = max([len(i + branch_str) for i in patches])

    if applied:
        for p in applied[:-1]:
            __print_patch(
                stack,
                p,
                branch_str,
                '+ ',
                max_len,
                options,
                config.get("stgit.color.applied"),
            )
        __print_patch(
            stack,
            applied[-1],
            branch_str,
            '> ',
            max_len,
            options,
            config.get("stgit.color.current"),
        )

    for p in unapplied:
        __print_patch(
            stack,
            p,
            branch_str,
            '- ',
            max_len,
            options,
            config.get("stgit.color.unapplied"),
        )

    for p in hidden:
        __print_patch(
            stack,
            p,
            branch_str,
            '! ',
            max_len,
            options,
            config.get("stgit.color.hidden"),
        )
Example #20
0
def func(parser, options, args):
    """Show the patch series
    """
    if options.all and options.short:
        raise common.CmdException, 'combining --all and --short is meaningless'

    stack = directory.repository.get_stack(options.branch)
    if options.missing:
        cmp_stack = stack
        stack = directory.repository.get_stack(options.missing)

    # current series patches
    applied = unapplied = hidden = ()
    if options.applied or options.unapplied or options.hidden:
        if options.all:
            raise common.CmdException, \
                '--all cannot be used with --applied/unapplied/hidden'
        if options.applied:
            applied = stack.patchorder.applied
        if options.unapplied:
            unapplied = stack.patchorder.unapplied
        if options.hidden:
            hidden = stack.patchorder.hidden
    elif options.all:
        applied = stack.patchorder.applied
        unapplied = stack.patchorder.unapplied
        hidden = stack.patchorder.hidden
    else:
        applied = stack.patchorder.applied
        unapplied = stack.patchorder.unapplied

    if options.missing:
        cmp_patches = cmp_stack.patchorder.all
    else:
        cmp_patches = ()

    # the filtering range covers the whole series
    if args:
        show_patches = parse_patches(args, applied + unapplied + hidden,
                                     len(applied))
    else:
        show_patches = applied + unapplied + hidden

    # missing filtering
    show_patches = [p for p in show_patches if p not in cmp_patches]

    # filter the patches
    applied = [p for p in applied if p in show_patches]
    unapplied = [p for p in unapplied if p in show_patches]
    hidden = [p for p in hidden if p in show_patches]

    if options.short:
        nr = int(config.get('stgit.shortnr'))
        if len(applied) > nr:
            applied = applied[-(nr+1):]
        n = len(unapplied)
        if n > nr:
            unapplied = unapplied[:nr]
        elif n < nr:
            hidden = hidden[:nr-n]

    patches = applied + unapplied + hidden

    if options.count:
        out.stdout(len(patches))
        return

    if not patches:
        return

    if options.showbranch:
        branch_str = stack.name + ':'
    else:
        branch_str = ''

    max_len = 0
    if len(patches) > 0:
        max_len = max([len(i + branch_str) for i in patches])

    if applied:
        for p in applied[:-1]:
            __print_patch(stack, p, branch_str, '+ ', max_len, options, config.get("stgit.color.applied"))
        __print_patch(stack, applied[-1], branch_str, '> ', max_len, options, config.get("stgit.color.current"))

    for p in unapplied:
        __print_patch(stack, p, branch_str, '- ', max_len, options, config.get("stgit.color.unapplied"))

    for p in hidden:
        __print_patch(stack, p, branch_str, '! ', max_len, options, config.get("stgit.color.hidden"))
Example #21
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)
        log.log_entry(stack, 'branch --create %s' % stack.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
            base = repository.refs.get(repository.head_ref)
        else:
            check_head_top_equal(stack)
            base = stack.base

        out.start('Cloning current branch to "%s"' % clone_name)
        clone = Stack.create(
            repository,
            name=clone_name,
            create_at=base,
            parent_remote=cur_branch.parent_remote,
            parent_branch=cur_branch.name,
        )
        if stack:
            for pn in stack.patchorder.all_visible:
                patch = stack.patches.get(pn)
                clone.patches.new(pn, patch.commit, 'clone %s' % stack.name)
            clone.patchorder.set_order(applied=[],
                                       unapplied=stack.patchorder.all_visible,
                                       hidden=[])
            trans = StackTransaction(clone, 'clone')
            try:
                for pn in stack.patchorder.applied:
                    trans.push_patch(pn)
            except TransactionHalted:
                pass
            trans.run()
        prefix = 'branch.%s.' % cur_branch.name
        new_prefix = 'branch.%s.' % clone.name
        for n, v in list(config.getstartswith(prefix)):
            config.set(n.replace(prefix, new_prefix, 1), v)
        clone.set_description('clone of "%s"' % cur_branch.name)
        clone.switch_to()
        out.done()

        log.copy_log(log.default_repo(), cur_branch.name, clone.name,
                     '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 = repository.current_branch_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')

        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))
        log.rename_log(repository, old_name, new_name, 'branch --rename')
        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)
Example #22
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:
                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)