diff options
| -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): |
