0001 #!/usr/bin/env python3
0002 # SPDX-License-Identifier: GPL-2.0
0003 #
0004 # diffconfig - a tool to compare .config files.
0005 #
0006 # originally written in 2006 by Matt Mackall
0007 # (at least, this was in his bloatwatch source code)
0008 # last worked on 2008 by Tim Bird
0009 #
0010
0011 import sys, os
0012
0013 def usage():
0014 print("""Usage: diffconfig [-h] [-m] [<config1> <config2>]
0015
0016 Diffconfig is a simple utility for comparing two .config files.
0017 Using standard diff to compare .config files often includes extraneous and
0018 distracting information. This utility produces sorted output with only the
0019 changes in configuration values between the two files.
0020
0021 Added and removed items are shown with a leading plus or minus, respectively.
0022 Changed items show the old and new values on a single line.
0023
0024 If -m is specified, then output will be in "merge" style, which has the
0025 changed and new values in kernel config option format.
0026
0027 If no config files are specified, .config and .config.old are used.
0028
0029 Example usage:
0030 $ diffconfig .config config-with-some-changes
0031 -EXT2_FS_XATTR n
0032 CRAMFS n -> y
0033 EXT2_FS y -> n
0034 LOG_BUF_SHIFT 14 -> 16
0035 PRINTK_TIME n -> y
0036 """)
0037 sys.exit(0)
0038
0039 # returns a dictionary of name/value pairs for config items in the file
0040 def readconfig(config_file):
0041 d = {}
0042 for line in config_file:
0043 line = line[:-1]
0044 if line[:7] == "CONFIG_":
0045 name, val = line[7:].split("=", 1)
0046 d[name] = val
0047 if line[-11:] == " is not set":
0048 d[line[9:-11]] = "n"
0049 return d
0050
0051 def print_config(op, config, value, new_value):
0052 global merge_style
0053
0054 if merge_style:
0055 if new_value:
0056 if new_value=="n":
0057 print("# CONFIG_%s is not set" % config)
0058 else:
0059 print("CONFIG_%s=%s" % (config, new_value))
0060 else:
0061 if op=="-":
0062 print("-%s %s" % (config, value))
0063 elif op=="+":
0064 print("+%s %s" % (config, new_value))
0065 else:
0066 print(" %s %s -> %s" % (config, value, new_value))
0067
0068 def main():
0069 global merge_style
0070
0071 # parse command line args
0072 if ("-h" in sys.argv or "--help" in sys.argv):
0073 usage()
0074
0075 merge_style = 0
0076 if "-m" in sys.argv:
0077 merge_style = 1
0078 sys.argv.remove("-m")
0079
0080 argc = len(sys.argv)
0081 if not (argc==1 or argc == 3):
0082 print("Error: incorrect number of arguments or unrecognized option")
0083 usage()
0084
0085 if argc == 1:
0086 # if no filenames given, assume .config and .config.old
0087 build_dir=""
0088 if "KBUILD_OUTPUT" in os.environ:
0089 build_dir = os.environ["KBUILD_OUTPUT"]+"/"
0090 configa_filename = build_dir + ".config.old"
0091 configb_filename = build_dir + ".config"
0092 else:
0093 configa_filename = sys.argv[1]
0094 configb_filename = sys.argv[2]
0095
0096 try:
0097 a = readconfig(open(configa_filename))
0098 b = readconfig(open(configb_filename))
0099 except (IOError):
0100 e = sys.exc_info()[1]
0101 print("I/O error[%s]: %s\n" % (e.args[0],e.args[1]))
0102 usage()
0103
0104 # print items in a but not b (accumulate, sort and print)
0105 old = []
0106 for config in a:
0107 if config not in b:
0108 old.append(config)
0109 old.sort()
0110 for config in old:
0111 print_config("-", config, a[config], None)
0112 del a[config]
0113
0114 # print items that changed (accumulate, sort, and print)
0115 changed = []
0116 for config in a:
0117 if a[config] != b[config]:
0118 changed.append(config)
0119 else:
0120 del b[config]
0121 changed.sort()
0122 for config in changed:
0123 print_config("->", config, a[config], b[config])
0124 del b[config]
0125
0126 # now print items in b but not in a
0127 # (items from b that were in a were removed above)
0128 new = sorted(b.keys())
0129 for config in new:
0130 print_config("+", config, None, b[config])
0131
0132 main()