1#!/usr/bin/env python3 2# 3# SPDX-License-Identifier: Apache-2.0 4# 5# diffconfig - a tool to compare .config files. 6# 7# originally written in 2006 by Matt Mackall 8# (at least, this was in his bloatwatch source code) 9# last worked on 2008 by Tim Bird 10# 11 12import sys, os 13 14def usage(): 15 print("""Usage: diffconfig [-h] [-m] [<config1> <config2>] 16 17Diffconfig is a simple utility for comparing two .config files. 18Using standard diff to compare .config files often includes extraneous and 19distracting information. This utility produces sorted output with only the 20changes in configuration values between the two files. 21 22Added and removed items are shown with a leading plus or minus, respectively. 23Changed items show the old and new values on a single line. 24 25If -m is specified, then output will be in "merge" style, which has the 26changed and new values in kernel config option format. 27 28If no config files are specified, .config and .config.old are used. 29 30Example usage: 31 $ diffconfig .config config-with-some-changes 32-EXT2_FS_XATTR n 33-EXT2_FS_XIP n 34 CRAMFS n -> y 35 EXT2_FS y -> n 36 LOG_BUF_SHIFT 14 -> 16 37 PRINTK_TIME n -> y 38""") 39 sys.exit(0) 40 41# returns a dictionary of name/value pairs for config items in the file 42def readconfig(config_file): 43 d = {} 44 for line in config_file: 45 line = line[:-1] 46 if line[:7] == "CONFIG_": 47 name, val = line[7:].split("=", 1) 48 d[name] = val 49 if line[-11:] == " is not set": 50 d[line[9:-11]] = "n" 51 return d 52 53def print_config(op, config, value, new_value): 54 global merge_style 55 56 if merge_style: 57 if new_value: 58 if new_value=="n": 59 print("# CONFIG_%s is not set" % config) 60 else: 61 print("CONFIG_%s=%s" % (config, new_value)) 62 else: 63 if op=="-": 64 print("-%s %s" % (config, value)) 65 elif op=="+": 66 print("+%s %s" % (config, new_value)) 67 else: 68 print(" %s %s -> %s" % (config, value, new_value)) 69 70def main(): 71 global merge_style 72 73 # parse command line args 74 if ("-h" in sys.argv or "--help" in sys.argv): 75 usage() 76 77 merge_style = 0 78 if "-m" in sys.argv: 79 merge_style = 1 80 sys.argv.remove("-m") 81 82 argc = len(sys.argv) 83 if not (argc==1 or argc == 3): 84 print("Error: incorrect number of arguments or unrecognized option") 85 usage() 86 87 if argc == 1: 88 # if no filenames given, assume .config and .config.old 89 build_dir="" 90 if "KBUILD_OUTPUT" in os.environ: 91 build_dir = os.environ["KBUILD_OUTPUT"]+"/" 92 configa_filename = build_dir + ".config.old" 93 configb_filename = build_dir + ".config" 94 else: 95 configa_filename = sys.argv[1] 96 configb_filename = sys.argv[2] 97 98 try: 99 a = readconfig(open(configa_filename)) 100 b = readconfig(open(configb_filename)) 101 except (IOError): 102 e = sys.exc_info()[1] 103 print("I/O error[%s]: %s\n" % (e.args[0],e.args[1])) 104 usage() 105 106 # print items in a but not b (accumulate, sort and print) 107 old = [] 108 for config in a: 109 if config not in b: 110 old.append(config) 111 old.sort() 112 for config in old: 113 print_config("-", config, a[config], None) 114 del a[config] 115 116 # print items that changed (accumulate, sort, and print) 117 changed = [] 118 for config in a: 119 if a[config] != b[config]: 120 changed.append(config) 121 else: 122 del b[config] 123 changed.sort() 124 for config in changed: 125 print_config("->", config, a[config], b[config]) 126 del b[config] 127 128 # now print items in b but not in a 129 # (items from b that were in a were removed above) 130 new = sorted(b.keys()) 131 for config in new: 132 print_config("+", config, None, b[config]) 133 134main() 135