Example #1
0
def auto_edit_patch(repo, cd, msg, contains_diff, author, committer, sign_str):
    """Edit the patch noninteractively in a couple of ways:

         - If C{msg} is not C{None}, parse it to find a replacement
           message, and possibly also replacement author and
           timestamp. If C{contains_diff} is true, also look for a
           replacement diff.

         - C{author} and C{committer} are two functions that take the
           original L{Person<stgit.lib.git.Person>} value as argument,
           and return the new one.

         - C{sign_str}, if not C{None}, is a sign string to append to
           the message.

    Return a pair: the new L{CommitData<stgit.lib.git.CommitData>};
    and the diff text if it didn't apply, or C{None} otherwise."""
    if msg is None:
        failed_diff = None
    else:
        cd, failed_diff = update_patch_description(repo, cd, msg,
                                                   contains_diff)
    a, c = author(cd.author), committer(cd.committer)
    if (a, c) != (cd.author, cd.committer):
        cd = cd.set_author(a).set_committer(c)
    if sign_str is not None:
        cd = cd.set_message(
            utils.add_sign_line(
                cd.message,
                sign_str,
                Person.committer().name,
                Person.committer().email,
            ))
    return cd, failed_diff
Example #2
0
def auto_edit_patch(repo, cd, msg, author, sign_str):
    """Edit the patch noninteractively in a couple of ways:

         - If C{msg} is not C{None}, parse it to find a replacement
           message, and possibly also replacement author and timestamp.

         - C{author} is a function that takes the original
           L{Person<stgit.lib.git.Person>} value as argument, and
           return the new one.

         - C{sign_str}, if not C{None}, is a sign string to append to
           the message.

    Return a pair: the new L{CommitData<stgit.lib.git.CommitData>};
    and the diff text if it didn't apply, or C{None} otherwise."""
    if msg is not None:
        cd, failed_diff = update_patch_description(repo,
                                                   cd,
                                                   msg,
                                                   contains_diff=False)
        assert not failed_diff
    a = author(cd.author)
    if a != cd.author:
        cd = cd.set_author(a)
    if sign_str is not None:
        cd = cd.set_message(
            utils.add_trailer(
                cd.message_str,
                sign_str,
                Person.committer().name,
                Person.committer().email,
            ))
    return cd
Example #3
0
def auto_edit_patch(repo, cd, msg, author, sign_str):
    """Edit the patch noninteractively in a couple of ways:

    * If ``msg`` is not None, parse it to find a replacement message, and possibly also
      replacement author and timestamp.

    * ``author`` is a function that takes the original :class:`stgit.lib.git.Person`
      value as argument, and returns the new one.

    * ``sign_str, if not None, is a trailer string to append to the message.

    :returns: tuple with the new :class:`stgit.lib.git.CommitData` and the diff text if
              it did not apply, or None otherwise.

    """
    if msg is not None:
        cd, failed_diff = update_patch_description(repo,
                                                   cd,
                                                   msg,
                                                   contains_diff=False)
        assert not failed_diff
    a = author(cd.author)
    if a != cd.author:
        cd = cd.set_author(a)
    if sign_str is not None:
        cd = cd.set_message(
            utils.add_trailer(
                cd.message_str,
                sign_str,
                Person.committer().name,
                Person.committer().email,
            ))
    return cd
Example #4
0
def auto_edit_patch(repo, cd, msg, author, trailers):
    """Edit the patch noninteractively in a couple of ways:

    * If ``msg`` is not None, parse it to find a replacement message, and possibly also
      replacement author and timestamp.

    * ``author`` is a function that takes the original :class:`stgit.lib.git.Person`
      value as argument, and returns the new one.

    * ``trailers`` is a list of trailer strings to append to the message.

    :returns: 3-tuple:
        - the new :class:`commitdata<stgit.lib.git.commitdata>`
        - the patch name if given or none otherwise
        - the diff text if it did not apply or none otherwise

    """
    if msg is not None:
        cd, _, failed_diff = _update_patch_description(repo,
                                                       cd,
                                                       msg,
                                                       contains_diff=False)
        assert not failed_diff
    a = author(cd.author)
    if a != cd.author:
        cd = cd.set_author(a)
    if trailers:
        cd = cd.set_message(
            utils.add_trailers(
                cd.message_str,
                trailers,
                Person.committer().name,
                Person.committer().email,
            ))
    return cd
