18c2ecf20Sopenharmony_ci#!/usr/bin/env python3 28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0 38c2ecf20Sopenharmony_ci# 48c2ecf20Sopenharmony_ci# diffconfig - a tool to compare .config files. 58c2ecf20Sopenharmony_ci# 68c2ecf20Sopenharmony_ci# originally written in 2006 by Matt Mackall 78c2ecf20Sopenharmony_ci# (at least, this was in his bloatwatch source code) 88c2ecf20Sopenharmony_ci# last worked on 2008 by Tim Bird 98c2ecf20Sopenharmony_ci# 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ciimport sys, os 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cidef usage(): 148c2ecf20Sopenharmony_ci print("""Usage: diffconfig [-h] [-m] [<config1> <config2>] 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciDiffconfig is a simple utility for comparing two .config files. 178c2ecf20Sopenharmony_ciUsing standard diff to compare .config files often includes extraneous and 188c2ecf20Sopenharmony_cidistracting information. This utility produces sorted output with only the 198c2ecf20Sopenharmony_cichanges in configuration values between the two files. 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ciAdded and removed items are shown with a leading plus or minus, respectively. 228c2ecf20Sopenharmony_ciChanged items show the old and new values on a single line. 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciIf -m is specified, then output will be in "merge" style, which has the 258c2ecf20Sopenharmony_cichanged and new values in kernel config option format. 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ciIf no config files are specified, .config and .config.old are used. 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ciExample usage: 308c2ecf20Sopenharmony_ci $ diffconfig .config config-with-some-changes 318c2ecf20Sopenharmony_ci-EXT2_FS_XATTR n 328c2ecf20Sopenharmony_ci CRAMFS n -> y 338c2ecf20Sopenharmony_ci EXT2_FS y -> n 348c2ecf20Sopenharmony_ci LOG_BUF_SHIFT 14 -> 16 358c2ecf20Sopenharmony_ci PRINTK_TIME n -> y 368c2ecf20Sopenharmony_ci""") 378c2ecf20Sopenharmony_ci sys.exit(0) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci# returns a dictionary of name/value pairs for config items in the file 408c2ecf20Sopenharmony_cidef readconfig(config_file): 418c2ecf20Sopenharmony_ci d = {} 428c2ecf20Sopenharmony_ci for line in config_file: 438c2ecf20Sopenharmony_ci line = line[:-1] 448c2ecf20Sopenharmony_ci if line[:7] == "CONFIG_": 458c2ecf20Sopenharmony_ci name, val = line[7:].split("=", 1) 468c2ecf20Sopenharmony_ci d[name] = val 478c2ecf20Sopenharmony_ci if line[-11:] == " is not set": 488c2ecf20Sopenharmony_ci d[line[9:-11]] = "n" 498c2ecf20Sopenharmony_ci return d 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cidef print_config(op, config, value, new_value): 528c2ecf20Sopenharmony_ci global merge_style 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if merge_style: 558c2ecf20Sopenharmony_ci if new_value: 568c2ecf20Sopenharmony_ci if new_value=="n": 578c2ecf20Sopenharmony_ci print("# CONFIG_%s is not set" % config) 588c2ecf20Sopenharmony_ci else: 598c2ecf20Sopenharmony_ci print("CONFIG_%s=%s" % (config, new_value)) 608c2ecf20Sopenharmony_ci else: 618c2ecf20Sopenharmony_ci if op=="-": 628c2ecf20Sopenharmony_ci print("-%s %s" % (config, value)) 638c2ecf20Sopenharmony_ci elif op=="+": 648c2ecf20Sopenharmony_ci print("+%s %s" % (config, new_value)) 658c2ecf20Sopenharmony_ci else: 668c2ecf20Sopenharmony_ci print(" %s %s -> %s" % (config, value, new_value)) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cidef show_diff(): 698c2ecf20Sopenharmony_ci global merge_style 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci # parse command line args 728c2ecf20Sopenharmony_ci if ("-h" in sys.argv or "--help" in sys.argv): 738c2ecf20Sopenharmony_ci usage() 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci merge_style = 0 768c2ecf20Sopenharmony_ci if "-m" in sys.argv: 778c2ecf20Sopenharmony_ci merge_style = 1 788c2ecf20Sopenharmony_ci sys.argv.remove("-m") 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci argc = len(sys.argv) 818c2ecf20Sopenharmony_ci if not (argc==1 or argc == 3): 828c2ecf20Sopenharmony_ci print("Error: incorrect number of arguments or unrecognized option") 838c2ecf20Sopenharmony_ci usage() 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if argc == 1: 868c2ecf20Sopenharmony_ci # if no filenames given, assume .config and .config.old 878c2ecf20Sopenharmony_ci build_dir="" 888c2ecf20Sopenharmony_ci if "KBUILD_OUTPUT" in os.environ: 898c2ecf20Sopenharmony_ci build_dir = os.environ["KBUILD_OUTPUT"]+"/" 908c2ecf20Sopenharmony_ci configa_filename = build_dir + ".config.old" 918c2ecf20Sopenharmony_ci configb_filename = build_dir + ".config" 928c2ecf20Sopenharmony_ci else: 938c2ecf20Sopenharmony_ci configa_filename = sys.argv[1] 948c2ecf20Sopenharmony_ci configb_filename = sys.argv[2] 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci try: 978c2ecf20Sopenharmony_ci a = readconfig(open(configa_filename)) 988c2ecf20Sopenharmony_ci b = readconfig(open(configb_filename)) 998c2ecf20Sopenharmony_ci except (IOError): 1008c2ecf20Sopenharmony_ci e = sys.exc_info()[1] 1018c2ecf20Sopenharmony_ci print("I/O error[%s]: %s\n" % (e.args[0],e.args[1])) 1028c2ecf20Sopenharmony_ci usage() 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci # print items in a but not b (accumulate, sort and print) 1058c2ecf20Sopenharmony_ci old = [] 1068c2ecf20Sopenharmony_ci for config in a: 1078c2ecf20Sopenharmony_ci if config not in b: 1088c2ecf20Sopenharmony_ci old.append(config) 1098c2ecf20Sopenharmony_ci old.sort() 1108c2ecf20Sopenharmony_ci for config in old: 1118c2ecf20Sopenharmony_ci print_config("-", config, a[config], None) 1128c2ecf20Sopenharmony_ci del a[config] 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci # print items that changed (accumulate, sort, and print) 1158c2ecf20Sopenharmony_ci changed = [] 1168c2ecf20Sopenharmony_ci for config in a: 1178c2ecf20Sopenharmony_ci if a[config] != b[config]: 1188c2ecf20Sopenharmony_ci changed.append(config) 1198c2ecf20Sopenharmony_ci else: 1208c2ecf20Sopenharmony_ci del b[config] 1218c2ecf20Sopenharmony_ci changed.sort() 1228c2ecf20Sopenharmony_ci for config in changed: 1238c2ecf20Sopenharmony_ci print_config("->", config, a[config], b[config]) 1248c2ecf20Sopenharmony_ci del b[config] 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci # now print items in b but not in a 1278c2ecf20Sopenharmony_ci # (items from b that were in a were removed above) 1288c2ecf20Sopenharmony_ci new = sorted(b.keys()) 1298c2ecf20Sopenharmony_ci for config in new: 1308c2ecf20Sopenharmony_ci print_config("+", config, None, b[config]) 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cidef main(): 1338c2ecf20Sopenharmony_ci try: 1348c2ecf20Sopenharmony_ci show_diff() 1358c2ecf20Sopenharmony_ci except BrokenPipeError: 1368c2ecf20Sopenharmony_ci # Python flushes standard streams on exit; redirect remaining output 1378c2ecf20Sopenharmony_ci # to devnull to avoid another BrokenPipeError at shutdown 1388c2ecf20Sopenharmony_ci devnull = os.open(os.devnull, os.O_WRONLY) 1398c2ecf20Sopenharmony_ci os.dup2(devnull, sys.stdout.fileno()) 1408c2ecf20Sopenharmony_ci sys.exit(1) # Python exits with error code 1 on EPIPE 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ciif __name__ == '__main__': 1448c2ecf20Sopenharmony_ci main() 145