1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
# Icon checker: test that icon themes contain all needed icons
# Author: Martin Owens <doctormo@geek-2.com>
# Licensed under GPL version 2 or any later version, read the file "COPYING" for more information.
import fnmatch
import os
import sys
from collections import defaultdict
THEME_PATH = os.path.join('.', 'share', 'icons')
IGNORE_THEMES = [
'application',
'Tango',
]
IGNORE_ICONS = [
# These are hard coded as symbolic in the gtk source code
'list-add-symbolic.svg',
'list-remove-symbolic.svg',
]
NO_PROBLEM,\
BAD_SYMBOLIC_NAME,\
BAD_SCALABLE_NAME,\
MISSING_FROM,\
ONLY_FOUND_IN = range(5)
def icon_themes():
for name in os.listdir(THEME_PATH):
filename = os.path.join(THEME_PATH, name)
if name in IGNORE_THEMES or not os.path.isdir(filename):
continue
yield name, filename
def find_errors_in(themes):
data = defaultdict(set)
bad_symbolic = []
bad_scalable = []
names = set()
for name, path in themes:
for root, dirs, files in os.walk(path):
orig = root
root = root[len(path)+1:]
if '/' not in root:
continue
(kind, root) = root.split('/', 1)
if kind not in ("symbolic", "scalable"):
continue # Not testing cursors, maybe later.
theme_name = f"{name}-{kind}"
names.add(theme_name)
for fname in files:
if fname in IGNORE_ICONS:
continue
if not fname.endswith('.svg'):
continue
if kind == "symbolic":
if not fname.endswith('-symbolic.svg'):
bad_symbolic.append(os.path.join(orig, fname))
continue
else:
# Make filenames consistant for comparison
fname = fname.replace('-symbolic.svg', '.svg')
elif kind == "scalable" and fname.endswith('-symbolic.svg'):
bad_scalable.append(os.path.join(orig, fname))
continue
filename = os.path.join(root, fname)
data[filename].add(theme_name)
if bad_symbolic:
yield BAD_SYMBOLIC_NAME, bad_symbolic
if bad_scalable:
yield BAD_SCALABLE_NAME, bad_scalable
only_found_in = defaultdict(list)
missing_from = defaultdict(list)
for filename in sorted(data):
datum = data[filename]
if datum == names:
continue
elif len(datum) == 1:
only_found_in[list(datum)[0]].append(filename)
continue
for theme in (names - datum):
missing_from[theme].append(filename)
if only_found_in:
yield ONLY_FOUND_IN, only_found_in
if missing_from:
yield MISSING_FROM, missing_from
if __name__ == '__main__':
errors = list(find_errors_in(icon_themes()))
if errors:
count = 0
for error, themes in errors:
if isinstance(themes, list):
count += len(themes)
elif isinstance(themes, dict):
count += sum([len(v) for v in themes.values()])
sys.stderr.write(f" == {count} problems found in icon themes! == \n\n")
for error, themes in errors:
if error is BAD_SCALABLE_NAME:
sys.stderr.write(f"Scalable themes should not have symbolic icons in them (They end with -symbolic.svg so won't be used):\n")
for name in themes:
sys.stderr.write(f" - {name}\n")
sys.stderr.write("\n")
elif error is BAD_SYMBOLIC_NAME:
sys.stderr.write(f"Symbolic themes should only have symbolic icons in them (They don't end with -symbolic.svg so can't be used):\n")
for name in themes:
sys.stderr.write(f" - {name}\n")
sys.stderr.write("\n")
elif error is MISSING_FROM:
for theme in themes:
sys.stderr.write(f"Icons missing from {theme}:\n")
for name in themes[theme]:
sys.stderr.write(f" - {name}\n")
sys.stderr.write("\n")
elif error is ONLY_FOUND_IN:
for theme in themes:
sys.stderr.write(f"Icons only found in {theme}:\n")
for name in themes[theme]:
sys.stderr.write(f" + {name}\n")
sys.stderr.write("\n")
else:
pass
sys.exit(5)
# vi:sw=4:expandtab:
|