Example #5
0
def func(parser, options, args):
    """Create a new patch."""
    stack = directory.repository.current_stack
    if stack.repository.default_index.conflicts():
        raise CmdException(
            'Cannot create a new patch -- resolve conflicts first')

    # Choose a name for the new patch -- or None, which means make one
    # up later when we've gotten hold of the commit message.
    if len(args) == 0:
        name = None
    elif len(args) == 1:
        name = args[0]
        if not stack.patches.is_name_valid(name):
            raise CmdException('Invalid patch name: "%s"' % name)
        elif name in stack.patches:
            raise CmdException('%s: patch already exists' % name)
    else:
        parser.error('incorrect number of arguments')

    if options.verbose:
        verbose = options.verbose
    else:
        verbose = config.getbool('stgit.new.verbose') or False

    cd = CommitData(
        tree=stack.head.data.tree,
        parents=[stack.head],
        message='',
        author=Person.author(),
        committer=Person.committer(),
    )
    cd = update_commit_data(
        stack.repository,
        cd,
        message=options.message,
        author=options.author(cd.author),
        trailers=options.trailers,
        edit=(not options.save_template and options.message is None),
        verbose=verbose,
    )

    if options.save_template:
        options.save_template(cd.message)
        return utils.STGIT_SUCCESS

    if not options.no_verify:
        cd = run_commit_msg_hook(stack.repository, cd)

    if name is None:
        name = stack.patches.make_name(cd.message_str)

    # Write the new patch.
    check_head_top_equal(stack)
    trans = StackTransaction(stack)
    trans.patches[name] = stack.repository.commit(cd)
    trans.applied.append(name)
    return trans.execute('new: %s' % name)
Example #6
0
def __create_commit(repository, tree, parents, options, message=''):
    """Return a new Commit object."""
    cd = CommitData(
        tree=tree,
        parents=parents,
        message=message,
        author=Person.author(),
        committer=Person.committer(),
    )
    cd = common.update_commit_data(cd, options)
    return repository.commit(cd)
Example #7
0
File: new.py Project: gwd/stgit
def func(parser, options, args):
    """Create a new patch."""
    stack = directory.repository.current_stack
    if stack.repository.default_index.conflicts():
        raise CmdException(
            'Cannot create a new patch -- resolve conflicts first')

    # Choose a name for the new patch -- or None, which means make one
    # up later when we've gotten hold of the commit message.
    if len(args) == 0:
        name = None
    elif len(args) == 1:
        name = args[0]
        if stack.patches.exists(name):
            raise CmdException('%s: patch already exists' % name)
        elif not stack.patches.is_name_valid(name):
            raise CmdException('Invalid patch name: "%s"' % name)
    else:
        parser.error('incorrect number of arguments')

    cd = CommitData(
        tree=stack.head.data.tree,
        parents=[stack.head],
        message='',
        author=Person.author(),
        committer=Person.committer(),
    )
    cd = update_commit_data(cd, options)

    if options.save_template:
        options.save_template(cd.message.encode('utf-8'))
        return utils.STGIT_SUCCESS

    if not options.no_verify:
        cd = run_commit_msg_hook(stack.repository, cd)

    if name is None:
        name = utils.make_patch_name(cd.message, stack.patches.exists)
        assert stack.patches.is_name_valid(name)

    # Write the new patch.
    stack.repository.default_iw
    trans = StackTransaction(stack, 'new: %s' % name)
    trans.patches[name] = stack.repository.commit(cd)
    trans.applied.append(name)
    return trans.run()
Example #8
0
def __create_commit(repository, tree, parents, options, message=''):
    """Return a new Commit object."""
    cd = CommitData(
        tree=tree,
        parents=parents,
        message=message,
        author=Person.author(),
        committer=Person.committer(),
    )
    cd = update_commit_data(
        cd,
        message=options.message,
        author=options.author(cd.author),
        sign_str=options.sign_str,
        edit=options.message is None,
    )
    return repository.commit(cd)
