162306a36Sopenharmony_ci#!/usr/bin/env python3 262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0 362306a36Sopenharmony_ci# 462306a36Sopenharmony_ci# diffconfig - a tool to compare .config files. 562306a36Sopenharmony_ci# 662306a36Sopenharmony_ci# originally written in 2006 by Matt Mackall 762306a36Sopenharmony_ci# (at least, this was in his bloatwatch source code) 862306a36Sopenharmony_ci# last worked on 2008 by Tim Bird 962306a36Sopenharmony_ci# 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ciimport sys, os 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cidef usage(): 1462306a36Sopenharmony_ci print("""Usage: diffconfig [-h] [-m] [<config1> <config2>] 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciDiffconfig is a simple utility for comparing two .config files. 1762306a36Sopenharmony_ciUsing standard diff to compare .config files often includes extraneous and 1862306a36Sopenharmony_cidistracting information. This utility produces sorted output with only the 1962306a36Sopenharmony_cichanges in configuration values between the two files. 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciAdded and removed items are shown with a leading plus or minus, respectively. 2262306a36Sopenharmony_ciChanged items show the old and new values on a single line. 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciIf -m is specified, then output will be in "merge" style, which has the 2562306a36Sopenharmony_cichanged and new values in kernel config option format. 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ciIf no config files are specified, .config and .config.old are used. 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ciExample usage: 3062306a36Sopenharmony_ci $ diffconfig .config config-with-some-changes 3162306a36Sopenharmony_ci-EXT2_FS_XATTR n 3262306a36Sopenharmony_ci CRAMFS n -> y 3362306a36Sopenharmony_ci EXT2_FS y -> n 3462306a36Sopenharmony_ci LOG_BUF_SHIFT 14 -> 16 3562306a36Sopenharmony_ci PRINTK_TIME n -> y 3662306a36Sopenharmony_ci""") 3762306a36Sopenharmony_ci sys.exit(0) 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci# returns a dictionary of name/value pairs for config items in the file 4062306a36Sopenharmony_cidef readconfig(config_file): 4162306a36Sopenharmony_ci d = {} 4262306a36Sopenharmony_ci for line in config_file: 4362306a36Sopenharmony_ci line = line[:-1] 4462306a36Sopenharmony_ci if line[:7] == "CONFIG_": 4562306a36Sopenharmony_ci name, val = line[7:].split("=", 1) 4662306a36Sopenharmony_ci d[name] = val 4762306a36Sopenharmony_ci if line[-11:] == " is not set": 4862306a36Sopenharmony_ci d[line[9:-11]] = "n" 4962306a36Sopenharmony_ci return d 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cidef print_config(op, config, value, new_value): 5262306a36Sopenharmony_ci global merge_style 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if merge_style: 5562306a36Sopenharmony_ci if new_value: 5662306a36Sopenharmony_ci if new_value=="n": 5762306a36Sopenharmony_ci print("# CONFIG_%s is not set" % config) 5862306a36Sopenharmony_ci else: 5962306a36Sopenharmony_ci print("CONFIG_%s=%s" % (config, new_value)) 6062306a36Sopenharmony_ci else: 6162306a36Sopenharmony_ci if op=="-": 6262306a36Sopenharmony_ci print("-%s %s" % (config, value)) 6362306a36Sopenharmony_ci elif op=="+": 6462306a36Sopenharmony_ci print("+%s %s" % (config, new_value)) 6562306a36Sopenharmony_ci else: 6662306a36Sopenharmony_ci print(" %s %s -> %s" % (config, value, new_value)) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cidef show_diff(): 6962306a36Sopenharmony_ci global merge_style 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci # parse command line args 7262306a36Sopenharmony_ci if ("-h" in sys.argv or "--help" in sys.argv): 7362306a36Sopenharmony_ci usage() 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci merge_style = 0 7662306a36Sopenharmony_ci if "-m" in sys.argv: 7762306a36Sopenharmony_ci merge_style = 1 7862306a36Sopenharmony_ci sys.argv.remove("-m") 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci argc = len(sys.argv) 8162306a36Sopenharmony_ci if not (argc==1 or argc == 3): 8262306a36Sopenharmony_ci print("Error: incorrect number of arguments or unrecognized option") 8362306a36Sopenharmony_ci usage() 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if argc == 1: 8662306a36Sopenharmony_ci # if no filenames given, assume .config and .config.old 8762306a36Sopenharmony_ci build_dir="" 8862306a36Sopenharmony_ci if "KBUILD_OUTPUT" in os.environ: 8962306a36Sopenharmony_ci build_dir = os.environ["KBUILD_OUTPUT"]+"/" 9062306a36Sopenharmony_ci configa_filename = build_dir + ".config.old" 9162306a36Sopenharmony_ci configb_filename = build_dir + ".config" 9262306a36Sopenharmony_ci else: 9362306a36Sopenharmony_ci configa_filename = sys.argv[1] 9462306a36Sopenharmony_ci configb_filename = sys.argv[2] 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci try: 9762306a36Sopenharmony_ci a = readconfig(open(configa_filename)) 9862306a36Sopenharmony_ci b = readconfig(open(configb_filename)) 9962306a36Sopenharmony_ci except (IOError): 10062306a36Sopenharmony_ci e = sys.exc_info()[1] 10162306a36Sopenharmony_ci print("I/O error[%s]: %s\n" % (e.args[0],e.args[1])) 10262306a36Sopenharmony_ci usage() 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci # print items in a but not b (accumulate, sort and print) 10562306a36Sopenharmony_ci old = [] 10662306a36Sopenharmony_ci for config in a: 10762306a36Sopenharmony_ci if config not in b: 10862306a36Sopenharmony_ci old.append(config) 10962306a36Sopenharmony_ci old.sort() 11062306a36Sopenharmony_ci for config in old: 11162306a36Sopenharmony_ci print_config("-", config, a[config], None) 11262306a36Sopenharmony_ci del a[config] 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci # print items that changed (accumulate, sort, and print) 11562306a36Sopenharmony_ci changed = [] 11662306a36Sopenharmony_ci for config in a: 11762306a36Sopenharmony_ci if a[config] != b[config]: 11862306a36Sopenharmony_ci changed.append(config) 11962306a36Sopenharmony_ci else: 12062306a36Sopenharmony_ci del b[config] 12162306a36Sopenharmony_ci changed.sort() 12262306a36Sopenharmony_ci for config in changed: 12362306a36Sopenharmony_ci print_config("->", config, a[config], b[config]) 12462306a36Sopenharmony_ci del b[config] 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci # now print items in b but not in a 12762306a36Sopenharmony_ci # (items from b that were in a were removed above) 12862306a36Sopenharmony_ci new = sorted(b.keys()) 12962306a36Sopenharmony_ci for config in new: 13062306a36Sopenharmony_ci print_config("+", config, None, b[config]) 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cidef main(): 13362306a36Sopenharmony_ci try: 13462306a36Sopenharmony_ci show_diff() 13562306a36Sopenharmony_ci except BrokenPipeError: 13662306a36Sopenharmony_ci # Python flushes standard streams on exit; redirect remaining output 13762306a36Sopenharmony_ci # to devnull to avoid another BrokenPipeError at shutdown 13862306a36Sopenharmony_ci devnull = os.open(os.devnull, os.O_WRONLY) 13962306a36Sopenharmony_ci os.dup2(devnull, sys.stdout.fileno()) 14062306a36Sopenharmony_ci sys.exit(1) # Python exits with error code 1 on EPIPE 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ciif __name__ == '__main__': 14462306a36Sopenharmony_ci main() 145