<br><br>On Friday, October 11, 2019, Vladimir Sementsov-Ogievskiy <<a href="mailto:vsementsov@virtuozzo.com">vsementsov@virtuozzo.com</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Add script to automatically commit tree-wide changes per-subsystem.<br>
<br>
Signed-off-by: Vladimir Sementsov-Ogievskiy <<a href="mailto:vsementsov@virtuozzo.com">vsementsov@virtuozzo.com</a>><br>
---</blockquote><div><br></div><div>Great idea!</div><div><br></div><div>Can you just add a comment somewhere close to the top of the file on script usage? Or "--help" option? If you would like to be the script maintainer, please change the MAINTAINERS too.</div><div><br></div><div>Reviewed-by: Aleksandar Markovic <<a href="mailto:amarkovic@wavecomp.com">amarkovic@wavecomp.com</a>></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
CC: Gerd Hoffmann <<a href="mailto:kraxel@redhat.com">kraxel@redhat.com</a>><br>
CC: "Gonglei (Arei)" <<a href="mailto:arei.gonglei@huawei.com">arei.gonglei@huawei.com</a>><br>
CC: Eduardo Habkost <<a href="mailto:ehabkost@redhat.com">ehabkost@redhat.com</a>><br>
CC: Igor Mammedov <<a href="mailto:imammedo@redhat.com">imammedo@redhat.com</a>><br>
CC: Laurent Vivier <<a href="mailto:lvivier@redhat.com">lvivier@redhat.com</a>><br>
CC: Amit Shah <<a href="mailto:amit@kernel.org">amit@kernel.org</a>><br>
CC: Kevin Wolf <<a href="mailto:kwolf@redhat.com">kwolf@redhat.com</a>><br>
CC: Max Reitz <<a href="mailto:mreitz@redhat.com">mreitz@redhat.com</a>><br>
CC: John Snow <<a href="mailto:jsnow@redhat.com">jsnow@redhat.com</a>><br>
CC: Ari Sundholm <<a href="mailto:ari@tuxera.com">ari@tuxera.com</a>><br>
CC: Pavel Dovgalyuk <<a href="mailto:pavel.dovgaluk@ispras.ru">pavel.dovgaluk@ispras.ru</a>><br>
CC: Paolo Bonzini <<a href="mailto:pbonzini@redhat.com">pbonzini@redhat.com</a>><br>
CC: Stefan Hajnoczi <<a href="mailto:stefanha@redhat.com">stefanha@redhat.com</a>><br>
CC: Fam Zheng <<a href="mailto:fam@euphon.net">fam@euphon.net</a>><br>
CC: Stefan Weil <<a href="mailto:sw@weilnetz.de">sw@weilnetz.de</a>><br>
CC: Ronnie Sahlberg <<a href="mailto:ronniesahlberg@gmail.com">ronniesahlberg@gmail.com</a>><br>
CC: Peter Lieven <<a href="mailto:pl@kamp.de">pl@kamp.de</a>><br>
CC: Eric Blake <<a href="mailto:eblake@redhat.com">eblake@redhat.com</a>><br>
CC: "Denis V. Lunev" <<a href="mailto:den@openvz.org">den@openvz.org</a>><br>
CC: Markus Armbruster <<a href="mailto:armbru@redhat.com">armbru@redhat.com</a>><br>
CC: Alberto Garcia <<a href="mailto:berto@igalia.com">berto@igalia.com</a>><br>
CC: Jason Dillaman <<a href="mailto:dillaman@redhat.com">dillaman@redhat.com</a>><br>
CC: Wen Congyang <<a href="mailto:wencongyang2@huawei.com">wencongyang2@huawei.com</a>><br>
CC: Xie Changlong <<a href="mailto:xiechanglong.d@gmail.com">xiechanglong.d@gmail.com</a>><br>
CC: Liu Yuan <<a href="mailto:namei.unix@gmail.com">namei.unix@gmail.com</a>><br>
CC: "Richard W.M. Jones" <<a href="mailto:rjones@redhat.com">rjones@redhat.com</a>><br>
CC: Jeff Cody <<a href="mailto:codyprime@gmail.com">codyprime@gmail.com</a>><br>
CC: "Marc-André Lureau" <<a href="mailto:marcandre.lureau@redhat.com">marcandre.lureau@redhat.com</a>><br>
CC: "Daniel P. Berrangé" <<a href="mailto:berrange@redhat.com">berrange@redhat.com</a>><br>
CC: Richard Henderson <<a href="mailto:rth@twiddle.net">rth@twiddle.net</a>><br>
CC: Greg Kurz <<a href="mailto:groug@kaod.org">groug@kaod.org</a>><br>
CC: "Michael S. Tsirkin" <<a href="mailto:mst@redhat.com">mst@redhat.com</a>><br>
CC: Marcel Apfelbaum <<a href="mailto:marcel.apfelbaum@gmail.com">marcel.apfelbaum@gmail.com</a>><br>
CC: Beniamino Galvani <<a href="mailto:b.galvani@gmail.com">b.galvani@gmail.com</a>><br>
CC: Peter Maydell <<a href="mailto:peter.maydell@linaro.org">peter.maydell@linaro.org</a>><br>
CC: "Cédric Le Goater" <<a href="mailto:clg@kaod.org">clg@kaod.org</a>><br>
CC: Andrew Jeffery <<a href="mailto:andrew@aj.id.au">andrew@aj.id.au</a>><br>
CC: Joel Stanley <<a href="mailto:joel@jms.id.au">joel@jms.id.au</a>><br>
CC: Andrew Baumann <<a href="mailto:Andrew.Baumann@microsoft.com">Andrew.Baumann@microsoft.com</a>><br>
CC: "Philippe Mathieu-Daudé" <<a href="mailto:philmd@redhat.com">philmd@redhat.com</a>><br>
CC: Antony Pavlov <<a href="mailto:antonynpavlov@gmail.com">antonynpavlov@gmail.com</a>><br>
CC: Jean-Christophe Dubois <<a href="mailto:jcd@tribudubois.net">jcd@tribudubois.net</a>><br>
CC: Peter Chubb <<a href="mailto:peter.chubb@nicta.com.au">peter.chubb@nicta.com.au</a>><br>
CC: Subbaraya Sundeep <<a href="mailto:sundeep.lkml@gmail.com">sundeep.lkml@gmail.com</a>><br>
CC: Eric Auger <<a href="mailto:eric.auger@redhat.com">eric.auger@redhat.com</a>><br>
CC: Alistair Francis <<a href="mailto:alistair@alistair23.me">alistair@alistair23.me</a>><br>
CC: "Edgar E. Iglesias" <<a href="mailto:edgar.iglesias@gmail.com">edgar.iglesias@gmail.com</a>><br>
CC: Stefano Stabellini <<a href="mailto:sstabellini@kernel.org">sstabellini@kernel.org</a>><br>
CC: Anthony Perard <<a href="mailto:anthony.perard@citrix.com">anthony.perard@citrix.com</a>><br>
CC: Paul Durrant <<a href="mailto:paul@xen.org">paul@xen.org</a>><br>
CC: Paul Burton <<a href="mailto:pburton@wavecomp.com">pburton@wavecomp.com</a>><br>
CC: Aleksandar Rikalo <<a href="mailto:arikalo@wavecomp.com">arikalo@wavecomp.com</a>><br>
CC: Chris Wulff <<a href="mailto:crwulff@gmail.com">crwulff@gmail.com</a>><br>
CC: Marek Vasut <<a href="mailto:marex@denx.de">marex@denx.de</a>><br>
CC: David Gibson <<a href="mailto:david@gibson.dropbear.id.au">david@gibson.dropbear.id.au</a>><br>
CC: Cornelia Huck <<a href="mailto:cohuck@redhat.com">cohuck@redhat.com</a>><br>
CC: Halil Pasic <<a href="mailto:pasic@linux.ibm.com">pasic@linux.ibm.com</a>><br>
CC: Christian Borntraeger <<a href="mailto:borntraeger@de.ibm.com">borntraeger@de.ibm.com</a>><br>
CC: "Hervé Poussineau" <<a href="mailto:hpoussin@reactos.org">hpoussin@reactos.org</a>><br>
CC: Xiao Guangrong <<a href="mailto:xiaoguangrong.eric@gmail.com">xiaoguangrong.eric@gmail.com</a>><br>
CC: Aurelien Jarno <<a href="mailto:aurelien@aurel32.net">aurelien@aurel32.net</a>><br>
CC: Aleksandar Markovic <<a href="mailto:amarkovic@wavecomp.com">amarkovic@wavecomp.com</a>><br>
CC: Mark Cave-Ayland <<a href="mailto:mark.cave-ayland@ilande.co.uk">mark.cave-ayland@ilande.co.uk</a>><br>
CC: Jason Wang <<a href="mailto:jasowang@redhat.com">jasowang@redhat.com</a>><br>
CC: Laszlo Ersek <<a href="mailto:lersek@redhat.com">lersek@redhat.com</a>><br>
CC: Yuval Shaia <<a href="mailto:yuval.shaia@oracle.com">yuval.shaia@oracle.com</a>><br>
CC: Palmer Dabbelt <<a href="mailto:palmer@sifive.com">palmer@sifive.com</a>><br>
CC: Sagar Karandikar <<a href="mailto:sagark@eecs.berkeley.edu">sagark@eecs.berkeley.edu</a>><br>
CC: Bastian Koppelmann <<a href="mailto:kbastian@mail.uni-paderborn.de">kbastian@mail.uni-paderborn.de</a>><br>
CC: David Hildenbrand <<a href="mailto:david@redhat.com">david@redhat.com</a>><br>
CC: Thomas Huth <<a href="mailto:thuth@redhat.com">thuth@redhat.com</a>><br>
CC: Eric Farman <<a href="mailto:farman@linux.ibm.com">farman@linux.ibm.com</a>><br>
CC: Matthew Rosato <<a href="mailto:mjrosato@linux.ibm.com">mjrosato@linux.ibm.com</a>><br>
CC: Hannes Reinecke <<a href="mailto:hare@suse.com">hare@suse.com</a>><br>
CC: Michael Walle <michael@walle.cc><br>
CC: Artyom Tarasenko <<a href="mailto:atar4qemu@gmail.com">atar4qemu@gmail.com</a>><br>
CC: Stefan Berger <<a href="mailto:stefanb@linux.ibm.com">stefanb@linux.ibm.com</a>><br>
CC: Samuel Thibault <<a href="mailto:samuel.thibault@ens-lyon.org">samuel.thibault@ens-lyon.org</a>><br>
CC: Alex Williamson <<a href="mailto:alex.williamson@redhat.com">alex.williamson@redhat.com</a>><br>
CC: Tony Krowiak <<a href="mailto:akrowiak@linux.ibm.com">akrowiak@linux.ibm.com</a>><br>
CC: Pierre Morel <<a href="mailto:pmorel@linux.ibm.com">pmorel@linux.ibm.com</a>><br>
CC: Michael Roth <<a href="mailto:mdroth@linux.vnet.ibm.com">mdroth@linux.vnet.ibm.com</a>><br>
CC: Hailiang Zhang <<a href="mailto:zhang.zhanghailiang@huawei.com">zhang.zhanghailiang@huawei.com</a>><br>
CC: Juan Quintela <<a href="mailto:quintela@redhat.com">quintela@redhat.com</a>><br>
CC: "Dr. David Alan Gilbert" <<a href="mailto:dgilbert@redhat.com">dgilbert@redhat.com</a>><br>
CC: Luigi Rizzo <<a href="mailto:rizzo@iet.unipi.it">rizzo@iet.unipi.it</a>><br>
CC: Giuseppe Lettieri <<a href="mailto:g.lettieri@iet.unipi.it">g.lettieri@iet.unipi.it</a>><br>
CC: Vincenzo Maffione <<a href="mailto:v.maffione@gmail.com">v.maffione@gmail.com</a>><br>
CC: Jan Kiszka <<a href="mailto:jan.kiszka@siemens.com">jan.kiszka@siemens.com</a>><br>
CC: Anthony Green <<a href="mailto:green@moxielogic.com">green@moxielogic.com</a>><br>
CC: Stafford Horne <<a href="mailto:shorne@gmail.com">shorne@gmail.com</a>><br>
CC: Guan Xuetao <<a href="mailto:gxt@mprc.pku.edu.cn">gxt@mprc.pku.edu.cn</a>><br>
CC: Max Filippov <<a href="mailto:jcmvbkbc@gmail.com">jcmvbkbc@gmail.com</a>><br>
CC: <a href="mailto:qemu-block@nongnu.org">qemu-block@nongnu.org</a><br>
CC: <a href="mailto:integration@gluster.org">integration@gluster.org</a><br>
CC: <a href="mailto:sheepdog@lists.wpkg.org">sheepdog@lists.wpkg.org</a><br>
CC: <a href="mailto:qemu-arm@nongnu.org">qemu-arm@nongnu.org</a><br>
CC: <a href="mailto:xen-devel@lists.xenproject.org">xen-devel@lists.xenproject.org</a><br>
CC: <a href="mailto:qemu-ppc@nongnu.org">qemu-ppc@nongnu.org</a><br>
CC: <a href="mailto:qemu-s390x@nongnu.org">qemu-s390x@nongnu.org</a><br>
CC: <a href="mailto:qemu-riscv@nongnu.org">qemu-riscv@nongnu.org</a><br>
<br>
 python/commit-per-subsystem.py | 204 ++++++++++++++++++++++++++++++<wbr>+++<br>
 1 file changed, 204 insertions(+)<br>
 create mode 100755 python/commit-per-subsystem.py<br>
