#!/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.
# This script is used by the commit hook to detect if there are changes in the
# sorted section. Developers may commit to kernel-source without having changed
# the sorted section and used the git-sort tools, therefore without having the
# pygit2 module available. Therefore, this script should avoid a dependency on
# pygit2 since it's not present on a default python install and we don't want to
# force developers to install pygit2 just to commit unrelated changes to
# kernel-source.
import argparse
import contextlib
import errno
import sys
import exc
from patch import Patch
start_text = "sorted patches"
end_text = "end of sorted patches"
def split(series):
before = []
inside = []
after = []
whitespace = []
comments = []
current = before
for line in series:
l = line.strip()
if l == "":
if comments:
current.extend(comments)
comments = []
whitespace.append(line)
continue
elif l.startswith("#"):
if whitespace:
current.extend(whitespace)
whitespace = []
comments.append(line)
if current == before and l.lower() == "# %s" % (start_text,):
current = inside
elif current == inside and l.lower() == "# %s" % (end_text,):
current = after
else:
if comments:
current.extend(comments)
comments = []
if whitespace:
current.extend(whitespace)
whitespace = []
current.append(line)
if comments:
current.extend(comments)
comments = []
if whitespace:
current.extend(whitespace)
whitespace = []
if current is before:
raise exc.KSNotFound("Sorted subseries not found.")
current.extend(comments)
current.extend(whitespace)
return (before, inside, after,)
def filter_patches(line):
line = line.strip()
if line == "" or line.startswith(("#", "-", "+",)):
return False
else:
return True
def firstword(value):
return value.split(None, 1)[0]
filter_series = lambda lines : [firstword(line) for line in lines
if filter_patches(line)]
@contextlib.contextmanager
def find_commit(commit, series, mode="rb"):
"""
commit: unabbreviated git commit id
series: list of lines from series.conf
mode: mode to open the patch files in, should be "rb" or "r+b"
Caller must chdir to where the entries in series can be found.
Returns patch.Patch instances
"""
for name in filter_series(series):
patch = Patch(open(name, mode=mode))
found = False
if commit in [firstword(value)
for value in patch.get("Git-commit")
if value]:
found = True
yield name, patch
patch.writeback()
if found:
return
raise exc.KSNotFound()
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Extract the sorted patches section of a series.conf file.")
parser.add_argument("-n", "--name-only", action="store_true",
help="Print only patch names.")
parser.add_argument("series", nargs="?", metavar="series.conf",
help="series.conf file. Default: read input from stdin.")
args = parser.parse_args()
if args.series is not None:
f = open(args.series)
else:
f = sys.stdin
lines = f.readlines()
try:
before, inside, after = split(lines)
except exc.KSNotFound:
pass
else:
if args.name_only:
inside = filter_series(inside)
inside = [line + "\n" for line in inside]
try:
sys.stdout.writelines(inside)
# Avoid an unsightly error that may occur when not all output is
# read:
# Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
# BrokenPipeError: [Errno 32] Broken pipe
sys.stdout.flush()
except BrokenPipeError:
sys.stderr.close()
sys.exit()