59 text[f] = open(f, encoding=
'utf-8', errors=
'replace').read()
64 users = collections.defaultdict(set)
65 for f, t
in text.items():
66 for inc
in re.findall(
r'^\s*#\s*include\s+"([^"]+)"', t, re.M):
67 for cand
in (os.path.normpath(os.path.join(SRC, inc)),
68 os.path.normpath(os.path.join(os.path.dirname(f), inc))):
69 if cand
in known
and cand != f:
76 only_dir = sys.argv[sys.argv.index(
'--dir') + 1]
if '--dir' in sys.argv
else None
79 movable, clusters = [], []
81 if not f.endswith((
'.h',
'.hh',
'.hpp')):
83 if os.path.basename(f)
in NEVER_MOVE:
86 if home
is None or (only_dir
and home != only_dir):
88 consumers = collections.Counter(
subsystem(u)
for u
in users.get(f, ()))
89 own = consumers.pop(home, 0)
90 if len(consumers) != 1:
92 dest, n = next(iter(consumers.items()))
93 if LAYER.get(dest, 99) <= LAYER.get(home, 0):
95 impl = [f[:-2] + e
for e
in (
'c',
'cc')
if os.path.exists(f[:-2] + e)]
96 rec = (n, f, dest, own, impl)
97 (clusters
if own
else movable).append(rec)
99 movable.sort(reverse=
True)
100 clusters.sort(reverse=
True)
102 print(
'=== MOVABLE: only one consuming subsystem, and nothing in its own directory '
104 by_dest = collections.defaultdict(list)
105 for n, f, dest, _, impl
in movable:
106 by_dest[dest].append((f, n, impl))
107 for dest, items
in sorted(by_dest.items(), key=
lambda kv: -len(kv[1])):
108 print(
'\n -> %s/ (%d)' % (dest, len(items)))
109 for f, n, impl
in items:
110 print(
' %-44s %d includer(s)%s'
111 % (f, n,
' + ' +
', '.join(os.path.basename(i)
for i
in impl)
if impl
else ''))
113 if '--clusters' in sys.argv:
114 print(
'\n=== BLOCKED: one external consumer, but siblings use it too ===')
115 print(
' (moving these alone creates an inversion -- move the cluster or nothing)')
116 for n, f, dest, own, _
in clusters:
117 print(
' %-44s -> %-9s %d external, %d sibling(s)' % (f, dest, n, own))
119 print(
'\n%d further files have a single external consumer but are also used by '
120 'siblings; run --clusters to see them.' % len(clusters))