<br>
diff --git a/python/commit-per-subsystem.<wbr>py b/python/commit-per-subsystem.<wbr>py<br>
new file mode 100755<br>
index 0000000000..2ccf84cb15<br>
--- /dev/null<br>
+++ b/python/commit-per-subsystem.<wbr>py<br>
@@ -0,0 +1,204 @@<br>
+#!/usr/bin/env python3<br>
+#<br>
+# Copyright (c) 2019 Virtuozzo International GmbH<br>
+#<br>
+# This program is free software; you can redistribute it and/or modify<br>
+# it under the terms of the GNU General Public License as published by<br>
+# the Free Software Foundation; either version 2 of the License, or<br>
+# (at your option) any later version.<br>
+#<br>
+# This program is distributed in the hope that it will be useful,<br>
+# but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br>
+# GNU General Public License for more details.<br>
+#<br>
+# You should have received a copy of the GNU General Public License<br>
+# along with this program.  If not, see <<a href="http://www.gnu.org/licenses/" target="_blank">http://www.gnu.org/licenses/</a>><wbr>.<br>
+#<br>
+<br>
+import subprocess<br>
+import sys<br>
+import os<br>
+import glob<br>
+<br>
+<br>
+def git_add(pattern):<br>
+    subprocess.run(['git', 'add', pattern])<br>
+<br>
+<br>
+def git_commit(msg):<br>
+    subprocess.run(['git', 'commit', '-m', msg], capture_output=True)<br>
+<br>
+<br>
+def git_changed_files():<br>
+    ret = subprocess.check_output(['git'<wbr>, 'diff', '--name-only'], encoding='utf-8').split('\n')<br>
+    if ret[-1] == '':<br>
+        del ret[-1]<br>
+    return ret<br>
+<br>
+<br>
+maintainers = sys.argv[1]<br>
+message = sys.argv[2].strip()<br>
+<br>
+subsystem = None<br>
+<br>
+remap = {<br>
+    'Block layer core': 'block',<br>
+    'Block Jobs': 'block',<br>
+    'Dirty Bitmaps': 'block',<br>
+    'Block QAPI, monitor, command line': 'block',<br>
+    'Block I/O path': 'block',<br>
+    'Throttling infrastructure': 'block',<br>
+    'Architecture support': 's390x',<br>
+    'Guest CPU Cores (KVM)': 'kvm',<br>
+    'Guest CPU Cores (Xen)': 'xen',<br>
+    'Guest CPU cores (TCG)': 'tcg',<br>
+    'Network Block Device (NBD)': 'nbd',<br>
+    'Parallel NOR Flash devices': 'pflash',<br>
+    'Firmware configuration (fw_cfg)': 'fw_cfg',<br>
+    'Block SCSI subsystem': 'scsi',<br>
+    'Network device backends': 'net',<br>
+    'Netmap network backend': 'net',<br>
+    'Host Memory Backends': 'hostmem',<br>
+    'Cryptodev Backends': 'cryptodev',<br>
+    'QEMU Guest Agent': 'qga',<br>
+    'COLO Framework': 'colo',<br>
+    'Command line option argument parsing': 'cmdline',<br>
+    'Character device backends': 'chardev'<br>
+}<br>
+<br>
+<br>
+class Maintainers:<br>
+    def add(self, subsystem, path, mapper, mapper_name, glob_count=1):<br>
+        if subsystem in remap:<br>
+            subsystem = remap[subsystem]<br>
+        if subsystem not in self.subsystems:<br>
+            self.subsystems.append(<wbr>subsystem)<br>
+<br>
+        if path[-1] == '/':<br>
+            path = path[:-1]<br>
+<br>
+        if path in mapper:<br>
+            if mapper[path][1] == glob_count:<br>
+                print('Warning: "{}" both in "{}" and "{}" in {} mapper with '<br>
+                      'same glob-count={}. {} ignored for this path.'.format(<br>
+                        path, mapper[path][0], subsystem, mapper_name, glob_count,<br>
+                          subsystem))<br>
+                return<br>
+            if mapper[path][1] < glob_count:<br>
+                # silently ignore worse match<br>
+                return<br>
+<br>
+        mapper[path] = (subsystem, glob_count)<br>
+<br>
+    def __init__(self, file_name):<br>
+        self.map_file = {}<br>
+        self.map_glob_file = {}<br>
+        self.map_dir = {}<br>
+        self.map_glob_dir = {}<br>
+        self.map_unmaintained_dir = {<br>
+            'python': ('python', 1),<br>
+            'hw/misc': ('misc', 1)<br>
+        }<br>
+        self.subsystems = ['python', 'misc']<br>
+        subsystem = None<br>
+<br>
+        with open(file_name) as f:<br>
+            mode2 = False<br>
+            prevline = ''<br>
+            for line in f:<br>
+                line = line.rstrip()<br>
+                if not line:<br>
+                    continue<br>
+                if len(line) >= 2 and line[1] == ':':<br>
+                    if line[0] == 'F':<br>
+                        fname = line[3:]<br>
+                        if fname in ['*', '*/']:<br>
+                            continue<br>
+                        if os.path.isfile(fname):<br>
+                            self.add(subsystem, fname, self.map_file, 'file')<br>
+                        elif os.path.isdir(fname):<br>
+                            self.add(subsystem, fname, self.map_dir, 'dir')<br>
+                        else:<br>
+                            paths = glob.glob(fname)<br>
+                            if not paths:<br>
+                                print('Warning: nothing corresponds to "{}"'.format(fname))<br>
+                                continue<br>
+<br>
+                            n = len(paths)<br>
+                            for f in paths:<br>
+                                if os.path.isfile(f):<br>
+                                    self.add(subsystem, f, self.map_glob_file, 'glob-file', n)<br>
+                                else:<br>
+                                    assert os.path.isdir(f)<br>
+                                    self.add(subsystem, f, self.map_glob_dir, 'glob-dir', n)<br>
+                elif line[:3] == '---':<br>
+                    subsystem = prevline<br>
+                    if subsystem == 'Devices':<br>
+                        mode2 = True<br>
+                elif mode2:<br>
+                    subsystem = line<br>
+                prevline = line<br>
+<br>
+    def find_in_map_dir(self, file_name, mapper):<br>
+        while file_name != '' and file_name not in mapper:<br>
+            file_name = os.path.dirname(file_name)<br>
+<br>
+        return None if file_name == '' else mapper[file_name][0]<br>
+<br>
+    def find_in_map_file(self, file_name, mapper):<br>
+        if file_name in mapper:<br>
+            return mapper[file_name][0]<br>
+<br>
+    def find_subsystem(self, file_name):<br>
+        s = self.find_in_map_file(file_<wbr>name, self.map_file)<br>
+        if s is not None:<br>
+            return s<br>
+<br>
+        s = self.find_in_map_file(file_<wbr>name, self.map_glob_file)<br>
+        if s is not None:<br>
+            return s<br>
+<br>
+        s = self.find_in_map_dir(file_<wbr>name, self.map_dir)<br>
+        if s is not None:<br>
+            return s<br>
+<br>
+        s = self.find_in_map_dir(file_<wbr>name, self.map_glob_dir)<br>
+        if s is not None:<br>
+            return s<br>
+<br>
+        s = self.find_in_map_dir(file_<wbr>name, self.map_unmaintained_dir)<br>
+        if s is not None:<br>
+            return s<br>
+<br>
+        self.subsystems.append(file_<wbr>name)<br>
+        return file_name<br>
+<br>
+<br>
+def commit(subsystem):<br>
+    msg = subsystem<br>
+    if msg in remap:<br>
+        msg = remap[msg]<br>
+    msg += ': ' + message<br>
+    git_commit(msg)<br>
+<br>
+mnt = Maintainers(maintainers)<br>
+res = {}<br>
+for f in git_changed_files():<br>
+    s = mnt.find_subsystem(f)<br>
+    if s in res:<br>
+        res[s].append(f)<br>
+    else:<br>
+        res[s] = [f]<br>
+<br>
+for s in mnt.subsystems:<br>
+    if s in res:<br>
+        print(s)<br>
+        for f in res[s]:<br>
+            print('  ', f)<br>
+<br>
+for s in mnt.subsystems:<br>
+    if s in res:<br>
+        for f in res[s]:<br>
+            git_add(f)<br>
+        commit(s)<br>
-- <br>
2.21.0<br>
<br>
<br>
</blockquote>