Example #9
0
def __get_sender():
    """Return the 'authname <authemail>' string as read from the
    configuration file
    """
    sender = config.get('stgit.sender')
    if not sender:
        user = Person.user()
        if user.email:
            sender = user.name_email
        else:
            author = Person.author()
            if author.email:
                sender = author.name_email
            else:
                raise CmdException(
                    'Unknown sender name and e-mail; you should for '
                    'example set git config user.name and user.email')

    sender = email.utils.parseaddr(sender)

    return email.utils.formataddr(address_or_alias(sender))
Example #10
0
def __pick_commit(stack, ref_stack, iw, commit, patchname, options):
    """Pick a commit."""
    repository = stack.repository

    if options.name:
        patchname = options.name
    elif patchname and options.revert:
        patchname = 'revert-' + patchname

    if patchname:
        patchname = find_patch_name(patchname, stack.patches.exists)
    else:
        patchname = make_patch_name(commit.data.message_str,
                                    stack.patches.exists)

    if options.parent:
        parent = git_commit(options.parent, repository, ref_stack.name)
    else:
        parent = commit.data.parent

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

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

        diff = repository.diff_tree(bottom.data.tree,
                                    top.data.tree,
                                    pathlimits=options.file)

        if diff:
            try:
                # try a direct git apply first
                iw.apply(diff, quiet=True)
            except MergeException:
                if options.file:
                    out.done('conflict(s)')
                    out.error('%s does not apply cleanly' % patchname)
                    return STGIT_CONFLICT
                else:
                    try:
                        iw.merge(
                            bottom.data.tree,
                            stack.head.data.tree,
                            top.data.tree,
                        )
                    except MergeConflictException as e:
                        out.done('%s conflicts' % len(e.conflicts))
                        out.error('%s does not apply cleanly' % patchname,
                                  *e.conflicts)
                        return STGIT_CONFLICT
            out.done()
        else:
            out.done('no changes')
        return STGIT_SUCCESS
    elif options.update:
        files = [
            fn1 for _, _, _, _, _, fn1, fn2 in repository.diff_tree_files(
                stack.top.data.parent.data.tree, stack.top.data.tree)
        ]

        diff = repository.diff_tree(bottom.data.tree,
                                    top.data.tree,
                                    pathlimits=files)

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

        try:
            iw.apply(diff, quiet=True)
        except MergeException:
            out.done('conflict(s)')
            out.error('%s does not apply cleanly' % patchname)
            return STGIT_CONFLICT
        else:
            out.done()
            return STGIT_SUCCESS
    else:
        author = commit.data.author
        message = commit.data.message_str

        if options.revert:
            author = Person.author()
            if message:
                lines = message.splitlines()
                subject = lines[0]
                body = '\n'.join(lines[2:])
            else:
                subject = commit.sha1
                body = ''
            message = 'Revert "%s"\n\nThis reverts commit %s.\n\n%s\n' % (
                subject,
                commit.sha1,
                body,
            )
        elif options.expose:
            fmt = config.get('stgit.pick.expose-format')
            message = Run('git', 'show', '--no-patch', '--pretty=' + fmt,
                          commit.sha1).raw_output()
            message = message.rstrip() + '\n'

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

        new_commit = repository.commit(
            CommitData(
                tree=top.data.tree,
                parents=[bottom],
                message=message,
                author=author,
            ))

        trans = StackTransaction(
            stack, 'pick %s from %s' % (patchname, ref_stack.name))
        trans.patches[patchname] = new_commit

        trans.unapplied.append(patchname)
        if not options.unapplied:
            try:
                trans.push_patch(patchname, iw, allow_interactive=True)
            except TransactionHalted:
                pass

        retval = trans.run(iw, print_current_patch=False)

        if retval == STGIT_CONFLICT:
            out.done('conflict(s)')
        elif stack.patches.get(patchname).is_empty():
            out.done('empty patch')
        else:
            out.done()

        return retval
Example #11
0
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:

            def unacceptable_name(name):
                return 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)

    # override the automatically parsed settings
    author = options.author(Person())
    if author.name:
        author_name = author.name
    if author.email:
        author_email = author.email
    if author.date:
        author_date = text(author.date)

    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()
Example #12
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()
Example #13
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()