blob: 0b33f3190e3dbb2d87840c32a7917624d7ce6912 [file] [log] [blame]
Simon Glass1f701862019-10-31 07:42:57 -06001#!/usr/bin/env python3
Tom Rini10e47792018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Masahiro Yamadab6160812015-05-20 11:36:07 +09003#
4# Author: Masahiro Yamada <yamada.masahiro@socionext.com>
5#
Masahiro Yamadab6160812015-05-20 11:36:07 +09006
7"""
8Move config options from headers to defconfig files.
9
Simon Glass83cc72e2021-07-21 21:35:51 -060010See doc/develop/moveconfig.rst for documentation.
Masahiro Yamadab6160812015-05-20 11:36:07 +090011"""
12
Simon Glassd9c1da22021-12-18 14:54:31 -070013from argparse import ArgumentParser
Markus Klotzbuecherbac0bb52020-02-12 20:46:44 +010014import asteval
Simon Glassc6e73cf2017-06-01 19:39:03 -060015import collections
Masahiro Yamadaea8f5342016-07-25 19:15:24 +090016import copy
Masahiro Yamada573b3902016-07-25 19:15:25 +090017import difflib
Simon Glassbb57be72021-12-18 08:09:45 -070018import doctest
Masahiro Yamada0f6beda2016-05-19 15:52:07 +090019import filecmp
Masahiro Yamadab6160812015-05-20 11:36:07 +090020import fnmatch
Masahiro Yamada3984d6e2016-10-19 14:39:54 +090021import glob
Masahiro Yamadab6160812015-05-20 11:36:07 +090022import multiprocessing
Masahiro Yamadab6160812015-05-20 11:36:07 +090023import os
Simon Glass1f701862019-10-31 07:42:57 -060024import queue
Masahiro Yamadab6160812015-05-20 11:36:07 +090025import re
26import shutil
27import subprocess
28import sys
29import tempfile
Simon Glass43cf08f2017-06-01 19:39:02 -060030import threading
Masahiro Yamadab6160812015-05-20 11:36:07 +090031import time
Simon Glassbb57be72021-12-18 08:09:45 -070032import unittest
Masahiro Yamadab6160812015-05-20 11:36:07 +090033
Simon Glassf0d9c102020-04-17 18:09:02 -060034from buildman import bsettings
35from buildman import kconfiglib
36from buildman import toolchain
Simon Glass44116332017-06-15 21:39:33 -060037
Masahiro Yamadab6160812015-05-20 11:36:07 +090038SHOW_GNU_MAKE = 'scripts/show-gnu-make'
39SLEEP_TIME=0.03
40
Masahiro Yamadab6160812015-05-20 11:36:07 +090041STATE_IDLE = 0
42STATE_DEFCONFIG = 1
43STATE_AUTOCONF = 2
Joe Hershberger166edec2015-05-19 13:21:17 -050044STATE_SAVEDEFCONFIG = 3
Masahiro Yamadab6160812015-05-20 11:36:07 +090045
46ACTION_MOVE = 0
Masahiro Yamada5643d6e2016-05-19 15:51:56 +090047ACTION_NO_ENTRY = 1
Masahiro Yamada35204d92016-08-22 22:18:21 +090048ACTION_NO_ENTRY_WARN = 2
49ACTION_NO_CHANGE = 3
Masahiro Yamadab6160812015-05-20 11:36:07 +090050
51COLOR_BLACK = '0;30'
52COLOR_RED = '0;31'
53COLOR_GREEN = '0;32'
54COLOR_BROWN = '0;33'
55COLOR_BLUE = '0;34'
56COLOR_PURPLE = '0;35'
57COLOR_CYAN = '0;36'
58COLOR_LIGHT_GRAY = '0;37'
59COLOR_DARK_GRAY = '1;30'
60COLOR_LIGHT_RED = '1;31'
61COLOR_LIGHT_GREEN = '1;32'
62COLOR_YELLOW = '1;33'
63COLOR_LIGHT_BLUE = '1;34'
64COLOR_LIGHT_PURPLE = '1;35'
65COLOR_LIGHT_CYAN = '1;36'
66COLOR_WHITE = '1;37'
67
Simon Glass8fb5bd02017-06-01 19:39:01 -060068AUTO_CONF_PATH = 'include/config/auto.conf'
Simon Glass43cf08f2017-06-01 19:39:02 -060069CONFIG_DATABASE = 'moveconfig.db'
Simon Glass8fb5bd02017-06-01 19:39:01 -060070
Simon Glass44116332017-06-15 21:39:33 -060071CONFIG_LEN = len('CONFIG_')
Simon Glass8fb5bd02017-06-01 19:39:01 -060072
Markus Klotzbuecher3d5d4182019-05-15 15:15:52 +020073SIZES = {
Simon Glassdc634d92021-12-18 14:54:30 -070074 'SZ_1': 0x00000001, 'SZ_2': 0x00000002,
75 'SZ_4': 0x00000004, 'SZ_8': 0x00000008,
76 'SZ_16': 0x00000010, 'SZ_32': 0x00000020,
77 'SZ_64': 0x00000040, 'SZ_128': 0x00000080,
78 'SZ_256': 0x00000100, 'SZ_512': 0x00000200,
79 'SZ_1K': 0x00000400, 'SZ_2K': 0x00000800,
80 'SZ_4K': 0x00001000, 'SZ_8K': 0x00002000,
81 'SZ_16K': 0x00004000, 'SZ_32K': 0x00008000,
82 'SZ_64K': 0x00010000, 'SZ_128K': 0x00020000,
83 'SZ_256K': 0x00040000, 'SZ_512K': 0x00080000,
84 'SZ_1M': 0x00100000, 'SZ_2M': 0x00200000,
85 'SZ_4M': 0x00400000, 'SZ_8M': 0x00800000,
86 'SZ_16M': 0x01000000, 'SZ_32M': 0x02000000,
87 'SZ_64M': 0x04000000, 'SZ_128M': 0x08000000,
88 'SZ_256M': 0x10000000, 'SZ_512M': 0x20000000,
89 'SZ_1G': 0x40000000, 'SZ_2G': 0x80000000,
90 'SZ_4G': 0x100000000
Markus Klotzbuecher3d5d4182019-05-15 15:15:52 +020091}
92
Masahiro Yamadab6160812015-05-20 11:36:07 +090093### helper functions ###
Masahiro Yamadab6160812015-05-20 11:36:07 +090094def check_top_directory():
95 """Exit if we are not at the top of source directory."""
96 for f in ('README', 'Licenses'):
97 if not os.path.exists(f):
98 sys.exit('Please run at the top of source directory.')
99
Masahiro Yamada990e6772016-05-19 15:51:54 +0900100def check_clean_directory():
101 """Exit if the source tree is not clean."""
102 for f in ('.config', 'include/config'):
103 if os.path.exists(f):
104 sys.exit("source tree is not clean, please run 'make mrproper'")
105
Masahiro Yamadab6160812015-05-20 11:36:07 +0900106def get_make_cmd():
107 """Get the command name of GNU Make.
108
109 U-Boot needs GNU Make for building, but the command name is not
110 necessarily "make". (for example, "gmake" on FreeBSD).
111 Returns the most appropriate command name on your system.
112 """
113 process = subprocess.Popen([SHOW_GNU_MAKE], stdout=subprocess.PIPE)
114 ret = process.communicate()
115 if process.returncode:
116 sys.exit('GNU Make not found')
117 return ret[0].rstrip()
118
Simon Glass18774bc2017-06-01 19:38:58 -0600119def get_matched_defconfig(line):
120 """Get the defconfig files that match a pattern
121
122 Args:
123 line: Path or filename to match, e.g. 'configs/snow_defconfig' or
124 'k2*_defconfig'. If no directory is provided, 'configs/' is
125 prepended
126
127 Returns:
128 a list of matching defconfig files
129 """
130 dirname = os.path.dirname(line)
131 if dirname:
132 pattern = line
133 else:
134 pattern = os.path.join('configs', line)
135 return glob.glob(pattern) + glob.glob(pattern + '_defconfig')
136
Masahiro Yamada3984d6e2016-10-19 14:39:54 +0900137def get_matched_defconfigs(defconfigs_file):
Simon Glass8f3cf312017-06-01 19:38:59 -0600138 """Get all the defconfig files that match the patterns in a file.
139
140 Args:
141 defconfigs_file: File containing a list of defconfigs to process, or
142 '-' to read the list from stdin
143
144 Returns:
145 A list of paths to defconfig files, with no duplicates
146 """
Masahiro Yamada3984d6e2016-10-19 14:39:54 +0900147 defconfigs = []
Simon Glass8f3cf312017-06-01 19:38:59 -0600148 if defconfigs_file == '-':
149 fd = sys.stdin
150 defconfigs_file = 'stdin'
151 else:
152 fd = open(defconfigs_file)
153 for i, line in enumerate(fd):
Masahiro Yamada3984d6e2016-10-19 14:39:54 +0900154 line = line.strip()
155 if not line:
156 continue # skip blank lines silently
Simon Glass452fa8e2017-06-15 21:39:31 -0600157 if ' ' in line:
158 line = line.split(' ')[0] # handle 'git log' input
Simon Glass18774bc2017-06-01 19:38:58 -0600159 matched = get_matched_defconfig(line)
Masahiro Yamada3984d6e2016-10-19 14:39:54 +0900160 if not matched:
Simon Glass1f701862019-10-31 07:42:57 -0600161 print("warning: %s:%d: no defconfig matched '%s'" % \
162 (defconfigs_file, i + 1, line), file=sys.stderr)
Masahiro Yamada3984d6e2016-10-19 14:39:54 +0900163
164 defconfigs += matched
165
166 # use set() to drop multiple matching
167 return [ defconfig[len('configs') + 1:] for defconfig in set(defconfigs) ]
168
Masahiro Yamada58175e32016-07-25 19:15:28 +0900169def get_all_defconfigs():
170 """Get all the defconfig files under the configs/ directory."""
171 defconfigs = []
172 for (dirpath, dirnames, filenames) in os.walk('configs'):
173 dirpath = dirpath[len('configs') + 1:]
174 for filename in fnmatch.filter(filenames, '*_defconfig'):
175 defconfigs.append(os.path.join(dirpath, filename))
176
177 return defconfigs
178
Masahiro Yamadab6160812015-05-20 11:36:07 +0900179def color_text(color_enabled, color, string):
180 """Return colored string."""
181 if color_enabled:
Masahiro Yamada465b7c02016-05-19 15:52:02 +0900182 # LF should not be surrounded by the escape sequence.
183 # Otherwise, additional whitespace or line-feed might be printed.
184 return '\n'.join([ '\033[' + color + 'm' + s + '\033[0m' if s else ''
185 for s in string.split('\n') ])
Masahiro Yamadab6160812015-05-20 11:36:07 +0900186 else:
187 return string
188
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900189def show_diff(a, b, file_path, color_enabled):
Masahiro Yamada573b3902016-07-25 19:15:25 +0900190 """Show unidified diff.
191
192 Arguments:
193 a: A list of lines (before)
194 b: A list of lines (after)
195 file_path: Path to the file
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900196 color_enabled: Display the diff in color
Masahiro Yamada573b3902016-07-25 19:15:25 +0900197 """
198
199 diff = difflib.unified_diff(a, b,
200 fromfile=os.path.join('a', file_path),
201 tofile=os.path.join('b', file_path))
202
203 for line in diff:
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900204 if line[0] == '-' and line[1] != '-':
Simon Glass1f701862019-10-31 07:42:57 -0600205 print(color_text(color_enabled, COLOR_RED, line), end=' ')
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900206 elif line[0] == '+' and line[1] != '+':
Simon Glass1f701862019-10-31 07:42:57 -0600207 print(color_text(color_enabled, COLOR_GREEN, line), end=' ')
Masahiro Yamadaa1a4b092016-07-25 19:15:26 +0900208 else:
Simon Glass1f701862019-10-31 07:42:57 -0600209 print(line, end=' ')
Masahiro Yamada573b3902016-07-25 19:15:25 +0900210
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900211def extend_matched_lines(lines, matched, pre_patterns, post_patterns, extend_pre,
212 extend_post):
213 """Extend matched lines if desired patterns are found before/after already
214 matched lines.
215
216 Arguments:
217 lines: A list of lines handled.
218 matched: A list of line numbers that have been already matched.
219 (will be updated by this function)
220 pre_patterns: A list of regular expression that should be matched as
221 preamble.
222 post_patterns: A list of regular expression that should be matched as
223 postamble.
224 extend_pre: Add the line number of matched preamble to the matched list.
225 extend_post: Add the line number of matched postamble to the matched list.
226 """
227 extended_matched = []
228
229 j = matched[0]
230
231 for i in matched:
232 if i == 0 or i < j:
233 continue
234 j = i
235 while j in matched:
236 j += 1
237 if j >= len(lines):
238 break
239
240 for p in pre_patterns:
241 if p.search(lines[i - 1]):
242 break
243 else:
244 # not matched
245 continue
246
247 for p in post_patterns:
248 if p.search(lines[j]):
249 break
250 else:
251 # not matched
252 continue
253
254 if extend_pre:
255 extended_matched.append(i - 1)
256 if extend_post:
257 extended_matched.append(j)
258
259 matched += extended_matched
260 matched.sort()
261
Simon Glassd9c1da22021-12-18 14:54:31 -0700262def confirm(args, prompt):
263 if not args.yes:
Chris Packham85e15c52017-05-02 21:30:46 +1200264 while True:
Simon Glass1f701862019-10-31 07:42:57 -0600265 choice = input('{} [y/n]: '.format(prompt))
Chris Packham85e15c52017-05-02 21:30:46 +1200266 choice = choice.lower()
Simon Glass1f701862019-10-31 07:42:57 -0600267 print(choice)
Chris Packham85e15c52017-05-02 21:30:46 +1200268 if choice == 'y' or choice == 'n':
269 break
270
271 if choice == 'n':
272 return False
273
274 return True
275
Simon Glassd9c1da22021-12-18 14:54:31 -0700276def cleanup_empty_blocks(header_path, args):
Chris Packham73f6c7c2019-01-30 20:23:16 +1300277 """Clean up empty conditional blocks
278
279 Arguments:
280 header_path: path to the cleaned file.
Simon Glassd9c1da22021-12-18 14:54:31 -0700281 args: program arguments
Chris Packham73f6c7c2019-01-30 20:23:16 +1300282 """
283 pattern = re.compile(r'^\s*#\s*if.*$\n^\s*#\s*endif.*$\n*', flags=re.M)
284 with open(header_path) as f:
Simon Glassea52c2d2021-03-26 16:17:29 +1300285 try:
286 data = f.read()
287 except UnicodeDecodeError as e:
288 print("Failed on file %s': %s" % (header_path, e))
289 return
Chris Packham73f6c7c2019-01-30 20:23:16 +1300290
291 new_data = pattern.sub('\n', data)
292
293 show_diff(data.splitlines(True), new_data.splitlines(True), header_path,
Simon Glassd9c1da22021-12-18 14:54:31 -0700294 args.color)
Chris Packham73f6c7c2019-01-30 20:23:16 +1300295
Simon Glassd9c1da22021-12-18 14:54:31 -0700296 if args.dry_run:
Chris Packham73f6c7c2019-01-30 20:23:16 +1300297 return
298
299 with open(header_path, 'w') as f:
300 f.write(new_data)
301
Simon Glassd9c1da22021-12-18 14:54:31 -0700302def cleanup_one_header(header_path, patterns, args):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900303 """Clean regex-matched lines away from a file.
304
305 Arguments:
306 header_path: path to the cleaned file.
307 patterns: list of regex patterns. Any lines matching to these
308 patterns are deleted.
Simon Glassd9c1da22021-12-18 14:54:31 -0700309 args: program arguments
Masahiro Yamadab6160812015-05-20 11:36:07 +0900310 """
311 with open(header_path) as f:
Simon Glassea52c2d2021-03-26 16:17:29 +1300312 try:
313 lines = f.readlines()
314 except UnicodeDecodeError as e:
315 print("Failed on file %s': %s" % (header_path, e))
316 return
Masahiro Yamadab6160812015-05-20 11:36:07 +0900317
318 matched = []
319 for i, line in enumerate(lines):
Masahiro Yamada6d798ba2016-07-25 19:15:27 +0900320 if i - 1 in matched and lines[i - 1][-2:] == '\\\n':
321 matched.append(i)
322 continue
Masahiro Yamadab6160812015-05-20 11:36:07 +0900323 for pattern in patterns:
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900324 if pattern.search(line):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900325 matched.append(i)
326 break
327
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900328 if not matched:
329 return
330
331 # remove empty #ifdef ... #endif, successive blank lines
332 pattern_if = re.compile(r'#\s*if(def|ndef)?\W') # #if, #ifdef, #ifndef
333 pattern_elif = re.compile(r'#\s*el(if|se)\W') # #elif, #else
334 pattern_endif = re.compile(r'#\s*endif\W') # #endif
335 pattern_blank = re.compile(r'^\s*$') # empty line
336
337 while True:
338 old_matched = copy.copy(matched)
339 extend_matched_lines(lines, matched, [pattern_if],
340 [pattern_endif], True, True)
341 extend_matched_lines(lines, matched, [pattern_elif],
342 [pattern_elif, pattern_endif], True, False)
343 extend_matched_lines(lines, matched, [pattern_if, pattern_elif],
344 [pattern_blank], False, True)
345 extend_matched_lines(lines, matched, [pattern_blank],
346 [pattern_elif, pattern_endif], True, False)
347 extend_matched_lines(lines, matched, [pattern_blank],
348 [pattern_blank], True, False)
349 if matched == old_matched:
350 break
351
Masahiro Yamada573b3902016-07-25 19:15:25 +0900352 tolines = copy.copy(lines)
353
354 for i in reversed(matched):
355 tolines.pop(i)
356
Simon Glassd9c1da22021-12-18 14:54:31 -0700357 show_diff(lines, tolines, header_path, args.color)
Masahiro Yamadaea8f5342016-07-25 19:15:24 +0900358
Simon Glassd9c1da22021-12-18 14:54:31 -0700359 if args.dry_run:
Masahiro Yamadab6160812015-05-20 11:36:07 +0900360 return
361
362 with open(header_path, 'w') as f:
Masahiro Yamada573b3902016-07-25 19:15:25 +0900363 for line in tolines:
364 f.write(line)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900365
Simon Glassd9c1da22021-12-18 14:54:31 -0700366def cleanup_headers(configs, args):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900367 """Delete config defines from board headers.
368
369 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900370 configs: A list of CONFIGs to remove.
Simon Glassd9c1da22021-12-18 14:54:31 -0700371 args: program arguments
Masahiro Yamadab6160812015-05-20 11:36:07 +0900372 """
Simon Glassd9c1da22021-12-18 14:54:31 -0700373 if not confirm(args, 'Clean up headers?'):
Chris Packham85e15c52017-05-02 21:30:46 +1200374 return
Masahiro Yamadab6160812015-05-20 11:36:07 +0900375
376 patterns = []
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900377 for config in configs:
Masahiro Yamadab6160812015-05-20 11:36:07 +0900378 patterns.append(re.compile(r'#\s*define\s+%s\W' % config))
379 patterns.append(re.compile(r'#\s*undef\s+%s\W' % config))
380
Joe Hershbergerb78ad422015-05-19 13:21:21 -0500381 for dir in 'include', 'arch', 'board':
382 for (dirpath, dirnames, filenames) in os.walk(dir):
Masahiro Yamada28a6d352016-07-25 19:15:22 +0900383 if dirpath == os.path.join('include', 'generated'):
384 continue
Joe Hershbergerb78ad422015-05-19 13:21:21 -0500385 for filename in filenames:
Simon Glassce44bf52020-08-11 11:23:34 -0600386 if not filename.endswith(('~', '.dts', '.dtsi', '.bin',
Trevor Woerneraaad0c22021-03-15 12:01:33 -0400387 '.elf','.aml','.dat')):
Chris Packham73f6c7c2019-01-30 20:23:16 +1300388 header_path = os.path.join(dirpath, filename)
Tom Rinie90c0072019-11-10 21:19:37 -0500389 # This file contains UTF-16 data and no CONFIG symbols
390 if header_path == 'include/video_font_data.h':
391 continue
Simon Glassd9c1da22021-12-18 14:54:31 -0700392 cleanup_one_header(header_path, patterns, args)
393 cleanup_empty_blocks(header_path, args)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900394
Simon Glassd9c1da22021-12-18 14:54:31 -0700395def cleanup_one_extra_option(defconfig_path, configs, args):
Masahiro Yamadadce28de2016-07-25 19:15:29 +0900396 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in one defconfig file.
397
398 Arguments:
399 defconfig_path: path to the cleaned defconfig file.
400 configs: A list of CONFIGs to remove.
Simon Glassd9c1da22021-12-18 14:54:31 -0700401 args: program arguments
Masahiro Yamadadce28de2016-07-25 19:15:29 +0900402 """
403
404 start = 'CONFIG_SYS_EXTRA_OPTIONS="'
405 end = '"\n'
406
407 with open(defconfig_path) as f:
408 lines = f.readlines()
409
410 for i, line in enumerate(lines):
411 if line.startswith(start) and line.endswith(end):
412 break
413 else:
414 # CONFIG_SYS_EXTRA_OPTIONS was not found in this defconfig
415 return
416
417 old_tokens = line[len(start):-len(end)].split(',')
418 new_tokens = []
419
420 for token in old_tokens:
421 pos = token.find('=')
422 if not (token[:pos] if pos >= 0 else token) in configs:
423 new_tokens.append(token)
424
425 if new_tokens == old_tokens:
426 return
427
428 tolines = copy.copy(lines)
429
430 if new_tokens:
431 tolines[i] = start + ','.join(new_tokens) + end
432 else:
433 tolines.pop(i)
434
Simon Glassd9c1da22021-12-18 14:54:31 -0700435 show_diff(lines, tolines, defconfig_path, args.color)
Masahiro Yamadadce28de2016-07-25 19:15:29 +0900436
Simon Glassd9c1da22021-12-18 14:54:31 -0700437 if args.dry_run:
Masahiro Yamadadce28de2016-07-25 19:15:29 +0900438 return
439
440 with open(defconfig_path, 'w') as f:
441 for line in tolines:
442 f.write(line)
443
Simon Glassd9c1da22021-12-18 14:54:31 -0700444def cleanup_extra_options(configs, args):
Masahiro Yamadadce28de2016-07-25 19:15:29 +0900445 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in defconfig files.
446
447 Arguments:
448 configs: A list of CONFIGs to remove.
Simon Glassd9c1da22021-12-18 14:54:31 -0700449 args: program arguments
Masahiro Yamadadce28de2016-07-25 19:15:29 +0900450 """
Simon Glassd9c1da22021-12-18 14:54:31 -0700451 if not confirm(args, 'Clean up CONFIG_SYS_EXTRA_OPTIONS?'):
Chris Packham85e15c52017-05-02 21:30:46 +1200452 return
Masahiro Yamadadce28de2016-07-25 19:15:29 +0900453
454 configs = [ config[len('CONFIG_'):] for config in configs ]
455
456 defconfigs = get_all_defconfigs()
457
458 for defconfig in defconfigs:
459 cleanup_one_extra_option(os.path.join('configs', defconfig), configs,
Simon Glassd9c1da22021-12-18 14:54:31 -0700460 args)
Masahiro Yamadadce28de2016-07-25 19:15:29 +0900461
Simon Glassd9c1da22021-12-18 14:54:31 -0700462def cleanup_whitelist(configs, args):
Chris Packham9d5274f2017-05-02 21:30:47 +1200463 """Delete config whitelist entries
464
465 Arguments:
466 configs: A list of CONFIGs to remove.
Simon Glassd9c1da22021-12-18 14:54:31 -0700467 args: program arguments
Chris Packham9d5274f2017-05-02 21:30:47 +1200468 """
Simon Glassd9c1da22021-12-18 14:54:31 -0700469 if not confirm(args, 'Clean up whitelist entries?'):
Chris Packham9d5274f2017-05-02 21:30:47 +1200470 return
471
472 with open(os.path.join('scripts', 'config_whitelist.txt')) as f:
473 lines = f.readlines()
474
475 lines = [x for x in lines if x.strip() not in configs]
476
477 with open(os.path.join('scripts', 'config_whitelist.txt'), 'w') as f:
478 f.write(''.join(lines))
479
Chris Packham0e6deff2017-05-02 21:30:48 +1200480def find_matching(patterns, line):
481 for pat in patterns:
482 if pat.search(line):
483 return True
484 return False
485
Simon Glassd9c1da22021-12-18 14:54:31 -0700486def cleanup_readme(configs, args):
Chris Packham0e6deff2017-05-02 21:30:48 +1200487 """Delete config description in README
488
489 Arguments:
490 configs: A list of CONFIGs to remove.
Simon Glassd9c1da22021-12-18 14:54:31 -0700491 args: program arguments
Chris Packham0e6deff2017-05-02 21:30:48 +1200492 """
Simon Glassd9c1da22021-12-18 14:54:31 -0700493 if not confirm(args, 'Clean up README?'):
Chris Packham0e6deff2017-05-02 21:30:48 +1200494 return
495
496 patterns = []
497 for config in configs:
498 patterns.append(re.compile(r'^\s+%s' % config))
499
500 with open('README') as f:
501 lines = f.readlines()
502
503 found = False
504 newlines = []
505 for line in lines:
506 if not found:
507 found = find_matching(patterns, line)
508 if found:
509 continue
510
511 if found and re.search(r'^\s+CONFIG', line):
512 found = False
513
514 if not found:
515 newlines.append(line)
516
517 with open('README', 'w') as f:
518 f.write(''.join(newlines))
519
Markus Klotzbuecher3d5d4182019-05-15 15:15:52 +0200520def try_expand(line):
521 """If value looks like an expression, try expanding it
522 Otherwise just return the existing value
523 """
524 if line.find('=') == -1:
525 return line
526
527 try:
Markus Klotzbuecherbac0bb52020-02-12 20:46:44 +0100528 aeval = asteval.Interpreter( usersyms=SIZES, minimal=True )
Markus Klotzbuecher3d5d4182019-05-15 15:15:52 +0200529 cfg, val = re.split("=", line)
530 val= val.strip('\"')
Simon Glassdc634d92021-12-18 14:54:30 -0700531 if re.search(r'[*+-/]|<<|SZ_+|\(([^\)]+)\)', val):
Markus Klotzbuecherbac0bb52020-02-12 20:46:44 +0100532 newval = hex(aeval(val))
Simon Glassdc634d92021-12-18 14:54:30 -0700533 print('\tExpanded expression %s to %s' % (val, newval))
Markus Klotzbuecher3d5d4182019-05-15 15:15:52 +0200534 return cfg+'='+newval
535 except:
Simon Glassdc634d92021-12-18 14:54:30 -0700536 print('\tFailed to expand expression in %s' % line)
Markus Klotzbuecher3d5d4182019-05-15 15:15:52 +0200537
538 return line
539
Chris Packham9d5274f2017-05-02 21:30:47 +1200540
Masahiro Yamadab6160812015-05-20 11:36:07 +0900541### classes ###
Masahiro Yamadacefaa582016-05-19 15:51:55 +0900542class Progress:
543
544 """Progress Indicator"""
545
546 def __init__(self, total):
547 """Create a new progress indicator.
548
549 Arguments:
550 total: A number of defconfig files to process.
551 """
552 self.current = 0
553 self.total = total
554
555 def inc(self):
556 """Increment the number of processed defconfig files."""
557
558 self.current += 1
559
560 def show(self):
561 """Display the progress."""
Simon Glass1f701862019-10-31 07:42:57 -0600562 print(' %d defconfigs out of %d\r' % (self.current, self.total), end=' ')
Masahiro Yamadacefaa582016-05-19 15:51:55 +0900563 sys.stdout.flush()
564
Simon Glass44116332017-06-15 21:39:33 -0600565
566class KconfigScanner:
567 """Kconfig scanner."""
568
569 def __init__(self):
570 """Scan all the Kconfig files and create a Config object."""
571 # Define environment variables referenced from Kconfig
572 os.environ['srctree'] = os.getcwd()
573 os.environ['UBOOTVERSION'] = 'dummy'
574 os.environ['KCONFIG_OBJDIR'] = ''
Tom Rini3c5f4152019-09-20 17:42:09 -0400575 self.conf = kconfiglib.Kconfig()
Simon Glass44116332017-06-15 21:39:33 -0600576
577
Masahiro Yamadab6160812015-05-20 11:36:07 +0900578class KconfigParser:
579
580 """A parser of .config and include/autoconf.mk."""
581
582 re_arch = re.compile(r'CONFIG_SYS_ARCH="(.*)"')
583 re_cpu = re.compile(r'CONFIG_SYS_CPU="(.*)"')
584
Simon Glassd9c1da22021-12-18 14:54:31 -0700585 def __init__(self, configs, args, build_dir):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900586 """Create a new parser.
587
588 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900589 configs: A list of CONFIGs to move.
Simon Glassd9c1da22021-12-18 14:54:31 -0700590 args: program arguments
Masahiro Yamadab6160812015-05-20 11:36:07 +0900591 build_dir: Build directory.
592 """
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900593 self.configs = configs
Simon Glassd9c1da22021-12-18 14:54:31 -0700594 self.args = args
Masahiro Yamada5393b612016-05-19 15:52:00 +0900595 self.dotconfig = os.path.join(build_dir, '.config')
596 self.autoconf = os.path.join(build_dir, 'include', 'autoconf.mk')
Masahiro Yamada6d139172016-08-22 22:18:22 +0900597 self.spl_autoconf = os.path.join(build_dir, 'spl', 'include',
598 'autoconf.mk')
Simon Glass8fb5bd02017-06-01 19:39:01 -0600599 self.config_autoconf = os.path.join(build_dir, AUTO_CONF_PATH)
Masahiro Yamada07f98522016-05-19 15:52:06 +0900600 self.defconfig = os.path.join(build_dir, 'defconfig')
Masahiro Yamadab6160812015-05-20 11:36:07 +0900601
Simon Glass257f5232017-07-10 14:47:47 -0600602 def get_arch(self):
603 """Parse .config file and return the architecture.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900604
605 Returns:
Simon Glass257f5232017-07-10 14:47:47 -0600606 Architecture name (e.g. 'arm').
Masahiro Yamadab6160812015-05-20 11:36:07 +0900607 """
608 arch = ''
609 cpu = ''
Masahiro Yamada5393b612016-05-19 15:52:00 +0900610 for line in open(self.dotconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900611 m = self.re_arch.match(line)
612 if m:
613 arch = m.group(1)
614 continue
615 m = self.re_cpu.match(line)
616 if m:
617 cpu = m.group(1)
618
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900619 if not arch:
620 return None
Masahiro Yamadab6160812015-05-20 11:36:07 +0900621
622 # fix-up for aarch64
623 if arch == 'arm' and cpu == 'armv8':
624 arch = 'aarch64'
625
Simon Glass257f5232017-07-10 14:47:47 -0600626 return arch
Masahiro Yamadab6160812015-05-20 11:36:07 +0900627
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900628 def parse_one_config(self, config, dotconfig_lines, autoconf_lines):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900629 """Parse .config, defconfig, include/autoconf.mk for one config.
630
631 This function looks for the config options in the lines from
632 defconfig, .config, and include/autoconf.mk in order to decide
633 which action should be taken for this defconfig.
634
635 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900636 config: CONFIG name to parse.
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900637 dotconfig_lines: lines from the .config file.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900638 autoconf_lines: lines from the include/autoconf.mk file.
639
640 Returns:
641 A tupple of the action for this defconfig and the line
642 matched for the config.
643 """
Masahiro Yamadab6160812015-05-20 11:36:07 +0900644 not_set = '# %s is not set' % config
645
Masahiro Yamadab6160812015-05-20 11:36:07 +0900646 for line in autoconf_lines:
647 line = line.rstrip()
648 if line.startswith(config + '='):
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900649 new_val = line
Masahiro Yamadab6160812015-05-20 11:36:07 +0900650 break
Masahiro Yamadab6160812015-05-20 11:36:07 +0900651 else:
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900652 new_val = not_set
653
Markus Klotzbuecher3d5d4182019-05-15 15:15:52 +0200654 new_val = try_expand(new_val)
655
Masahiro Yamada35204d92016-08-22 22:18:21 +0900656 for line in dotconfig_lines:
657 line = line.rstrip()
658 if line.startswith(config + '=') or line == not_set:
659 old_val = line
660 break
661 else:
662 if new_val == not_set:
663 return (ACTION_NO_ENTRY, config)
664 else:
665 return (ACTION_NO_ENTRY_WARN, config)
666
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900667 # If this CONFIG is neither bool nor trisate
668 if old_val[-2:] != '=y' and old_val[-2:] != '=m' and old_val != not_set:
669 # tools/scripts/define2mk.sed changes '1' to 'y'.
670 # This is a problem if the CONFIG is int type.
671 # Check the type in Kconfig and handle it correctly.
672 if new_val[-2:] == '=y':
673 new_val = new_val[:-1] + '1'
674
Masahiro Yamadab48387f2016-06-15 14:33:50 +0900675 return (ACTION_NO_CHANGE if old_val == new_val else ACTION_MOVE,
676 new_val)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900677
Masahiro Yamada465b7c02016-05-19 15:52:02 +0900678 def update_dotconfig(self):
Masahiro Yamada7c0d9d22016-05-19 15:51:50 +0900679 """Parse files for the config options and update the .config.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900680
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900681 This function parses the generated .config and include/autoconf.mk
682 searching the target options.
Masahiro Yamada7c0d9d22016-05-19 15:51:50 +0900683 Move the config option(s) to the .config as needed.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900684
685 Arguments:
686 defconfig: defconfig name.
Masahiro Yamada69e2bbc2016-05-19 15:52:01 +0900687
688 Returns:
Masahiro Yamada263d1372016-05-19 15:52:04 +0900689 Return a tuple of (updated flag, log string).
690 The "updated flag" is True if the .config was updated, False
691 otherwise. The "log string" shows what happend to the .config.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900692 """
693
Masahiro Yamadab6160812015-05-20 11:36:07 +0900694 results = []
Masahiro Yamada263d1372016-05-19 15:52:04 +0900695 updated = False
Masahiro Yamada35204d92016-08-22 22:18:21 +0900696 suspicious = False
Masahiro Yamada6d139172016-08-22 22:18:22 +0900697 rm_files = [self.config_autoconf, self.autoconf]
698
Simon Glassd9c1da22021-12-18 14:54:31 -0700699 if self.args.spl:
Masahiro Yamada6d139172016-08-22 22:18:22 +0900700 if os.path.exists(self.spl_autoconf):
701 autoconf_path = self.spl_autoconf
702 rm_files.append(self.spl_autoconf)
703 else:
704 for f in rm_files:
705 os.remove(f)
706 return (updated, suspicious,
Simon Glassd9c1da22021-12-18 14:54:31 -0700707 color_text(self.args.color, COLOR_BROWN,
Masahiro Yamada6d139172016-08-22 22:18:22 +0900708 "SPL is not enabled. Skipped.") + '\n')
709 else:
710 autoconf_path = self.autoconf
Masahiro Yamadab6160812015-05-20 11:36:07 +0900711
Masahiro Yamada5393b612016-05-19 15:52:00 +0900712 with open(self.dotconfig) as f:
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900713 dotconfig_lines = f.readlines()
Masahiro Yamadab6160812015-05-20 11:36:07 +0900714
Masahiro Yamada6d139172016-08-22 22:18:22 +0900715 with open(autoconf_path) as f:
Masahiro Yamadab6160812015-05-20 11:36:07 +0900716 autoconf_lines = f.readlines()
717
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900718 for config in self.configs:
719 result = self.parse_one_config(config, dotconfig_lines,
Joe Hershberger166edec2015-05-19 13:21:17 -0500720 autoconf_lines)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900721 results.append(result)
722
723 log = ''
724
725 for (action, value) in results:
726 if action == ACTION_MOVE:
727 actlog = "Move '%s'" % value
728 log_color = COLOR_LIGHT_GREEN
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900729 elif action == ACTION_NO_ENTRY:
Simon Glassdc634d92021-12-18 14:54:30 -0700730 actlog = '%s is not defined in Kconfig. Do nothing.' % value
Masahiro Yamadab6160812015-05-20 11:36:07 +0900731 log_color = COLOR_LIGHT_BLUE
Masahiro Yamada35204d92016-08-22 22:18:21 +0900732 elif action == ACTION_NO_ENTRY_WARN:
Simon Glassdc634d92021-12-18 14:54:30 -0700733 actlog = '%s is not defined in Kconfig (suspicious). Do nothing.' % value
Masahiro Yamada35204d92016-08-22 22:18:21 +0900734 log_color = COLOR_YELLOW
735 suspicious = True
Masahiro Yamada5643d6e2016-05-19 15:51:56 +0900736 elif action == ACTION_NO_CHANGE:
737 actlog = "'%s' is the same as the define in Kconfig. Do nothing." \
738 % value
Masahiro Yamadab6160812015-05-20 11:36:07 +0900739 log_color = COLOR_LIGHT_PURPLE
Masahiro Yamada6d139172016-08-22 22:18:22 +0900740 elif action == ACTION_SPL_NOT_EXIST:
Simon Glassdc634d92021-12-18 14:54:30 -0700741 actlog = 'SPL is not enabled for this defconfig. Skip.'
Masahiro Yamada6d139172016-08-22 22:18:22 +0900742 log_color = COLOR_PURPLE
Masahiro Yamadab6160812015-05-20 11:36:07 +0900743 else:
Simon Glassdc634d92021-12-18 14:54:30 -0700744 sys.exit('Internal Error. This should not happen.')
Masahiro Yamadab6160812015-05-20 11:36:07 +0900745
Simon Glassd9c1da22021-12-18 14:54:31 -0700746 log += color_text(self.args.color, log_color, actlog) + '\n'
Masahiro Yamadab6160812015-05-20 11:36:07 +0900747
Masahiro Yamada5393b612016-05-19 15:52:00 +0900748 with open(self.dotconfig, 'a') as f:
Masahiro Yamada953d93b2016-05-19 15:51:49 +0900749 for (action, value) in results:
750 if action == ACTION_MOVE:
751 f.write(value + '\n')
Masahiro Yamada263d1372016-05-19 15:52:04 +0900752 updated = True
Masahiro Yamadab6160812015-05-20 11:36:07 +0900753
Masahiro Yamada07f98522016-05-19 15:52:06 +0900754 self.results = results
Masahiro Yamada6d139172016-08-22 22:18:22 +0900755 for f in rm_files:
756 os.remove(f)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900757
Masahiro Yamada35204d92016-08-22 22:18:21 +0900758 return (updated, suspicious, log)
Masahiro Yamada69e2bbc2016-05-19 15:52:01 +0900759
Masahiro Yamada07f98522016-05-19 15:52:06 +0900760 def check_defconfig(self):
761 """Check the defconfig after savedefconfig
762
763 Returns:
764 Return additional log if moved CONFIGs were removed again by
765 'make savedefconfig'.
766 """
767
768 log = ''
769
770 with open(self.defconfig) as f:
771 defconfig_lines = f.readlines()
772
773 for (action, value) in self.results:
774 if action != ACTION_MOVE:
775 continue
776 if not value + '\n' in defconfig_lines:
Simon Glassd9c1da22021-12-18 14:54:31 -0700777 log += color_text(self.args.color, COLOR_YELLOW,
Masahiro Yamada07f98522016-05-19 15:52:06 +0900778 "'%s' was removed by savedefconfig.\n" %
779 value)
780
781 return log
782
Simon Glass43cf08f2017-06-01 19:39:02 -0600783
784class DatabaseThread(threading.Thread):
785 """This thread processes results from Slot threads.
786
787 It collects the data in the master config directary. There is only one
788 result thread, and this helps to serialise the build output.
789 """
790 def __init__(self, config_db, db_queue):
791 """Set up a new result thread
792
793 Args:
794 builder: Builder which will be sent each result
795 """
796 threading.Thread.__init__(self)
797 self.config_db = config_db
798 self.db_queue= db_queue
799
800 def run(self):
801 """Called to start up the result thread.
802
803 We collect the next result job and pass it on to the build.
804 """
805 while True:
806 defconfig, configs = self.db_queue.get()
807 self.config_db[defconfig] = configs
808 self.db_queue.task_done()
809
810
Masahiro Yamadab6160812015-05-20 11:36:07 +0900811class Slot:
812
813 """A slot to store a subprocess.
814
815 Each instance of this class handles one subprocess.
816 This class is useful to control multiple threads
817 for faster processing.
818 """
819
Simon Glassd9c1da22021-12-18 14:54:31 -0700820 def __init__(self, toolchains, configs, args, progress, devnull,
Simon Glass257f5232017-07-10 14:47:47 -0600821 make_cmd, reference_src_dir, db_queue):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900822 """Create a new process slot.
823
824 Arguments:
Simon Glass257f5232017-07-10 14:47:47 -0600825 toolchains: Toolchains object containing toolchains.
Masahiro Yamadab80a6672016-05-19 15:51:57 +0900826 configs: A list of CONFIGs to move.
Simon Glassd9c1da22021-12-18 14:54:31 -0700827 args: Program arguments
Masahiro Yamadacefaa582016-05-19 15:51:55 +0900828 progress: A progress indicator.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900829 devnull: A file object of '/dev/null'.
830 make_cmd: command name of GNU Make.
Joe Hershbergerb1a570f2016-06-10 14:53:32 -0500831 reference_src_dir: Determine the true starting config state from this
832 source tree.
Simon Glass43cf08f2017-06-01 19:39:02 -0600833 db_queue: output queue to write config info for the database
Masahiro Yamadab6160812015-05-20 11:36:07 +0900834 """
Simon Glass257f5232017-07-10 14:47:47 -0600835 self.toolchains = toolchains
Simon Glassd9c1da22021-12-18 14:54:31 -0700836 self.args = args
Masahiro Yamadacefaa582016-05-19 15:51:55 +0900837 self.progress = progress
Masahiro Yamadab6160812015-05-20 11:36:07 +0900838 self.build_dir = tempfile.mkdtemp()
839 self.devnull = devnull
840 self.make_cmd = (make_cmd, 'O=' + self.build_dir)
Joe Hershbergerb1a570f2016-06-10 14:53:32 -0500841 self.reference_src_dir = reference_src_dir
Simon Glass43cf08f2017-06-01 19:39:02 -0600842 self.db_queue = db_queue
Simon Glassd9c1da22021-12-18 14:54:31 -0700843 self.parser = KconfigParser(configs, args, self.build_dir)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900844 self.state = STATE_IDLE
Masahiro Yamada1271b672016-08-22 22:18:20 +0900845 self.failed_boards = set()
846 self.suspicious_boards = set()
Masahiro Yamadab6160812015-05-20 11:36:07 +0900847
848 def __del__(self):
849 """Delete the working directory
850
851 This function makes sure the temporary directory is cleaned away
852 even if Python suddenly dies due to error. It should be done in here
Joe Hershberger640de872016-06-10 14:53:29 -0500853 because it is guaranteed the destructor is always invoked when the
Masahiro Yamadab6160812015-05-20 11:36:07 +0900854 instance of the class gets unreferenced.
855
856 If the subprocess is still running, wait until it finishes.
857 """
858 if self.state != STATE_IDLE:
859 while self.ps.poll() == None:
860 pass
861 shutil.rmtree(self.build_dir)
862
Masahiro Yamadacefaa582016-05-19 15:51:55 +0900863 def add(self, defconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +0900864 """Assign a new subprocess for defconfig and add it to the slot.
865
866 If the slot is vacant, create a new subprocess for processing the
867 given defconfig and add it to the slot. Just returns False if
868 the slot is occupied (i.e. the current subprocess is still running).
869
870 Arguments:
871 defconfig: defconfig name.
872
873 Returns:
874 Return True on success or False on failure
875 """
876 if self.state != STATE_IDLE:
877 return False
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900878
Masahiro Yamadab6160812015-05-20 11:36:07 +0900879 self.defconfig = defconfig
Masahiro Yamada465b7c02016-05-19 15:52:02 +0900880 self.log = ''
Masahiro Yamada8f5256a2016-06-15 14:33:52 +0900881 self.current_src_dir = self.reference_src_dir
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900882 self.do_defconfig()
Masahiro Yamadab6160812015-05-20 11:36:07 +0900883 return True
884
885 def poll(self):
886 """Check the status of the subprocess and handle it as needed.
887
888 Returns True if the slot is vacant (i.e. in idle state).
889 If the configuration is successfully finished, assign a new
890 subprocess to build include/autoconf.mk.
891 If include/autoconf.mk is generated, invoke the parser to
Masahiro Yamada263d1372016-05-19 15:52:04 +0900892 parse the .config and the include/autoconf.mk, moving
893 config options to the .config as needed.
894 If the .config was updated, run "make savedefconfig" to sync
895 it, update the original defconfig, and then set the slot back
896 to the idle state.
Masahiro Yamadab6160812015-05-20 11:36:07 +0900897
898 Returns:
899 Return True if the subprocess is terminated, False otherwise
900 """
901 if self.state == STATE_IDLE:
902 return True
903
904 if self.ps.poll() == None:
905 return False
906
907 if self.ps.poll() != 0:
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900908 self.handle_error()
909 elif self.state == STATE_DEFCONFIG:
Masahiro Yamada8f5256a2016-06-15 14:33:52 +0900910 if self.reference_src_dir and not self.current_src_dir:
Joe Hershbergerb1a570f2016-06-10 14:53:32 -0500911 self.do_savedefconfig()
912 else:
913 self.do_autoconf()
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900914 elif self.state == STATE_AUTOCONF:
Masahiro Yamada8f5256a2016-06-15 14:33:52 +0900915 if self.current_src_dir:
916 self.current_src_dir = None
Joe Hershbergerb1a570f2016-06-10 14:53:32 -0500917 self.do_defconfig()
Simon Glassd9c1da22021-12-18 14:54:31 -0700918 elif self.args.build_db:
Simon Glass43cf08f2017-06-01 19:39:02 -0600919 self.do_build_db()
Joe Hershbergerb1a570f2016-06-10 14:53:32 -0500920 else:
921 self.do_savedefconfig()
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900922 elif self.state == STATE_SAVEDEFCONFIG:
923 self.update_defconfig()
924 else:
Simon Glassdc634d92021-12-18 14:54:30 -0700925 sys.exit('Internal Error. This should not happen.')
Masahiro Yamadab6160812015-05-20 11:36:07 +0900926
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900927 return True if self.state == STATE_IDLE else False
Joe Hershberger166edec2015-05-19 13:21:17 -0500928
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900929 def handle_error(self):
930 """Handle error cases."""
Masahiro Yamada83c17672016-05-19 15:52:08 +0900931
Simon Glassd9c1da22021-12-18 14:54:31 -0700932 self.log += color_text(self.args.color, COLOR_LIGHT_RED,
Simon Glassdc634d92021-12-18 14:54:30 -0700933 'Failed to process.\n')
Simon Glassd9c1da22021-12-18 14:54:31 -0700934 if self.args.verbose:
935 self.log += color_text(self.args.color, COLOR_LIGHT_CYAN,
Markus Klotzbuecher8773f352020-02-12 20:46:45 +0100936 self.ps.stderr.read().decode())
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900937 self.finish(False)
Joe Hershberger166edec2015-05-19 13:21:17 -0500938
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900939 def do_defconfig(self):
940 """Run 'make <board>_defconfig' to create the .config file."""
Masahiro Yamada0f6beda2016-05-19 15:52:07 +0900941
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900942 cmd = list(self.make_cmd)
943 cmd.append(self.defconfig)
944 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Masahiro Yamada8f5256a2016-06-15 14:33:52 +0900945 stderr=subprocess.PIPE,
946 cwd=self.current_src_dir)
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900947 self.state = STATE_DEFCONFIG
Masahiro Yamada0f6beda2016-05-19 15:52:07 +0900948
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900949 def do_autoconf(self):
Simon Glass8fb5bd02017-06-01 19:39:01 -0600950 """Run 'make AUTO_CONF_PATH'."""
Masahiro Yamadab6160812015-05-20 11:36:07 +0900951
Simon Glass257f5232017-07-10 14:47:47 -0600952 arch = self.parser.get_arch()
953 try:
954 toolchain = self.toolchains.Select(arch)
955 except ValueError:
Simon Glassd9c1da22021-12-18 14:54:31 -0700956 self.log += color_text(self.args.color, COLOR_YELLOW,
Chris Packham1ebcbd12017-08-27 20:00:51 +1200957 "Tool chain for '%s' is missing. Do nothing.\n" % arch)
Masahiro Yamada274a5ee2016-05-19 15:52:03 +0900958 self.finish(False)
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900959 return
Simon Glass1f701862019-10-31 07:42:57 -0600960 env = toolchain.MakeEnvironment(False)
Masahiro Yamadac4d76eb2016-05-19 15:51:53 +0900961
Masahiro Yamadab6160812015-05-20 11:36:07 +0900962 cmd = list(self.make_cmd)
Joe Hershberger765442b2015-05-19 13:21:18 -0500963 cmd.append('KCONFIG_IGNORE_DUPLICATES=1')
Simon Glass8fb5bd02017-06-01 19:39:01 -0600964 cmd.append(AUTO_CONF_PATH)
Simon Glass257f5232017-07-10 14:47:47 -0600965 self.ps = subprocess.Popen(cmd, stdout=self.devnull, env=env,
Masahiro Yamada8f5256a2016-06-15 14:33:52 +0900966 stderr=subprocess.PIPE,
967 cwd=self.current_src_dir)
Masahiro Yamadab6160812015-05-20 11:36:07 +0900968 self.state = STATE_AUTOCONF
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900969
Simon Glass43cf08f2017-06-01 19:39:02 -0600970 def do_build_db(self):
971 """Add the board to the database"""
972 configs = {}
973 with open(os.path.join(self.build_dir, AUTO_CONF_PATH)) as fd:
974 for line in fd.readlines():
975 if line.startswith('CONFIG'):
976 config, value = line.split('=', 1)
977 configs[config] = value.rstrip()
978 self.db_queue.put([self.defconfig, configs])
979 self.finish(True)
980
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900981 def do_savedefconfig(self):
982 """Update the .config and run 'make savedefconfig'."""
983
Masahiro Yamada35204d92016-08-22 22:18:21 +0900984 (updated, suspicious, log) = self.parser.update_dotconfig()
985 if suspicious:
986 self.suspicious_boards.add(self.defconfig)
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900987 self.log += log
988
Simon Glassd9c1da22021-12-18 14:54:31 -0700989 if not self.args.force_sync and not updated:
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900990 self.finish(True)
991 return
992 if updated:
Simon Glassd9c1da22021-12-18 14:54:31 -0700993 self.log += color_text(self.args.color, COLOR_LIGHT_GREEN,
Simon Glassdc634d92021-12-18 14:54:30 -0700994 'Syncing by savedefconfig...\n')
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900995 else:
Simon Glassdc634d92021-12-18 14:54:30 -0700996 self.log += 'Syncing by savedefconfig (forced by option)...\n'
Masahiro Yamadacb256cb2016-06-08 11:47:37 +0900997
998 cmd = list(self.make_cmd)
999 cmd.append('savedefconfig')
1000 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
1001 stderr=subprocess.PIPE)
1002 self.state = STATE_SAVEDEFCONFIG
1003
1004 def update_defconfig(self):
1005 """Update the input defconfig and go back to the idle state."""
1006
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001007 log = self.parser.check_defconfig()
1008 if log:
Masahiro Yamada1271b672016-08-22 22:18:20 +09001009 self.suspicious_boards.add(self.defconfig)
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001010 self.log += log
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001011 orig_defconfig = os.path.join('configs', self.defconfig)
1012 new_defconfig = os.path.join(self.build_dir, 'defconfig')
1013 updated = not filecmp.cmp(orig_defconfig, new_defconfig)
1014
1015 if updated:
Simon Glassd9c1da22021-12-18 14:54:31 -07001016 self.log += color_text(self.args.color, COLOR_LIGHT_BLUE,
Simon Glassdc634d92021-12-18 14:54:30 -07001017 'defconfig was updated.\n')
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001018
Simon Glassd9c1da22021-12-18 14:54:31 -07001019 if not self.args.dry_run and updated:
Masahiro Yamadacb256cb2016-06-08 11:47:37 +09001020 shutil.move(new_defconfig, orig_defconfig)
1021 self.finish(True)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001022
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001023 def finish(self, success):
1024 """Display log along with progress and go to the idle state.
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001025
1026 Arguments:
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001027 success: Should be True when the defconfig was processed
1028 successfully, or False when it fails.
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001029 """
1030 # output at least 30 characters to hide the "* defconfigs out of *".
1031 log = self.defconfig.ljust(30) + '\n'
1032
1033 log += '\n'.join([ ' ' + s for s in self.log.split('\n') ])
1034 # Some threads are running in parallel.
1035 # Print log atomically to not mix up logs from different threads.
Simon Glass1f701862019-10-31 07:42:57 -06001036 print(log, file=(sys.stdout if success else sys.stderr))
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001037
1038 if not success:
Simon Glassd9c1da22021-12-18 14:54:31 -07001039 if self.args.exit_on_error:
Simon Glassdc634d92021-12-18 14:54:30 -07001040 sys.exit('Exit on error.')
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001041 # If --exit-on-error flag is not set, skip this board and continue.
1042 # Record the failed board.
Masahiro Yamada1271b672016-08-22 22:18:20 +09001043 self.failed_boards.add(self.defconfig)
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001044
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001045 self.progress.inc()
1046 self.progress.show()
Masahiro Yamada274a5ee2016-05-19 15:52:03 +09001047 self.state = STATE_IDLE
Masahiro Yamada465b7c02016-05-19 15:52:02 +09001048
Masahiro Yamadab6160812015-05-20 11:36:07 +09001049 def get_failed_boards(self):
Masahiro Yamada1271b672016-08-22 22:18:20 +09001050 """Returns a set of failed boards (defconfigs) in this slot.
Masahiro Yamadab6160812015-05-20 11:36:07 +09001051 """
1052 return self.failed_boards
1053
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001054 def get_suspicious_boards(self):
Masahiro Yamada1271b672016-08-22 22:18:20 +09001055 """Returns a set of boards (defconfigs) with possible misconversion.
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001056 """
Masahiro Yamada35204d92016-08-22 22:18:21 +09001057 return self.suspicious_boards - self.failed_boards
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001058
Masahiro Yamadab6160812015-05-20 11:36:07 +09001059class Slots:
1060
1061 """Controller of the array of subprocess slots."""
1062
Simon Glassd9c1da22021-12-18 14:54:31 -07001063 def __init__(self, toolchains, configs, args, progress,
Simon Glass257f5232017-07-10 14:47:47 -06001064 reference_src_dir, db_queue):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001065 """Create a new slots controller.
1066
1067 Arguments:
Simon Glass257f5232017-07-10 14:47:47 -06001068 toolchains: Toolchains object containing toolchains.
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001069 configs: A list of CONFIGs to move.
Simon Glassd9c1da22021-12-18 14:54:31 -07001070 args: Program arguments
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001071 progress: A progress indicator.
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001072 reference_src_dir: Determine the true starting config state from this
1073 source tree.
Simon Glass43cf08f2017-06-01 19:39:02 -06001074 db_queue: output queue to write config info for the database
Masahiro Yamadab6160812015-05-20 11:36:07 +09001075 """
Simon Glassd9c1da22021-12-18 14:54:31 -07001076 self.args = args
Masahiro Yamadab6160812015-05-20 11:36:07 +09001077 self.slots = []
Simon Glass34c505f2021-12-18 14:54:32 -07001078 devnull = subprocess.DEVNULL
Masahiro Yamadab6160812015-05-20 11:36:07 +09001079 make_cmd = get_make_cmd()
Simon Glassd9c1da22021-12-18 14:54:31 -07001080 for i in range(args.jobs):
1081 self.slots.append(Slot(toolchains, configs, args, progress,
Simon Glass257f5232017-07-10 14:47:47 -06001082 devnull, make_cmd, reference_src_dir,
1083 db_queue))
Masahiro Yamadab6160812015-05-20 11:36:07 +09001084
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001085 def add(self, defconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001086 """Add a new subprocess if a vacant slot is found.
1087
1088 Arguments:
1089 defconfig: defconfig name to be put into.
1090
1091 Returns:
1092 Return True on success or False on failure
1093 """
1094 for slot in self.slots:
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001095 if slot.add(defconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001096 return True
1097 return False
1098
1099 def available(self):
1100 """Check if there is a vacant slot.
1101
1102 Returns:
1103 Return True if at lease one vacant slot is found, False otherwise.
1104 """
1105 for slot in self.slots:
1106 if slot.poll():
1107 return True
1108 return False
1109
1110 def empty(self):
1111 """Check if all slots are vacant.
1112
1113 Returns:
1114 Return True if all the slots are vacant, False otherwise.
1115 """
1116 ret = True
1117 for slot in self.slots:
1118 if not slot.poll():
1119 ret = False
1120 return ret
1121
1122 def show_failed_boards(self):
1123 """Display all of the failed boards (defconfigs)."""
Masahiro Yamada1271b672016-08-22 22:18:20 +09001124 boards = set()
Masahiro Yamada0153f032016-06-15 14:33:53 +09001125 output_file = 'moveconfig.failed'
Masahiro Yamadab6160812015-05-20 11:36:07 +09001126
1127 for slot in self.slots:
Masahiro Yamada1271b672016-08-22 22:18:20 +09001128 boards |= slot.get_failed_boards()
Masahiro Yamadab6160812015-05-20 11:36:07 +09001129
Masahiro Yamada0153f032016-06-15 14:33:53 +09001130 if boards:
1131 boards = '\n'.join(boards) + '\n'
Simon Glassdc634d92021-12-18 14:54:30 -07001132 msg = 'The following boards were not processed due to error:\n'
Masahiro Yamada0153f032016-06-15 14:33:53 +09001133 msg += boards
Simon Glassdc634d92021-12-18 14:54:30 -07001134 msg += '(the list has been saved in %s)\n' % output_file
Simon Glassd9c1da22021-12-18 14:54:31 -07001135 print(color_text(self.args.color, COLOR_LIGHT_RED,
Simon Glass1f701862019-10-31 07:42:57 -06001136 msg), file=sys.stderr)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001137
Masahiro Yamada0153f032016-06-15 14:33:53 +09001138 with open(output_file, 'w') as f:
1139 f.write(boards)
Joe Hershbergerdade12e2015-05-19 13:21:22 -05001140
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001141 def show_suspicious_boards(self):
1142 """Display all boards (defconfigs) with possible misconversion."""
Masahiro Yamada1271b672016-08-22 22:18:20 +09001143 boards = set()
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001144 output_file = 'moveconfig.suspicious'
1145
1146 for slot in self.slots:
Masahiro Yamada1271b672016-08-22 22:18:20 +09001147 boards |= slot.get_suspicious_boards()
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001148
1149 if boards:
1150 boards = '\n'.join(boards) + '\n'
Simon Glassdc634d92021-12-18 14:54:30 -07001151 msg = 'The following boards might have been converted incorrectly.\n'
1152 msg += 'It is highly recommended to check them manually:\n'
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001153 msg += boards
Simon Glassdc634d92021-12-18 14:54:30 -07001154 msg += '(the list has been saved in %s)\n' % output_file
Simon Glassd9c1da22021-12-18 14:54:31 -07001155 print(color_text(self.args.color, COLOR_YELLOW,
Simon Glass1f701862019-10-31 07:42:57 -06001156 msg), file=sys.stderr)
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001157
1158 with open(output_file, 'w') as f:
1159 f.write(boards)
1160
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001161class ReferenceSource:
1162
1163 """Reference source against which original configs should be parsed."""
1164
1165 def __init__(self, commit):
1166 """Create a reference source directory based on a specified commit.
1167
1168 Arguments:
1169 commit: commit to git-clone
1170 """
1171 self.src_dir = tempfile.mkdtemp()
Simon Glassdc634d92021-12-18 14:54:30 -07001172 print('Cloning git repo to a separate work directory...')
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001173 subprocess.check_output(['git', 'clone', os.getcwd(), '.'],
1174 cwd=self.src_dir)
Simon Glass1f701862019-10-31 07:42:57 -06001175 print("Checkout '%s' to build the original autoconf.mk." % \
1176 subprocess.check_output(['git', 'rev-parse', '--short', commit]).strip())
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001177 subprocess.check_output(['git', 'checkout', commit],
1178 stderr=subprocess.STDOUT, cwd=self.src_dir)
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001179
1180 def __del__(self):
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001181 """Delete the reference source directory
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001182
1183 This function makes sure the temporary directory is cleaned away
1184 even if Python suddenly dies due to error. It should be done in here
1185 because it is guaranteed the destructor is always invoked when the
1186 instance of the class gets unreferenced.
1187 """
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001188 shutil.rmtree(self.src_dir)
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001189
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001190 def get_dir(self):
1191 """Return the absolute path to the reference source directory."""
1192
1193 return self.src_dir
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001194
Simon Glassd9c1da22021-12-18 14:54:31 -07001195def move_config(toolchains, configs, args, db_queue):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001196 """Move config options to defconfig files.
1197
1198 Arguments:
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001199 configs: A list of CONFIGs to move.
Simon Glassd9c1da22021-12-18 14:54:31 -07001200 args: Program arguments
Masahiro Yamadab6160812015-05-20 11:36:07 +09001201 """
Masahiro Yamadab80a6672016-05-19 15:51:57 +09001202 if len(configs) == 0:
Simon Glassd9c1da22021-12-18 14:54:31 -07001203 if args.force_sync:
Simon Glass1f701862019-10-31 07:42:57 -06001204 print('No CONFIG is specified. You are probably syncing defconfigs.', end=' ')
Simon Glassd9c1da22021-12-18 14:54:31 -07001205 elif args.build_db:
Simon Glass1f701862019-10-31 07:42:57 -06001206 print('Building %s database' % CONFIG_DATABASE)
Masahiro Yamada9566abd2016-05-19 15:52:09 +09001207 else:
Simon Glass1f701862019-10-31 07:42:57 -06001208 print('Neither CONFIG nor --force-sync is specified. Nothing will happen.', end=' ')
Masahiro Yamada9566abd2016-05-19 15:52:09 +09001209 else:
Simon Glass1f701862019-10-31 07:42:57 -06001210 print('Move ' + ', '.join(configs), end=' ')
Simon Glassd9c1da22021-12-18 14:54:31 -07001211 print('(jobs: %d)\n' % args.jobs)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001212
Simon Glassd9c1da22021-12-18 14:54:31 -07001213 if args.git_ref:
1214 reference_src = ReferenceSource(args.git_ref)
Masahiro Yamada2e74fee2016-06-15 14:33:51 +09001215 reference_src_dir = reference_src.get_dir()
1216 else:
Masahiro Yamada8f5256a2016-06-15 14:33:52 +09001217 reference_src_dir = None
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001218
Simon Glassd9c1da22021-12-18 14:54:31 -07001219 if args.defconfigs:
1220 defconfigs = get_matched_defconfigs(args.defconfigs)
Joe Hershbergerc6e043a2015-05-19 13:21:19 -05001221 else:
Masahiro Yamada58175e32016-07-25 19:15:28 +09001222 defconfigs = get_all_defconfigs()
Masahiro Yamadab6160812015-05-20 11:36:07 +09001223
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001224 progress = Progress(len(defconfigs))
Simon Glassd9c1da22021-12-18 14:54:31 -07001225 slots = Slots(toolchains, configs, args, progress, reference_src_dir,
Simon Glass257f5232017-07-10 14:47:47 -06001226 db_queue)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001227
1228 # Main loop to process defconfig files:
1229 # Add a new subprocess into a vacant slot.
1230 # Sleep if there is no available slot.
Masahiro Yamadacefaa582016-05-19 15:51:55 +09001231 for defconfig in defconfigs:
1232 while not slots.add(defconfig):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001233 while not slots.available():
1234 # No available slot: sleep for a while
1235 time.sleep(SLEEP_TIME)
1236
1237 # wait until all the subprocesses finish
1238 while not slots.empty():
1239 time.sleep(SLEEP_TIME)
1240
Simon Glass1f701862019-10-31 07:42:57 -06001241 print('')
Masahiro Yamadab6160812015-05-20 11:36:07 +09001242 slots.show_failed_boards()
Masahiro Yamada3c9bfea2016-06-15 14:33:54 +09001243 slots.show_suspicious_boards()
Masahiro Yamadab6160812015-05-20 11:36:07 +09001244
Simon Glass44116332017-06-15 21:39:33 -06001245def find_kconfig_rules(kconf, config, imply_config):
1246 """Check whether a config has a 'select' or 'imply' keyword
1247
1248 Args:
Tom Rini3c5f4152019-09-20 17:42:09 -04001249 kconf: Kconfiglib.Kconfig object
Simon Glass44116332017-06-15 21:39:33 -06001250 config: Name of config to check (without CONFIG_ prefix)
1251 imply_config: Implying config (without CONFIG_ prefix) which may or
1252 may not have an 'imply' for 'config')
1253
1254 Returns:
1255 Symbol object for 'config' if found, else None
1256 """
Tom Rini3c5f4152019-09-20 17:42:09 -04001257 sym = kconf.syms.get(imply_config)
Simon Glass44116332017-06-15 21:39:33 -06001258 if sym:
Simon Glass520b47a2021-07-21 21:35:53 -06001259 for sel, cond in (sym.selects + sym.implies):
Simon Glass93c0a9e2021-12-18 08:09:42 -07001260 if sel.name == config:
Simon Glass44116332017-06-15 21:39:33 -06001261 return sym
1262 return None
1263
1264def check_imply_rule(kconf, config, imply_config):
1265 """Check if we can add an 'imply' option
1266
1267 This finds imply_config in the Kconfig and looks to see if it is possible
1268 to add an 'imply' for 'config' to that part of the Kconfig.
1269
1270 Args:
Tom Rini3c5f4152019-09-20 17:42:09 -04001271 kconf: Kconfiglib.Kconfig object
Simon Glass44116332017-06-15 21:39:33 -06001272 config: Name of config to check (without CONFIG_ prefix)
1273 imply_config: Implying config (without CONFIG_ prefix) which may or
1274 may not have an 'imply' for 'config')
1275
1276 Returns:
1277 tuple:
1278 filename of Kconfig file containing imply_config, or None if none
1279 line number within the Kconfig file, or 0 if none
1280 message indicating the result
1281 """
Tom Rini3c5f4152019-09-20 17:42:09 -04001282 sym = kconf.syms.get(imply_config)
Simon Glass44116332017-06-15 21:39:33 -06001283 if not sym:
1284 return 'cannot find sym'
Simon Glass520b47a2021-07-21 21:35:53 -06001285 nodes = sym.nodes
1286 if len(nodes) != 1:
1287 return '%d locations' % len(nodes)
Simon Glass93c0a9e2021-12-18 08:09:42 -07001288 node = nodes[0]
1289 fname, linenum = node.filename, node.linenr
Simon Glass44116332017-06-15 21:39:33 -06001290 cwd = os.getcwd()
1291 if cwd and fname.startswith(cwd):
1292 fname = fname[len(cwd) + 1:]
1293 file_line = ' at %s:%d' % (fname, linenum)
1294 with open(fname) as fd:
1295 data = fd.read().splitlines()
1296 if data[linenum - 1] != 'config %s' % imply_config:
1297 return None, 0, 'bad sym format %s%s' % (data[linenum], file_line)
1298 return fname, linenum, 'adding%s' % file_line
1299
1300def add_imply_rule(config, fname, linenum):
1301 """Add a new 'imply' option to a Kconfig
1302
1303 Args:
1304 config: config option to add an imply for (without CONFIG_ prefix)
1305 fname: Kconfig filename to update
1306 linenum: Line number to place the 'imply' before
1307
1308 Returns:
1309 Message indicating the result
1310 """
1311 file_line = ' at %s:%d' % (fname, linenum)
1312 data = open(fname).read().splitlines()
1313 linenum -= 1
1314
1315 for offset, line in enumerate(data[linenum:]):
1316 if line.strip().startswith('help') or not line:
1317 data.insert(linenum + offset, '\timply %s' % config)
1318 with open(fname, 'w') as fd:
1319 fd.write('\n'.join(data) + '\n')
1320 return 'added%s' % file_line
1321
1322 return 'could not insert%s'
1323
1324(IMPLY_MIN_2, IMPLY_TARGET, IMPLY_CMD, IMPLY_NON_ARCH_BOARD) = (
1325 1, 2, 4, 8)
Simon Glass92e55582017-06-15 21:39:32 -06001326
1327IMPLY_FLAGS = {
1328 'min2': [IMPLY_MIN_2, 'Show options which imply >2 boards (normally >5)'],
1329 'target': [IMPLY_TARGET, 'Allow CONFIG_TARGET_... options to imply'],
1330 'cmd': [IMPLY_CMD, 'Allow CONFIG_CMD_... to imply'],
Simon Glass44116332017-06-15 21:39:33 -06001331 'non-arch-board': [
1332 IMPLY_NON_ARCH_BOARD,
1333 'Allow Kconfig options outside arch/ and /board/ to imply'],
Simon Glass92e55582017-06-15 21:39:32 -06001334};
1335
Simon Glassf931c2f2021-12-18 08:09:43 -07001336
1337def read_database():
1338 """Read in the config database
1339
1340 Returns:
1341 tuple:
1342 set of all config options seen (each a str)
1343 set of all defconfigs seen (each a str)
1344 dict of configs for each defconfig:
1345 key: defconfig name, e.g. "MPC8548CDS_legacy_defconfig"
1346 value: dict:
1347 key: CONFIG option
1348 value: Value of option
1349 dict of defconfigs for each config:
1350 key: CONFIG option
1351 value: set of boards using that option
1352
1353 """
1354 configs = {}
1355
1356 # key is defconfig name, value is dict of (CONFIG_xxx, value)
1357 config_db = {}
1358
1359 # Set of all config options we have seen
1360 all_configs = set()
1361
1362 # Set of all defconfigs we have seen
1363 all_defconfigs = set()
1364
1365 defconfig_db = collections.defaultdict(set)
1366 with open(CONFIG_DATABASE) as fd:
1367 for line in fd.readlines():
1368 line = line.rstrip()
1369 if not line: # Separator between defconfigs
1370 config_db[defconfig] = configs
1371 all_defconfigs.add(defconfig)
1372 configs = {}
1373 elif line[0] == ' ': # CONFIG line
1374 config, value = line.strip().split('=', 1)
1375 configs[config] = value
1376 defconfig_db[config].add(defconfig)
1377 all_configs.add(config)
1378 else: # New defconfig
1379 defconfig = line
1380
1381 return all_configs, all_defconfigs, config_db, defconfig_db
1382
1383
Simon Glass44116332017-06-15 21:39:33 -06001384def do_imply_config(config_list, add_imply, imply_flags, skip_added,
1385 check_kconfig=True, find_superset=False):
Simon Glassc6e73cf2017-06-01 19:39:03 -06001386 """Find CONFIG options which imply those in the list
1387
1388 Some CONFIG options can be implied by others and this can help to reduce
1389 the size of the defconfig files. For example, CONFIG_X86 implies
1390 CONFIG_CMD_IRQ, so we can put 'imply CMD_IRQ' under 'config X86' and
1391 all x86 boards will have that option, avoiding adding CONFIG_CMD_IRQ to
1392 each of the x86 defconfig files.
1393
1394 This function uses the moveconfig database to find such options. It
1395 displays a list of things that could possibly imply those in the list.
1396 The algorithm ignores any that start with CONFIG_TARGET since these
1397 typically refer to only a few defconfigs (often one). It also does not
1398 display a config with less than 5 defconfigs.
1399
1400 The algorithm works using sets. For each target config in config_list:
1401 - Get the set 'defconfigs' which use that target config
1402 - For each config (from a list of all configs):
1403 - Get the set 'imply_defconfig' of defconfigs which use that config
1404 -
1405 - If imply_defconfigs contains anything not in defconfigs then
1406 this config does not imply the target config
1407
1408 Params:
1409 config_list: List of CONFIG options to check (each a string)
Simon Glass44116332017-06-15 21:39:33 -06001410 add_imply: Automatically add an 'imply' for each config.
Simon Glass92e55582017-06-15 21:39:32 -06001411 imply_flags: Flags which control which implying configs are allowed
1412 (IMPLY_...)
Simon Glass44116332017-06-15 21:39:33 -06001413 skip_added: Don't show options which already have an imply added.
1414 check_kconfig: Check if implied symbols already have an 'imply' or
1415 'select' for the target config, and show this information if so.
Simon Glassc6e73cf2017-06-01 19:39:03 -06001416 find_superset: True to look for configs which are a superset of those
1417 already found. So for example if CONFIG_EXYNOS5 implies an option,
1418 but CONFIG_EXYNOS covers a larger set of defconfigs and also
1419 implies that option, this will drop the former in favour of the
1420 latter. In practice this option has not proved very used.
1421
1422 Note the terminoloy:
1423 config - a CONFIG_XXX options (a string, e.g. 'CONFIG_CMD_EEPROM')
1424 defconfig - a defconfig file (a string, e.g. 'configs/snow_defconfig')
1425 """
Simon Glass44116332017-06-15 21:39:33 -06001426 kconf = KconfigScanner().conf if check_kconfig else None
1427 if add_imply and add_imply != 'all':
Simon Glass93c0a9e2021-12-18 08:09:42 -07001428 add_imply = add_imply.split(',')
Simon Glass44116332017-06-15 21:39:33 -06001429
Simon Glassf931c2f2021-12-18 08:09:43 -07001430 all_configs, all_defconfigs, config_db, defconfig_db = read_database()
Simon Glassc6e73cf2017-06-01 19:39:03 -06001431
Simon Glass93c0a9e2021-12-18 08:09:42 -07001432 # Work through each target config option in turn, independently
Simon Glassc6e73cf2017-06-01 19:39:03 -06001433 for config in config_list:
1434 defconfigs = defconfig_db.get(config)
1435 if not defconfigs:
Simon Glass1f701862019-10-31 07:42:57 -06001436 print('%s not found in any defconfig' % config)
Simon Glassc6e73cf2017-06-01 19:39:03 -06001437 continue
1438
1439 # Get the set of defconfigs without this one (since a config cannot
1440 # imply itself)
1441 non_defconfigs = all_defconfigs - defconfigs
1442 num_defconfigs = len(defconfigs)
Simon Glass1f701862019-10-31 07:42:57 -06001443 print('%s found in %d/%d defconfigs' % (config, num_defconfigs,
1444 len(all_configs)))
Simon Glassc6e73cf2017-06-01 19:39:03 -06001445
1446 # This will hold the results: key=config, value=defconfigs containing it
1447 imply_configs = {}
1448 rest_configs = all_configs - set([config])
1449
1450 # Look at every possible config, except the target one
1451 for imply_config in rest_configs:
Simon Glass92e55582017-06-15 21:39:32 -06001452 if 'ERRATUM' in imply_config:
Simon Glassc6e73cf2017-06-01 19:39:03 -06001453 continue
Simon Glass92e55582017-06-15 21:39:32 -06001454 if not (imply_flags & IMPLY_CMD):
1455 if 'CONFIG_CMD' in imply_config:
1456 continue
1457 if not (imply_flags & IMPLY_TARGET):
1458 if 'CONFIG_TARGET' in imply_config:
1459 continue
Simon Glassc6e73cf2017-06-01 19:39:03 -06001460
1461 # Find set of defconfigs that have this config
1462 imply_defconfig = defconfig_db[imply_config]
1463
1464 # Get the intersection of this with defconfigs containing the
1465 # target config
1466 common_defconfigs = imply_defconfig & defconfigs
1467
1468 # Get the set of defconfigs containing this config which DO NOT
1469 # also contain the taret config. If this set is non-empty it means
1470 # that this config affects other defconfigs as well as (possibly)
1471 # the ones affected by the target config. This means it implies
1472 # things we don't want to imply.
1473 not_common_defconfigs = imply_defconfig & non_defconfigs
1474 if not_common_defconfigs:
1475 continue
1476
1477 # If there are common defconfigs, imply_config may be useful
1478 if common_defconfigs:
1479 skip = False
1480 if find_superset:
Simon Glass1f701862019-10-31 07:42:57 -06001481 for prev in list(imply_configs.keys()):
Simon Glassc6e73cf2017-06-01 19:39:03 -06001482 prev_count = len(imply_configs[prev])
1483 count = len(common_defconfigs)
1484 if (prev_count > count and
1485 (imply_configs[prev] & common_defconfigs ==
1486 common_defconfigs)):
1487 # skip imply_config because prev is a superset
1488 skip = True
1489 break
1490 elif count > prev_count:
1491 # delete prev because imply_config is a superset
1492 del imply_configs[prev]
1493 if not skip:
1494 imply_configs[imply_config] = common_defconfigs
1495
1496 # Now we have a dict imply_configs of configs which imply each config
1497 # The value of each dict item is the set of defconfigs containing that
1498 # config. Rank them so that we print the configs that imply the largest
1499 # number of defconfigs first.
Simon Glass44116332017-06-15 21:39:33 -06001500 ranked_iconfigs = sorted(imply_configs,
Simon Glassc6e73cf2017-06-01 19:39:03 -06001501 key=lambda k: len(imply_configs[k]), reverse=True)
Simon Glass44116332017-06-15 21:39:33 -06001502 kconfig_info = ''
1503 cwd = os.getcwd()
1504 add_list = collections.defaultdict(list)
1505 for iconfig in ranked_iconfigs:
1506 num_common = len(imply_configs[iconfig])
Simon Glassc6e73cf2017-06-01 19:39:03 -06001507
1508 # Don't bother if there are less than 5 defconfigs affected.
Simon Glass92e55582017-06-15 21:39:32 -06001509 if num_common < (2 if imply_flags & IMPLY_MIN_2 else 5):
Simon Glassc6e73cf2017-06-01 19:39:03 -06001510 continue
Simon Glass44116332017-06-15 21:39:33 -06001511 missing = defconfigs - imply_configs[iconfig]
Simon Glassc6e73cf2017-06-01 19:39:03 -06001512 missing_str = ', '.join(missing) if missing else 'all'
1513 missing_str = ''
Simon Glass44116332017-06-15 21:39:33 -06001514 show = True
1515 if kconf:
1516 sym = find_kconfig_rules(kconf, config[CONFIG_LEN:],
1517 iconfig[CONFIG_LEN:])
1518 kconfig_info = ''
1519 if sym:
Simon Glass520b47a2021-07-21 21:35:53 -06001520 nodes = sym.nodes
1521 if len(nodes) == 1:
1522 fname, linenum = nodes[0].filename, nodes[0].linenr
Simon Glass44116332017-06-15 21:39:33 -06001523 if cwd and fname.startswith(cwd):
1524 fname = fname[len(cwd) + 1:]
1525 kconfig_info = '%s:%d' % (fname, linenum)
1526 if skip_added:
1527 show = False
1528 else:
Tom Rini3c5f4152019-09-20 17:42:09 -04001529 sym = kconf.syms.get(iconfig[CONFIG_LEN:])
Simon Glass44116332017-06-15 21:39:33 -06001530 fname = ''
1531 if sym:
Simon Glass520b47a2021-07-21 21:35:53 -06001532 nodes = sym.nodes
1533 if len(nodes) == 1:
1534 fname, linenum = nodes[0].filename, nodes[0].linenr
Simon Glass44116332017-06-15 21:39:33 -06001535 if cwd and fname.startswith(cwd):
1536 fname = fname[len(cwd) + 1:]
1537 in_arch_board = not sym or (fname.startswith('arch') or
1538 fname.startswith('board'))
1539 if (not in_arch_board and
1540 not (imply_flags & IMPLY_NON_ARCH_BOARD)):
1541 continue
1542
1543 if add_imply and (add_imply == 'all' or
1544 iconfig in add_imply):
1545 fname, linenum, kconfig_info = (check_imply_rule(kconf,
1546 config[CONFIG_LEN:], iconfig[CONFIG_LEN:]))
1547 if fname:
1548 add_list[fname].append(linenum)
Simon Glassc6e73cf2017-06-01 19:39:03 -06001549
Simon Glass44116332017-06-15 21:39:33 -06001550 if show and kconfig_info != 'skip':
Simon Glass1f701862019-10-31 07:42:57 -06001551 print('%5d : %-30s%-25s %s' % (num_common, iconfig.ljust(30),
1552 kconfig_info, missing_str))
Simon Glass44116332017-06-15 21:39:33 -06001553
1554 # Having collected a list of things to add, now we add them. We process
1555 # each file from the largest line number to the smallest so that
1556 # earlier additions do not affect our line numbers. E.g. if we added an
1557 # imply at line 20 it would change the position of each line after
1558 # that.
Simon Glass1f701862019-10-31 07:42:57 -06001559 for fname, linenums in add_list.items():
Simon Glass44116332017-06-15 21:39:33 -06001560 for linenum in sorted(linenums, reverse=True):
1561 add_imply_rule(config[CONFIG_LEN:], fname, linenum)
1562
Simon Glassc6e73cf2017-06-01 19:39:03 -06001563
Simon Glass0082b2e2021-12-18 08:09:46 -07001564def do_find_config(config_list):
1565 """Find boards with a given combination of CONFIGs
1566
1567 Params:
1568 config_list: List of CONFIG options to check (each a string consisting
1569 of a config option, with or without a CONFIG_ prefix. If an option
1570 is preceded by a tilde (~) then it must be false, otherwise it must
1571 be true)
1572 """
1573 all_configs, all_defconfigs, config_db, defconfig_db = read_database()
1574
1575 # Get the whitelist
1576 with open('scripts/config_whitelist.txt') as inf:
1577 adhoc_configs = set(inf.read().splitlines())
1578
1579 # Start with all defconfigs
1580 out = all_defconfigs
1581
1582 # Work through each config in turn
1583 adhoc = []
1584 for item in config_list:
1585 # Get the real config name and whether we want this config or not
1586 cfg = item
1587 want = True
1588 if cfg[0] == '~':
1589 want = False
1590 cfg = cfg[1:]
1591
1592 if cfg in adhoc_configs:
1593 adhoc.append(cfg)
1594 continue
1595
1596 # Search everything that is still in the running. If it has a config
1597 # that we want, or doesn't have one that we don't, add it into the
1598 # running for the next stage
1599 in_list = out
1600 out = set()
1601 for defc in in_list:
1602 has_cfg = cfg in config_db[defc]
1603 if has_cfg == want:
1604 out.add(defc)
1605 if adhoc:
1606 print(f"Error: Not in Kconfig: %s" % ' '.join(adhoc))
1607 else:
1608 print(f'{len(out)} matches')
1609 print(' '.join(out))
1610
1611
1612def prefix_config(cfg):
1613 """Prefix a config with CONFIG_ if needed
1614
1615 This handles ~ operator, which indicates that the CONFIG should be disabled
1616
1617 >>> prefix_config('FRED')
1618 'CONFIG_FRED'
1619 >>> prefix_config('CONFIG_FRED')
1620 'CONFIG_FRED'
1621 >>> prefix_config('~FRED')
1622 '~CONFIG_FRED'
1623 >>> prefix_config('~CONFIG_FRED')
1624 '~CONFIG_FRED'
1625 >>> prefix_config('A123')
1626 'CONFIG_A123'
1627 """
1628 op = ''
1629 if cfg[0] == '~':
1630 op = cfg[0]
1631 cfg = cfg[1:]
1632 if not cfg.startswith('CONFIG_'):
1633 cfg = 'CONFIG_' + cfg
1634 return op + cfg
1635
1636
Masahiro Yamadab6160812015-05-20 11:36:07 +09001637def main():
1638 try:
1639 cpu_count = multiprocessing.cpu_count()
1640 except NotImplementedError:
1641 cpu_count = 1
1642
Simon Glassd9c1da22021-12-18 14:54:31 -07001643 epilog = '''Move config options from headers to defconfig files. See
1644doc/develop/moveconfig.rst for documentation.'''
1645
1646 parser = ArgumentParser(epilog=epilog)
1647 # Add arguments here
1648 parser.add_argument('-a', '--add-imply', type=str, default='',
Simon Glass44116332017-06-15 21:39:33 -06001649 help='comma-separated list of CONFIG options to add '
1650 "an 'imply' statement to for the CONFIG in -i")
Simon Glassd9c1da22021-12-18 14:54:31 -07001651 parser.add_argument('-A', '--skip-added', action='store_true', default=False,
Simon Glass44116332017-06-15 21:39:33 -06001652 help="don't show options which are already marked as "
1653 'implying others')
Simon Glassd9c1da22021-12-18 14:54:31 -07001654 parser.add_argument('-b', '--build-db', action='store_true', default=False,
Simon Glass43cf08f2017-06-01 19:39:02 -06001655 help='build a CONFIG database')
Simon Glassd9c1da22021-12-18 14:54:31 -07001656 parser.add_argument('-c', '--color', action='store_true', default=False,
Masahiro Yamadab6160812015-05-20 11:36:07 +09001657 help='display the log in color')
Simon Glassd9c1da22021-12-18 14:54:31 -07001658 parser.add_argument('-C', '--commit', action='store_true', default=False,
Simon Glass8bf41c22016-09-12 23:18:21 -06001659 help='Create a git commit for the operation')
Simon Glassd9c1da22021-12-18 14:54:31 -07001660 parser.add_argument('-d', '--defconfigs', type=str,
Simon Glass8f3cf312017-06-01 19:38:59 -06001661 help='a file containing a list of defconfigs to move, '
1662 "one per line (for example 'snow_defconfig') "
1663 "or '-' to read from stdin")
Simon Glassd9c1da22021-12-18 14:54:31 -07001664 parser.add_argument('-e', '--exit-on-error', action='store_true',
Masahiro Yamadab6160812015-05-20 11:36:07 +09001665 default=False,
1666 help='exit immediately on any error')
Simon Glassd9c1da22021-12-18 14:54:31 -07001667 parser.add_argument('-f', '--find', action='store_true', default=False,
Simon Glass0082b2e2021-12-18 08:09:46 -07001668 help='Find boards with a given config combination')
Simon Glassd9c1da22021-12-18 14:54:31 -07001669 parser.add_argument('-H', '--headers-only', dest='cleanup_headers_only',
Joe Hershberger23475932015-05-19 13:21:20 -05001670 action='store_true', default=False,
1671 help='only cleanup the headers')
Simon Glassd9c1da22021-12-18 14:54:31 -07001672 parser.add_argument('-i', '--imply', action='store_true', default=False,
Simon Glass0559a742021-12-18 08:09:44 -07001673 help='find options which imply others')
Simon Glassd9c1da22021-12-18 14:54:31 -07001674 parser.add_argument('-I', '--imply-flags', type=str, default='',
Simon Glass0559a742021-12-18 08:09:44 -07001675 help="control the -i option ('help' for help")
Simon Glassd9c1da22021-12-18 14:54:31 -07001676 parser.add_argument('-j', '--jobs', type=int, default=cpu_count,
Masahiro Yamadab6160812015-05-20 11:36:07 +09001677 help='the number of jobs to run simultaneously')
Simon Glassd9c1da22021-12-18 14:54:31 -07001678 parser.add_argument('-n', '--dry-run', action='store_true', default=False,
Simon Glass0559a742021-12-18 08:09:44 -07001679 help='perform a trial run (show log with no changes)')
Simon Glassd9c1da22021-12-18 14:54:31 -07001680 parser.add_argument('-r', '--git-ref', type=str,
Joe Hershbergerb1a570f2016-06-10 14:53:32 -05001681 help='the git ref to clone for building the autoconf.mk')
Simon Glassd9c1da22021-12-18 14:54:31 -07001682 parser.add_argument('-s', '--force-sync', action='store_true', default=False,
Simon Glass0559a742021-12-18 08:09:44 -07001683 help='force sync by savedefconfig')
Simon Glassd9c1da22021-12-18 14:54:31 -07001684 parser.add_argument('-S', '--spl', action='store_true', default=False,
Simon Glass0559a742021-12-18 08:09:44 -07001685 help='parse config options defined for SPL build')
Simon Glassd9c1da22021-12-18 14:54:31 -07001686 parser.add_argument('-t', '--test', action='store_true', default=False,
Simon Glass0559a742021-12-18 08:09:44 -07001687 help='run unit tests')
Simon Glassd9c1da22021-12-18 14:54:31 -07001688 parser.add_argument('-y', '--yes', action='store_true', default=False,
Simon Glass13e05a02016-09-12 23:18:20 -06001689 help="respond 'yes' to any prompts")
Simon Glassd9c1da22021-12-18 14:54:31 -07001690 parser.add_argument('-v', '--verbose', action='store_true', default=False,
Joe Hershberger808b63f2015-05-19 13:21:24 -05001691 help='show any build errors as boards are built')
Simon Glassd9c1da22021-12-18 14:54:31 -07001692 parser.add_argument('configs', nargs='*')
Masahiro Yamadab6160812015-05-20 11:36:07 +09001693
Simon Glassd9c1da22021-12-18 14:54:31 -07001694 args = parser.parse_args()
1695 configs = args.configs
Masahiro Yamadab6160812015-05-20 11:36:07 +09001696
Simon Glassd9c1da22021-12-18 14:54:31 -07001697 if args.test:
Simon Glassbb57be72021-12-18 08:09:45 -07001698 sys.argv = [sys.argv[0]]
1699 fail, count = doctest.testmod()
1700 if fail:
1701 return 1
1702 unittest.main()
1703
Simon Glassd9c1da22021-12-18 14:54:31 -07001704 if not any((len(configs), args.force_sync, args.build_db, args.imply,
1705 args.find)):
Masahiro Yamadab6160812015-05-20 11:36:07 +09001706 parser.print_usage()
1707 sys.exit(1)
1708
Masahiro Yamadab903c4e2016-05-19 15:51:58 +09001709 # prefix the option name with CONFIG_ if missing
Simon Glass0082b2e2021-12-18 08:09:46 -07001710 configs = [prefix_config(cfg) for cfg in configs]
Masahiro Yamadab6160812015-05-20 11:36:07 +09001711
Joe Hershberger23475932015-05-19 13:21:20 -05001712 check_top_directory()
1713
Simon Glassd9c1da22021-12-18 14:54:31 -07001714 if args.imply:
Simon Glass92e55582017-06-15 21:39:32 -06001715 imply_flags = 0
Simon Glassd9c1da22021-12-18 14:54:31 -07001716 if args.imply_flags == 'all':
Simon Glass5f096922017-07-10 14:47:46 -06001717 imply_flags = -1
1718
Simon Glassd9c1da22021-12-18 14:54:31 -07001719 elif args.imply_flags:
1720 for flag in args.imply_flags.split(','):
Simon Glass5f096922017-07-10 14:47:46 -06001721 bad = flag not in IMPLY_FLAGS
1722 if bad:
Simon Glass1f701862019-10-31 07:42:57 -06001723 print("Invalid flag '%s'" % flag)
Simon Glass5f096922017-07-10 14:47:46 -06001724 if flag == 'help' or bad:
Simon Glass1f701862019-10-31 07:42:57 -06001725 print("Imply flags: (separate with ',')")
1726 for name, info in IMPLY_FLAGS.items():
1727 print(' %-15s: %s' % (name, info[1]))
Simon Glass5f096922017-07-10 14:47:46 -06001728 parser.print_usage()
1729 sys.exit(1)
1730 imply_flags |= IMPLY_FLAGS[flag][0]
Simon Glass92e55582017-06-15 21:39:32 -06001731
Simon Glassd9c1da22021-12-18 14:54:31 -07001732 do_imply_config(configs, args.add_imply, imply_flags, args.skip_added)
Simon Glassc6e73cf2017-06-01 19:39:03 -06001733 return
1734
Simon Glassd9c1da22021-12-18 14:54:31 -07001735 if args.find:
Simon Glass0082b2e2021-12-18 08:09:46 -07001736 do_find_config(configs)
1737 return
1738
Simon Glass43cf08f2017-06-01 19:39:02 -06001739 config_db = {}
Simon Glass1f701862019-10-31 07:42:57 -06001740 db_queue = queue.Queue()
Simon Glass43cf08f2017-06-01 19:39:02 -06001741 t = DatabaseThread(config_db, db_queue)
1742 t.setDaemon(True)
1743 t.start()
1744
Simon Glassd9c1da22021-12-18 14:54:31 -07001745 if not args.cleanup_headers_only:
Masahiro Yamadad0a9d2a2016-07-25 19:15:23 +09001746 check_clean_directory()
Simon Glass1f701862019-10-31 07:42:57 -06001747 bsettings.Setup('')
Simon Glass257f5232017-07-10 14:47:47 -06001748 toolchains = toolchain.Toolchains()
1749 toolchains.GetSettings()
1750 toolchains.Scan(verbose=False)
Simon Glassd9c1da22021-12-18 14:54:31 -07001751 move_config(toolchains, configs, args, db_queue)
Simon Glass43cf08f2017-06-01 19:39:02 -06001752 db_queue.join()
Joe Hershberger23475932015-05-19 13:21:20 -05001753
Masahiro Yamada9566abd2016-05-19 15:52:09 +09001754 if configs:
Simon Glassd9c1da22021-12-18 14:54:31 -07001755 cleanup_headers(configs, args)
1756 cleanup_extra_options(configs, args)
1757 cleanup_whitelist(configs, args)
1758 cleanup_readme(configs, args)
Masahiro Yamadab6160812015-05-20 11:36:07 +09001759
Simon Glassd9c1da22021-12-18 14:54:31 -07001760 if args.commit:
Simon Glass8bf41c22016-09-12 23:18:21 -06001761 subprocess.call(['git', 'add', '-u'])
1762 if configs:
1763 msg = 'Convert %s %sto Kconfig' % (configs[0],
1764 'et al ' if len(configs) > 1 else '')
1765 msg += ('\n\nThis converts the following to Kconfig:\n %s\n' %
1766 '\n '.join(configs))
1767 else:
1768 msg = 'configs: Resync with savedefconfig'
1769 msg += '\n\nRsync all defconfig files using moveconfig.py'
1770 subprocess.call(['git', 'commit', '-s', '-m', msg])
1771
Simon Glassd9c1da22021-12-18 14:54:31 -07001772 if args.build_db:
Simon Glass43cf08f2017-06-01 19:39:02 -06001773 with open(CONFIG_DATABASE, 'w') as fd:
Simon Glass1f701862019-10-31 07:42:57 -06001774 for defconfig, configs in config_db.items():
Simon Glass1c879312017-08-13 16:02:54 -06001775 fd.write('%s\n' % defconfig)
Simon Glass43cf08f2017-06-01 19:39:02 -06001776 for config in sorted(configs.keys()):
Simon Glass1c879312017-08-13 16:02:54 -06001777 fd.write(' %s=%s\n' % (config, configs[config]))
1778 fd.write('\n')
Simon Glass43cf08f2017-06-01 19:39:02 -06001779
Masahiro Yamadab6160812015-05-20 11:36:07 +09001780if __name__ == '__main__':
Simon Glass0082b2e2021-12-18 08:09:46 -07001781 sys.exit(main())