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 sort series.conf lines according to the upstream order of commits that
the patches backport.

The script can either read series.conf lines (or a subset thereof) from stdin or
from the file named in the first argument.

A convenient way to use series_sort.py to filter a subset of lines
within series.conf when using the vim text editor is to visually
select the lines and filter them through the script:
    shift-v
    j j j j [...] # or ctrl-d or /pattern<enter>
    :'<,'>! ~/<path>/series_sort.py
"""

import argparse
import os
import sys

import pygit2_wrapper as pygit2

import exc
import git_sort
import lib
import series_conf


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Sort series.conf lines according to the upstream order of "
        "commits that the patches backport.")
    parser.add_argument("-p", "--prefix", metavar="DIR",
                        help="Search for patches in this directory. Default: "
                        "current directory.")
    parser.add_argument("-c", "--check", action="store_true",
                        help="Report via exit status 2 if the series is not "
                        "sorted. Default: false.")
    parser.add_argument("-u", "--upstream", action="store_true",
                        help="Move patches upstream between subsystem sections "
                        "as appropriate. Default: false.")
    parser.add_argument("series", nargs="?", metavar="series.conf",
                        help="series.conf file which will be modified in "
                        "place. Default: if stdin is a terminal, "
                        "\"series.conf\"; otherwise, read input from stdin.")
    args = parser.parse_args()

    repo_path = lib.repo_path()
    repo = pygit2.Repository(repo_path)
    index = git_sort.SortIndex(repo)
    if git_sort.remotes[0] not in index.repo_heads:
        print("WARNING: Did not find a remote fetching from \"%s\" in LINUX_GIT remotes." %
              (git_sort.remotes[0].repo_url.url,))

    filter_mode = False
    if args.series is None:
        if sys.stdin.isatty():
            path = "series.conf"
        else:
            filter_mode = True
    else:
        path = args.series
    if filter_mode:
        f = sys.stdin
    else:
        try:
            f = open(path)
        except FileNotFoundError as err:
            print("Error: %s" % (err,), file=sys.stderr)
            sys.exit(1)
        series_path = os.path.abspath(path)
    lines = f.readlines()

    if args.prefix is not None:
        os.chdir(args.prefix)

    try:
        before, inside, after = series_conf.split(lines)
    except exc.KSNotFound as err:
        if filter_mode:
            before = []
            inside = lines
            after = []
        elif args.check:
            # no sorted section
            sys.exit(0)
        else:
            print("Error: %s" % (err,), file=sys.stderr)
            sys.exit(1)

    try:
        input_entries = lib.parse_inside(index, inside, args.upstream)
    except exc.KSError as err:
        print("Error: %s" % (err,), file=sys.stderr)
        sys.exit(1)

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

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

    to_update = list(filter(lib.tag_needs_update, input_entries))
    if args.check:
        result = 0
        if inside != new_inside:
            print("Input is not sorted.")
            result = 2
        if len(to_update):
            print("Git-repo tags are outdated.")
            result = 2
        sys.exit(result)
    else:
        output = lib.flatten([
            before,
            new_inside,
            after,
        ])

        if filter_mode:
            f = sys.stdout
        else:
            f = open(series_path, mode="w")
        f.writelines(output)
        try:
            lib.update_tags(index, to_update)
        except exc.KSError as err:
            print("Error: %s" % (err,), file=sys.stderr)
            sys.exit(1)