Blob Blame History Raw
#!/usr/bin/python3
# -*- coding: utf-8 -*-

# Copyright (C) 2018 SUSE LLC
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
# USA.

"""
Script to insert new patches in series.conf according to the upstream order of
commits that the patches backport.
"""

import argparse
import collections
import sys

import pygit2_wrapper as pygit2

import exc
import git_sort
import lib
import series_conf


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Insert new patches in series.conf according to the "
        "upstream order of commits that the patches backport.")
    parser.add_argument("patches", nargs="+", metavar="PATCH",
                        help="Patch file to insert in series.conf")
    args = parser.parse_args()

    repo_path = lib.repo_path()
    repo = pygit2.Repository(repo_path)
    index = lib.git_sort.SortIndex(repo)

    try:
        with open("series.conf") as f:
            lines = f.readlines()
    except IOError as err:
        print("Error: could not open series file, %s" % (err,), file=sys.stderr)
        sys.exit(1)

    try:
        before, inside, after = series_conf.split(lines)
        current_entries = lib.parse_inside(index, inside, False)
    except exc.KSError as err:
        print("Error: %s" % (err,), file=sys.stderr)
        sys.exit(1)

    if list(filter(lib.tag_needs_update, current_entries)):
        print("Error: Some Git-repo tags for patches currently in series.conf "
              "are outdated. Please run series_sort.py first and commit the "
              "result before adding new patches.", file=sys.stderr)
        sys.exit(1)

    current_names = set([entry.name for entry in current_entries])
    current_revs = {rev : entry.name
                    for entry in current_entries
                        if entry.dest_head != git_sort.oot
                            for rev in entry.revs}
    new_lines = set()
    new_entries = []
    for name in args.patches:
        if name in current_names:
            print("Error: patch \"%s\" is already in series.conf." % (name,),
                  file=sys.stderr)
            sys.exit(1)
        entry = lib.InputEntry("\t%s\n" % (name,))
        new_lines.add(entry.value)
        try:
            entry.from_patch(index, name, git_sort.oot, True)
        except exc.KSError as err:
            print("Error: %s" % (err,), file=sys.stderr)
            sys.exit(1)
        if entry.dest_head != git_sort.oot:
            for rev in entry.revs:
                try:
                    match = current_revs[rev]
                except KeyError:
                    continue
                else:
                    print("Warning: commit %s in new patch \"%s\" is already "
                          "present in patch \"%s\" from series.conf." % (
                              rev[12:], entry.name, match,), file=sys.stderr)
        new_entries.append(entry)

    try:
        sorted_entries = lib.series_sort(index, current_entries + new_entries)
    except exc.KSError as err:
        print("Error: %s" % (err,), file=sys.stderr)
        sys.exit(1)

    cur_sorted_entries = collections.OrderedDict()
    for head, lines in list(sorted_entries.items()):
        current_lines = [line for line in lines if line not in new_lines]
        if current_lines:
            cur_sorted_entries[head] = current_lines

    cur_inside = lib.flatten([
        lib.series_header(inside),
        lib.series_format(cur_sorted_entries),
        lib.series_footer(inside),
    ])

    if inside != cur_inside:
        print("Error: Current series.conf is not sorted. "
              "Please run series_sort.py first and commit the result before "
              "adding new patches.", file=sys.stderr)
        sys.exit(1)

    new_inside = lib.flatten([
        lib.series_header(inside),
        lib.series_format(sorted_entries),
        lib.series_footer(inside),
    ])

    output = lib.flatten([
        before,
        new_inside,
        after,
    ])

    with open("series.conf", mode="w") as f:
        f.writelines(output)

    try:
        lib.update_tags(index, list(filter(lib.tag_needs_update, new_entries)))
    except exc.KSError as err:
        print("Error: %s" % (err,), file=sys.stderr)
        sys.exit(1)