diff options
author | Valentin Rothberg <valentinrothberg@gmail.com> | 2015-11-26 08:17:15 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-12-14 13:54:23 -0500 |
commit | 1b2c841467515425636c15799ac90f6c4821acc0 (patch) | |
tree | fcf54e64d69be2dd35ab4fb45345f13c9ffa6c57 /scripts/checkkconfigsymbols.py | |
parent | e2042a8a80ab598bbb8d06cd7f3078923c7c77e3 (diff) |
checkkconfigsymbols.py: find similar symbols
Add support to find string-similar symbols. When option --sim SYM is
specified, checkkconfigsymbols.py will print at most 10 symbols defined
in Kconfig that are string similar to SYM in the following format:
Similar symbols: $COMMA_SEPARATED_LIST_OF_SYMBOLS
Note, if no similar symbols are found it is indicated as follows:
Similar symbols: no similar symbols found
Since the implemented functionality is also useful when searching the
entire source or when diffing two commits, a list of similar symbols is
printed unconditionally with the other data. In order to make the
output more readable, the format now looks as follows:
$UNDEFINED_SYMBOL
Referencing files: $COMMA_SEPARATED_LIST_OF_FILES
Similar symbols: $COMMA_SEPARATED_LIST_OF_SYMBOLS
[Optional with '--find']
Commits changing symbol:
- $COMMIT_1_HASH ("$COMMIT_1_MESSAGE")
- $COMMIT_2_HASH ("$COMMIT_2_MESSAGE")
or
- no commit found
Signed-off-by: Valentin Rothberg <valentinrothberg@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'scripts/checkkconfigsymbols.py')
-rwxr-xr-x | scripts/checkkconfigsymbols.py | 114 |
1 files changed, 88 insertions, 26 deletions
diff --git a/scripts/checkkconfigsymbols.py b/scripts/checkkconfigsymbols.py index cfe397b61c48..d8f6c094cce5 100755 --- a/scripts/checkkconfigsymbols.py +++ b/scripts/checkkconfigsymbols.py | |||
@@ -8,6 +8,7 @@ | |||
8 | # Licensed under the terms of the GNU GPL License version 2 | 8 | # Licensed under the terms of the GNU GPL License version 2 |
9 | 9 | ||
10 | 10 | ||
11 | import difflib | ||
11 | import os | 12 | import os |
12 | import re | 13 | import re |
13 | import signal | 14 | import signal |
@@ -74,6 +75,9 @@ def parse_options(): | |||
74 | "the pattern needs to be a Python regex. To " | 75 | "the pattern needs to be a Python regex. To " |
75 | "ignore defconfigs, specify -i '.*defconfig'.") | 76 | "ignore defconfigs, specify -i '.*defconfig'.") |
76 | 77 | ||
78 | parser.add_option('-s', '--sim', dest='sim', action='store', default="", | ||
79 | help="Print a list of maximum 10 string-similar symbols.") | ||
80 | |||
77 | parser.add_option('', '--force', dest='force', action='store_true', | 81 | parser.add_option('', '--force', dest='force', action='store_true', |
78 | default=False, | 82 | default=False, |
79 | help="Reset current Git tree even when it's dirty.") | 83 | help="Reset current Git tree even when it's dirty.") |
@@ -112,6 +116,18 @@ def main(): | |||
112 | """Main function of this module.""" | 116 | """Main function of this module.""" |
113 | opts = parse_options() | 117 | opts = parse_options() |
114 | 118 | ||
119 | if opts.sim and not opts.commit and not opts.diff: | ||
120 | sims = find_sims(opts.sim, opts.ignore) | ||
121 | if sims: | ||
122 | print "%s: %s" % (yel("Similar symbols"), ', '.join(sims)) | ||
123 | else: | ||
124 | print "%s: no similar symbols found" % yel("Similar symbols") | ||
125 | sys.exit(0) | ||
126 | |||
127 | # dictionary of (un)defined symbols | ||
128 | defined = {} | ||
129 | undefined = {} | ||
130 | |||
115 | if opts.commit or opts.diff: | 131 | if opts.commit or opts.diff: |
116 | head = get_head() | 132 | head = get_head() |
117 | 133 | ||
@@ -130,40 +146,56 @@ def main(): | |||
130 | 146 | ||
131 | # get undefined items before the commit | 147 | # get undefined items before the commit |
132 | execute("git reset --hard %s" % commit_a) | 148 | execute("git reset --hard %s" % commit_a) |
133 | undefined_a = check_symbols(opts.ignore) | 149 | undefined_a, _ = check_symbols(opts.ignore) |
134 | 150 | ||
135 | # get undefined items for the commit | 151 | # get undefined items for the commit |
136 | execute("git reset --hard %s" % commit_b) | 152 | execute("git reset --hard %s" % commit_b) |
137 | undefined_b = check_symbols(opts.ignore) | 153 | undefined_b, defined = check_symbols(opts.ignore) |
138 | 154 | ||
139 | # report cases that are present for the commit but not before | 155 | # report cases that are present for the commit but not before |
140 | for feature in sorted(undefined_b): | 156 | for feature in sorted(undefined_b): |
141 | # feature has not been undefined before | 157 | # feature has not been undefined before |
142 | if not feature in undefined_a: | 158 | if not feature in undefined_a: |
143 | files = sorted(undefined_b.get(feature)) | 159 | files = sorted(undefined_b.get(feature)) |
144 | print "%s\t%s" % (yel(feature), ", ".join(files)) | 160 | undefined[feature] = files |
145 | if opts.find: | ||
146 | commits = find_commits(feature, opts.diff) | ||
147 | print red(commits) | ||
148 | # check if there are new files that reference the undefined feature | 161 | # check if there are new files that reference the undefined feature |
149 | else: | 162 | else: |
150 | files = sorted(undefined_b.get(feature) - | 163 | files = sorted(undefined_b.get(feature) - |
151 | undefined_a.get(feature)) | 164 | undefined_a.get(feature)) |
152 | if files: | 165 | if files: |
153 | print "%s\t%s" % (yel(feature), ", ".join(files)) | 166 | undefined[feature] = files |
154 | if opts.find: | ||
155 | commits = find_commits(feature, opts.diff) | ||
156 | print red(commits) | ||
157 | 167 | ||
158 | # reset to head | 168 | # reset to head |
159 | execute("git reset --hard %s" % head) | 169 | execute("git reset --hard %s" % head) |
160 | 170 | ||
161 | # default to check the entire tree | 171 | # default to check the entire tree |
162 | else: | 172 | else: |
163 | undefined = check_symbols(opts.ignore) | 173 | undefined, defined = check_symbols(opts.ignore) |
164 | for feature in sorted(undefined): | 174 | |
165 | files = sorted(undefined.get(feature)) | 175 | # now print the output |
166 | print "%s\t%s" % (yel(feature), ", ".join(files)) | 176 | for feature in sorted(undefined): |
177 | print red(feature) | ||
178 | |||
179 | files = sorted(undefined.get(feature)) | ||
180 | print "%s: %s" % (yel("Referencing files"), ", ".join(files)) | ||
181 | |||
182 | sims = find_sims(feature, opts.ignore, defined) | ||
183 | sims_out = yel("Similar symbols") | ||
184 | if sims: | ||
185 | print "%s: %s" % (sims_out, ', '.join(sims)) | ||
186 | else: | ||
187 | print "%s: %s" % (sims_out, "no similar symbols found") | ||
188 | |||
189 | if opts.find: | ||
190 | print "%s:" % yel("Commits changing symbol") | ||
191 | commits = find_commits(feature, opts.diff) | ||
192 | if commits: | ||
193 | for commit in commits: | ||
194 | commit = commit.split(" ", 1) | ||
195 | print "\t- %s (\"%s\")" % (yel(commit[0]), commit[1]) | ||
196 | else: | ||
197 | print "\t- no commit found" | ||
198 | print # new line | ||
167 | 199 | ||
168 | 200 | ||
169 | def yel(string): | 201 | def yel(string): |
@@ -193,7 +225,7 @@ def find_commits(symbol, diff): | |||
193 | """Find commits changing %symbol in the given range of %diff.""" | 225 | """Find commits changing %symbol in the given range of %diff.""" |
194 | commits = execute("git log --pretty=oneline --abbrev-commit -G %s %s" | 226 | commits = execute("git log --pretty=oneline --abbrev-commit -G %s %s" |
195 | % (symbol, diff)) | 227 | % (symbol, diff)) |
196 | return commits | 228 | return [x for x in commits.split("\n") if x] |
197 | 229 | ||
198 | 230 | ||
199 | def tree_is_dirty(): | 231 | def tree_is_dirty(): |
@@ -222,6 +254,45 @@ def init_worker(): | |||
222 | signal.signal(signal.SIGINT, signal.SIG_IGN) | 254 | signal.signal(signal.SIGINT, signal.SIG_IGN) |
223 | 255 | ||
224 | 256 | ||
257 | def find_sims(symbol, ignore, defined = []): | ||
258 | """Return a list of max. ten Kconfig symbols that are string-similar to | ||
259 | @symbol.""" | ||
260 | if defined: | ||
261 | return sorted(difflib.get_close_matches(symbol, set(defined), 10)) | ||
262 | |||
263 | pool = Pool(cpu_count(), init_worker) | ||
264 | kfiles = [] | ||
265 | for gitfile in get_files(): | ||
266 | if REGEX_FILE_KCONFIG.match(gitfile): | ||
267 | kfiles.append(gitfile) | ||
268 | |||
269 | arglist = [] | ||
270 | for part in partition(kfiles, cpu_count()): | ||
271 | arglist.append((part, ignore)) | ||
272 | |||
273 | for res in pool.map(parse_kconfig_files, arglist): | ||
274 | defined.extend(res[0]) | ||
275 | |||
276 | return sorted(difflib.get_close_matches(symbol, set(defined), 10)) | ||
277 | |||
278 | |||
279 | def get_files(): | ||
280 | """Return a list of all files in the current git directory.""" | ||
281 | # use 'git ls-files' to get the worklist | ||
282 | stdout = execute("git ls-files") | ||
283 | if len(stdout) > 0 and stdout[-1] == "\n": | ||
284 | stdout = stdout[:-1] | ||
285 | |||
286 | files = [] | ||
287 | for gitfile in stdout.rsplit("\n"): | ||
288 | if ".git" in gitfile or "ChangeLog" in gitfile or \ | ||
289 | ".log" in gitfile or os.path.isdir(gitfile) or \ | ||
290 | gitfile.startswith("tools/"): | ||
291 | continue | ||
292 | files.append(gitfile) | ||
293 | return files | ||
294 | |||
295 | |||
225 | def check_symbols(ignore): | 296 | def check_symbols(ignore): |
226 | """Find undefined Kconfig symbols and return a dict with the symbol as key | 297 | """Find undefined Kconfig symbols and return a dict with the symbol as key |
227 | and a list of referencing files as value. Files matching %ignore are not | 298 | and a list of referencing files as value. Files matching %ignore are not |
@@ -243,16 +314,7 @@ def check_symbols_helper(pool, ignore): | |||
243 | defined_features = [] | 314 | defined_features = [] |
244 | referenced_features = dict() # {file: [features]} | 315 | referenced_features = dict() # {file: [features]} |
245 | 316 | ||
246 | # use 'git ls-files' to get the worklist | 317 | for gitfile in get_files(): |
247 | stdout = execute("git ls-files") | ||
248 | if len(stdout) > 0 and stdout[-1] == "\n": | ||
249 | stdout = stdout[:-1] | ||
250 | |||
251 | for gitfile in stdout.rsplit("\n"): | ||
252 | if ".git" in gitfile or "ChangeLog" in gitfile or \ | ||
253 | ".log" in gitfile or os.path.isdir(gitfile) or \ | ||
254 | gitfile.startswith("tools/"): | ||
255 | continue | ||
256 | if REGEX_FILE_KCONFIG.match(gitfile): | 318 | if REGEX_FILE_KCONFIG.match(gitfile): |
257 | kconfig_files.append(gitfile) | 319 | kconfig_files.append(gitfile) |
258 | else: | 320 | else: |
@@ -296,7 +358,7 @@ def check_symbols_helper(pool, ignore): | |||
296 | if feature[:-len("_MODULE")] in defined_features: | 358 | if feature[:-len("_MODULE")] in defined_features: |
297 | continue | 359 | continue |
298 | undefined[feature] = referenced_features.get(feature) | 360 | undefined[feature] = referenced_features.get(feature) |
299 | return undefined | 361 | return undefined, defined_features |
300 | 362 | ||
301 | 363 | ||
302 | def parse_source_files(source_files): | 364 | def parse_source_files(source_files): |