blob: 00101ba43d8d589190619d9010eebe90fc596830 [file] [log] [blame]
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001#!/usr/bin/env python2
2#
3# Author: Masahiro Yamada <yamada.masahiro@socionext.com>
4#
5# SPDX-License-Identifier: GPL-2.0+
6#
7
8"""
9Move config options from headers to defconfig files.
10
11Since Kconfig was introduced to U-Boot, we have worked on moving
12config options from headers to Kconfig (defconfig).
13
14This tool intends to help this tremendous work.
15
16
17Usage
18-----
19
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090020First, you must edit the Kconfig to add the menu entries for the configs
Joe Hershberger96464ba2015-05-19 13:21:17 -050021you are moving.
22
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090023And then run this tool giving CONFIG names you want to move.
24For example, if you want to move CONFIG_CMD_USB and CONFIG_SYS_TEXT_BASE,
25simply type as follows:
Masahiro Yamada5a27c732015-05-20 11:36:07 +090026
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090027 $ tools/moveconfig.py CONFIG_CMD_USB CONFIG_SYS_TEXT_BASE
Masahiro Yamada5a27c732015-05-20 11:36:07 +090028
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090029The tool walks through all the defconfig files and move the given CONFIGs.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090030
31The log is also displayed on the terminal.
32
Masahiro Yamada1d085562016-05-19 15:52:02 +090033The log is printed for each defconfig as follows:
Masahiro Yamada5a27c732015-05-20 11:36:07 +090034
Masahiro Yamada1d085562016-05-19 15:52:02 +090035<defconfig_name>
36 <action1>
37 <action2>
38 <action3>
39 ...
Masahiro Yamada5a27c732015-05-20 11:36:07 +090040
Masahiro Yamada1d085562016-05-19 15:52:02 +090041<defconfig_name> is the name of the defconfig.
42
43<action*> shows what the tool did for that defconfig.
Masahiro Yamadac21fc7e2016-08-21 16:12:36 +090044It looks like one of the following:
Masahiro Yamada5a27c732015-05-20 11:36:07 +090045
46 - Move 'CONFIG_... '
47 This config option was moved to the defconfig
48
Masahiro Yamadacc008292016-05-19 15:51:56 +090049 - CONFIG_... is not defined in Kconfig. Do nothing.
Masahiro Yamada916224c2016-08-22 22:18:21 +090050 The entry for this CONFIG was not found in Kconfig. The option is not
51 defined in the config header, either. So, this case can be just skipped.
52
53 - CONFIG_... is not defined in Kconfig (suspicious). Do nothing.
54 This option is defined in the config header, but its entry was not found
55 in Kconfig.
Masahiro Yamadacc008292016-05-19 15:51:56 +090056 There are two common cases:
57 - You forgot to create an entry for the CONFIG before running
58 this tool, or made a typo in a CONFIG passed to this tool.
59 - The entry was hidden due to unmet 'depends on'.
Masahiro Yamada916224c2016-08-22 22:18:21 +090060 The tool does not know if the result is reasonable, so please check it
61 manually.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090062
Masahiro Yamadacc008292016-05-19 15:51:56 +090063 - 'CONFIG_...' is the same as the define in Kconfig. Do nothing.
64 The define in the config header matched the one in Kconfig.
65 We do not need to touch it.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090066
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +090067 - Compiler is missing. Do nothing.
68 The compiler specified for this architecture was not found
69 in your PATH environment.
70 (If -e option is passed, the tool exits immediately.)
71
72 - Failed to process.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090073 An error occurred during processing this defconfig. Skipped.
74 (If -e option is passed, the tool exits immediately on error.)
75
76Finally, you will be asked, Clean up headers? [y/n]:
77
78If you say 'y' here, the unnecessary config defines are removed
79from the config headers (include/configs/*.h).
80It just uses the regex method, so you should not rely on it.
81Just in case, please do 'git diff' to see what happened.
82
83
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090084How does it work?
85-----------------
Masahiro Yamada5a27c732015-05-20 11:36:07 +090086
87This tool runs configuration and builds include/autoconf.mk for every
88defconfig. The config options defined in Kconfig appear in the .config
89file (unless they are hidden because of unmet dependency.)
90On the other hand, the config options defined by board headers are seen
91in include/autoconf.mk. The tool looks for the specified options in both
Masahiro Yamadab6ef3932016-05-19 15:51:58 +090092of them to decide the appropriate action for the options. If the given
93config option is found in the .config, but its value does not match the
94one from the board header, the config option in the .config is replaced
95with the define in the board header. Then, the .config is synced by
96"make savedefconfig" and the defconfig is updated with it.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090097
98For faster processing, this tool handles multi-threading. It creates
99separate build directories where the out-of-tree build is run. The
100temporary build directories are automatically created and deleted as
101needed. The number of threads are chosen based on the number of the CPU
102cores of your system although you can change it via -j (--jobs) option.
103
104
105Toolchains
106----------
107
108Appropriate toolchain are necessary to generate include/autoconf.mk
109for all the architectures supported by U-Boot. Most of them are available
110at the kernel.org site, some are not provided by kernel.org.
111
112The default per-arch CROSS_COMPILE used by this tool is specified by
113the list below, CROSS_COMPILE. You may wish to update the list to
114use your own. Instead of modifying the list directly, you can give
115them via environments.
116
117
Simon Glassddf91c62017-06-01 19:39:00 -0600118Tips and trips
119--------------
120
121To sync only X86 defconfigs:
122
123 ./tools/moveconfig.py -s -d <(grep -l X86 configs/*)
124
125or:
126
127 grep -l X86 configs/* | ./tools/moveconfig.py -s -d -
128
129To process CONFIG_CMD_FPGAD only for a subset of configs based on path match:
130
131 ls configs/{hrcon*,iocon*,strider*} | \
132 ./tools/moveconfig.py -Cy CONFIG_CMD_FPGAD -d -
133
134
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900135Available options
136-----------------
137
138 -c, --color
139 Surround each portion of the log with escape sequences to display it
140 in color on the terminal.
141
Simon Glass9ede2122016-09-12 23:18:21 -0600142 -C, --commit
143 Create a git commit with the changes when the operation is complete. A
144 standard commit message is used which may need to be edited.
145
Joe Hershberger91040e82015-05-19 13:21:19 -0500146 -d, --defconfigs
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900147 Specify a file containing a list of defconfigs to move. The defconfig
Simon Glassddf91c62017-06-01 19:39:00 -0600148 files can be given with shell-style wildcards. Use '-' to read from stdin.
Joe Hershberger91040e82015-05-19 13:21:19 -0500149
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900150 -n, --dry-run
Masahiro Yamadab6ef3932016-05-19 15:51:58 +0900151 Perform a trial run that does not make any changes. It is useful to
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900152 see what is going to happen before one actually runs it.
153
154 -e, --exit-on-error
155 Exit immediately if Make exits with a non-zero status while processing
156 a defconfig file.
157
Masahiro Yamada8513dc02016-05-19 15:52:08 +0900158 -s, --force-sync
159 Do "make savedefconfig" forcibly for all the defconfig files.
160 If not specified, "make savedefconfig" only occurs for cases
161 where at least one CONFIG was moved.
162
Masahiro Yamada07913d12016-08-22 22:18:22 +0900163 -S, --spl
164 Look for moved config options in spl/include/autoconf.mk instead of
165 include/autoconf.mk. This is useful for moving options for SPL build
166 because SPL related options (mostly prefixed with CONFIG_SPL_) are
167 sometimes blocked by CONFIG_SPL_BUILD ifdef conditionals.
168
Joe Hershberger2144f882015-05-19 13:21:20 -0500169 -H, --headers-only
170 Only cleanup the headers; skip the defconfig processing
171
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900172 -j, --jobs
173 Specify the number of threads to run simultaneously. If not specified,
174 the number of threads is the same as the number of CPU cores.
175
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500176 -r, --git-ref
177 Specify the git ref to clone for building the autoconf.mk. If unspecified
178 use the CWD. This is useful for when changes to the Kconfig affect the
179 default values and you want to capture the state of the defconfig from
180 before that change was in effect. If in doubt, specify a ref pre-Kconfig
181 changes (use HEAD if Kconfig changes are not committed). Worst case it will
182 take a bit longer to run, but will always do the right thing.
183
Joe Hershberger95bf9c72015-05-19 13:21:24 -0500184 -v, --verbose
185 Show any build errors as boards are built
186
Simon Glass6b403df2016-09-12 23:18:20 -0600187 -y, --yes
188 Instead of prompting, automatically go ahead with all operations. This
Simon Glassddf91c62017-06-01 19:39:00 -0600189 includes cleaning up headers, CONFIG_SYS_EXTRA_OPTIONS, the config whitelist
190 and the README.
Simon Glass6b403df2016-09-12 23:18:20 -0600191
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900192To see the complete list of supported options, run
193
194 $ tools/moveconfig.py -h
195
196"""
197
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900198import copy
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900199import difflib
Masahiro Yamadac8e1b102016-05-19 15:52:07 +0900200import filecmp
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900201import fnmatch
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900202import glob
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900203import multiprocessing
204import optparse
205import os
Simon Glassd73fcb12017-06-01 19:39:02 -0600206import Queue
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900207import re
208import shutil
209import subprocess
210import sys
211import tempfile
Simon Glassd73fcb12017-06-01 19:39:02 -0600212import threading
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900213import time
214
215SHOW_GNU_MAKE = 'scripts/show-gnu-make'
216SLEEP_TIME=0.03
217
218# Here is the list of cross-tools I use.
219# Most of them are available at kernel.org
Masahiro Yamadac21fc7e2016-08-21 16:12:36 +0900220# (https://www.kernel.org/pub/tools/crosstool/files/bin/), except the following:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900221# arc: https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain/releases
Bin Meng4440ece2015-09-25 01:22:39 -0700222# nds32: http://osdk.andestech.com/packages/nds32le-linux-glibc-v1.tgz
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900223# nios2: https://sourcery.mentor.com/GNUToolchain/subscription42545
224# sh: http://sourcery.mentor.com/public/gnu_toolchain/sh-linux-gnu
225CROSS_COMPILE = {
226 'arc': 'arc-linux-',
227 'aarch64': 'aarch64-linux-',
228 'arm': 'arm-unknown-linux-gnueabi-',
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900229 'm68k': 'm68k-linux-',
230 'microblaze': 'microblaze-linux-',
231 'mips': 'mips-linux-',
232 'nds32': 'nds32le-linux-',
233 'nios2': 'nios2-linux-gnu-',
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900234 'powerpc': 'powerpc-linux-',
235 'sh': 'sh-linux-gnu-',
Masahiro Yamada88e13462016-08-21 16:03:08 +0900236 'x86': 'i386-linux-',
237 'xtensa': 'xtensa-linux-'
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900238}
239
240STATE_IDLE = 0
241STATE_DEFCONFIG = 1
242STATE_AUTOCONF = 2
Joe Hershberger96464ba2015-05-19 13:21:17 -0500243STATE_SAVEDEFCONFIG = 3
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900244
245ACTION_MOVE = 0
Masahiro Yamadacc008292016-05-19 15:51:56 +0900246ACTION_NO_ENTRY = 1
Masahiro Yamada916224c2016-08-22 22:18:21 +0900247ACTION_NO_ENTRY_WARN = 2
248ACTION_NO_CHANGE = 3
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900249
250COLOR_BLACK = '0;30'
251COLOR_RED = '0;31'
252COLOR_GREEN = '0;32'
253COLOR_BROWN = '0;33'
254COLOR_BLUE = '0;34'
255COLOR_PURPLE = '0;35'
256COLOR_CYAN = '0;36'
257COLOR_LIGHT_GRAY = '0;37'
258COLOR_DARK_GRAY = '1;30'
259COLOR_LIGHT_RED = '1;31'
260COLOR_LIGHT_GREEN = '1;32'
261COLOR_YELLOW = '1;33'
262COLOR_LIGHT_BLUE = '1;34'
263COLOR_LIGHT_PURPLE = '1;35'
264COLOR_LIGHT_CYAN = '1;36'
265COLOR_WHITE = '1;37'
266
Simon Glassf3b8e642017-06-01 19:39:01 -0600267AUTO_CONF_PATH = 'include/config/auto.conf'
Simon Glassd73fcb12017-06-01 19:39:02 -0600268CONFIG_DATABASE = 'moveconfig.db'
Simon Glassf3b8e642017-06-01 19:39:01 -0600269
270
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900271### helper functions ###
272def get_devnull():
273 """Get the file object of '/dev/null' device."""
274 try:
275 devnull = subprocess.DEVNULL # py3k
276 except AttributeError:
277 devnull = open(os.devnull, 'wb')
278 return devnull
279
280def check_top_directory():
281 """Exit if we are not at the top of source directory."""
282 for f in ('README', 'Licenses'):
283 if not os.path.exists(f):
284 sys.exit('Please run at the top of source directory.')
285
Masahiro Yamadabd63e5b2016-05-19 15:51:54 +0900286def check_clean_directory():
287 """Exit if the source tree is not clean."""
288 for f in ('.config', 'include/config'):
289 if os.path.exists(f):
290 sys.exit("source tree is not clean, please run 'make mrproper'")
291
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900292def get_make_cmd():
293 """Get the command name of GNU Make.
294
295 U-Boot needs GNU Make for building, but the command name is not
296 necessarily "make". (for example, "gmake" on FreeBSD).
297 Returns the most appropriate command name on your system.
298 """
299 process = subprocess.Popen([SHOW_GNU_MAKE], stdout=subprocess.PIPE)
300 ret = process.communicate()
301 if process.returncode:
302 sys.exit('GNU Make not found')
303 return ret[0].rstrip()
304
Simon Glass25f978c2017-06-01 19:38:58 -0600305def get_matched_defconfig(line):
306 """Get the defconfig files that match a pattern
307
308 Args:
309 line: Path or filename to match, e.g. 'configs/snow_defconfig' or
310 'k2*_defconfig'. If no directory is provided, 'configs/' is
311 prepended
312
313 Returns:
314 a list of matching defconfig files
315 """
316 dirname = os.path.dirname(line)
317 if dirname:
318 pattern = line
319 else:
320 pattern = os.path.join('configs', line)
321 return glob.glob(pattern) + glob.glob(pattern + '_defconfig')
322
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900323def get_matched_defconfigs(defconfigs_file):
Simon Glassee4e61b2017-06-01 19:38:59 -0600324 """Get all the defconfig files that match the patterns in a file.
325
326 Args:
327 defconfigs_file: File containing a list of defconfigs to process, or
328 '-' to read the list from stdin
329
330 Returns:
331 A list of paths to defconfig files, with no duplicates
332 """
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900333 defconfigs = []
Simon Glassee4e61b2017-06-01 19:38:59 -0600334 if defconfigs_file == '-':
335 fd = sys.stdin
336 defconfigs_file = 'stdin'
337 else:
338 fd = open(defconfigs_file)
339 for i, line in enumerate(fd):
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900340 line = line.strip()
341 if not line:
342 continue # skip blank lines silently
Simon Glass25f978c2017-06-01 19:38:58 -0600343 matched = get_matched_defconfig(line)
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900344 if not matched:
345 print >> sys.stderr, "warning: %s:%d: no defconfig matched '%s'" % \
346 (defconfigs_file, i + 1, line)
347
348 defconfigs += matched
349
350 # use set() to drop multiple matching
351 return [ defconfig[len('configs') + 1:] for defconfig in set(defconfigs) ]
352
Masahiro Yamada684c3062016-07-25 19:15:28 +0900353def get_all_defconfigs():
354 """Get all the defconfig files under the configs/ directory."""
355 defconfigs = []
356 for (dirpath, dirnames, filenames) in os.walk('configs'):
357 dirpath = dirpath[len('configs') + 1:]
358 for filename in fnmatch.filter(filenames, '*_defconfig'):
359 defconfigs.append(os.path.join(dirpath, filename))
360
361 return defconfigs
362
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900363def color_text(color_enabled, color, string):
364 """Return colored string."""
365 if color_enabled:
Masahiro Yamada1d085562016-05-19 15:52:02 +0900366 # LF should not be surrounded by the escape sequence.
367 # Otherwise, additional whitespace or line-feed might be printed.
368 return '\n'.join([ '\033[' + color + 'm' + s + '\033[0m' if s else ''
369 for s in string.split('\n') ])
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900370 else:
371 return string
372
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900373def show_diff(a, b, file_path, color_enabled):
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900374 """Show unidified diff.
375
376 Arguments:
377 a: A list of lines (before)
378 b: A list of lines (after)
379 file_path: Path to the file
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900380 color_enabled: Display the diff in color
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900381 """
382
383 diff = difflib.unified_diff(a, b,
384 fromfile=os.path.join('a', file_path),
385 tofile=os.path.join('b', file_path))
386
387 for line in diff:
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900388 if line[0] == '-' and line[1] != '-':
389 print color_text(color_enabled, COLOR_RED, line),
390 elif line[0] == '+' and line[1] != '+':
391 print color_text(color_enabled, COLOR_GREEN, line),
392 else:
393 print line,
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900394
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900395def update_cross_compile(color_enabled):
Robert P. J. Day1cc0a9f2016-05-04 04:47:31 -0400396 """Update per-arch CROSS_COMPILE via environment variables
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900397
398 The default CROSS_COMPILE values are available
399 in the CROSS_COMPILE list above.
400
Robert P. J. Day1cc0a9f2016-05-04 04:47:31 -0400401 You can override them via environment variables
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900402 CROSS_COMPILE_{ARCH}.
403
404 For example, if you want to override toolchain prefixes
405 for ARM and PowerPC, you can do as follows in your shell:
406
407 export CROSS_COMPILE_ARM=...
408 export CROSS_COMPILE_POWERPC=...
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900409
410 Then, this function checks if specified compilers really exist in your
411 PATH environment.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900412 """
413 archs = []
414
415 for arch in os.listdir('arch'):
416 if os.path.exists(os.path.join('arch', arch, 'Makefile')):
417 archs.append(arch)
418
419 # arm64 is a special case
420 archs.append('aarch64')
421
422 for arch in archs:
423 env = 'CROSS_COMPILE_' + arch.upper()
424 cross_compile = os.environ.get(env)
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900425 if not cross_compile:
426 cross_compile = CROSS_COMPILE.get(arch, '')
427
428 for path in os.environ["PATH"].split(os.pathsep):
429 gcc_path = os.path.join(path, cross_compile + 'gcc')
430 if os.path.isfile(gcc_path) and os.access(gcc_path, os.X_OK):
431 break
432 else:
433 print >> sys.stderr, color_text(color_enabled, COLOR_YELLOW,
434 'warning: %sgcc: not found in PATH. %s architecture boards will be skipped'
435 % (cross_compile, arch))
436 cross_compile = None
437
438 CROSS_COMPILE[arch] = cross_compile
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900439
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900440def extend_matched_lines(lines, matched, pre_patterns, post_patterns, extend_pre,
441 extend_post):
442 """Extend matched lines if desired patterns are found before/after already
443 matched lines.
444
445 Arguments:
446 lines: A list of lines handled.
447 matched: A list of line numbers that have been already matched.
448 (will be updated by this function)
449 pre_patterns: A list of regular expression that should be matched as
450 preamble.
451 post_patterns: A list of regular expression that should be matched as
452 postamble.
453 extend_pre: Add the line number of matched preamble to the matched list.
454 extend_post: Add the line number of matched postamble to the matched list.
455 """
456 extended_matched = []
457
458 j = matched[0]
459
460 for i in matched:
461 if i == 0 or i < j:
462 continue
463 j = i
464 while j in matched:
465 j += 1
466 if j >= len(lines):
467 break
468
469 for p in pre_patterns:
470 if p.search(lines[i - 1]):
471 break
472 else:
473 # not matched
474 continue
475
476 for p in post_patterns:
477 if p.search(lines[j]):
478 break
479 else:
480 # not matched
481 continue
482
483 if extend_pre:
484 extended_matched.append(i - 1)
485 if extend_post:
486 extended_matched.append(j)
487
488 matched += extended_matched
489 matched.sort()
490
Chris Packham85edfc12017-05-02 21:30:46 +1200491def confirm(options, prompt):
492 if not options.yes:
493 while True:
494 choice = raw_input('{} [y/n]: '.format(prompt))
495 choice = choice.lower()
496 print choice
497 if choice == 'y' or choice == 'n':
498 break
499
500 if choice == 'n':
501 return False
502
503 return True
504
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900505def cleanup_one_header(header_path, patterns, options):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900506 """Clean regex-matched lines away from a file.
507
508 Arguments:
509 header_path: path to the cleaned file.
510 patterns: list of regex patterns. Any lines matching to these
511 patterns are deleted.
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900512 options: option flags.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900513 """
514 with open(header_path) as f:
515 lines = f.readlines()
516
517 matched = []
518 for i, line in enumerate(lines):
Masahiro Yamadaa3a779f2016-07-25 19:15:27 +0900519 if i - 1 in matched and lines[i - 1][-2:] == '\\\n':
520 matched.append(i)
521 continue
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900522 for pattern in patterns:
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900523 if pattern.search(line):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900524 matched.append(i)
525 break
526
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900527 if not matched:
528 return
529
530 # remove empty #ifdef ... #endif, successive blank lines
531 pattern_if = re.compile(r'#\s*if(def|ndef)?\W') # #if, #ifdef, #ifndef
532 pattern_elif = re.compile(r'#\s*el(if|se)\W') # #elif, #else
533 pattern_endif = re.compile(r'#\s*endif\W') # #endif
534 pattern_blank = re.compile(r'^\s*$') # empty line
535
536 while True:
537 old_matched = copy.copy(matched)
538 extend_matched_lines(lines, matched, [pattern_if],
539 [pattern_endif], True, True)
540 extend_matched_lines(lines, matched, [pattern_elif],
541 [pattern_elif, pattern_endif], True, False)
542 extend_matched_lines(lines, matched, [pattern_if, pattern_elif],
543 [pattern_blank], False, True)
544 extend_matched_lines(lines, matched, [pattern_blank],
545 [pattern_elif, pattern_endif], True, False)
546 extend_matched_lines(lines, matched, [pattern_blank],
547 [pattern_blank], True, False)
548 if matched == old_matched:
549 break
550
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900551 tolines = copy.copy(lines)
552
553 for i in reversed(matched):
554 tolines.pop(i)
555
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900556 show_diff(lines, tolines, header_path, options.color)
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900557
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900558 if options.dry_run:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900559 return
560
561 with open(header_path, 'w') as f:
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900562 for line in tolines:
563 f.write(line)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900564
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900565def cleanup_headers(configs, options):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900566 """Delete config defines from board headers.
567
568 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900569 configs: A list of CONFIGs to remove.
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900570 options: option flags.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900571 """
Chris Packham85edfc12017-05-02 21:30:46 +1200572 if not confirm(options, 'Clean up headers?'):
573 return
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900574
575 patterns = []
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900576 for config in configs:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900577 patterns.append(re.compile(r'#\s*define\s+%s\W' % config))
578 patterns.append(re.compile(r'#\s*undef\s+%s\W' % config))
579
Joe Hershberger60727f52015-05-19 13:21:21 -0500580 for dir in 'include', 'arch', 'board':
581 for (dirpath, dirnames, filenames) in os.walk(dir):
Masahiro Yamadadc6de502016-07-25 19:15:22 +0900582 if dirpath == os.path.join('include', 'generated'):
583 continue
Joe Hershberger60727f52015-05-19 13:21:21 -0500584 for filename in filenames:
585 if not fnmatch.fnmatch(filename, '*~'):
586 cleanup_one_header(os.path.join(dirpath, filename),
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900587 patterns, options)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900588
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900589def cleanup_one_extra_option(defconfig_path, configs, options):
590 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in one defconfig file.
591
592 Arguments:
593 defconfig_path: path to the cleaned defconfig file.
594 configs: A list of CONFIGs to remove.
595 options: option flags.
596 """
597
598 start = 'CONFIG_SYS_EXTRA_OPTIONS="'
599 end = '"\n'
600
601 with open(defconfig_path) as f:
602 lines = f.readlines()
603
604 for i, line in enumerate(lines):
605 if line.startswith(start) and line.endswith(end):
606 break
607 else:
608 # CONFIG_SYS_EXTRA_OPTIONS was not found in this defconfig
609 return
610
611 old_tokens = line[len(start):-len(end)].split(',')
612 new_tokens = []
613
614 for token in old_tokens:
615 pos = token.find('=')
616 if not (token[:pos] if pos >= 0 else token) in configs:
617 new_tokens.append(token)
618
619 if new_tokens == old_tokens:
620 return
621
622 tolines = copy.copy(lines)
623
624 if new_tokens:
625 tolines[i] = start + ','.join(new_tokens) + end
626 else:
627 tolines.pop(i)
628
629 show_diff(lines, tolines, defconfig_path, options.color)
630
631 if options.dry_run:
632 return
633
634 with open(defconfig_path, 'w') as f:
635 for line in tolines:
636 f.write(line)
637
638def cleanup_extra_options(configs, options):
639 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in defconfig files.
640
641 Arguments:
642 configs: A list of CONFIGs to remove.
643 options: option flags.
644 """
Chris Packham85edfc12017-05-02 21:30:46 +1200645 if not confirm(options, 'Clean up CONFIG_SYS_EXTRA_OPTIONS?'):
646 return
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900647
648 configs = [ config[len('CONFIG_'):] for config in configs ]
649
650 defconfigs = get_all_defconfigs()
651
652 for defconfig in defconfigs:
653 cleanup_one_extra_option(os.path.join('configs', defconfig), configs,
654 options)
655
Chris Packhamca438342017-05-02 21:30:47 +1200656def cleanup_whitelist(configs, options):
657 """Delete config whitelist entries
658
659 Arguments:
660 configs: A list of CONFIGs to remove.
661 options: option flags.
662 """
663 if not confirm(options, 'Clean up whitelist entries?'):
664 return
665
666 with open(os.path.join('scripts', 'config_whitelist.txt')) as f:
667 lines = f.readlines()
668
669 lines = [x for x in lines if x.strip() not in configs]
670
671 with open(os.path.join('scripts', 'config_whitelist.txt'), 'w') as f:
672 f.write(''.join(lines))
673
Chris Packhamf90df592017-05-02 21:30:48 +1200674def find_matching(patterns, line):
675 for pat in patterns:
676 if pat.search(line):
677 return True
678 return False
679
680def cleanup_readme(configs, options):
681 """Delete config description in README
682
683 Arguments:
684 configs: A list of CONFIGs to remove.
685 options: option flags.
686 """
687 if not confirm(options, 'Clean up README?'):
688 return
689
690 patterns = []
691 for config in configs:
692 patterns.append(re.compile(r'^\s+%s' % config))
693
694 with open('README') as f:
695 lines = f.readlines()
696
697 found = False
698 newlines = []
699 for line in lines:
700 if not found:
701 found = find_matching(patterns, line)
702 if found:
703 continue
704
705 if found and re.search(r'^\s+CONFIG', line):
706 found = False
707
708 if not found:
709 newlines.append(line)
710
711 with open('README', 'w') as f:
712 f.write(''.join(newlines))
713
Chris Packhamca438342017-05-02 21:30:47 +1200714
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900715### classes ###
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900716class Progress:
717
718 """Progress Indicator"""
719
720 def __init__(self, total):
721 """Create a new progress indicator.
722
723 Arguments:
724 total: A number of defconfig files to process.
725 """
726 self.current = 0
727 self.total = total
728
729 def inc(self):
730 """Increment the number of processed defconfig files."""
731
732 self.current += 1
733
734 def show(self):
735 """Display the progress."""
736 print ' %d defconfigs out of %d\r' % (self.current, self.total),
737 sys.stdout.flush()
738
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900739class KconfigParser:
740
741 """A parser of .config and include/autoconf.mk."""
742
743 re_arch = re.compile(r'CONFIG_SYS_ARCH="(.*)"')
744 re_cpu = re.compile(r'CONFIG_SYS_CPU="(.*)"')
745
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900746 def __init__(self, configs, options, build_dir):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900747 """Create a new parser.
748
749 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900750 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900751 options: option flags.
752 build_dir: Build directory.
753 """
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900754 self.configs = configs
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900755 self.options = options
Masahiro Yamada1f169922016-05-19 15:52:00 +0900756 self.dotconfig = os.path.join(build_dir, '.config')
757 self.autoconf = os.path.join(build_dir, 'include', 'autoconf.mk')
Masahiro Yamada07913d12016-08-22 22:18:22 +0900758 self.spl_autoconf = os.path.join(build_dir, 'spl', 'include',
759 'autoconf.mk')
Simon Glassf3b8e642017-06-01 19:39:01 -0600760 self.config_autoconf = os.path.join(build_dir, AUTO_CONF_PATH)
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900761 self.defconfig = os.path.join(build_dir, 'defconfig')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900762
763 def get_cross_compile(self):
764 """Parse .config file and return CROSS_COMPILE.
765
766 Returns:
767 A string storing the compiler prefix for the architecture.
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900768 Return a NULL string for architectures that do not require
769 compiler prefix (Sandbox and native build is the case).
770 Return None if the specified compiler is missing in your PATH.
771 Caller should distinguish '' and None.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900772 """
773 arch = ''
774 cpu = ''
Masahiro Yamada1f169922016-05-19 15:52:00 +0900775 for line in open(self.dotconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900776 m = self.re_arch.match(line)
777 if m:
778 arch = m.group(1)
779 continue
780 m = self.re_cpu.match(line)
781 if m:
782 cpu = m.group(1)
783
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900784 if not arch:
785 return None
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900786
787 # fix-up for aarch64
788 if arch == 'arm' and cpu == 'armv8':
789 arch = 'aarch64'
790
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900791 return CROSS_COMPILE.get(arch, None)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900792
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900793 def parse_one_config(self, config, dotconfig_lines, autoconf_lines):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900794 """Parse .config, defconfig, include/autoconf.mk for one config.
795
796 This function looks for the config options in the lines from
797 defconfig, .config, and include/autoconf.mk in order to decide
798 which action should be taken for this defconfig.
799
800 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900801 config: CONFIG name to parse.
Masahiro Yamadacc008292016-05-19 15:51:56 +0900802 dotconfig_lines: lines from the .config file.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900803 autoconf_lines: lines from the include/autoconf.mk file.
804
805 Returns:
806 A tupple of the action for this defconfig and the line
807 matched for the config.
808 """
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900809 not_set = '# %s is not set' % config
810
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900811 for line in autoconf_lines:
812 line = line.rstrip()
813 if line.startswith(config + '='):
Masahiro Yamadacc008292016-05-19 15:51:56 +0900814 new_val = line
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900815 break
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900816 else:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900817 new_val = not_set
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900818
Masahiro Yamada916224c2016-08-22 22:18:21 +0900819 for line in dotconfig_lines:
820 line = line.rstrip()
821 if line.startswith(config + '=') or line == not_set:
822 old_val = line
823 break
824 else:
825 if new_val == not_set:
826 return (ACTION_NO_ENTRY, config)
827 else:
828 return (ACTION_NO_ENTRY_WARN, config)
829
Masahiro Yamadacc008292016-05-19 15:51:56 +0900830 # If this CONFIG is neither bool nor trisate
831 if old_val[-2:] != '=y' and old_val[-2:] != '=m' and old_val != not_set:
832 # tools/scripts/define2mk.sed changes '1' to 'y'.
833 # This is a problem if the CONFIG is int type.
834 # Check the type in Kconfig and handle it correctly.
835 if new_val[-2:] == '=y':
836 new_val = new_val[:-1] + '1'
837
Masahiro Yamada50301592016-06-15 14:33:50 +0900838 return (ACTION_NO_CHANGE if old_val == new_val else ACTION_MOVE,
839 new_val)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900840
Masahiro Yamada1d085562016-05-19 15:52:02 +0900841 def update_dotconfig(self):
Masahiro Yamada6ff36d22016-05-19 15:51:50 +0900842 """Parse files for the config options and update the .config.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900843
Masahiro Yamadacc008292016-05-19 15:51:56 +0900844 This function parses the generated .config and include/autoconf.mk
845 searching the target options.
Masahiro Yamada6ff36d22016-05-19 15:51:50 +0900846 Move the config option(s) to the .config as needed.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900847
848 Arguments:
849 defconfig: defconfig name.
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900850
851 Returns:
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900852 Return a tuple of (updated flag, log string).
853 The "updated flag" is True if the .config was updated, False
854 otherwise. The "log string" shows what happend to the .config.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900855 """
856
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900857 results = []
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900858 updated = False
Masahiro Yamada916224c2016-08-22 22:18:21 +0900859 suspicious = False
Masahiro Yamada07913d12016-08-22 22:18:22 +0900860 rm_files = [self.config_autoconf, self.autoconf]
861
862 if self.options.spl:
863 if os.path.exists(self.spl_autoconf):
864 autoconf_path = self.spl_autoconf
865 rm_files.append(self.spl_autoconf)
866 else:
867 for f in rm_files:
868 os.remove(f)
869 return (updated, suspicious,
870 color_text(self.options.color, COLOR_BROWN,
871 "SPL is not enabled. Skipped.") + '\n')
872 else:
873 autoconf_path = self.autoconf
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900874
Masahiro Yamada1f169922016-05-19 15:52:00 +0900875 with open(self.dotconfig) as f:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900876 dotconfig_lines = f.readlines()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900877
Masahiro Yamada07913d12016-08-22 22:18:22 +0900878 with open(autoconf_path) as f:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900879 autoconf_lines = f.readlines()
880
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900881 for config in self.configs:
882 result = self.parse_one_config(config, dotconfig_lines,
Joe Hershberger96464ba2015-05-19 13:21:17 -0500883 autoconf_lines)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900884 results.append(result)
885
886 log = ''
887
888 for (action, value) in results:
889 if action == ACTION_MOVE:
890 actlog = "Move '%s'" % value
891 log_color = COLOR_LIGHT_GREEN
Masahiro Yamadacc008292016-05-19 15:51:56 +0900892 elif action == ACTION_NO_ENTRY:
893 actlog = "%s is not defined in Kconfig. Do nothing." % value
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900894 log_color = COLOR_LIGHT_BLUE
Masahiro Yamada916224c2016-08-22 22:18:21 +0900895 elif action == ACTION_NO_ENTRY_WARN:
896 actlog = "%s is not defined in Kconfig (suspicious). Do nothing." % value
897 log_color = COLOR_YELLOW
898 suspicious = True
Masahiro Yamadacc008292016-05-19 15:51:56 +0900899 elif action == ACTION_NO_CHANGE:
900 actlog = "'%s' is the same as the define in Kconfig. Do nothing." \
901 % value
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900902 log_color = COLOR_LIGHT_PURPLE
Masahiro Yamada07913d12016-08-22 22:18:22 +0900903 elif action == ACTION_SPL_NOT_EXIST:
904 actlog = "SPL is not enabled for this defconfig. Skip."
905 log_color = COLOR_PURPLE
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900906 else:
907 sys.exit("Internal Error. This should not happen.")
908
Masahiro Yamada1d085562016-05-19 15:52:02 +0900909 log += color_text(self.options.color, log_color, actlog) + '\n'
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900910
Masahiro Yamada1f169922016-05-19 15:52:00 +0900911 with open(self.dotconfig, 'a') as f:
Masahiro Yamadae423d172016-05-19 15:51:49 +0900912 for (action, value) in results:
913 if action == ACTION_MOVE:
914 f.write(value + '\n')
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900915 updated = True
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900916
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900917 self.results = results
Masahiro Yamada07913d12016-08-22 22:18:22 +0900918 for f in rm_files:
919 os.remove(f)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900920
Masahiro Yamada916224c2016-08-22 22:18:21 +0900921 return (updated, suspicious, log)
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900922
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900923 def check_defconfig(self):
924 """Check the defconfig after savedefconfig
925
926 Returns:
927 Return additional log if moved CONFIGs were removed again by
928 'make savedefconfig'.
929 """
930
931 log = ''
932
933 with open(self.defconfig) as f:
934 defconfig_lines = f.readlines()
935
936 for (action, value) in self.results:
937 if action != ACTION_MOVE:
938 continue
939 if not value + '\n' in defconfig_lines:
940 log += color_text(self.options.color, COLOR_YELLOW,
941 "'%s' was removed by savedefconfig.\n" %
942 value)
943
944 return log
945
Simon Glassd73fcb12017-06-01 19:39:02 -0600946
947class DatabaseThread(threading.Thread):
948 """This thread processes results from Slot threads.
949
950 It collects the data in the master config directary. There is only one
951 result thread, and this helps to serialise the build output.
952 """
953 def __init__(self, config_db, db_queue):
954 """Set up a new result thread
955
956 Args:
957 builder: Builder which will be sent each result
958 """
959 threading.Thread.__init__(self)
960 self.config_db = config_db
961 self.db_queue= db_queue
962
963 def run(self):
964 """Called to start up the result thread.
965
966 We collect the next result job and pass it on to the build.
967 """
968 while True:
969 defconfig, configs = self.db_queue.get()
970 self.config_db[defconfig] = configs
971 self.db_queue.task_done()
972
973
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900974class Slot:
975
976 """A slot to store a subprocess.
977
978 Each instance of this class handles one subprocess.
979 This class is useful to control multiple threads
980 for faster processing.
981 """
982
Simon Glassd73fcb12017-06-01 19:39:02 -0600983 def __init__(self, configs, options, progress, devnull, make_cmd,
984 reference_src_dir, db_queue):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900985 """Create a new process slot.
986
987 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900988 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900989 options: option flags.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900990 progress: A progress indicator.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900991 devnull: A file object of '/dev/null'.
992 make_cmd: command name of GNU Make.
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500993 reference_src_dir: Determine the true starting config state from this
994 source tree.
Simon Glassd73fcb12017-06-01 19:39:02 -0600995 db_queue: output queue to write config info for the database
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900996 """
997 self.options = options
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900998 self.progress = progress
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900999 self.build_dir = tempfile.mkdtemp()
1000 self.devnull = devnull
1001 self.make_cmd = (make_cmd, 'O=' + self.build_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001002 self.reference_src_dir = reference_src_dir
Simon Glassd73fcb12017-06-01 19:39:02 -06001003 self.db_queue = db_queue
Masahiro Yamada522e8dc2016-05-19 15:52:01 +09001004 self.parser = KconfigParser(configs, options, self.build_dir)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001005 self.state = STATE_IDLE
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001006 self.failed_boards = set()
1007 self.suspicious_boards = set()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001008
1009 def __del__(self):
1010 """Delete the working directory
1011
1012 This function makes sure the temporary directory is cleaned away
1013 even if Python suddenly dies due to error. It should be done in here
Joe Hershbergerf2dae752016-06-10 14:53:29 -05001014 because it is guaranteed the destructor is always invoked when the
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001015 instance of the class gets unreferenced.
1016
1017 If the subprocess is still running, wait until it finishes.
1018 """
1019 if self.state != STATE_IDLE:
1020 while self.ps.poll() == None:
1021 pass
1022 shutil.rmtree(self.build_dir)
1023
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001024 def add(self, defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001025 """Assign a new subprocess for defconfig and add it to the slot.
1026
1027 If the slot is vacant, create a new subprocess for processing the
1028 given defconfig and add it to the slot. Just returns False if
1029 the slot is occupied (i.e. the current subprocess is still running).
1030
1031 Arguments:
1032 defconfig: defconfig name.
1033
1034 Returns:
1035 Return True on success or False on failure
1036 """
1037 if self.state != STATE_IDLE:
1038 return False
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001039
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001040 self.defconfig = defconfig
Masahiro Yamada1d085562016-05-19 15:52:02 +09001041 self.log = ''
Masahiro Yamadaf432c332016-06-15 14:33:52 +09001042 self.current_src_dir = self.reference_src_dir
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001043 self.do_defconfig()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001044 return True
1045
1046 def poll(self):
1047 """Check the status of the subprocess and handle it as needed.
1048
1049 Returns True if the slot is vacant (i.e. in idle state).
1050 If the configuration is successfully finished, assign a new
1051 subprocess to build include/autoconf.mk.
1052 If include/autoconf.mk is generated, invoke the parser to
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +09001053 parse the .config and the include/autoconf.mk, moving
1054 config options to the .config as needed.
1055 If the .config was updated, run "make savedefconfig" to sync
1056 it, update the original defconfig, and then set the slot back
1057 to the idle state.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001058
1059 Returns:
1060 Return True if the subprocess is terminated, False otherwise
1061 """
1062 if self.state == STATE_IDLE:
1063 return True
1064
1065 if self.ps.poll() == None:
1066 return False
1067
1068 if self.ps.poll() != 0:
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001069 self.handle_error()
1070 elif self.state == STATE_DEFCONFIG:
Masahiro Yamadaf432c332016-06-15 14:33:52 +09001071 if self.reference_src_dir and not self.current_src_dir:
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001072 self.do_savedefconfig()
1073 else:
1074 self.do_autoconf()
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001075 elif self.state == STATE_AUTOCONF:
Masahiro Yamadaf432c332016-06-15 14:33:52 +09001076 if self.current_src_dir:
1077 self.current_src_dir = None
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001078 self.do_defconfig()
Simon Glassd73fcb12017-06-01 19:39:02 -06001079 elif self.options.build_db:
1080 self.do_build_db()
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001081 else:
1082 self.do_savedefconfig()
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001083 elif self.state == STATE_SAVEDEFCONFIG:
1084 self.update_defconfig()
1085 else:
1086 sys.exit("Internal Error. This should not happen.")
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001087
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001088 return True if self.state == STATE_IDLE else False
Joe Hershberger96464ba2015-05-19 13:21:17 -05001089
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001090 def handle_error(self):
1091 """Handle error cases."""
Masahiro Yamada8513dc02016-05-19 15:52:08 +09001092
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001093 self.log += color_text(self.options.color, COLOR_LIGHT_RED,
1094 "Failed to process.\n")
1095 if self.options.verbose:
1096 self.log += color_text(self.options.color, COLOR_LIGHT_CYAN,
1097 self.ps.stderr.read())
1098 self.finish(False)
Joe Hershberger96464ba2015-05-19 13:21:17 -05001099
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001100 def do_defconfig(self):
1101 """Run 'make <board>_defconfig' to create the .config file."""
Masahiro Yamadac8e1b102016-05-19 15:52:07 +09001102
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001103 cmd = list(self.make_cmd)
1104 cmd.append(self.defconfig)
1105 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Masahiro Yamadaf432c332016-06-15 14:33:52 +09001106 stderr=subprocess.PIPE,
1107 cwd=self.current_src_dir)
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001108 self.state = STATE_DEFCONFIG
Masahiro Yamadac8e1b102016-05-19 15:52:07 +09001109
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001110 def do_autoconf(self):
Simon Glassf3b8e642017-06-01 19:39:01 -06001111 """Run 'make AUTO_CONF_PATH'."""
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001112
Joe Hershberger25400092015-05-19 13:21:23 -05001113 self.cross_compile = self.parser.get_cross_compile()
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +09001114 if self.cross_compile is None:
Masahiro Yamada1d085562016-05-19 15:52:02 +09001115 self.log += color_text(self.options.color, COLOR_YELLOW,
1116 "Compiler is missing. Do nothing.\n")
Masahiro Yamada4efef992016-05-19 15:52:03 +09001117 self.finish(False)
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001118 return
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +09001119
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001120 cmd = list(self.make_cmd)
Joe Hershberger25400092015-05-19 13:21:23 -05001121 if self.cross_compile:
1122 cmd.append('CROSS_COMPILE=%s' % self.cross_compile)
Joe Hershberger7740f652015-05-19 13:21:18 -05001123 cmd.append('KCONFIG_IGNORE_DUPLICATES=1')
Simon Glassf3b8e642017-06-01 19:39:01 -06001124 cmd.append(AUTO_CONF_PATH)
Joe Hershberger25400092015-05-19 13:21:23 -05001125 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Masahiro Yamadaf432c332016-06-15 14:33:52 +09001126 stderr=subprocess.PIPE,
1127 cwd=self.current_src_dir)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001128 self.state = STATE_AUTOCONF
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001129
Simon Glassd73fcb12017-06-01 19:39:02 -06001130 def do_build_db(self):
1131 """Add the board to the database"""
1132 configs = {}
1133 with open(os.path.join(self.build_dir, AUTO_CONF_PATH)) as fd:
1134 for line in fd.readlines():
1135 if line.startswith('CONFIG'):
1136 config, value = line.split('=', 1)
1137 configs[config] = value.rstrip()
1138 self.db_queue.put([self.defconfig, configs])
1139 self.finish(True)
1140
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001141 def do_savedefconfig(self):
1142 """Update the .config and run 'make savedefconfig'."""
1143
Masahiro Yamada916224c2016-08-22 22:18:21 +09001144 (updated, suspicious, log) = self.parser.update_dotconfig()
1145 if suspicious:
1146 self.suspicious_boards.add(self.defconfig)
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001147 self.log += log
1148
1149 if not self.options.force_sync and not updated:
1150 self.finish(True)
1151 return
1152 if updated:
1153 self.log += color_text(self.options.color, COLOR_LIGHT_GREEN,
1154 "Syncing by savedefconfig...\n")
1155 else:
1156 self.log += "Syncing by savedefconfig (forced by option)...\n"
1157
1158 cmd = list(self.make_cmd)
1159 cmd.append('savedefconfig')
1160 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
1161 stderr=subprocess.PIPE)
1162 self.state = STATE_SAVEDEFCONFIG
1163
1164 def update_defconfig(self):
1165 """Update the input defconfig and go back to the idle state."""
1166
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001167 log = self.parser.check_defconfig()
1168 if log:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001169 self.suspicious_boards.add(self.defconfig)
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001170 self.log += log
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001171 orig_defconfig = os.path.join('configs', self.defconfig)
1172 new_defconfig = os.path.join(self.build_dir, 'defconfig')
1173 updated = not filecmp.cmp(orig_defconfig, new_defconfig)
1174
1175 if updated:
Joe Hershberger06cc1d32016-06-10 14:53:30 -05001176 self.log += color_text(self.options.color, COLOR_LIGHT_BLUE,
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001177 "defconfig was updated.\n")
1178
1179 if not self.options.dry_run and updated:
1180 shutil.move(new_defconfig, orig_defconfig)
1181 self.finish(True)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001182
Masahiro Yamada4efef992016-05-19 15:52:03 +09001183 def finish(self, success):
1184 """Display log along with progress and go to the idle state.
Masahiro Yamada1d085562016-05-19 15:52:02 +09001185
1186 Arguments:
Masahiro Yamada4efef992016-05-19 15:52:03 +09001187 success: Should be True when the defconfig was processed
1188 successfully, or False when it fails.
Masahiro Yamada1d085562016-05-19 15:52:02 +09001189 """
1190 # output at least 30 characters to hide the "* defconfigs out of *".
1191 log = self.defconfig.ljust(30) + '\n'
1192
1193 log += '\n'.join([ ' ' + s for s in self.log.split('\n') ])
1194 # Some threads are running in parallel.
1195 # Print log atomically to not mix up logs from different threads.
Masahiro Yamada4efef992016-05-19 15:52:03 +09001196 print >> (sys.stdout if success else sys.stderr), log
1197
1198 if not success:
1199 if self.options.exit_on_error:
1200 sys.exit("Exit on error.")
1201 # If --exit-on-error flag is not set, skip this board and continue.
1202 # Record the failed board.
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001203 self.failed_boards.add(self.defconfig)
Masahiro Yamada4efef992016-05-19 15:52:03 +09001204
Masahiro Yamada1d085562016-05-19 15:52:02 +09001205 self.progress.inc()
1206 self.progress.show()
Masahiro Yamada4efef992016-05-19 15:52:03 +09001207 self.state = STATE_IDLE
Masahiro Yamada1d085562016-05-19 15:52:02 +09001208
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001209 def get_failed_boards(self):
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001210 """Returns a set of failed boards (defconfigs) in this slot.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001211 """
1212 return self.failed_boards
1213
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001214 def get_suspicious_boards(self):
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001215 """Returns a set of boards (defconfigs) with possible misconversion.
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001216 """
Masahiro Yamada916224c2016-08-22 22:18:21 +09001217 return self.suspicious_boards - self.failed_boards
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001218
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001219class Slots:
1220
1221 """Controller of the array of subprocess slots."""
1222
Simon Glassd73fcb12017-06-01 19:39:02 -06001223 def __init__(self, configs, options, progress, reference_src_dir, db_queue):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001224 """Create a new slots controller.
1225
1226 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001227 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001228 options: option flags.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001229 progress: A progress indicator.
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001230 reference_src_dir: Determine the true starting config state from this
1231 source tree.
Simon Glassd73fcb12017-06-01 19:39:02 -06001232 db_queue: output queue to write config info for the database
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001233 """
1234 self.options = options
1235 self.slots = []
1236 devnull = get_devnull()
1237 make_cmd = get_make_cmd()
1238 for i in range(options.jobs):
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001239 self.slots.append(Slot(configs, options, progress, devnull,
Simon Glassd73fcb12017-06-01 19:39:02 -06001240 make_cmd, reference_src_dir, db_queue))
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001241
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001242 def add(self, defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001243 """Add a new subprocess if a vacant slot is found.
1244
1245 Arguments:
1246 defconfig: defconfig name to be put into.
1247
1248 Returns:
1249 Return True on success or False on failure
1250 """
1251 for slot in self.slots:
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001252 if slot.add(defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001253 return True
1254 return False
1255
1256 def available(self):
1257 """Check if there is a vacant slot.
1258
1259 Returns:
1260 Return True if at lease one vacant slot is found, False otherwise.
1261 """
1262 for slot in self.slots:
1263 if slot.poll():
1264 return True
1265 return False
1266
1267 def empty(self):
1268 """Check if all slots are vacant.
1269
1270 Returns:
1271 Return True if all the slots are vacant, False otherwise.
1272 """
1273 ret = True
1274 for slot in self.slots:
1275 if not slot.poll():
1276 ret = False
1277 return ret
1278
1279 def show_failed_boards(self):
1280 """Display all of the failed boards (defconfigs)."""
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001281 boards = set()
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001282 output_file = 'moveconfig.failed'
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001283
1284 for slot in self.slots:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001285 boards |= slot.get_failed_boards()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001286
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001287 if boards:
1288 boards = '\n'.join(boards) + '\n'
1289 msg = "The following boards were not processed due to error:\n"
1290 msg += boards
1291 msg += "(the list has been saved in %s)\n" % output_file
1292 print >> sys.stderr, color_text(self.options.color, COLOR_LIGHT_RED,
1293 msg)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001294
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001295 with open(output_file, 'w') as f:
1296 f.write(boards)
Joe Hershberger2559cd82015-05-19 13:21:22 -05001297
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001298 def show_suspicious_boards(self):
1299 """Display all boards (defconfigs) with possible misconversion."""
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001300 boards = set()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001301 output_file = 'moveconfig.suspicious'
1302
1303 for slot in self.slots:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001304 boards |= slot.get_suspicious_boards()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001305
1306 if boards:
1307 boards = '\n'.join(boards) + '\n'
1308 msg = "The following boards might have been converted incorrectly.\n"
1309 msg += "It is highly recommended to check them manually:\n"
1310 msg += boards
1311 msg += "(the list has been saved in %s)\n" % output_file
1312 print >> sys.stderr, color_text(self.options.color, COLOR_YELLOW,
1313 msg)
1314
1315 with open(output_file, 'w') as f:
1316 f.write(boards)
1317
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001318class ReferenceSource:
1319
1320 """Reference source against which original configs should be parsed."""
1321
1322 def __init__(self, commit):
1323 """Create a reference source directory based on a specified commit.
1324
1325 Arguments:
1326 commit: commit to git-clone
1327 """
1328 self.src_dir = tempfile.mkdtemp()
1329 print "Cloning git repo to a separate work directory..."
1330 subprocess.check_output(['git', 'clone', os.getcwd(), '.'],
1331 cwd=self.src_dir)
1332 print "Checkout '%s' to build the original autoconf.mk." % \
1333 subprocess.check_output(['git', 'rev-parse', '--short', commit]).strip()
1334 subprocess.check_output(['git', 'checkout', commit],
1335 stderr=subprocess.STDOUT, cwd=self.src_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001336
1337 def __del__(self):
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001338 """Delete the reference source directory
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001339
1340 This function makes sure the temporary directory is cleaned away
1341 even if Python suddenly dies due to error. It should be done in here
1342 because it is guaranteed the destructor is always invoked when the
1343 instance of the class gets unreferenced.
1344 """
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001345 shutil.rmtree(self.src_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001346
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001347 def get_dir(self):
1348 """Return the absolute path to the reference source directory."""
1349
1350 return self.src_dir
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001351
Simon Glassd73fcb12017-06-01 19:39:02 -06001352def move_config(configs, options, db_queue):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001353 """Move config options to defconfig files.
1354
1355 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001356 configs: A list of CONFIGs to move.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001357 options: option flags
1358 """
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001359 if len(configs) == 0:
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001360 if options.force_sync:
1361 print 'No CONFIG is specified. You are probably syncing defconfigs.',
Simon Glassd73fcb12017-06-01 19:39:02 -06001362 elif options.build_db:
1363 print 'Building %s database' % CONFIG_DATABASE
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001364 else:
1365 print 'Neither CONFIG nor --force-sync is specified. Nothing will happen.',
1366 else:
1367 print 'Move ' + ', '.join(configs),
1368 print '(jobs: %d)\n' % options.jobs
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001369
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001370 if options.git_ref:
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001371 reference_src = ReferenceSource(options.git_ref)
1372 reference_src_dir = reference_src.get_dir()
1373 else:
Masahiro Yamadaf432c332016-06-15 14:33:52 +09001374 reference_src_dir = None
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001375
Joe Hershberger91040e82015-05-19 13:21:19 -05001376 if options.defconfigs:
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +09001377 defconfigs = get_matched_defconfigs(options.defconfigs)
Joe Hershberger91040e82015-05-19 13:21:19 -05001378 else:
Masahiro Yamada684c3062016-07-25 19:15:28 +09001379 defconfigs = get_all_defconfigs()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001380
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001381 progress = Progress(len(defconfigs))
Simon Glassd73fcb12017-06-01 19:39:02 -06001382 slots = Slots(configs, options, progress, reference_src_dir, db_queue)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001383
1384 # Main loop to process defconfig files:
1385 # Add a new subprocess into a vacant slot.
1386 # Sleep if there is no available slot.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001387 for defconfig in defconfigs:
1388 while not slots.add(defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001389 while not slots.available():
1390 # No available slot: sleep for a while
1391 time.sleep(SLEEP_TIME)
1392
1393 # wait until all the subprocesses finish
1394 while not slots.empty():
1395 time.sleep(SLEEP_TIME)
1396
Joe Hershberger2e2ce6c2015-05-19 13:21:25 -05001397 print ''
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001398 slots.show_failed_boards()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001399 slots.show_suspicious_boards()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001400
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001401def main():
1402 try:
1403 cpu_count = multiprocessing.cpu_count()
1404 except NotImplementedError:
1405 cpu_count = 1
1406
1407 parser = optparse.OptionParser()
1408 # Add options here
Simon Glassd73fcb12017-06-01 19:39:02 -06001409 parser.add_option('-b', '--build-db', action='store_true', default=False,
1410 help='build a CONFIG database')
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001411 parser.add_option('-c', '--color', action='store_true', default=False,
1412 help='display the log in color')
Simon Glass9ede2122016-09-12 23:18:21 -06001413 parser.add_option('-C', '--commit', action='store_true', default=False,
1414 help='Create a git commit for the operation')
Joe Hershberger91040e82015-05-19 13:21:19 -05001415 parser.add_option('-d', '--defconfigs', type='string',
Simon Glassee4e61b2017-06-01 19:38:59 -06001416 help='a file containing a list of defconfigs to move, '
1417 "one per line (for example 'snow_defconfig') "
1418 "or '-' to read from stdin")
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001419 parser.add_option('-n', '--dry-run', action='store_true', default=False,
1420 help='perform a trial run (show log with no changes)')
1421 parser.add_option('-e', '--exit-on-error', action='store_true',
1422 default=False,
1423 help='exit immediately on any error')
Masahiro Yamada8513dc02016-05-19 15:52:08 +09001424 parser.add_option('-s', '--force-sync', action='store_true', default=False,
1425 help='force sync by savedefconfig')
Masahiro Yamada07913d12016-08-22 22:18:22 +09001426 parser.add_option('-S', '--spl', action='store_true', default=False,
1427 help='parse config options defined for SPL build')
Joe Hershberger2144f882015-05-19 13:21:20 -05001428 parser.add_option('-H', '--headers-only', dest='cleanup_headers_only',
1429 action='store_true', default=False,
1430 help='only cleanup the headers')
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001431 parser.add_option('-j', '--jobs', type='int', default=cpu_count,
1432 help='the number of jobs to run simultaneously')
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001433 parser.add_option('-r', '--git-ref', type='string',
1434 help='the git ref to clone for building the autoconf.mk')
Simon Glass6b403df2016-09-12 23:18:20 -06001435 parser.add_option('-y', '--yes', action='store_true', default=False,
1436 help="respond 'yes' to any prompts")
Joe Hershberger95bf9c72015-05-19 13:21:24 -05001437 parser.add_option('-v', '--verbose', action='store_true', default=False,
1438 help='show any build errors as boards are built')
Masahiro Yamadab6ef3932016-05-19 15:51:58 +09001439 parser.usage += ' CONFIG ...'
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001440
Masahiro Yamadab6ef3932016-05-19 15:51:58 +09001441 (options, configs) = parser.parse_args()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001442
Simon Glassd73fcb12017-06-01 19:39:02 -06001443 if len(configs) == 0 and not any((options.force_sync, options.build_db)):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001444 parser.print_usage()
1445 sys.exit(1)
1446
Masahiro Yamadab6ef3932016-05-19 15:51:58 +09001447 # prefix the option name with CONFIG_ if missing
1448 configs = [ config if config.startswith('CONFIG_') else 'CONFIG_' + config
1449 for config in configs ]
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001450
Joe Hershberger2144f882015-05-19 13:21:20 -05001451 check_top_directory()
1452
Simon Glassd73fcb12017-06-01 19:39:02 -06001453 config_db = {}
1454 db_queue = Queue.Queue()
1455 t = DatabaseThread(config_db, db_queue)
1456 t.setDaemon(True)
1457 t.start()
1458
Joe Hershberger2144f882015-05-19 13:21:20 -05001459 if not options.cleanup_headers_only:
Masahiro Yamadaf7536f72016-07-25 19:15:23 +09001460 check_clean_directory()
1461 update_cross_compile(options.color)
Simon Glassd73fcb12017-06-01 19:39:02 -06001462 move_config(configs, options, db_queue)
1463 db_queue.join()
Joe Hershberger2144f882015-05-19 13:21:20 -05001464
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001465 if configs:
Masahiro Yamadae9ea1222016-07-25 19:15:26 +09001466 cleanup_headers(configs, options)
Masahiro Yamada9ab02962016-07-25 19:15:29 +09001467 cleanup_extra_options(configs, options)
Chris Packhamca438342017-05-02 21:30:47 +12001468 cleanup_whitelist(configs, options)
Chris Packhamf90df592017-05-02 21:30:48 +12001469 cleanup_readme(configs, options)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001470
Simon Glass9ede2122016-09-12 23:18:21 -06001471 if options.commit:
1472 subprocess.call(['git', 'add', '-u'])
1473 if configs:
1474 msg = 'Convert %s %sto Kconfig' % (configs[0],
1475 'et al ' if len(configs) > 1 else '')
1476 msg += ('\n\nThis converts the following to Kconfig:\n %s\n' %
1477 '\n '.join(configs))
1478 else:
1479 msg = 'configs: Resync with savedefconfig'
1480 msg += '\n\nRsync all defconfig files using moveconfig.py'
1481 subprocess.call(['git', 'commit', '-s', '-m', msg])
1482
Simon Glassd73fcb12017-06-01 19:39:02 -06001483 if options.build_db:
1484 with open(CONFIG_DATABASE, 'w') as fd:
1485 for defconfig, configs in config_db.iteritems():
1486 print >>fd, '%s' % defconfig
1487 for config in sorted(configs.keys()):
1488 print >>fd, ' %s=%s' % (config, configs[config])
1489 print >>fd
1490
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001491if __name__ == '__main__':
1492 main()