#!/usr/bin/env python3 # SPDX-License-Identifier: GPL-2.0-or-later # # Rewrite #include "x.h" to the folder x.h lives in under include/. # # include/ is split by subsystem -- arch/, core/, fs/, dev/, gfx/, net/, # uapi/, ldls/ -- and every include names the folder, as Linux's do. Code # written before the split, or by habit, says #include "proc.h"; this turns it # into #include "core/proc.h". The folder each header is in is read from the # tree, so moving a header and running this again is the whole procedure. # # python3 tools/fix-includes.py FILE... rewrite these files # python3 tools/fix-includes.py --modified every file git says is changed # python3 tools/fix-includes.py --check FILE print what would change, write # nothing; exit 1 if anything would # # Only quoted includes are touched. in a host tool is the system's # errno.h and stays that way, and a file with a same-named header next to it # keeps its own. import os import re import subprocess import sys ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) INC = os.path.join(ROOT, "include") where = {} for sub in sorted(os.listdir(INC)): d = os.path.join(INC, sub) if os.path.isdir(d): for h in os.listdir(d): if h.endswith(".h"): where[h] = sub pat = re.compile(r'(#\s*include\s*")((?:\.\./)*)(include/)?([A-Za-z0-9_]+\.h)"') def fix(path, text): def one(m): pre, dots, incdir, h = m.groups() if h not in where: return m.group(0) if incdir: return '%s%sinclude/%s/%s"' % (pre, dots, where[h], h) if dots or os.path.exists(os.path.join(os.path.dirname(path), h)): return m.group(0) return '%s%s/%s"' % (pre, where[h], h) return pat.sub(one, text) def modified(): out = subprocess.run(["git", "-C", ROOT, "status", "--porcelain"], capture_output=True, text=True, check=True).stdout files = [] for line in out.splitlines(): p = line[3:].split(" -> ")[-1] if p.endswith((".c", ".h", ".S", ".inc")): files.append(os.path.join(ROOT, p)) return files def main(argv): check = "--check" in argv args = [a for a in argv if not a.startswith("--")] files = modified() if "--modified" in argv else args if not files: print(__doc__ or "usage: fix-includes.py [--check] [--modified] FILE...") return 2 changed = 0 for f in files: if not os.path.isfile(f): continue with open(f, encoding="utf-8", errors="surrogateescape") as fh: old = fh.read() new = fix(f, old) if new == old: continue changed += 1 if check: for a, b in zip(old.splitlines(), new.splitlines()): if a != b: print("%s: %s -> %s" % (os.path.relpath(f), a.strip(), b.strip())) else: with open(f, "w", encoding="utf-8", errors="surrogateescape") as fh: fh.write(new) print("fixed", os.path.relpath(f)) return 1 if check and changed else 0 if __name__ == "__main__": sys.exit(main(sys.argv[1:]))