xref: /openbmc/u-boot/tools/moveconfig.py (revision 2e8560797fc69a34c330a875da4f5d2992452f1e)
15a27c734SMasahiro Yamada#!/usr/bin/env python2
283d290c5STom Rini# SPDX-License-Identifier: GPL-2.0+
35a27c734SMasahiro Yamada#
45a27c734SMasahiro Yamada# Author: Masahiro Yamada <yamada.masahiro@socionext.com>
55a27c734SMasahiro Yamada#
65a27c734SMasahiro Yamada
75a27c734SMasahiro Yamada"""
85a27c734SMasahiro YamadaMove config options from headers to defconfig files.
95a27c734SMasahiro Yamada
105a27c734SMasahiro YamadaSince Kconfig was introduced to U-Boot, we have worked on moving
115a27c734SMasahiro Yamadaconfig options from headers to Kconfig (defconfig).
125a27c734SMasahiro Yamada
135a27c734SMasahiro YamadaThis tool intends to help this tremendous work.
145a27c734SMasahiro Yamada
155a27c734SMasahiro Yamada
165a27c734SMasahiro YamadaUsage
175a27c734SMasahiro Yamada-----
185a27c734SMasahiro Yamada
19b6ef393aSMasahiro YamadaFirst, you must edit the Kconfig to add the menu entries for the configs
2096464badSJoe Hershbergeryou are moving.
2196464badSJoe Hershberger
22b6ef393aSMasahiro YamadaAnd then run this tool giving CONFIG names you want to move.
23b6ef393aSMasahiro YamadaFor example, if you want to move CONFIG_CMD_USB and CONFIG_SYS_TEXT_BASE,
24b6ef393aSMasahiro Yamadasimply type as follows:
255a27c734SMasahiro Yamada
26b6ef393aSMasahiro Yamada  $ tools/moveconfig.py CONFIG_CMD_USB CONFIG_SYS_TEXT_BASE
275a27c734SMasahiro Yamada
28b6ef393aSMasahiro YamadaThe tool walks through all the defconfig files and move the given CONFIGs.
295a27c734SMasahiro Yamada
305a27c734SMasahiro YamadaThe log is also displayed on the terminal.
315a27c734SMasahiro Yamada
321d085568SMasahiro YamadaThe log is printed for each defconfig as follows:
335a27c734SMasahiro Yamada
341d085568SMasahiro Yamada<defconfig_name>
351d085568SMasahiro Yamada    <action1>
361d085568SMasahiro Yamada    <action2>
371d085568SMasahiro Yamada    <action3>
381d085568SMasahiro Yamada    ...
395a27c734SMasahiro Yamada
401d085568SMasahiro Yamada<defconfig_name> is the name of the defconfig.
411d085568SMasahiro Yamada
421d085568SMasahiro Yamada<action*> shows what the tool did for that defconfig.
43c21fc7e2SMasahiro YamadaIt looks like one of the following:
445a27c734SMasahiro Yamada
455a27c734SMasahiro Yamada - Move 'CONFIG_... '
465a27c734SMasahiro Yamada   This config option was moved to the defconfig
475a27c734SMasahiro Yamada
48cc008299SMasahiro Yamada - CONFIG_... is not defined in Kconfig.  Do nothing.
49916224c3SMasahiro Yamada   The entry for this CONFIG was not found in Kconfig.  The option is not
50916224c3SMasahiro Yamada   defined in the config header, either.  So, this case can be just skipped.
51916224c3SMasahiro Yamada
52916224c3SMasahiro Yamada - CONFIG_... is not defined in Kconfig (suspicious).  Do nothing.
53916224c3SMasahiro Yamada   This option is defined in the config header, but its entry was not found
54916224c3SMasahiro Yamada   in Kconfig.
55cc008299SMasahiro Yamada   There are two common cases:
56cc008299SMasahiro Yamada     - You forgot to create an entry for the CONFIG before running
57cc008299SMasahiro Yamada       this tool, or made a typo in a CONFIG passed to this tool.
58cc008299SMasahiro Yamada     - The entry was hidden due to unmet 'depends on'.
59916224c3SMasahiro Yamada   The tool does not know if the result is reasonable, so please check it
60916224c3SMasahiro Yamada   manually.
615a27c734SMasahiro Yamada
62cc008299SMasahiro Yamada - 'CONFIG_...' is the same as the define in Kconfig.  Do nothing.
63cc008299SMasahiro Yamada   The define in the config header matched the one in Kconfig.
64cc008299SMasahiro Yamada   We do not need to touch it.
655a27c734SMasahiro Yamada
6690ed6cbaSMasahiro Yamada - Compiler is missing.  Do nothing.
6790ed6cbaSMasahiro Yamada   The compiler specified for this architecture was not found
6890ed6cbaSMasahiro Yamada   in your PATH environment.
6990ed6cbaSMasahiro Yamada   (If -e option is passed, the tool exits immediately.)
7090ed6cbaSMasahiro Yamada
7190ed6cbaSMasahiro Yamada - Failed to process.
725a27c734SMasahiro Yamada   An error occurred during processing this defconfig.  Skipped.
735a27c734SMasahiro Yamada   (If -e option is passed, the tool exits immediately on error.)
745a27c734SMasahiro Yamada
755a27c734SMasahiro YamadaFinally, you will be asked, Clean up headers? [y/n]:
765a27c734SMasahiro Yamada
775a27c734SMasahiro YamadaIf you say 'y' here, the unnecessary config defines are removed
785a27c734SMasahiro Yamadafrom the config headers (include/configs/*.h).
795a27c734SMasahiro YamadaIt just uses the regex method, so you should not rely on it.
805a27c734SMasahiro YamadaJust in case, please do 'git diff' to see what happened.
815a27c734SMasahiro Yamada
825a27c734SMasahiro Yamada
83b6ef393aSMasahiro YamadaHow does it work?
84b6ef393aSMasahiro Yamada-----------------
855a27c734SMasahiro Yamada
865a27c734SMasahiro YamadaThis tool runs configuration and builds include/autoconf.mk for every
875a27c734SMasahiro Yamadadefconfig.  The config options defined in Kconfig appear in the .config
885a27c734SMasahiro Yamadafile (unless they are hidden because of unmet dependency.)
895a27c734SMasahiro YamadaOn the other hand, the config options defined by board headers are seen
905a27c734SMasahiro Yamadain include/autoconf.mk.  The tool looks for the specified options in both
91b6ef393aSMasahiro Yamadaof them to decide the appropriate action for the options.  If the given
92b6ef393aSMasahiro Yamadaconfig option is found in the .config, but its value does not match the
93b6ef393aSMasahiro Yamadaone from the board header, the config option in the .config is replaced
94b6ef393aSMasahiro Yamadawith the define in the board header.  Then, the .config is synced by
95b6ef393aSMasahiro Yamada"make savedefconfig" and the defconfig is updated with it.
965a27c734SMasahiro Yamada
975a27c734SMasahiro YamadaFor faster processing, this tool handles multi-threading.  It creates
985a27c734SMasahiro Yamadaseparate build directories where the out-of-tree build is run.  The
995a27c734SMasahiro Yamadatemporary build directories are automatically created and deleted as
1005a27c734SMasahiro Yamadaneeded.  The number of threads are chosen based on the number of the CPU
1015a27c734SMasahiro Yamadacores of your system although you can change it via -j (--jobs) option.
1025a27c734SMasahiro Yamada
1035a27c734SMasahiro Yamada
1045a27c734SMasahiro YamadaToolchains
1055a27c734SMasahiro Yamada----------
1065a27c734SMasahiro Yamada
1075a27c734SMasahiro YamadaAppropriate toolchain are necessary to generate include/autoconf.mk
1085a27c734SMasahiro Yamadafor all the architectures supported by U-Boot.  Most of them are available
1096821a745SSimon Glassat the kernel.org site, some are not provided by kernel.org. This tool uses
1106821a745SSimon Glassthe same tools as buildman, so see that tool for setup (e.g. --fetch-arch).
1115a27c734SMasahiro Yamada
1125a27c734SMasahiro Yamada
113ddf91c64SSimon GlassTips and trips
114ddf91c64SSimon Glass--------------
115ddf91c64SSimon Glass
116ddf91c64SSimon GlassTo sync only X86 defconfigs:
117ddf91c64SSimon Glass
118ddf91c64SSimon Glass   ./tools/moveconfig.py -s -d <(grep -l X86 configs/*)
119ddf91c64SSimon Glass
120ddf91c64SSimon Glassor:
121ddf91c64SSimon Glass
122ddf91c64SSimon Glass   grep -l X86 configs/* | ./tools/moveconfig.py -s -d -
123ddf91c64SSimon Glass
124ddf91c64SSimon GlassTo process CONFIG_CMD_FPGAD only for a subset of configs based on path match:
125ddf91c64SSimon Glass
126ddf91c64SSimon Glass   ls configs/{hrcon*,iocon*,strider*} | \
127ddf91c64SSimon Glass       ./tools/moveconfig.py -Cy CONFIG_CMD_FPGAD -d -
128ddf91c64SSimon Glass
129ddf91c64SSimon Glass
13099b66605SSimon GlassFinding implied CONFIGs
13199b66605SSimon Glass-----------------------
13299b66605SSimon Glass
13399b66605SSimon GlassSome CONFIG options can be implied by others and this can help to reduce
13499b66605SSimon Glassthe size of the defconfig files. For example, CONFIG_X86 implies
13599b66605SSimon GlassCONFIG_CMD_IRQ, so we can put 'imply CMD_IRQ' under 'config X86' and
13699b66605SSimon Glassall x86 boards will have that option, avoiding adding CONFIG_CMD_IRQ to
13799b66605SSimon Glasseach of the x86 defconfig files.
13899b66605SSimon Glass
13999b66605SSimon GlassThis tool can help find such configs. To use it, first build a database:
14099b66605SSimon Glass
14199b66605SSimon Glass    ./tools/moveconfig.py -b
14299b66605SSimon Glass
14399b66605SSimon GlassThen try to query it:
14499b66605SSimon Glass
14599b66605SSimon Glass    ./tools/moveconfig.py -i CONFIG_CMD_IRQ
14699b66605SSimon Glass    CONFIG_CMD_IRQ found in 311/2384 defconfigs
14799b66605SSimon Glass    44 : CONFIG_SYS_FSL_ERRATUM_IFC_A002769
14899b66605SSimon Glass    41 : CONFIG_SYS_FSL_ERRATUM_A007075
14999b66605SSimon Glass    31 : CONFIG_SYS_FSL_DDR_VER_44
15099b66605SSimon Glass    28 : CONFIG_ARCH_P1010
15199b66605SSimon Glass    28 : CONFIG_SYS_FSL_ERRATUM_P1010_A003549
15299b66605SSimon Glass    28 : CONFIG_SYS_FSL_ERRATUM_SEC_A003571
15399b66605SSimon Glass    28 : CONFIG_SYS_FSL_ERRATUM_IFC_A003399
15499b66605SSimon Glass    25 : CONFIG_SYS_FSL_ERRATUM_A008044
15599b66605SSimon Glass    22 : CONFIG_ARCH_P1020
15699b66605SSimon Glass    21 : CONFIG_SYS_FSL_DDR_VER_46
15799b66605SSimon Glass    20 : CONFIG_MAX_PIRQ_LINKS
15899b66605SSimon Glass    20 : CONFIG_HPET_ADDRESS
15999b66605SSimon Glass    20 : CONFIG_X86
16099b66605SSimon Glass    20 : CONFIG_PCIE_ECAM_SIZE
16199b66605SSimon Glass    20 : CONFIG_IRQ_SLOT_COUNT
16299b66605SSimon Glass    20 : CONFIG_I8259_PIC
16399b66605SSimon Glass    20 : CONFIG_CPU_ADDR_BITS
16499b66605SSimon Glass    20 : CONFIG_RAMBASE
16599b66605SSimon Glass    20 : CONFIG_SYS_FSL_ERRATUM_A005871
16699b66605SSimon Glass    20 : CONFIG_PCIE_ECAM_BASE
16799b66605SSimon Glass    20 : CONFIG_X86_TSC_TIMER
16899b66605SSimon Glass    20 : CONFIG_I8254_TIMER
16999b66605SSimon Glass    20 : CONFIG_CMD_GETTIME
17099b66605SSimon Glass    19 : CONFIG_SYS_FSL_ERRATUM_A005812
17199b66605SSimon Glass    18 : CONFIG_X86_RUN_32BIT
17299b66605SSimon Glass    17 : CONFIG_CMD_CHIP_CONFIG
17399b66605SSimon Glass    ...
17499b66605SSimon Glass
17599b66605SSimon GlassThis shows a list of config options which might imply CONFIG_CMD_EEPROM along
17699b66605SSimon Glasswith how many defconfigs they cover. From this you can see that CONFIG_X86
17799b66605SSimon Glassimplies CONFIG_CMD_EEPROM. Therefore, instead of adding CONFIG_CMD_EEPROM to
17899b66605SSimon Glassthe defconfig of every x86 board, you could add a single imply line to the
17999b66605SSimon GlassKconfig file:
18099b66605SSimon Glass
18199b66605SSimon Glass    config X86
18299b66605SSimon Glass        bool "x86 architecture"
18399b66605SSimon Glass        ...
18499b66605SSimon Glass        imply CMD_EEPROM
18599b66605SSimon Glass
18699b66605SSimon GlassThat will cover 20 defconfigs. Many of the options listed are not suitable as
18799b66605SSimon Glassthey are not related. E.g. it would be odd for CONFIG_CMD_GETTIME to imply
18899b66605SSimon GlassCMD_EEPROM.
18999b66605SSimon Glass
19099b66605SSimon GlassUsing this search you can reduce the size of moveconfig patches.
19199b66605SSimon Glass
192cb008830SSimon GlassYou can automatically add 'imply' statements in the Kconfig with the -a
193cb008830SSimon Glassoption:
194cb008830SSimon Glass
195cb008830SSimon Glass    ./tools/moveconfig.py -s -i CONFIG_SCSI \
196cb008830SSimon Glass            -a CONFIG_ARCH_LS1021A,CONFIG_ARCH_LS1043A
197cb008830SSimon Glass
198cb008830SSimon GlassThis will add 'imply SCSI' to the two CONFIG options mentioned, assuming that
199cb008830SSimon Glassthe database indicates that they do actually imply CONFIG_SCSI and do not
200cb008830SSimon Glassalready have an 'imply SCSI'.
201cb008830SSimon Glass
202cb008830SSimon GlassThe output shows where the imply is added:
203cb008830SSimon Glass
204cb008830SSimon Glass   18 : CONFIG_ARCH_LS1021A       arch/arm/cpu/armv7/ls102xa/Kconfig:1
205cb008830SSimon Glass   13 : CONFIG_ARCH_LS1043A       arch/arm/cpu/armv8/fsl-layerscape/Kconfig:11
206cb008830SSimon Glass   12 : CONFIG_ARCH_LS1046A       arch/arm/cpu/armv8/fsl-layerscape/Kconfig:31
207cb008830SSimon Glass
208cb008830SSimon GlassThe first number is the number of boards which can avoid having a special
209cb008830SSimon GlassCONFIG_SCSI option in their defconfig file if this 'imply' is added.
210cb008830SSimon GlassThe location at the right is the Kconfig file and line number where the config
211cb008830SSimon Glassappears. For example, adding 'imply CONFIG_SCSI' to the 'config ARCH_LS1021A'
212cb008830SSimon Glassin arch/arm/cpu/armv7/ls102xa/Kconfig at line 1 will help 18 boards to reduce
213cb008830SSimon Glassthe size of their defconfig files.
214cb008830SSimon Glass
215cb008830SSimon GlassIf you want to add an 'imply' to every imply config in the list, you can use
216cb008830SSimon Glass
217cb008830SSimon Glass    ./tools/moveconfig.py -s -i CONFIG_SCSI -a all
218cb008830SSimon Glass
219cb008830SSimon GlassTo control which ones are displayed, use -I <list> where list is a list of
220cb008830SSimon Glassoptions (use '-I help' to see possible options and their meaning).
221cb008830SSimon Glass
222cb008830SSimon GlassTo skip showing you options that already have an 'imply' attached, use -A.
223cb008830SSimon Glass
224cb008830SSimon GlassWhen you have finished adding 'imply' options you can regenerate the
225cb008830SSimon Glassdefconfig files for affected boards with something like:
226cb008830SSimon Glass
227cb008830SSimon Glass    git show --stat | ./tools/moveconfig.py -s -d -
228cb008830SSimon Glass
229cb008830SSimon GlassThis will regenerate only those defconfigs changed in the current commit.
230cb008830SSimon GlassIf you start with (say) 100 defconfigs being changed in the commit, and add
231cb008830SSimon Glassa few 'imply' options as above, then regenerate, hopefully you can reduce the
232cb008830SSimon Glassnumber of defconfigs changed in the commit.
233cb008830SSimon Glass
23499b66605SSimon Glass
2355a27c734SMasahiro YamadaAvailable options
2365a27c734SMasahiro Yamada-----------------
2375a27c734SMasahiro Yamada
2385a27c734SMasahiro Yamada -c, --color
2395a27c734SMasahiro Yamada   Surround each portion of the log with escape sequences to display it
2405a27c734SMasahiro Yamada   in color on the terminal.
2415a27c734SMasahiro Yamada
2429ede2123SSimon Glass -C, --commit
2439ede2123SSimon Glass   Create a git commit with the changes when the operation is complete. A
2449ede2123SSimon Glass   standard commit message is used which may need to be edited.
2459ede2123SSimon Glass
24691040e85SJoe Hershberger -d, --defconfigs
2470dbc9b59SMasahiro Yamada  Specify a file containing a list of defconfigs to move.  The defconfig
248ddf91c64SSimon Glass  files can be given with shell-style wildcards. Use '-' to read from stdin.
24991040e85SJoe Hershberger
2505a27c734SMasahiro Yamada -n, --dry-run
251b6ef393aSMasahiro Yamada   Perform a trial run that does not make any changes.  It is useful to
2525a27c734SMasahiro Yamada   see what is going to happen before one actually runs it.
2535a27c734SMasahiro Yamada
2545a27c734SMasahiro Yamada -e, --exit-on-error
2555a27c734SMasahiro Yamada   Exit immediately if Make exits with a non-zero status while processing
2565a27c734SMasahiro Yamada   a defconfig file.
2575a27c734SMasahiro Yamada
2588513dc04SMasahiro Yamada -s, --force-sync
2598513dc04SMasahiro Yamada   Do "make savedefconfig" forcibly for all the defconfig files.
2608513dc04SMasahiro Yamada   If not specified, "make savedefconfig" only occurs for cases
2618513dc04SMasahiro Yamada   where at least one CONFIG was moved.
2628513dc04SMasahiro Yamada
26307913d1eSMasahiro Yamada -S, --spl
26407913d1eSMasahiro Yamada   Look for moved config options in spl/include/autoconf.mk instead of
26507913d1eSMasahiro Yamada   include/autoconf.mk.  This is useful for moving options for SPL build
26607913d1eSMasahiro Yamada   because SPL related options (mostly prefixed with CONFIG_SPL_) are
26707913d1eSMasahiro Yamada   sometimes blocked by CONFIG_SPL_BUILD ifdef conditionals.
26807913d1eSMasahiro Yamada
2692144f880SJoe Hershberger -H, --headers-only
2702144f880SJoe Hershberger   Only cleanup the headers; skip the defconfig processing
2712144f880SJoe Hershberger
2725a27c734SMasahiro Yamada -j, --jobs
2735a27c734SMasahiro Yamada   Specify the number of threads to run simultaneously.  If not specified,
2745a27c734SMasahiro Yamada   the number of threads is the same as the number of CPU cores.
2755a27c734SMasahiro Yamada
2766b96c1a1SJoe Hershberger -r, --git-ref
2776b96c1a1SJoe Hershberger   Specify the git ref to clone for building the autoconf.mk. If unspecified
2786b96c1a1SJoe Hershberger   use the CWD. This is useful for when changes to the Kconfig affect the
2796b96c1a1SJoe Hershberger   default values and you want to capture the state of the defconfig from
2806b96c1a1SJoe Hershberger   before that change was in effect. If in doubt, specify a ref pre-Kconfig
2816b96c1a1SJoe Hershberger   changes (use HEAD if Kconfig changes are not committed). Worst case it will
2826b96c1a1SJoe Hershberger   take a bit longer to run, but will always do the right thing.
2836b96c1a1SJoe Hershberger
28495bf9c7eSJoe Hershberger -v, --verbose
28595bf9c7eSJoe Hershberger   Show any build errors as boards are built
28695bf9c7eSJoe Hershberger
2876b403dfdSSimon Glass -y, --yes
2886b403dfdSSimon Glass   Instead of prompting, automatically go ahead with all operations. This
289ddf91c64SSimon Glass   includes cleaning up headers, CONFIG_SYS_EXTRA_OPTIONS, the config whitelist
290ddf91c64SSimon Glass   and the README.
2916b403dfdSSimon Glass
2925a27c734SMasahiro YamadaTo see the complete list of supported options, run
2935a27c734SMasahiro Yamada
2945a27c734SMasahiro Yamada  $ tools/moveconfig.py -h
2955a27c734SMasahiro Yamada
2965a27c734SMasahiro Yamada"""
2975a27c734SMasahiro Yamada
29899b66605SSimon Glassimport collections
2998ba1f5deSMasahiro Yamadaimport copy
300f2f6981aSMasahiro Yamadaimport difflib
301c8e1b10dSMasahiro Yamadaimport filecmp
3025a27c734SMasahiro Yamadaimport fnmatch
3030dbc9b59SMasahiro Yamadaimport glob
3045a27c734SMasahiro Yamadaimport multiprocessing
3055a27c734SMasahiro Yamadaimport optparse
3065a27c734SMasahiro Yamadaimport os
307d73fcb12SSimon Glassimport Queue
3085a27c734SMasahiro Yamadaimport re
3095a27c734SMasahiro Yamadaimport shutil
3105a27c734SMasahiro Yamadaimport subprocess
3115a27c734SMasahiro Yamadaimport sys
3125a27c734SMasahiro Yamadaimport tempfile
313d73fcb12SSimon Glassimport threading
3145a27c734SMasahiro Yamadaimport time
3155a27c734SMasahiro Yamada
316cb008830SSimon Glasssys.path.append(os.path.join(os.path.dirname(__file__), 'buildman'))
3176821a745SSimon Glasssys.path.append(os.path.join(os.path.dirname(__file__), 'patman'))
3186821a745SSimon Glassimport bsettings
319cb008830SSimon Glassimport kconfiglib
3206821a745SSimon Glassimport toolchain
321cb008830SSimon Glass
3225a27c734SMasahiro YamadaSHOW_GNU_MAKE = 'scripts/show-gnu-make'
3235a27c734SMasahiro YamadaSLEEP_TIME=0.03
3245a27c734SMasahiro Yamada
3255a27c734SMasahiro YamadaSTATE_IDLE = 0
3265a27c734SMasahiro YamadaSTATE_DEFCONFIG = 1
3275a27c734SMasahiro YamadaSTATE_AUTOCONF = 2
32896464badSJoe HershbergerSTATE_SAVEDEFCONFIG = 3
3295a27c734SMasahiro Yamada
3305a27c734SMasahiro YamadaACTION_MOVE = 0
331cc008299SMasahiro YamadaACTION_NO_ENTRY = 1
332916224c3SMasahiro YamadaACTION_NO_ENTRY_WARN = 2
333916224c3SMasahiro YamadaACTION_NO_CHANGE = 3
3345a27c734SMasahiro Yamada
3355a27c734SMasahiro YamadaCOLOR_BLACK        = '0;30'
3365a27c734SMasahiro YamadaCOLOR_RED          = '0;31'
3375a27c734SMasahiro YamadaCOLOR_GREEN        = '0;32'
3385a27c734SMasahiro YamadaCOLOR_BROWN        = '0;33'
3395a27c734SMasahiro YamadaCOLOR_BLUE         = '0;34'
3405a27c734SMasahiro YamadaCOLOR_PURPLE       = '0;35'
3415a27c734SMasahiro YamadaCOLOR_CYAN         = '0;36'
3425a27c734SMasahiro YamadaCOLOR_LIGHT_GRAY   = '0;37'
3435a27c734SMasahiro YamadaCOLOR_DARK_GRAY    = '1;30'
3445a27c734SMasahiro YamadaCOLOR_LIGHT_RED    = '1;31'
3455a27c734SMasahiro YamadaCOLOR_LIGHT_GREEN  = '1;32'
3465a27c734SMasahiro YamadaCOLOR_YELLOW       = '1;33'
3475a27c734SMasahiro YamadaCOLOR_LIGHT_BLUE   = '1;34'
3485a27c734SMasahiro YamadaCOLOR_LIGHT_PURPLE = '1;35'
3495a27c734SMasahiro YamadaCOLOR_LIGHT_CYAN   = '1;36'
3505a27c734SMasahiro YamadaCOLOR_WHITE        = '1;37'
3515a27c734SMasahiro Yamada
352f3b8e647SSimon GlassAUTO_CONF_PATH = 'include/config/auto.conf'
353d73fcb12SSimon GlassCONFIG_DATABASE = 'moveconfig.db'
354f3b8e647SSimon Glass
355cb008830SSimon GlassCONFIG_LEN = len('CONFIG_')
356f3b8e647SSimon Glass
3575a27c734SMasahiro Yamada### helper functions ###
3585a27c734SMasahiro Yamadadef get_devnull():
3595a27c734SMasahiro Yamada    """Get the file object of '/dev/null' device."""
3605a27c734SMasahiro Yamada    try:
3615a27c734SMasahiro Yamada        devnull = subprocess.DEVNULL # py3k
3625a27c734SMasahiro Yamada    except AttributeError:
3635a27c734SMasahiro Yamada        devnull = open(os.devnull, 'wb')
3645a27c734SMasahiro Yamada    return devnull
3655a27c734SMasahiro Yamada
3665a27c734SMasahiro Yamadadef check_top_directory():
3675a27c734SMasahiro Yamada    """Exit if we are not at the top of source directory."""
3685a27c734SMasahiro Yamada    for f in ('README', 'Licenses'):
3695a27c734SMasahiro Yamada        if not os.path.exists(f):
3705a27c734SMasahiro Yamada            sys.exit('Please run at the top of source directory.')
3715a27c734SMasahiro Yamada
372bd63e5baSMasahiro Yamadadef check_clean_directory():
373bd63e5baSMasahiro Yamada    """Exit if the source tree is not clean."""
374bd63e5baSMasahiro Yamada    for f in ('.config', 'include/config'):
375bd63e5baSMasahiro Yamada        if os.path.exists(f):
376bd63e5baSMasahiro Yamada            sys.exit("source tree is not clean, please run 'make mrproper'")
377bd63e5baSMasahiro Yamada
3785a27c734SMasahiro Yamadadef get_make_cmd():
3795a27c734SMasahiro Yamada    """Get the command name of GNU Make.
3805a27c734SMasahiro Yamada
3815a27c734SMasahiro Yamada    U-Boot needs GNU Make for building, but the command name is not
3825a27c734SMasahiro Yamada    necessarily "make". (for example, "gmake" on FreeBSD).
3835a27c734SMasahiro Yamada    Returns the most appropriate command name on your system.
3845a27c734SMasahiro Yamada    """
3855a27c734SMasahiro Yamada    process = subprocess.Popen([SHOW_GNU_MAKE], stdout=subprocess.PIPE)
3865a27c734SMasahiro Yamada    ret = process.communicate()
3875a27c734SMasahiro Yamada    if process.returncode:
3885a27c734SMasahiro Yamada        sys.exit('GNU Make not found')
3895a27c734SMasahiro Yamada    return ret[0].rstrip()
3905a27c734SMasahiro Yamada
39125f978cbSSimon Glassdef get_matched_defconfig(line):
39225f978cbSSimon Glass    """Get the defconfig files that match a pattern
39325f978cbSSimon Glass
39425f978cbSSimon Glass    Args:
39525f978cbSSimon Glass        line: Path or filename to match, e.g. 'configs/snow_defconfig' or
39625f978cbSSimon Glass            'k2*_defconfig'. If no directory is provided, 'configs/' is
39725f978cbSSimon Glass            prepended
39825f978cbSSimon Glass
39925f978cbSSimon Glass    Returns:
40025f978cbSSimon Glass        a list of matching defconfig files
40125f978cbSSimon Glass    """
40225f978cbSSimon Glass    dirname = os.path.dirname(line)
40325f978cbSSimon Glass    if dirname:
40425f978cbSSimon Glass        pattern = line
40525f978cbSSimon Glass    else:
40625f978cbSSimon Glass        pattern = os.path.join('configs', line)
40725f978cbSSimon Glass    return glob.glob(pattern) + glob.glob(pattern + '_defconfig')
40825f978cbSSimon Glass
4090dbc9b59SMasahiro Yamadadef get_matched_defconfigs(defconfigs_file):
410ee4e61bdSSimon Glass    """Get all the defconfig files that match the patterns in a file.
411ee4e61bdSSimon Glass
412ee4e61bdSSimon Glass    Args:
413ee4e61bdSSimon Glass        defconfigs_file: File containing a list of defconfigs to process, or
414ee4e61bdSSimon Glass            '-' to read the list from stdin
415ee4e61bdSSimon Glass
416ee4e61bdSSimon Glass    Returns:
417ee4e61bdSSimon Glass        A list of paths to defconfig files, with no duplicates
418ee4e61bdSSimon Glass    """
4190dbc9b59SMasahiro Yamada    defconfigs = []
420ee4e61bdSSimon Glass    if defconfigs_file == '-':
421ee4e61bdSSimon Glass        fd = sys.stdin
422ee4e61bdSSimon Glass        defconfigs_file = 'stdin'
423ee4e61bdSSimon Glass    else:
424ee4e61bdSSimon Glass        fd = open(defconfigs_file)
425ee4e61bdSSimon Glass    for i, line in enumerate(fd):
4260dbc9b59SMasahiro Yamada        line = line.strip()
4270dbc9b59SMasahiro Yamada        if not line:
4280dbc9b59SMasahiro Yamada            continue # skip blank lines silently
4292ddd85dcSSimon Glass        if ' ' in line:
4302ddd85dcSSimon Glass            line = line.split(' ')[0]  # handle 'git log' input
43125f978cbSSimon Glass        matched = get_matched_defconfig(line)
4320dbc9b59SMasahiro Yamada        if not matched:
4330dbc9b59SMasahiro Yamada            print >> sys.stderr, "warning: %s:%d: no defconfig matched '%s'" % \
4340dbc9b59SMasahiro Yamada                                                 (defconfigs_file, i + 1, line)
4350dbc9b59SMasahiro Yamada
4360dbc9b59SMasahiro Yamada        defconfigs += matched
4370dbc9b59SMasahiro Yamada
4380dbc9b59SMasahiro Yamada    # use set() to drop multiple matching
4390dbc9b59SMasahiro Yamada    return [ defconfig[len('configs') + 1:]  for defconfig in set(defconfigs) ]
4400dbc9b59SMasahiro Yamada
441684c306eSMasahiro Yamadadef get_all_defconfigs():
442684c306eSMasahiro Yamada    """Get all the defconfig files under the configs/ directory."""
443684c306eSMasahiro Yamada    defconfigs = []
444684c306eSMasahiro Yamada    for (dirpath, dirnames, filenames) in os.walk('configs'):
445684c306eSMasahiro Yamada        dirpath = dirpath[len('configs') + 1:]
446684c306eSMasahiro Yamada        for filename in fnmatch.filter(filenames, '*_defconfig'):
447684c306eSMasahiro Yamada            defconfigs.append(os.path.join(dirpath, filename))
448684c306eSMasahiro Yamada
449684c306eSMasahiro Yamada    return defconfigs
450684c306eSMasahiro Yamada
4515a27c734SMasahiro Yamadadef color_text(color_enabled, color, string):
4525a27c734SMasahiro Yamada    """Return colored string."""
4535a27c734SMasahiro Yamada    if color_enabled:
4541d085568SMasahiro Yamada        # LF should not be surrounded by the escape sequence.
4551d085568SMasahiro Yamada        # Otherwise, additional whitespace or line-feed might be printed.
4561d085568SMasahiro Yamada        return '\n'.join([ '\033[' + color + 'm' + s + '\033[0m' if s else ''
4571d085568SMasahiro Yamada                           for s in string.split('\n') ])
4585a27c734SMasahiro Yamada    else:
4595a27c734SMasahiro Yamada        return string
4605a27c734SMasahiro Yamada
461e9ea1221SMasahiro Yamadadef show_diff(a, b, file_path, color_enabled):
462f2f6981aSMasahiro Yamada    """Show unidified diff.
463f2f6981aSMasahiro Yamada
464f2f6981aSMasahiro Yamada    Arguments:
465f2f6981aSMasahiro Yamada      a: A list of lines (before)
466f2f6981aSMasahiro Yamada      b: A list of lines (after)
467f2f6981aSMasahiro Yamada      file_path: Path to the file
468e9ea1221SMasahiro Yamada      color_enabled: Display the diff in color
469f2f6981aSMasahiro Yamada    """
470f2f6981aSMasahiro Yamada
471f2f6981aSMasahiro Yamada    diff = difflib.unified_diff(a, b,
472f2f6981aSMasahiro Yamada                                fromfile=os.path.join('a', file_path),
473f2f6981aSMasahiro Yamada                                tofile=os.path.join('b', file_path))
474f2f6981aSMasahiro Yamada
475f2f6981aSMasahiro Yamada    for line in diff:
476e9ea1221SMasahiro Yamada        if line[0] == '-' and line[1] != '-':
477e9ea1221SMasahiro Yamada            print color_text(color_enabled, COLOR_RED, line),
478e9ea1221SMasahiro Yamada        elif line[0] == '+' and line[1] != '+':
479e9ea1221SMasahiro Yamada            print color_text(color_enabled, COLOR_GREEN, line),
480e9ea1221SMasahiro Yamada        else:
481f2f6981aSMasahiro Yamada            print line,
482f2f6981aSMasahiro Yamada
4838ba1f5deSMasahiro Yamadadef extend_matched_lines(lines, matched, pre_patterns, post_patterns, extend_pre,
4848ba1f5deSMasahiro Yamada                         extend_post):
4858ba1f5deSMasahiro Yamada    """Extend matched lines if desired patterns are found before/after already
4868ba1f5deSMasahiro Yamada    matched lines.
4878ba1f5deSMasahiro Yamada
4888ba1f5deSMasahiro Yamada    Arguments:
4898ba1f5deSMasahiro Yamada      lines: A list of lines handled.
4908ba1f5deSMasahiro Yamada      matched: A list of line numbers that have been already matched.
4918ba1f5deSMasahiro Yamada               (will be updated by this function)
4928ba1f5deSMasahiro Yamada      pre_patterns: A list of regular expression that should be matched as
4938ba1f5deSMasahiro Yamada                    preamble.
4948ba1f5deSMasahiro Yamada      post_patterns: A list of regular expression that should be matched as
4958ba1f5deSMasahiro Yamada                     postamble.
4968ba1f5deSMasahiro Yamada      extend_pre: Add the line number of matched preamble to the matched list.
4978ba1f5deSMasahiro Yamada      extend_post: Add the line number of matched postamble to the matched list.
4988ba1f5deSMasahiro Yamada    """
4998ba1f5deSMasahiro Yamada    extended_matched = []
5008ba1f5deSMasahiro Yamada
5018ba1f5deSMasahiro Yamada    j = matched[0]
5028ba1f5deSMasahiro Yamada
5038ba1f5deSMasahiro Yamada    for i in matched:
5048ba1f5deSMasahiro Yamada        if i == 0 or i < j:
5058ba1f5deSMasahiro Yamada            continue
5068ba1f5deSMasahiro Yamada        j = i
5078ba1f5deSMasahiro Yamada        while j in matched:
5088ba1f5deSMasahiro Yamada            j += 1
5098ba1f5deSMasahiro Yamada        if j >= len(lines):
5108ba1f5deSMasahiro Yamada            break
5118ba1f5deSMasahiro Yamada
5128ba1f5deSMasahiro Yamada        for p in pre_patterns:
5138ba1f5deSMasahiro Yamada            if p.search(lines[i - 1]):
5148ba1f5deSMasahiro Yamada                break
5158ba1f5deSMasahiro Yamada        else:
5168ba1f5deSMasahiro Yamada            # not matched
5178ba1f5deSMasahiro Yamada            continue
5188ba1f5deSMasahiro Yamada
5198ba1f5deSMasahiro Yamada        for p in post_patterns:
5208ba1f5deSMasahiro Yamada            if p.search(lines[j]):
5218ba1f5deSMasahiro Yamada                break
5228ba1f5deSMasahiro Yamada        else:
5238ba1f5deSMasahiro Yamada            # not matched
5248ba1f5deSMasahiro Yamada            continue
5258ba1f5deSMasahiro Yamada
5268ba1f5deSMasahiro Yamada        if extend_pre:
5278ba1f5deSMasahiro Yamada            extended_matched.append(i - 1)
5288ba1f5deSMasahiro Yamada        if extend_post:
5298ba1f5deSMasahiro Yamada            extended_matched.append(j)
5308ba1f5deSMasahiro Yamada
5318ba1f5deSMasahiro Yamada    matched += extended_matched
5328ba1f5deSMasahiro Yamada    matched.sort()
5338ba1f5deSMasahiro Yamada
53485edfc1fSChris Packhamdef confirm(options, prompt):
53585edfc1fSChris Packham    if not options.yes:
53685edfc1fSChris Packham        while True:
53785edfc1fSChris Packham            choice = raw_input('{} [y/n]: '.format(prompt))
53885edfc1fSChris Packham            choice = choice.lower()
53985edfc1fSChris Packham            print choice
54085edfc1fSChris Packham            if choice == 'y' or choice == 'n':
54185edfc1fSChris Packham                break
54285edfc1fSChris Packham
54385edfc1fSChris Packham        if choice == 'n':
54485edfc1fSChris Packham            return False
54585edfc1fSChris Packham
54685edfc1fSChris Packham    return True
54785edfc1fSChris Packham
548*4d9dbb1fSChris Packhamdef cleanup_empty_blocks(header_path, options):
549*4d9dbb1fSChris Packham    """Clean up empty conditional blocks
550*4d9dbb1fSChris Packham
551*4d9dbb1fSChris Packham    Arguments:
552*4d9dbb1fSChris Packham      header_path: path to the cleaned file.
553*4d9dbb1fSChris Packham      options: option flags.
554*4d9dbb1fSChris Packham    """
555*4d9dbb1fSChris Packham    pattern = re.compile(r'^\s*#\s*if.*$\n^\s*#\s*endif.*$\n*', flags=re.M)
556*4d9dbb1fSChris Packham    with open(header_path) as f:
557*4d9dbb1fSChris Packham        data = f.read()
558*4d9dbb1fSChris Packham
559*4d9dbb1fSChris Packham    new_data = pattern.sub('\n', data)
560*4d9dbb1fSChris Packham
561*4d9dbb1fSChris Packham    show_diff(data.splitlines(True), new_data.splitlines(True), header_path,
562*4d9dbb1fSChris Packham              options.color)
563*4d9dbb1fSChris Packham
564*4d9dbb1fSChris Packham    if options.dry_run:
565*4d9dbb1fSChris Packham        return
566*4d9dbb1fSChris Packham
567*4d9dbb1fSChris Packham    with open(header_path, 'w') as f:
568*4d9dbb1fSChris Packham        f.write(new_data)
569*4d9dbb1fSChris Packham
570e9ea1221SMasahiro Yamadadef cleanup_one_header(header_path, patterns, options):
5715a27c734SMasahiro Yamada    """Clean regex-matched lines away from a file.
5725a27c734SMasahiro Yamada
5735a27c734SMasahiro Yamada    Arguments:
5745a27c734SMasahiro Yamada      header_path: path to the cleaned file.
5755a27c734SMasahiro Yamada      patterns: list of regex patterns.  Any lines matching to these
5765a27c734SMasahiro Yamada                patterns are deleted.
577e9ea1221SMasahiro Yamada      options: option flags.
5785a27c734SMasahiro Yamada    """
5795a27c734SMasahiro Yamada    with open(header_path) as f:
5805a27c734SMasahiro Yamada        lines = f.readlines()
5815a27c734SMasahiro Yamada
5825a27c734SMasahiro Yamada    matched = []
5835a27c734SMasahiro Yamada    for i, line in enumerate(lines):
584a3a779f7SMasahiro Yamada        if i - 1 in matched and lines[i - 1][-2:] == '\\\n':
585a3a779f7SMasahiro Yamada            matched.append(i)
586a3a779f7SMasahiro Yamada            continue
5875a27c734SMasahiro Yamada        for pattern in patterns:
5888ba1f5deSMasahiro Yamada            if pattern.search(line):
5895a27c734SMasahiro Yamada                matched.append(i)
5905a27c734SMasahiro Yamada                break
5915a27c734SMasahiro Yamada
5928ba1f5deSMasahiro Yamada    if not matched:
5938ba1f5deSMasahiro Yamada        return
5948ba1f5deSMasahiro Yamada
5958ba1f5deSMasahiro Yamada    # remove empty #ifdef ... #endif, successive blank lines
5968ba1f5deSMasahiro Yamada    pattern_if = re.compile(r'#\s*if(def|ndef)?\W') #  #if, #ifdef, #ifndef
5978ba1f5deSMasahiro Yamada    pattern_elif = re.compile(r'#\s*el(if|se)\W')   #  #elif, #else
5988ba1f5deSMasahiro Yamada    pattern_endif = re.compile(r'#\s*endif\W')      #  #endif
5998ba1f5deSMasahiro Yamada    pattern_blank = re.compile(r'^\s*$')            #  empty line
6008ba1f5deSMasahiro Yamada
6018ba1f5deSMasahiro Yamada    while True:
6028ba1f5deSMasahiro Yamada        old_matched = copy.copy(matched)
6038ba1f5deSMasahiro Yamada        extend_matched_lines(lines, matched, [pattern_if],
6048ba1f5deSMasahiro Yamada                             [pattern_endif], True, True)
6058ba1f5deSMasahiro Yamada        extend_matched_lines(lines, matched, [pattern_elif],
6068ba1f5deSMasahiro Yamada                             [pattern_elif, pattern_endif], True, False)
6078ba1f5deSMasahiro Yamada        extend_matched_lines(lines, matched, [pattern_if, pattern_elif],
6088ba1f5deSMasahiro Yamada                             [pattern_blank], False, True)
6098ba1f5deSMasahiro Yamada        extend_matched_lines(lines, matched, [pattern_blank],
6108ba1f5deSMasahiro Yamada                             [pattern_elif, pattern_endif], True, False)
6118ba1f5deSMasahiro Yamada        extend_matched_lines(lines, matched, [pattern_blank],
6128ba1f5deSMasahiro Yamada                             [pattern_blank], True, False)
6138ba1f5deSMasahiro Yamada        if matched == old_matched:
6148ba1f5deSMasahiro Yamada            break
6158ba1f5deSMasahiro Yamada
616f2f6981aSMasahiro Yamada    tolines = copy.copy(lines)
617f2f6981aSMasahiro Yamada
618f2f6981aSMasahiro Yamada    for i in reversed(matched):
619f2f6981aSMasahiro Yamada        tolines.pop(i)
620f2f6981aSMasahiro Yamada
621e9ea1221SMasahiro Yamada    show_diff(lines, tolines, header_path, options.color)
6228ba1f5deSMasahiro Yamada
623e9ea1221SMasahiro Yamada    if options.dry_run:
6245a27c734SMasahiro Yamada        return
6255a27c734SMasahiro Yamada
6265a27c734SMasahiro Yamada    with open(header_path, 'w') as f:
627f2f6981aSMasahiro Yamada        for line in tolines:
6285a27c734SMasahiro Yamada            f.write(line)
6295a27c734SMasahiro Yamada
630e9ea1221SMasahiro Yamadadef cleanup_headers(configs, options):
6315a27c734SMasahiro Yamada    """Delete config defines from board headers.
6325a27c734SMasahiro Yamada
6335a27c734SMasahiro Yamada    Arguments:
634b134bc13SMasahiro Yamada      configs: A list of CONFIGs to remove.
635e9ea1221SMasahiro Yamada      options: option flags.
6365a27c734SMasahiro Yamada    """
63785edfc1fSChris Packham    if not confirm(options, 'Clean up headers?'):
6385a27c734SMasahiro Yamada        return
6395a27c734SMasahiro Yamada
6405a27c734SMasahiro Yamada    patterns = []
641b134bc13SMasahiro Yamada    for config in configs:
6425a27c734SMasahiro Yamada        patterns.append(re.compile(r'#\s*define\s+%s\W' % config))
6435a27c734SMasahiro Yamada        patterns.append(re.compile(r'#\s*undef\s+%s\W' % config))
6445a27c734SMasahiro Yamada
64560727f51SJoe Hershberger    for dir in 'include', 'arch', 'board':
64660727f51SJoe Hershberger        for (dirpath, dirnames, filenames) in os.walk(dir):
647dc6de50bSMasahiro Yamada            if dirpath == os.path.join('include', 'generated'):
648dc6de50bSMasahiro Yamada                continue
6495a27c734SMasahiro Yamada            for filename in filenames:
6505a27c734SMasahiro Yamada                if not fnmatch.fnmatch(filename, '*~'):
651*4d9dbb1fSChris Packham                    header_path = os.path.join(dirpath, filename)
652*4d9dbb1fSChris Packham                    cleanup_one_header(header_path, patterns, options)
653*4d9dbb1fSChris Packham                    cleanup_empty_blocks(header_path, options)
6545a27c734SMasahiro Yamada
6559ab0296aSMasahiro Yamadadef cleanup_one_extra_option(defconfig_path, configs, options):
6569ab0296aSMasahiro Yamada    """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in one defconfig file.
6579ab0296aSMasahiro Yamada
6589ab0296aSMasahiro Yamada    Arguments:
6599ab0296aSMasahiro Yamada      defconfig_path: path to the cleaned defconfig file.
6609ab0296aSMasahiro Yamada      configs: A list of CONFIGs to remove.
6619ab0296aSMasahiro Yamada      options: option flags.
6629ab0296aSMasahiro Yamada    """
6639ab0296aSMasahiro Yamada
6649ab0296aSMasahiro Yamada    start = 'CONFIG_SYS_EXTRA_OPTIONS="'
6659ab0296aSMasahiro Yamada    end = '"\n'
6669ab0296aSMasahiro Yamada
6679ab0296aSMasahiro Yamada    with open(defconfig_path) as f:
6689ab0296aSMasahiro Yamada        lines = f.readlines()
6699ab0296aSMasahiro Yamada
6709ab0296aSMasahiro Yamada    for i, line in enumerate(lines):
6719ab0296aSMasahiro Yamada        if line.startswith(start) and line.endswith(end):
6729ab0296aSMasahiro Yamada            break
6739ab0296aSMasahiro Yamada    else:
6749ab0296aSMasahiro Yamada        # CONFIG_SYS_EXTRA_OPTIONS was not found in this defconfig
6759ab0296aSMasahiro Yamada        return
6769ab0296aSMasahiro Yamada
6779ab0296aSMasahiro Yamada    old_tokens = line[len(start):-len(end)].split(',')
6789ab0296aSMasahiro Yamada    new_tokens = []
6799ab0296aSMasahiro Yamada
6809ab0296aSMasahiro Yamada    for token in old_tokens:
6819ab0296aSMasahiro Yamada        pos = token.find('=')
6829ab0296aSMasahiro Yamada        if not (token[:pos] if pos >= 0 else token) in configs:
6839ab0296aSMasahiro Yamada            new_tokens.append(token)
6849ab0296aSMasahiro Yamada
6859ab0296aSMasahiro Yamada    if new_tokens == old_tokens:
6869ab0296aSMasahiro Yamada        return
6879ab0296aSMasahiro Yamada
6889ab0296aSMasahiro Yamada    tolines = copy.copy(lines)
6899ab0296aSMasahiro Yamada
6909ab0296aSMasahiro Yamada    if new_tokens:
6919ab0296aSMasahiro Yamada        tolines[i] = start + ','.join(new_tokens) + end
6929ab0296aSMasahiro Yamada    else:
6939ab0296aSMasahiro Yamada        tolines.pop(i)
6949ab0296aSMasahiro Yamada
6959ab0296aSMasahiro Yamada    show_diff(lines, tolines, defconfig_path, options.color)
6969ab0296aSMasahiro Yamada
6979ab0296aSMasahiro Yamada    if options.dry_run:
6989ab0296aSMasahiro Yamada        return
6999ab0296aSMasahiro Yamada
7009ab0296aSMasahiro Yamada    with open(defconfig_path, 'w') as f:
7019ab0296aSMasahiro Yamada        for line in tolines:
7029ab0296aSMasahiro Yamada            f.write(line)
7039ab0296aSMasahiro Yamada
7049ab0296aSMasahiro Yamadadef cleanup_extra_options(configs, options):
7059ab0296aSMasahiro Yamada    """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in defconfig files.
7069ab0296aSMasahiro Yamada
7079ab0296aSMasahiro Yamada    Arguments:
7089ab0296aSMasahiro Yamada      configs: A list of CONFIGs to remove.
7099ab0296aSMasahiro Yamada      options: option flags.
7109ab0296aSMasahiro Yamada    """
71185edfc1fSChris Packham    if not confirm(options, 'Clean up CONFIG_SYS_EXTRA_OPTIONS?'):
7129ab0296aSMasahiro Yamada        return
7139ab0296aSMasahiro Yamada
7149ab0296aSMasahiro Yamada    configs = [ config[len('CONFIG_'):] for config in configs ]
7159ab0296aSMasahiro Yamada
7169ab0296aSMasahiro Yamada    defconfigs = get_all_defconfigs()
7179ab0296aSMasahiro Yamada
7189ab0296aSMasahiro Yamada    for defconfig in defconfigs:
7199ab0296aSMasahiro Yamada        cleanup_one_extra_option(os.path.join('configs', defconfig), configs,
7209ab0296aSMasahiro Yamada                                 options)
7219ab0296aSMasahiro Yamada
722ca43834dSChris Packhamdef cleanup_whitelist(configs, options):
723ca43834dSChris Packham    """Delete config whitelist entries
724ca43834dSChris Packham
725ca43834dSChris Packham    Arguments:
726ca43834dSChris Packham      configs: A list of CONFIGs to remove.
727ca43834dSChris Packham      options: option flags.
728ca43834dSChris Packham    """
729ca43834dSChris Packham    if not confirm(options, 'Clean up whitelist entries?'):
730ca43834dSChris Packham        return
731ca43834dSChris Packham
732ca43834dSChris Packham    with open(os.path.join('scripts', 'config_whitelist.txt')) as f:
733ca43834dSChris Packham        lines = f.readlines()
734ca43834dSChris Packham
735ca43834dSChris Packham    lines = [x for x in lines if x.strip() not in configs]
736ca43834dSChris Packham
737ca43834dSChris Packham    with open(os.path.join('scripts', 'config_whitelist.txt'), 'w') as f:
738ca43834dSChris Packham        f.write(''.join(lines))
739ca43834dSChris Packham
740f90df596SChris Packhamdef find_matching(patterns, line):
741f90df596SChris Packham    for pat in patterns:
742f90df596SChris Packham        if pat.search(line):
743f90df596SChris Packham            return True
744f90df596SChris Packham    return False
745f90df596SChris Packham
746f90df596SChris Packhamdef cleanup_readme(configs, options):
747f90df596SChris Packham    """Delete config description in README
748f90df596SChris Packham
749f90df596SChris Packham    Arguments:
750f90df596SChris Packham      configs: A list of CONFIGs to remove.
751f90df596SChris Packham      options: option flags.
752f90df596SChris Packham    """
753f90df596SChris Packham    if not confirm(options, 'Clean up README?'):
754f90df596SChris Packham        return
755f90df596SChris Packham
756f90df596SChris Packham    patterns = []
757f90df596SChris Packham    for config in configs:
758f90df596SChris Packham        patterns.append(re.compile(r'^\s+%s' % config))
759f90df596SChris Packham
760f90df596SChris Packham    with open('README') as f:
761f90df596SChris Packham        lines = f.readlines()
762f90df596SChris Packham
763f90df596SChris Packham    found = False
764f90df596SChris Packham    newlines = []
765f90df596SChris Packham    for line in lines:
766f90df596SChris Packham        if not found:
767f90df596SChris Packham            found = find_matching(patterns, line)
768f90df596SChris Packham            if found:
769f90df596SChris Packham                continue
770f90df596SChris Packham
771f90df596SChris Packham        if found and re.search(r'^\s+CONFIG', line):
772f90df596SChris Packham            found = False
773f90df596SChris Packham
774f90df596SChris Packham        if not found:
775f90df596SChris Packham            newlines.append(line)
776f90df596SChris Packham
777f90df596SChris Packham    with open('README', 'w') as f:
778f90df596SChris Packham        f.write(''.join(newlines))
779f90df596SChris Packham
780ca43834dSChris Packham
7815a27c734SMasahiro Yamada### classes ###
782c5e60fd4SMasahiro Yamadaclass Progress:
783c5e60fd4SMasahiro Yamada
784c5e60fd4SMasahiro Yamada    """Progress Indicator"""
785c5e60fd4SMasahiro Yamada
786c5e60fd4SMasahiro Yamada    def __init__(self, total):
787c5e60fd4SMasahiro Yamada        """Create a new progress indicator.
788c5e60fd4SMasahiro Yamada
789c5e60fd4SMasahiro Yamada        Arguments:
790c5e60fd4SMasahiro Yamada          total: A number of defconfig files to process.
791c5e60fd4SMasahiro Yamada        """
792c5e60fd4SMasahiro Yamada        self.current = 0
793c5e60fd4SMasahiro Yamada        self.total = total
794c5e60fd4SMasahiro Yamada
795c5e60fd4SMasahiro Yamada    def inc(self):
796c5e60fd4SMasahiro Yamada        """Increment the number of processed defconfig files."""
797c5e60fd4SMasahiro Yamada
798c5e60fd4SMasahiro Yamada        self.current += 1
799c5e60fd4SMasahiro Yamada
800c5e60fd4SMasahiro Yamada    def show(self):
801c5e60fd4SMasahiro Yamada        """Display the progress."""
802c5e60fd4SMasahiro Yamada        print ' %d defconfigs out of %d\r' % (self.current, self.total),
803c5e60fd4SMasahiro Yamada        sys.stdout.flush()
804c5e60fd4SMasahiro Yamada
805cb008830SSimon Glass
806cb008830SSimon Glassclass KconfigScanner:
807cb008830SSimon Glass    """Kconfig scanner."""
808cb008830SSimon Glass
809cb008830SSimon Glass    def __init__(self):
810cb008830SSimon Glass        """Scan all the Kconfig files and create a Config object."""
811cb008830SSimon Glass        # Define environment variables referenced from Kconfig
812cb008830SSimon Glass        os.environ['srctree'] = os.getcwd()
813cb008830SSimon Glass        os.environ['UBOOTVERSION'] = 'dummy'
814cb008830SSimon Glass        os.environ['KCONFIG_OBJDIR'] = ''
815cb008830SSimon Glass        self.conf = kconfiglib.Config()
816cb008830SSimon Glass
817cb008830SSimon Glass
8185a27c734SMasahiro Yamadaclass KconfigParser:
8195a27c734SMasahiro Yamada
8205a27c734SMasahiro Yamada    """A parser of .config and include/autoconf.mk."""
8215a27c734SMasahiro Yamada
8225a27c734SMasahiro Yamada    re_arch = re.compile(r'CONFIG_SYS_ARCH="(.*)"')
8235a27c734SMasahiro Yamada    re_cpu = re.compile(r'CONFIG_SYS_CPU="(.*)"')
8245a27c734SMasahiro Yamada
825522e8dcbSMasahiro Yamada    def __init__(self, configs, options, build_dir):
8265a27c734SMasahiro Yamada        """Create a new parser.
8275a27c734SMasahiro Yamada
8285a27c734SMasahiro Yamada        Arguments:
829b134bc13SMasahiro Yamada          configs: A list of CONFIGs to move.
8305a27c734SMasahiro Yamada          options: option flags.
8315a27c734SMasahiro Yamada          build_dir: Build directory.
8325a27c734SMasahiro Yamada        """
833b134bc13SMasahiro Yamada        self.configs = configs
8345a27c734SMasahiro Yamada        self.options = options
8351f16992eSMasahiro Yamada        self.dotconfig = os.path.join(build_dir, '.config')
8361f16992eSMasahiro Yamada        self.autoconf = os.path.join(build_dir, 'include', 'autoconf.mk')
83707913d1eSMasahiro Yamada        self.spl_autoconf = os.path.join(build_dir, 'spl', 'include',
83807913d1eSMasahiro Yamada                                         'autoconf.mk')
839f3b8e647SSimon Glass        self.config_autoconf = os.path.join(build_dir, AUTO_CONF_PATH)
8405da4f857SMasahiro Yamada        self.defconfig = os.path.join(build_dir, 'defconfig')
8415a27c734SMasahiro Yamada
8426821a745SSimon Glass    def get_arch(self):
8436821a745SSimon Glass        """Parse .config file and return the architecture.
8445a27c734SMasahiro Yamada
8455a27c734SMasahiro Yamada        Returns:
8466821a745SSimon Glass          Architecture name (e.g. 'arm').
8475a27c734SMasahiro Yamada        """
8485a27c734SMasahiro Yamada        arch = ''
8495a27c734SMasahiro Yamada        cpu = ''
8501f16992eSMasahiro Yamada        for line in open(self.dotconfig):
8515a27c734SMasahiro Yamada            m = self.re_arch.match(line)
8525a27c734SMasahiro Yamada            if m:
8535a27c734SMasahiro Yamada                arch = m.group(1)
8545a27c734SMasahiro Yamada                continue
8555a27c734SMasahiro Yamada            m = self.re_cpu.match(line)
8565a27c734SMasahiro Yamada            if m:
8575a27c734SMasahiro Yamada                cpu = m.group(1)
8585a27c734SMasahiro Yamada
85990ed6cbaSMasahiro Yamada        if not arch:
86090ed6cbaSMasahiro Yamada            return None
8615a27c734SMasahiro Yamada
8625a27c734SMasahiro Yamada        # fix-up for aarch64
8635a27c734SMasahiro Yamada        if arch == 'arm' and cpu == 'armv8':
8645a27c734SMasahiro Yamada            arch = 'aarch64'
8655a27c734SMasahiro Yamada
8666821a745SSimon Glass        return arch
8675a27c734SMasahiro Yamada
868b134bc13SMasahiro Yamada    def parse_one_config(self, config, dotconfig_lines, autoconf_lines):
8695a27c734SMasahiro Yamada        """Parse .config, defconfig, include/autoconf.mk for one config.
8705a27c734SMasahiro Yamada
8715a27c734SMasahiro Yamada        This function looks for the config options in the lines from
8725a27c734SMasahiro Yamada        defconfig, .config, and include/autoconf.mk in order to decide
8735a27c734SMasahiro Yamada        which action should be taken for this defconfig.
8745a27c734SMasahiro Yamada
8755a27c734SMasahiro Yamada        Arguments:
876b134bc13SMasahiro Yamada          config: CONFIG name to parse.
877cc008299SMasahiro Yamada          dotconfig_lines: lines from the .config file.
8785a27c734SMasahiro Yamada          autoconf_lines: lines from the include/autoconf.mk file.
8795a27c734SMasahiro Yamada
8805a27c734SMasahiro Yamada        Returns:
8815a27c734SMasahiro Yamada          A tupple of the action for this defconfig and the line
8825a27c734SMasahiro Yamada          matched for the config.
8835a27c734SMasahiro Yamada        """
8845a27c734SMasahiro Yamada        not_set = '# %s is not set' % config
8855a27c734SMasahiro Yamada
8865a27c734SMasahiro Yamada        for line in autoconf_lines:
8875a27c734SMasahiro Yamada            line = line.rstrip()
8885a27c734SMasahiro Yamada            if line.startswith(config + '='):
889cc008299SMasahiro Yamada                new_val = line
8905a27c734SMasahiro Yamada                break
8915a27c734SMasahiro Yamada        else:
892cc008299SMasahiro Yamada            new_val = not_set
8935a27c734SMasahiro Yamada
894916224c3SMasahiro Yamada        for line in dotconfig_lines:
895916224c3SMasahiro Yamada            line = line.rstrip()
896916224c3SMasahiro Yamada            if line.startswith(config + '=') or line == not_set:
897916224c3SMasahiro Yamada                old_val = line
898916224c3SMasahiro Yamada                break
899916224c3SMasahiro Yamada        else:
900916224c3SMasahiro Yamada            if new_val == not_set:
901916224c3SMasahiro Yamada                return (ACTION_NO_ENTRY, config)
902916224c3SMasahiro Yamada            else:
903916224c3SMasahiro Yamada                return (ACTION_NO_ENTRY_WARN, config)
904916224c3SMasahiro Yamada
905cc008299SMasahiro Yamada        # If this CONFIG is neither bool nor trisate
906cc008299SMasahiro Yamada        if old_val[-2:] != '=y' and old_val[-2:] != '=m' and old_val != not_set:
907cc008299SMasahiro Yamada            # tools/scripts/define2mk.sed changes '1' to 'y'.
908cc008299SMasahiro Yamada            # This is a problem if the CONFIG is int type.
909cc008299SMasahiro Yamada            # Check the type in Kconfig and handle it correctly.
910cc008299SMasahiro Yamada            if new_val[-2:] == '=y':
911cc008299SMasahiro Yamada                new_val = new_val[:-1] + '1'
912cc008299SMasahiro Yamada
9135030159eSMasahiro Yamada        return (ACTION_NO_CHANGE if old_val == new_val else ACTION_MOVE,
9145030159eSMasahiro Yamada                new_val)
9155a27c734SMasahiro Yamada
9161d085568SMasahiro Yamada    def update_dotconfig(self):
9176ff36d21SMasahiro Yamada        """Parse files for the config options and update the .config.
9185a27c734SMasahiro Yamada
919cc008299SMasahiro Yamada        This function parses the generated .config and include/autoconf.mk
920cc008299SMasahiro Yamada        searching the target options.
9216ff36d21SMasahiro Yamada        Move the config option(s) to the .config as needed.
9225a27c734SMasahiro Yamada
9235a27c734SMasahiro Yamada        Arguments:
9245a27c734SMasahiro Yamada          defconfig: defconfig name.
925522e8dcbSMasahiro Yamada
926522e8dcbSMasahiro Yamada        Returns:
9277fb0bacdSMasahiro Yamada          Return a tuple of (updated flag, log string).
9287fb0bacdSMasahiro Yamada          The "updated flag" is True if the .config was updated, False
9297fb0bacdSMasahiro Yamada          otherwise.  The "log string" shows what happend to the .config.
9305a27c734SMasahiro Yamada        """
9315a27c734SMasahiro Yamada
9325a27c734SMasahiro Yamada        results = []
9337fb0bacdSMasahiro Yamada        updated = False
934916224c3SMasahiro Yamada        suspicious = False
93507913d1eSMasahiro Yamada        rm_files = [self.config_autoconf, self.autoconf]
93607913d1eSMasahiro Yamada
93707913d1eSMasahiro Yamada        if self.options.spl:
93807913d1eSMasahiro Yamada            if os.path.exists(self.spl_autoconf):
93907913d1eSMasahiro Yamada                autoconf_path = self.spl_autoconf
94007913d1eSMasahiro Yamada                rm_files.append(self.spl_autoconf)
94107913d1eSMasahiro Yamada            else:
94207913d1eSMasahiro Yamada                for f in rm_files:
94307913d1eSMasahiro Yamada                    os.remove(f)
94407913d1eSMasahiro Yamada                return (updated, suspicious,
94507913d1eSMasahiro Yamada                        color_text(self.options.color, COLOR_BROWN,
94607913d1eSMasahiro Yamada                                   "SPL is not enabled.  Skipped.") + '\n')
94707913d1eSMasahiro Yamada        else:
94807913d1eSMasahiro Yamada            autoconf_path = self.autoconf
9495a27c734SMasahiro Yamada
9501f16992eSMasahiro Yamada        with open(self.dotconfig) as f:
951cc008299SMasahiro Yamada            dotconfig_lines = f.readlines()
9525a27c734SMasahiro Yamada
95307913d1eSMasahiro Yamada        with open(autoconf_path) as f:
9545a27c734SMasahiro Yamada            autoconf_lines = f.readlines()
9555a27c734SMasahiro Yamada
956b134bc13SMasahiro Yamada        for config in self.configs:
957b134bc13SMasahiro Yamada            result = self.parse_one_config(config, dotconfig_lines,
95896464badSJoe Hershberger                                           autoconf_lines)
9595a27c734SMasahiro Yamada            results.append(result)
9605a27c734SMasahiro Yamada
9615a27c734SMasahiro Yamada        log = ''
9625a27c734SMasahiro Yamada
9635a27c734SMasahiro Yamada        for (action, value) in results:
9645a27c734SMasahiro Yamada            if action == ACTION_MOVE:
9655a27c734SMasahiro Yamada                actlog = "Move '%s'" % value
9665a27c734SMasahiro Yamada                log_color = COLOR_LIGHT_GREEN
967cc008299SMasahiro Yamada            elif action == ACTION_NO_ENTRY:
968cc008299SMasahiro Yamada                actlog = "%s is not defined in Kconfig.  Do nothing." % value
9695a27c734SMasahiro Yamada                log_color = COLOR_LIGHT_BLUE
970916224c3SMasahiro Yamada            elif action == ACTION_NO_ENTRY_WARN:
971916224c3SMasahiro Yamada                actlog = "%s is not defined in Kconfig (suspicious).  Do nothing." % value
972916224c3SMasahiro Yamada                log_color = COLOR_YELLOW
973916224c3SMasahiro Yamada                suspicious = True
974cc008299SMasahiro Yamada            elif action == ACTION_NO_CHANGE:
975cc008299SMasahiro Yamada                actlog = "'%s' is the same as the define in Kconfig.  Do nothing." \
976cc008299SMasahiro Yamada                         % value
9775a27c734SMasahiro Yamada                log_color = COLOR_LIGHT_PURPLE
97807913d1eSMasahiro Yamada            elif action == ACTION_SPL_NOT_EXIST:
97907913d1eSMasahiro Yamada                actlog = "SPL is not enabled for this defconfig.  Skip."
98007913d1eSMasahiro Yamada                log_color = COLOR_PURPLE
9815a27c734SMasahiro Yamada            else:
9825a27c734SMasahiro Yamada                sys.exit("Internal Error. This should not happen.")
9835a27c734SMasahiro Yamada
9841d085568SMasahiro Yamada            log += color_text(self.options.color, log_color, actlog) + '\n'
9855a27c734SMasahiro Yamada
9861f16992eSMasahiro Yamada        with open(self.dotconfig, 'a') as f:
9875a27c734SMasahiro Yamada            for (action, value) in results:
9885a27c734SMasahiro Yamada                if action == ACTION_MOVE:
9895a27c734SMasahiro Yamada                    f.write(value + '\n')
9907fb0bacdSMasahiro Yamada                    updated = True
9915a27c734SMasahiro Yamada
9925da4f857SMasahiro Yamada        self.results = results
99307913d1eSMasahiro Yamada        for f in rm_files:
99407913d1eSMasahiro Yamada            os.remove(f)
9955a27c734SMasahiro Yamada
996916224c3SMasahiro Yamada        return (updated, suspicious, log)
997522e8dcbSMasahiro Yamada
9985da4f857SMasahiro Yamada    def check_defconfig(self):
9995da4f857SMasahiro Yamada        """Check the defconfig after savedefconfig
10005da4f857SMasahiro Yamada
10015da4f857SMasahiro Yamada        Returns:
10025da4f857SMasahiro Yamada          Return additional log if moved CONFIGs were removed again by
10035da4f857SMasahiro Yamada          'make savedefconfig'.
10045da4f857SMasahiro Yamada        """
10055da4f857SMasahiro Yamada
10065da4f857SMasahiro Yamada        log = ''
10075da4f857SMasahiro Yamada
10085da4f857SMasahiro Yamada        with open(self.defconfig) as f:
10095da4f857SMasahiro Yamada            defconfig_lines = f.readlines()
10105da4f857SMasahiro Yamada
10115da4f857SMasahiro Yamada        for (action, value) in self.results:
10125da4f857SMasahiro Yamada            if action != ACTION_MOVE:
10135da4f857SMasahiro Yamada                continue
10145da4f857SMasahiro Yamada            if not value + '\n' in defconfig_lines:
10155da4f857SMasahiro Yamada                log += color_text(self.options.color, COLOR_YELLOW,
10165da4f857SMasahiro Yamada                                  "'%s' was removed by savedefconfig.\n" %
10175da4f857SMasahiro Yamada                                  value)
10185da4f857SMasahiro Yamada
10195da4f857SMasahiro Yamada        return log
10205da4f857SMasahiro Yamada
1021d73fcb12SSimon Glass
1022d73fcb12SSimon Glassclass DatabaseThread(threading.Thread):
1023d73fcb12SSimon Glass    """This thread processes results from Slot threads.
1024d73fcb12SSimon Glass
1025d73fcb12SSimon Glass    It collects the data in the master config directary. There is only one
1026d73fcb12SSimon Glass    result thread, and this helps to serialise the build output.
1027d73fcb12SSimon Glass    """
1028d73fcb12SSimon Glass    def __init__(self, config_db, db_queue):
1029d73fcb12SSimon Glass        """Set up a new result thread
1030d73fcb12SSimon Glass
1031d73fcb12SSimon Glass        Args:
1032d73fcb12SSimon Glass            builder: Builder which will be sent each result
1033d73fcb12SSimon Glass        """
1034d73fcb12SSimon Glass        threading.Thread.__init__(self)
1035d73fcb12SSimon Glass        self.config_db = config_db
1036d73fcb12SSimon Glass        self.db_queue= db_queue
1037d73fcb12SSimon Glass
1038d73fcb12SSimon Glass    def run(self):
1039d73fcb12SSimon Glass        """Called to start up the result thread.
1040d73fcb12SSimon Glass
1041d73fcb12SSimon Glass        We collect the next result job and pass it on to the build.
1042d73fcb12SSimon Glass        """
1043d73fcb12SSimon Glass        while True:
1044d73fcb12SSimon Glass            defconfig, configs = self.db_queue.get()
1045d73fcb12SSimon Glass            self.config_db[defconfig] = configs
1046d73fcb12SSimon Glass            self.db_queue.task_done()
1047d73fcb12SSimon Glass
1048d73fcb12SSimon Glass
10495a27c734SMasahiro Yamadaclass Slot:
10505a27c734SMasahiro Yamada
10515a27c734SMasahiro Yamada    """A slot to store a subprocess.
10525a27c734SMasahiro Yamada
10535a27c734SMasahiro Yamada    Each instance of this class handles one subprocess.
10545a27c734SMasahiro Yamada    This class is useful to control multiple threads
10555a27c734SMasahiro Yamada    for faster processing.
10565a27c734SMasahiro Yamada    """
10575a27c734SMasahiro Yamada
10586821a745SSimon Glass    def __init__(self, toolchains, configs, options, progress, devnull,
10596821a745SSimon Glass		 make_cmd, reference_src_dir, db_queue):
10605a27c734SMasahiro Yamada        """Create a new process slot.
10615a27c734SMasahiro Yamada
10625a27c734SMasahiro Yamada        Arguments:
10636821a745SSimon Glass          toolchains: Toolchains object containing toolchains.
1064b134bc13SMasahiro Yamada          configs: A list of CONFIGs to move.
10655a27c734SMasahiro Yamada          options: option flags.
1066c5e60fd4SMasahiro Yamada          progress: A progress indicator.
10675a27c734SMasahiro Yamada          devnull: A file object of '/dev/null'.
10685a27c734SMasahiro Yamada          make_cmd: command name of GNU Make.
10696b96c1a1SJoe Hershberger          reference_src_dir: Determine the true starting config state from this
10706b96c1a1SJoe Hershberger                             source tree.
1071d73fcb12SSimon Glass          db_queue: output queue to write config info for the database
10725a27c734SMasahiro Yamada        """
10736821a745SSimon Glass        self.toolchains = toolchains
10745a27c734SMasahiro Yamada        self.options = options
1075c5e60fd4SMasahiro Yamada        self.progress = progress
10765a27c734SMasahiro Yamada        self.build_dir = tempfile.mkdtemp()
10775a27c734SMasahiro Yamada        self.devnull = devnull
10785a27c734SMasahiro Yamada        self.make_cmd = (make_cmd, 'O=' + self.build_dir)
10796b96c1a1SJoe Hershberger        self.reference_src_dir = reference_src_dir
1080d73fcb12SSimon Glass        self.db_queue = db_queue
1081522e8dcbSMasahiro Yamada        self.parser = KconfigParser(configs, options, self.build_dir)
10825a27c734SMasahiro Yamada        self.state = STATE_IDLE
108309c6c066SMasahiro Yamada        self.failed_boards = set()
108409c6c066SMasahiro Yamada        self.suspicious_boards = set()
10855a27c734SMasahiro Yamada
10865a27c734SMasahiro Yamada    def __del__(self):
10875a27c734SMasahiro Yamada        """Delete the working directory
10885a27c734SMasahiro Yamada
10895a27c734SMasahiro Yamada        This function makes sure the temporary directory is cleaned away
10905a27c734SMasahiro Yamada        even if Python suddenly dies due to error.  It should be done in here
1091f2dae751SJoe Hershberger        because it is guaranteed the destructor is always invoked when the
10925a27c734SMasahiro Yamada        instance of the class gets unreferenced.
10935a27c734SMasahiro Yamada
10945a27c734SMasahiro Yamada        If the subprocess is still running, wait until it finishes.
10955a27c734SMasahiro Yamada        """
10965a27c734SMasahiro Yamada        if self.state != STATE_IDLE:
10975a27c734SMasahiro Yamada            while self.ps.poll() == None:
10985a27c734SMasahiro Yamada                pass
10995a27c734SMasahiro Yamada        shutil.rmtree(self.build_dir)
11005a27c734SMasahiro Yamada
1101c5e60fd4SMasahiro Yamada    def add(self, defconfig):
11025a27c734SMasahiro Yamada        """Assign a new subprocess for defconfig and add it to the slot.
11035a27c734SMasahiro Yamada
11045a27c734SMasahiro Yamada        If the slot is vacant, create a new subprocess for processing the
11055a27c734SMasahiro Yamada        given defconfig and add it to the slot.  Just returns False if
11065a27c734SMasahiro Yamada        the slot is occupied (i.e. the current subprocess is still running).
11075a27c734SMasahiro Yamada
11085a27c734SMasahiro Yamada        Arguments:
11095a27c734SMasahiro Yamada          defconfig: defconfig name.
11105a27c734SMasahiro Yamada
11115a27c734SMasahiro Yamada        Returns:
11125a27c734SMasahiro Yamada          Return True on success or False on failure
11135a27c734SMasahiro Yamada        """
11145a27c734SMasahiro Yamada        if self.state != STATE_IDLE:
11155a27c734SMasahiro Yamada            return False
1116e307fa9dSMasahiro Yamada
11175a27c734SMasahiro Yamada        self.defconfig = defconfig
11181d085568SMasahiro Yamada        self.log = ''
1119f432c33fSMasahiro Yamada        self.current_src_dir = self.reference_src_dir
1120e307fa9dSMasahiro Yamada        self.do_defconfig()
11215a27c734SMasahiro Yamada        return True
11225a27c734SMasahiro Yamada
11235a27c734SMasahiro Yamada    def poll(self):
11245a27c734SMasahiro Yamada        """Check the status of the subprocess and handle it as needed.
11255a27c734SMasahiro Yamada
11265a27c734SMasahiro Yamada        Returns True if the slot is vacant (i.e. in idle state).
11275a27c734SMasahiro Yamada        If the configuration is successfully finished, assign a new
11285a27c734SMasahiro Yamada        subprocess to build include/autoconf.mk.
11295a27c734SMasahiro Yamada        If include/autoconf.mk is generated, invoke the parser to
11307fb0bacdSMasahiro Yamada        parse the .config and the include/autoconf.mk, moving
11317fb0bacdSMasahiro Yamada        config options to the .config as needed.
11327fb0bacdSMasahiro Yamada        If the .config was updated, run "make savedefconfig" to sync
11337fb0bacdSMasahiro Yamada        it, update the original defconfig, and then set the slot back
11347fb0bacdSMasahiro Yamada        to the idle state.
11355a27c734SMasahiro Yamada
11365a27c734SMasahiro Yamada        Returns:
11375a27c734SMasahiro Yamada          Return True if the subprocess is terminated, False otherwise
11385a27c734SMasahiro Yamada        """
11395a27c734SMasahiro Yamada        if self.state == STATE_IDLE:
11405a27c734SMasahiro Yamada            return True
11415a27c734SMasahiro Yamada
11425a27c734SMasahiro Yamada        if self.ps.poll() == None:
11435a27c734SMasahiro Yamada            return False
11445a27c734SMasahiro Yamada
11455a27c734SMasahiro Yamada        if self.ps.poll() != 0:
1146e307fa9dSMasahiro Yamada            self.handle_error()
1147e307fa9dSMasahiro Yamada        elif self.state == STATE_DEFCONFIG:
1148f432c33fSMasahiro Yamada            if self.reference_src_dir and not self.current_src_dir:
11496b96c1a1SJoe Hershberger                self.do_savedefconfig()
11506b96c1a1SJoe Hershberger            else:
1151e307fa9dSMasahiro Yamada                self.do_autoconf()
1152e307fa9dSMasahiro Yamada        elif self.state == STATE_AUTOCONF:
1153f432c33fSMasahiro Yamada            if self.current_src_dir:
1154f432c33fSMasahiro Yamada                self.current_src_dir = None
11556b96c1a1SJoe Hershberger                self.do_defconfig()
1156d73fcb12SSimon Glass            elif self.options.build_db:
1157d73fcb12SSimon Glass                self.do_build_db()
11586b96c1a1SJoe Hershberger            else:
1159e307fa9dSMasahiro Yamada                self.do_savedefconfig()
1160e307fa9dSMasahiro Yamada        elif self.state == STATE_SAVEDEFCONFIG:
1161e307fa9dSMasahiro Yamada            self.update_defconfig()
1162e307fa9dSMasahiro Yamada        else:
1163e307fa9dSMasahiro Yamada            sys.exit("Internal Error. This should not happen.")
1164e307fa9dSMasahiro Yamada
1165e307fa9dSMasahiro Yamada        return True if self.state == STATE_IDLE else False
1166e307fa9dSMasahiro Yamada
1167e307fa9dSMasahiro Yamada    def handle_error(self):
1168e307fa9dSMasahiro Yamada        """Handle error cases."""
1169e307fa9dSMasahiro Yamada
11701d085568SMasahiro Yamada        self.log += color_text(self.options.color, COLOR_LIGHT_RED,
11711d085568SMasahiro Yamada                               "Failed to process.\n")
117295bf9c7eSJoe Hershberger        if self.options.verbose:
11731d085568SMasahiro Yamada            self.log += color_text(self.options.color, COLOR_LIGHT_CYAN,
117490ed6cbaSMasahiro Yamada                                   self.ps.stderr.read())
11754efef998SMasahiro Yamada        self.finish(False)
11765a27c734SMasahiro Yamada
1177e307fa9dSMasahiro Yamada    def do_defconfig(self):
1178e307fa9dSMasahiro Yamada        """Run 'make <board>_defconfig' to create the .config file."""
1179e307fa9dSMasahiro Yamada
1180e307fa9dSMasahiro Yamada        cmd = list(self.make_cmd)
1181e307fa9dSMasahiro Yamada        cmd.append(self.defconfig)
1182e307fa9dSMasahiro Yamada        self.ps = subprocess.Popen(cmd, stdout=self.devnull,
1183f432c33fSMasahiro Yamada                                   stderr=subprocess.PIPE,
1184f432c33fSMasahiro Yamada                                   cwd=self.current_src_dir)
1185e307fa9dSMasahiro Yamada        self.state = STATE_DEFCONFIG
1186e307fa9dSMasahiro Yamada
1187e307fa9dSMasahiro Yamada    def do_autoconf(self):
1188f3b8e647SSimon Glass        """Run 'make AUTO_CONF_PATH'."""
1189e307fa9dSMasahiro Yamada
11906821a745SSimon Glass        arch = self.parser.get_arch()
11916821a745SSimon Glass        try:
11926821a745SSimon Glass            toolchain = self.toolchains.Select(arch)
11936821a745SSimon Glass        except ValueError:
1194e307fa9dSMasahiro Yamada            self.log += color_text(self.options.color, COLOR_YELLOW,
1195ce3ba458SChris Packham                    "Tool chain for '%s' is missing.  Do nothing.\n" % arch)
1196e307fa9dSMasahiro Yamada            self.finish(False)
1197e307fa9dSMasahiro Yamada            return
11986821a745SSimon Glass	env = toolchain.MakeEnvironment(False)
1199e307fa9dSMasahiro Yamada
1200e307fa9dSMasahiro Yamada        cmd = list(self.make_cmd)
1201e307fa9dSMasahiro Yamada        cmd.append('KCONFIG_IGNORE_DUPLICATES=1')
1202f3b8e647SSimon Glass        cmd.append(AUTO_CONF_PATH)
12036821a745SSimon Glass        self.ps = subprocess.Popen(cmd, stdout=self.devnull, env=env,
1204f432c33fSMasahiro Yamada                                   stderr=subprocess.PIPE,
1205f432c33fSMasahiro Yamada                                   cwd=self.current_src_dir)
1206e307fa9dSMasahiro Yamada        self.state = STATE_AUTOCONF
1207e307fa9dSMasahiro Yamada
1208d73fcb12SSimon Glass    def do_build_db(self):
1209d73fcb12SSimon Glass        """Add the board to the database"""
1210d73fcb12SSimon Glass        configs = {}
1211d73fcb12SSimon Glass        with open(os.path.join(self.build_dir, AUTO_CONF_PATH)) as fd:
1212d73fcb12SSimon Glass            for line in fd.readlines():
1213d73fcb12SSimon Glass                if line.startswith('CONFIG'):
1214d73fcb12SSimon Glass                    config, value = line.split('=', 1)
1215d73fcb12SSimon Glass                    configs[config] = value.rstrip()
1216d73fcb12SSimon Glass        self.db_queue.put([self.defconfig, configs])
1217d73fcb12SSimon Glass        self.finish(True)
1218d73fcb12SSimon Glass
1219e307fa9dSMasahiro Yamada    def do_savedefconfig(self):
1220e307fa9dSMasahiro Yamada        """Update the .config and run 'make savedefconfig'."""
1221e307fa9dSMasahiro Yamada
1222916224c3SMasahiro Yamada        (updated, suspicious, log) = self.parser.update_dotconfig()
1223916224c3SMasahiro Yamada        if suspicious:
1224916224c3SMasahiro Yamada            self.suspicious_boards.add(self.defconfig)
12257fb0bacdSMasahiro Yamada        self.log += log
122696464badSJoe Hershberger
12278513dc04SMasahiro Yamada        if not self.options.force_sync and not updated:
12287fb0bacdSMasahiro Yamada            self.finish(True)
1229e307fa9dSMasahiro Yamada            return
12308513dc04SMasahiro Yamada        if updated:
1231c1c4d0f0SMasahiro Yamada            self.log += color_text(self.options.color, COLOR_LIGHT_GREEN,
1232c1c4d0f0SMasahiro Yamada                                   "Syncing by savedefconfig...\n")
12338513dc04SMasahiro Yamada        else:
12348513dc04SMasahiro Yamada            self.log += "Syncing by savedefconfig (forced by option)...\n"
12358513dc04SMasahiro Yamada
123696464badSJoe Hershberger        cmd = list(self.make_cmd)
123796464badSJoe Hershberger        cmd.append('savedefconfig')
123896464badSJoe Hershberger        self.ps = subprocess.Popen(cmd, stdout=self.devnull,
123925400090SJoe Hershberger                                   stderr=subprocess.PIPE)
124096464badSJoe Hershberger        self.state = STATE_SAVEDEFCONFIG
124196464badSJoe Hershberger
1242e307fa9dSMasahiro Yamada    def update_defconfig(self):
1243e307fa9dSMasahiro Yamada        """Update the input defconfig and go back to the idle state."""
1244e307fa9dSMasahiro Yamada
1245fc2661eeSMasahiro Yamada        log = self.parser.check_defconfig()
1246fc2661eeSMasahiro Yamada        if log:
124709c6c066SMasahiro Yamada            self.suspicious_boards.add(self.defconfig)
1248fc2661eeSMasahiro Yamada            self.log += log
1249c8e1b10dSMasahiro Yamada        orig_defconfig = os.path.join('configs', self.defconfig)
1250c8e1b10dSMasahiro Yamada        new_defconfig = os.path.join(self.build_dir, 'defconfig')
1251c8e1b10dSMasahiro Yamada        updated = not filecmp.cmp(orig_defconfig, new_defconfig)
1252c8e1b10dSMasahiro Yamada
1253c8e1b10dSMasahiro Yamada        if updated:
125406cc1d36SJoe Hershberger            self.log += color_text(self.options.color, COLOR_LIGHT_BLUE,
1255c8e1b10dSMasahiro Yamada                                   "defconfig was updated.\n")
1256c8e1b10dSMasahiro Yamada
1257c8e1b10dSMasahiro Yamada        if not self.options.dry_run and updated:
1258c8e1b10dSMasahiro Yamada            shutil.move(new_defconfig, orig_defconfig)
12594efef998SMasahiro Yamada        self.finish(True)
12605a27c734SMasahiro Yamada
12614efef998SMasahiro Yamada    def finish(self, success):
12624efef998SMasahiro Yamada        """Display log along with progress and go to the idle state.
12631d085568SMasahiro Yamada
12641d085568SMasahiro Yamada        Arguments:
12654efef998SMasahiro Yamada          success: Should be True when the defconfig was processed
12664efef998SMasahiro Yamada                   successfully, or False when it fails.
12671d085568SMasahiro Yamada        """
12681d085568SMasahiro Yamada        # output at least 30 characters to hide the "* defconfigs out of *".
12691d085568SMasahiro Yamada        log = self.defconfig.ljust(30) + '\n'
12701d085568SMasahiro Yamada
12711d085568SMasahiro Yamada        log += '\n'.join([ '    ' + s for s in self.log.split('\n') ])
12721d085568SMasahiro Yamada        # Some threads are running in parallel.
12731d085568SMasahiro Yamada        # Print log atomically to not mix up logs from different threads.
12744efef998SMasahiro Yamada        print >> (sys.stdout if success else sys.stderr), log
12754efef998SMasahiro Yamada
12764efef998SMasahiro Yamada        if not success:
12774efef998SMasahiro Yamada            if self.options.exit_on_error:
12784efef998SMasahiro Yamada                sys.exit("Exit on error.")
12794efef998SMasahiro Yamada            # If --exit-on-error flag is not set, skip this board and continue.
12804efef998SMasahiro Yamada            # Record the failed board.
128109c6c066SMasahiro Yamada            self.failed_boards.add(self.defconfig)
12824efef998SMasahiro Yamada
12831d085568SMasahiro Yamada        self.progress.inc()
12841d085568SMasahiro Yamada        self.progress.show()
12854efef998SMasahiro Yamada        self.state = STATE_IDLE
12861d085568SMasahiro Yamada
12875a27c734SMasahiro Yamada    def get_failed_boards(self):
128809c6c066SMasahiro Yamada        """Returns a set of failed boards (defconfigs) in this slot.
12895a27c734SMasahiro Yamada        """
12905a27c734SMasahiro Yamada        return self.failed_boards
12915a27c734SMasahiro Yamada
1292fc2661eeSMasahiro Yamada    def get_suspicious_boards(self):
129309c6c066SMasahiro Yamada        """Returns a set of boards (defconfigs) with possible misconversion.
1294fc2661eeSMasahiro Yamada        """
1295916224c3SMasahiro Yamada        return self.suspicious_boards - self.failed_boards
1296fc2661eeSMasahiro Yamada
12975a27c734SMasahiro Yamadaclass Slots:
12985a27c734SMasahiro Yamada
12995a27c734SMasahiro Yamada    """Controller of the array of subprocess slots."""
13005a27c734SMasahiro Yamada
13016821a745SSimon Glass    def __init__(self, toolchains, configs, options, progress,
13026821a745SSimon Glass		 reference_src_dir, db_queue):
13035a27c734SMasahiro Yamada        """Create a new slots controller.
13045a27c734SMasahiro Yamada
13055a27c734SMasahiro Yamada        Arguments:
13066821a745SSimon Glass          toolchains: Toolchains object containing toolchains.
1307b134bc13SMasahiro Yamada          configs: A list of CONFIGs to move.
13085a27c734SMasahiro Yamada          options: option flags.
1309c5e60fd4SMasahiro Yamada          progress: A progress indicator.
13106b96c1a1SJoe Hershberger          reference_src_dir: Determine the true starting config state from this
13116b96c1a1SJoe Hershberger                             source tree.
1312d73fcb12SSimon Glass          db_queue: output queue to write config info for the database
13135a27c734SMasahiro Yamada        """
13145a27c734SMasahiro Yamada        self.options = options
13155a27c734SMasahiro Yamada        self.slots = []
13165a27c734SMasahiro Yamada        devnull = get_devnull()
13175a27c734SMasahiro Yamada        make_cmd = get_make_cmd()
13185a27c734SMasahiro Yamada        for i in range(options.jobs):
13196821a745SSimon Glass            self.slots.append(Slot(toolchains, configs, options, progress,
13206821a745SSimon Glass				   devnull, make_cmd, reference_src_dir,
13216821a745SSimon Glass				   db_queue))
13225a27c734SMasahiro Yamada
1323c5e60fd4SMasahiro Yamada    def add(self, defconfig):
13245a27c734SMasahiro Yamada        """Add a new subprocess if a vacant slot is found.
13255a27c734SMasahiro Yamada
13265a27c734SMasahiro Yamada        Arguments:
13275a27c734SMasahiro Yamada          defconfig: defconfig name to be put into.
13285a27c734SMasahiro Yamada
13295a27c734SMasahiro Yamada        Returns:
13305a27c734SMasahiro Yamada          Return True on success or False on failure
13315a27c734SMasahiro Yamada        """
13325a27c734SMasahiro Yamada        for slot in self.slots:
1333c5e60fd4SMasahiro Yamada            if slot.add(defconfig):
13345a27c734SMasahiro Yamada                return True
13355a27c734SMasahiro Yamada        return False
13365a27c734SMasahiro Yamada
13375a27c734SMasahiro Yamada    def available(self):
13385a27c734SMasahiro Yamada        """Check if there is a vacant slot.
13395a27c734SMasahiro Yamada
13405a27c734SMasahiro Yamada        Returns:
13415a27c734SMasahiro Yamada          Return True if at lease one vacant slot is found, False otherwise.
13425a27c734SMasahiro Yamada        """
13435a27c734SMasahiro Yamada        for slot in self.slots:
13445a27c734SMasahiro Yamada            if slot.poll():
13455a27c734SMasahiro Yamada                return True
13465a27c734SMasahiro Yamada        return False
13475a27c734SMasahiro Yamada
13485a27c734SMasahiro Yamada    def empty(self):
13495a27c734SMasahiro Yamada        """Check if all slots are vacant.
13505a27c734SMasahiro Yamada
13515a27c734SMasahiro Yamada        Returns:
13525a27c734SMasahiro Yamada          Return True if all the slots are vacant, False otherwise.
13535a27c734SMasahiro Yamada        """
13545a27c734SMasahiro Yamada        ret = True
13555a27c734SMasahiro Yamada        for slot in self.slots:
13565a27c734SMasahiro Yamada            if not slot.poll():
13575a27c734SMasahiro Yamada                ret = False
13585a27c734SMasahiro Yamada        return ret
13595a27c734SMasahiro Yamada
13605a27c734SMasahiro Yamada    def show_failed_boards(self):
13615a27c734SMasahiro Yamada        """Display all of the failed boards (defconfigs)."""
136209c6c066SMasahiro Yamada        boards = set()
136396dccd97SMasahiro Yamada        output_file = 'moveconfig.failed'
13645a27c734SMasahiro Yamada
13655a27c734SMasahiro Yamada        for slot in self.slots:
136609c6c066SMasahiro Yamada            boards |= slot.get_failed_boards()
13675a27c734SMasahiro Yamada
136896dccd97SMasahiro Yamada        if boards:
136996dccd97SMasahiro Yamada            boards = '\n'.join(boards) + '\n'
137096dccd97SMasahiro Yamada            msg = "The following boards were not processed due to error:\n"
137196dccd97SMasahiro Yamada            msg += boards
137296dccd97SMasahiro Yamada            msg += "(the list has been saved in %s)\n" % output_file
137396dccd97SMasahiro Yamada            print >> sys.stderr, color_text(self.options.color, COLOR_LIGHT_RED,
137496dccd97SMasahiro Yamada                                            msg)
13755a27c734SMasahiro Yamada
137696dccd97SMasahiro Yamada            with open(output_file, 'w') as f:
137796dccd97SMasahiro Yamada                f.write(boards)
13782559cd89SJoe Hershberger
1379fc2661eeSMasahiro Yamada    def show_suspicious_boards(self):
1380fc2661eeSMasahiro Yamada        """Display all boards (defconfigs) with possible misconversion."""
138109c6c066SMasahiro Yamada        boards = set()
1382fc2661eeSMasahiro Yamada        output_file = 'moveconfig.suspicious'
1383fc2661eeSMasahiro Yamada
1384fc2661eeSMasahiro Yamada        for slot in self.slots:
138509c6c066SMasahiro Yamada            boards |= slot.get_suspicious_boards()
1386fc2661eeSMasahiro Yamada
1387fc2661eeSMasahiro Yamada        if boards:
1388fc2661eeSMasahiro Yamada            boards = '\n'.join(boards) + '\n'
1389fc2661eeSMasahiro Yamada            msg = "The following boards might have been converted incorrectly.\n"
1390fc2661eeSMasahiro Yamada            msg += "It is highly recommended to check them manually:\n"
1391fc2661eeSMasahiro Yamada            msg += boards
1392fc2661eeSMasahiro Yamada            msg += "(the list has been saved in %s)\n" % output_file
1393fc2661eeSMasahiro Yamada            print >> sys.stderr, color_text(self.options.color, COLOR_YELLOW,
1394fc2661eeSMasahiro Yamada                                            msg)
1395fc2661eeSMasahiro Yamada
1396fc2661eeSMasahiro Yamada            with open(output_file, 'w') as f:
1397fc2661eeSMasahiro Yamada                f.write(boards)
1398fc2661eeSMasahiro Yamada
13995cc42a51SMasahiro Yamadaclass ReferenceSource:
14005cc42a51SMasahiro Yamada
14015cc42a51SMasahiro Yamada    """Reference source against which original configs should be parsed."""
14025cc42a51SMasahiro Yamada
14035cc42a51SMasahiro Yamada    def __init__(self, commit):
14045cc42a51SMasahiro Yamada        """Create a reference source directory based on a specified commit.
14055cc42a51SMasahiro Yamada
14065cc42a51SMasahiro Yamada        Arguments:
14075cc42a51SMasahiro Yamada          commit: commit to git-clone
14085cc42a51SMasahiro Yamada        """
14095cc42a51SMasahiro Yamada        self.src_dir = tempfile.mkdtemp()
14105cc42a51SMasahiro Yamada        print "Cloning git repo to a separate work directory..."
14115cc42a51SMasahiro Yamada        subprocess.check_output(['git', 'clone', os.getcwd(), '.'],
14125cc42a51SMasahiro Yamada                                cwd=self.src_dir)
14135cc42a51SMasahiro Yamada        print "Checkout '%s' to build the original autoconf.mk." % \
14145cc42a51SMasahiro Yamada            subprocess.check_output(['git', 'rev-parse', '--short', commit]).strip()
14155cc42a51SMasahiro Yamada        subprocess.check_output(['git', 'checkout', commit],
14165cc42a51SMasahiro Yamada                                stderr=subprocess.STDOUT, cwd=self.src_dir)
14176b96c1a1SJoe Hershberger
14186b96c1a1SJoe Hershberger    def __del__(self):
14195cc42a51SMasahiro Yamada        """Delete the reference source directory
14206b96c1a1SJoe Hershberger
14216b96c1a1SJoe Hershberger        This function makes sure the temporary directory is cleaned away
14226b96c1a1SJoe Hershberger        even if Python suddenly dies due to error.  It should be done in here
14236b96c1a1SJoe Hershberger        because it is guaranteed the destructor is always invoked when the
14246b96c1a1SJoe Hershberger        instance of the class gets unreferenced.
14256b96c1a1SJoe Hershberger        """
14265cc42a51SMasahiro Yamada        shutil.rmtree(self.src_dir)
14276b96c1a1SJoe Hershberger
14285cc42a51SMasahiro Yamada    def get_dir(self):
14295cc42a51SMasahiro Yamada        """Return the absolute path to the reference source directory."""
14305cc42a51SMasahiro Yamada
14315cc42a51SMasahiro Yamada        return self.src_dir
14326b96c1a1SJoe Hershberger
14336821a745SSimon Glassdef move_config(toolchains, configs, options, db_queue):
14345a27c734SMasahiro Yamada    """Move config options to defconfig files.
14355a27c734SMasahiro Yamada
14365a27c734SMasahiro Yamada    Arguments:
1437b134bc13SMasahiro Yamada      configs: A list of CONFIGs to move.
14385a27c734SMasahiro Yamada      options: option flags
14395a27c734SMasahiro Yamada    """
1440b134bc13SMasahiro Yamada    if len(configs) == 0:
14416a9f79f7SMasahiro Yamada        if options.force_sync:
14426a9f79f7SMasahiro Yamada            print 'No CONFIG is specified. You are probably syncing defconfigs.',
1443d73fcb12SSimon Glass        elif options.build_db:
1444d73fcb12SSimon Glass            print 'Building %s database' % CONFIG_DATABASE
14456a9f79f7SMasahiro Yamada        else:
14466a9f79f7SMasahiro Yamada            print 'Neither CONFIG nor --force-sync is specified. Nothing will happen.',
14476a9f79f7SMasahiro Yamada    else:
14486a9f79f7SMasahiro Yamada        print 'Move ' + ', '.join(configs),
14496a9f79f7SMasahiro Yamada    print '(jobs: %d)\n' % options.jobs
14505a27c734SMasahiro Yamada
14516b96c1a1SJoe Hershberger    if options.git_ref:
14525cc42a51SMasahiro Yamada        reference_src = ReferenceSource(options.git_ref)
14535cc42a51SMasahiro Yamada        reference_src_dir = reference_src.get_dir()
14545cc42a51SMasahiro Yamada    else:
1455f432c33fSMasahiro Yamada        reference_src_dir = None
14566b96c1a1SJoe Hershberger
145791040e85SJoe Hershberger    if options.defconfigs:
14580dbc9b59SMasahiro Yamada        defconfigs = get_matched_defconfigs(options.defconfigs)
145991040e85SJoe Hershberger    else:
1460684c306eSMasahiro Yamada        defconfigs = get_all_defconfigs()
14615a27c734SMasahiro Yamada
1462c5e60fd4SMasahiro Yamada    progress = Progress(len(defconfigs))
14636821a745SSimon Glass    slots = Slots(toolchains, configs, options, progress, reference_src_dir,
14646821a745SSimon Glass		  db_queue)
14655a27c734SMasahiro Yamada
14665a27c734SMasahiro Yamada    # Main loop to process defconfig files:
14675a27c734SMasahiro Yamada    #  Add a new subprocess into a vacant slot.
14685a27c734SMasahiro Yamada    #  Sleep if there is no available slot.
1469c5e60fd4SMasahiro Yamada    for defconfig in defconfigs:
1470c5e60fd4SMasahiro Yamada        while not slots.add(defconfig):
14715a27c734SMasahiro Yamada            while not slots.available():
14725a27c734SMasahiro Yamada                # No available slot: sleep for a while
14735a27c734SMasahiro Yamada                time.sleep(SLEEP_TIME)
14745a27c734SMasahiro Yamada
14755a27c734SMasahiro Yamada    # wait until all the subprocesses finish
14765a27c734SMasahiro Yamada    while not slots.empty():
14775a27c734SMasahiro Yamada        time.sleep(SLEEP_TIME)
14785a27c734SMasahiro Yamada
14792e2ce6c0SJoe Hershberger    print ''
14805a27c734SMasahiro Yamada    slots.show_failed_boards()
1481fc2661eeSMasahiro Yamada    slots.show_suspicious_boards()
14825a27c734SMasahiro Yamada
1483cb008830SSimon Glassdef find_kconfig_rules(kconf, config, imply_config):
1484cb008830SSimon Glass    """Check whether a config has a 'select' or 'imply' keyword
1485cb008830SSimon Glass
1486cb008830SSimon Glass    Args:
1487cb008830SSimon Glass        kconf: Kconfig.Config object
1488cb008830SSimon Glass        config: Name of config to check (without CONFIG_ prefix)
1489cb008830SSimon Glass        imply_config: Implying config (without CONFIG_ prefix) which may or
1490cb008830SSimon Glass            may not have an 'imply' for 'config')
1491cb008830SSimon Glass
1492cb008830SSimon Glass    Returns:
1493cb008830SSimon Glass        Symbol object for 'config' if found, else None
1494cb008830SSimon Glass    """
1495cb008830SSimon Glass    sym = kconf.get_symbol(imply_config)
1496cb008830SSimon Glass    if sym:
14974e1102f6SUlf Magnusson        for sel in sym.get_selected_symbols() | sym.get_implied_symbols():
1498cb008830SSimon Glass            if sel.get_name() == config:
1499cb008830SSimon Glass                return sym
1500cb008830SSimon Glass    return None
1501cb008830SSimon Glass
1502cb008830SSimon Glassdef check_imply_rule(kconf, config, imply_config):
1503cb008830SSimon Glass    """Check if we can add an 'imply' option
1504cb008830SSimon Glass
1505cb008830SSimon Glass    This finds imply_config in the Kconfig and looks to see if it is possible
1506cb008830SSimon Glass    to add an 'imply' for 'config' to that part of the Kconfig.
1507cb008830SSimon Glass
1508cb008830SSimon Glass    Args:
1509cb008830SSimon Glass        kconf: Kconfig.Config object
1510cb008830SSimon Glass        config: Name of config to check (without CONFIG_ prefix)
1511cb008830SSimon Glass        imply_config: Implying config (without CONFIG_ prefix) which may or
1512cb008830SSimon Glass            may not have an 'imply' for 'config')
1513cb008830SSimon Glass
1514cb008830SSimon Glass    Returns:
1515cb008830SSimon Glass        tuple:
1516cb008830SSimon Glass            filename of Kconfig file containing imply_config, or None if none
1517cb008830SSimon Glass            line number within the Kconfig file, or 0 if none
1518cb008830SSimon Glass            message indicating the result
1519cb008830SSimon Glass    """
1520cb008830SSimon Glass    sym = kconf.get_symbol(imply_config)
1521cb008830SSimon Glass    if not sym:
1522cb008830SSimon Glass        return 'cannot find sym'
1523cb008830SSimon Glass    locs = sym.get_def_locations()
1524cb008830SSimon Glass    if len(locs) != 1:
1525cb008830SSimon Glass        return '%d locations' % len(locs)
1526cb008830SSimon Glass    fname, linenum = locs[0]
1527cb008830SSimon Glass    cwd = os.getcwd()
1528cb008830SSimon Glass    if cwd and fname.startswith(cwd):
1529cb008830SSimon Glass        fname = fname[len(cwd) + 1:]
1530cb008830SSimon Glass    file_line = ' at %s:%d' % (fname, linenum)
1531cb008830SSimon Glass    with open(fname) as fd:
1532cb008830SSimon Glass        data = fd.read().splitlines()
1533cb008830SSimon Glass    if data[linenum - 1] != 'config %s' % imply_config:
1534cb008830SSimon Glass        return None, 0, 'bad sym format %s%s' % (data[linenum], file_line)
1535cb008830SSimon Glass    return fname, linenum, 'adding%s' % file_line
1536cb008830SSimon Glass
1537cb008830SSimon Glassdef add_imply_rule(config, fname, linenum):
1538cb008830SSimon Glass    """Add a new 'imply' option to a Kconfig
1539cb008830SSimon Glass
1540cb008830SSimon Glass    Args:
1541cb008830SSimon Glass        config: config option to add an imply for (without CONFIG_ prefix)
1542cb008830SSimon Glass        fname: Kconfig filename to update
1543cb008830SSimon Glass        linenum: Line number to place the 'imply' before
1544cb008830SSimon Glass
1545cb008830SSimon Glass    Returns:
1546cb008830SSimon Glass        Message indicating the result
1547cb008830SSimon Glass    """
1548cb008830SSimon Glass    file_line = ' at %s:%d' % (fname, linenum)
1549cb008830SSimon Glass    data = open(fname).read().splitlines()
1550cb008830SSimon Glass    linenum -= 1
1551cb008830SSimon Glass
1552cb008830SSimon Glass    for offset, line in enumerate(data[linenum:]):
1553cb008830SSimon Glass        if line.strip().startswith('help') or not line:
1554cb008830SSimon Glass            data.insert(linenum + offset, '\timply %s' % config)
1555cb008830SSimon Glass            with open(fname, 'w') as fd:
1556cb008830SSimon Glass                fd.write('\n'.join(data) + '\n')
1557cb008830SSimon Glass            return 'added%s' % file_line
1558cb008830SSimon Glass
1559cb008830SSimon Glass    return 'could not insert%s'
1560cb008830SSimon Glass
1561cb008830SSimon Glass(IMPLY_MIN_2, IMPLY_TARGET, IMPLY_CMD, IMPLY_NON_ARCH_BOARD) = (
1562cb008830SSimon Glass    1, 2, 4, 8)
15639b2a2e87SSimon Glass
15649b2a2e87SSimon GlassIMPLY_FLAGS = {
15659b2a2e87SSimon Glass    'min2': [IMPLY_MIN_2, 'Show options which imply >2 boards (normally >5)'],
15669b2a2e87SSimon Glass    'target': [IMPLY_TARGET, 'Allow CONFIG_TARGET_... options to imply'],
15679b2a2e87SSimon Glass    'cmd': [IMPLY_CMD, 'Allow CONFIG_CMD_... to imply'],
1568cb008830SSimon Glass    'non-arch-board': [
1569cb008830SSimon Glass        IMPLY_NON_ARCH_BOARD,
1570cb008830SSimon Glass        'Allow Kconfig options outside arch/ and /board/ to imply'],
15719b2a2e87SSimon Glass};
15729b2a2e87SSimon Glass
1573cb008830SSimon Glassdef do_imply_config(config_list, add_imply, imply_flags, skip_added,
1574cb008830SSimon Glass                    check_kconfig=True, find_superset=False):
157599b66605SSimon Glass    """Find CONFIG options which imply those in the list
157699b66605SSimon Glass
157799b66605SSimon Glass    Some CONFIG options can be implied by others and this can help to reduce
157899b66605SSimon Glass    the size of the defconfig files. For example, CONFIG_X86 implies
157999b66605SSimon Glass    CONFIG_CMD_IRQ, so we can put 'imply CMD_IRQ' under 'config X86' and
158099b66605SSimon Glass    all x86 boards will have that option, avoiding adding CONFIG_CMD_IRQ to
158199b66605SSimon Glass    each of the x86 defconfig files.
158299b66605SSimon Glass
158399b66605SSimon Glass    This function uses the moveconfig database to find such options. It
158499b66605SSimon Glass    displays a list of things that could possibly imply those in the list.
158599b66605SSimon Glass    The algorithm ignores any that start with CONFIG_TARGET since these
158699b66605SSimon Glass    typically refer to only a few defconfigs (often one). It also does not
158799b66605SSimon Glass    display a config with less than 5 defconfigs.
158899b66605SSimon Glass
158999b66605SSimon Glass    The algorithm works using sets. For each target config in config_list:
159099b66605SSimon Glass        - Get the set 'defconfigs' which use that target config
159199b66605SSimon Glass        - For each config (from a list of all configs):
159299b66605SSimon Glass            - Get the set 'imply_defconfig' of defconfigs which use that config
159399b66605SSimon Glass            -
159499b66605SSimon Glass            - If imply_defconfigs contains anything not in defconfigs then
159599b66605SSimon Glass              this config does not imply the target config
159699b66605SSimon Glass
159799b66605SSimon Glass    Params:
159899b66605SSimon Glass        config_list: List of CONFIG options to check (each a string)
1599cb008830SSimon Glass        add_imply: Automatically add an 'imply' for each config.
16009b2a2e87SSimon Glass        imply_flags: Flags which control which implying configs are allowed
16019b2a2e87SSimon Glass           (IMPLY_...)
1602cb008830SSimon Glass        skip_added: Don't show options which already have an imply added.
1603cb008830SSimon Glass        check_kconfig: Check if implied symbols already have an 'imply' or
1604cb008830SSimon Glass            'select' for the target config, and show this information if so.
160599b66605SSimon Glass        find_superset: True to look for configs which are a superset of those
160699b66605SSimon Glass            already found. So for example if CONFIG_EXYNOS5 implies an option,
160799b66605SSimon Glass            but CONFIG_EXYNOS covers a larger set of defconfigs and also
160899b66605SSimon Glass            implies that option, this will drop the former in favour of the
160999b66605SSimon Glass            latter. In practice this option has not proved very used.
161099b66605SSimon Glass
161199b66605SSimon Glass    Note the terminoloy:
161299b66605SSimon Glass        config - a CONFIG_XXX options (a string, e.g. 'CONFIG_CMD_EEPROM')
161399b66605SSimon Glass        defconfig - a defconfig file (a string, e.g. 'configs/snow_defconfig')
161499b66605SSimon Glass    """
1615cb008830SSimon Glass    kconf = KconfigScanner().conf if check_kconfig else None
1616cb008830SSimon Glass    if add_imply and add_imply != 'all':
1617cb008830SSimon Glass        add_imply = add_imply.split()
1618cb008830SSimon Glass
161999b66605SSimon Glass    # key is defconfig name, value is dict of (CONFIG_xxx, value)
162099b66605SSimon Glass    config_db = {}
162199b66605SSimon Glass
162299b66605SSimon Glass    # Holds a dict containing the set of defconfigs that contain each config
162399b66605SSimon Glass    # key is config, value is set of defconfigs using that config
162499b66605SSimon Glass    defconfig_db = collections.defaultdict(set)
162599b66605SSimon Glass
162699b66605SSimon Glass    # Set of all config options we have seen
162799b66605SSimon Glass    all_configs = set()
162899b66605SSimon Glass
162999b66605SSimon Glass    # Set of all defconfigs we have seen
163099b66605SSimon Glass    all_defconfigs = set()
163199b66605SSimon Glass
163299b66605SSimon Glass    # Read in the database
163399b66605SSimon Glass    configs = {}
163499b66605SSimon Glass    with open(CONFIG_DATABASE) as fd:
163599b66605SSimon Glass        for line in fd.readlines():
163699b66605SSimon Glass            line = line.rstrip()
163799b66605SSimon Glass            if not line:  # Separator between defconfigs
163899b66605SSimon Glass                config_db[defconfig] = configs
163999b66605SSimon Glass                all_defconfigs.add(defconfig)
164099b66605SSimon Glass                configs = {}
164199b66605SSimon Glass            elif line[0] == ' ':  # CONFIG line
164299b66605SSimon Glass                config, value = line.strip().split('=', 1)
164399b66605SSimon Glass                configs[config] = value
164499b66605SSimon Glass                defconfig_db[config].add(defconfig)
164599b66605SSimon Glass                all_configs.add(config)
164699b66605SSimon Glass            else:  # New defconfig
164799b66605SSimon Glass                defconfig = line
164899b66605SSimon Glass
164999b66605SSimon Glass    # Work through each target config option in tern, independently
165099b66605SSimon Glass    for config in config_list:
165199b66605SSimon Glass        defconfigs = defconfig_db.get(config)
165299b66605SSimon Glass        if not defconfigs:
165399b66605SSimon Glass            print '%s not found in any defconfig' % config
165499b66605SSimon Glass            continue
165599b66605SSimon Glass
165699b66605SSimon Glass        # Get the set of defconfigs without this one (since a config cannot
165799b66605SSimon Glass        # imply itself)
165899b66605SSimon Glass        non_defconfigs = all_defconfigs - defconfigs
165999b66605SSimon Glass        num_defconfigs = len(defconfigs)
166099b66605SSimon Glass        print '%s found in %d/%d defconfigs' % (config, num_defconfigs,
166199b66605SSimon Glass                                                len(all_configs))
166299b66605SSimon Glass
166399b66605SSimon Glass        # This will hold the results: key=config, value=defconfigs containing it
166499b66605SSimon Glass        imply_configs = {}
166599b66605SSimon Glass        rest_configs = all_configs - set([config])
166699b66605SSimon Glass
166799b66605SSimon Glass        # Look at every possible config, except the target one
166899b66605SSimon Glass        for imply_config in rest_configs:
16699b2a2e87SSimon Glass            if 'ERRATUM' in imply_config:
16709b2a2e87SSimon Glass                continue
16719b2a2e87SSimon Glass            if not (imply_flags & IMPLY_CMD):
16729b2a2e87SSimon Glass                if 'CONFIG_CMD' in imply_config:
16739b2a2e87SSimon Glass                    continue
16749b2a2e87SSimon Glass            if not (imply_flags & IMPLY_TARGET):
167599b66605SSimon Glass                if 'CONFIG_TARGET' in imply_config:
167699b66605SSimon Glass                    continue
167799b66605SSimon Glass
167899b66605SSimon Glass            # Find set of defconfigs that have this config
167999b66605SSimon Glass            imply_defconfig = defconfig_db[imply_config]
168099b66605SSimon Glass
168199b66605SSimon Glass            # Get the intersection of this with defconfigs containing the
168299b66605SSimon Glass            # target config
168399b66605SSimon Glass            common_defconfigs = imply_defconfig & defconfigs
168499b66605SSimon Glass
168599b66605SSimon Glass            # Get the set of defconfigs containing this config which DO NOT
168699b66605SSimon Glass            # also contain the taret config. If this set is non-empty it means
168799b66605SSimon Glass            # that this config affects other defconfigs as well as (possibly)
168899b66605SSimon Glass            # the ones affected by the target config. This means it implies
168999b66605SSimon Glass            # things we don't want to imply.
169099b66605SSimon Glass            not_common_defconfigs = imply_defconfig & non_defconfigs
169199b66605SSimon Glass            if not_common_defconfigs:
169299b66605SSimon Glass                continue
169399b66605SSimon Glass
169499b66605SSimon Glass            # If there are common defconfigs, imply_config may be useful
169599b66605SSimon Glass            if common_defconfigs:
169699b66605SSimon Glass                skip = False
169799b66605SSimon Glass                if find_superset:
169899b66605SSimon Glass                    for prev in imply_configs.keys():
169999b66605SSimon Glass                        prev_count = len(imply_configs[prev])
170099b66605SSimon Glass                        count = len(common_defconfigs)
170199b66605SSimon Glass                        if (prev_count > count and
170299b66605SSimon Glass                            (imply_configs[prev] & common_defconfigs ==
170399b66605SSimon Glass                            common_defconfigs)):
170499b66605SSimon Glass                            # skip imply_config because prev is a superset
170599b66605SSimon Glass                            skip = True
170699b66605SSimon Glass                            break
170799b66605SSimon Glass                        elif count > prev_count:
170899b66605SSimon Glass                            # delete prev because imply_config is a superset
170999b66605SSimon Glass                            del imply_configs[prev]
171099b66605SSimon Glass                if not skip:
171199b66605SSimon Glass                    imply_configs[imply_config] = common_defconfigs
171299b66605SSimon Glass
171399b66605SSimon Glass        # Now we have a dict imply_configs of configs which imply each config
171499b66605SSimon Glass        # The value of each dict item is the set of defconfigs containing that
171599b66605SSimon Glass        # config. Rank them so that we print the configs that imply the largest
171699b66605SSimon Glass        # number of defconfigs first.
1717cb008830SSimon Glass        ranked_iconfigs = sorted(imply_configs,
171899b66605SSimon Glass                            key=lambda k: len(imply_configs[k]), reverse=True)
1719cb008830SSimon Glass        kconfig_info = ''
1720cb008830SSimon Glass        cwd = os.getcwd()
1721cb008830SSimon Glass        add_list = collections.defaultdict(list)
1722cb008830SSimon Glass        for iconfig in ranked_iconfigs:
1723cb008830SSimon Glass            num_common = len(imply_configs[iconfig])
172499b66605SSimon Glass
172599b66605SSimon Glass            # Don't bother if there are less than 5 defconfigs affected.
17269b2a2e87SSimon Glass            if num_common < (2 if imply_flags & IMPLY_MIN_2 else 5):
172799b66605SSimon Glass                continue
1728cb008830SSimon Glass            missing = defconfigs - imply_configs[iconfig]
172999b66605SSimon Glass            missing_str = ', '.join(missing) if missing else 'all'
173099b66605SSimon Glass            missing_str = ''
1731cb008830SSimon Glass            show = True
1732cb008830SSimon Glass            if kconf:
1733cb008830SSimon Glass                sym = find_kconfig_rules(kconf, config[CONFIG_LEN:],
1734cb008830SSimon Glass                                         iconfig[CONFIG_LEN:])
1735cb008830SSimon Glass                kconfig_info = ''
1736cb008830SSimon Glass                if sym:
1737cb008830SSimon Glass                    locs = sym.get_def_locations()
1738cb008830SSimon Glass                    if len(locs) == 1:
1739cb008830SSimon Glass                        fname, linenum = locs[0]
1740cb008830SSimon Glass                        if cwd and fname.startswith(cwd):
1741cb008830SSimon Glass                            fname = fname[len(cwd) + 1:]
1742cb008830SSimon Glass                        kconfig_info = '%s:%d' % (fname, linenum)
1743cb008830SSimon Glass                        if skip_added:
1744cb008830SSimon Glass                            show = False
1745cb008830SSimon Glass                else:
1746cb008830SSimon Glass                    sym = kconf.get_symbol(iconfig[CONFIG_LEN:])
1747cb008830SSimon Glass                    fname = ''
1748cb008830SSimon Glass                    if sym:
1749cb008830SSimon Glass                        locs = sym.get_def_locations()
1750cb008830SSimon Glass                        if len(locs) == 1:
1751cb008830SSimon Glass                            fname, linenum = locs[0]
1752cb008830SSimon Glass                            if cwd and fname.startswith(cwd):
1753cb008830SSimon Glass                                fname = fname[len(cwd) + 1:]
1754cb008830SSimon Glass                    in_arch_board = not sym or (fname.startswith('arch') or
1755cb008830SSimon Glass                                                fname.startswith('board'))
1756cb008830SSimon Glass                    if (not in_arch_board and
1757cb008830SSimon Glass                        not (imply_flags & IMPLY_NON_ARCH_BOARD)):
1758cb008830SSimon Glass                        continue
1759cb008830SSimon Glass
1760cb008830SSimon Glass                    if add_imply and (add_imply == 'all' or
1761cb008830SSimon Glass                                      iconfig in add_imply):
1762cb008830SSimon Glass                        fname, linenum, kconfig_info = (check_imply_rule(kconf,
1763cb008830SSimon Glass                                config[CONFIG_LEN:], iconfig[CONFIG_LEN:]))
1764cb008830SSimon Glass                        if fname:
1765cb008830SSimon Glass                            add_list[fname].append(linenum)
1766cb008830SSimon Glass
1767cb008830SSimon Glass            if show and kconfig_info != 'skip':
1768cb008830SSimon Glass                print '%5d : %-30s%-25s %s' % (num_common, iconfig.ljust(30),
1769cb008830SSimon Glass                                              kconfig_info, missing_str)
1770cb008830SSimon Glass
1771cb008830SSimon Glass        # Having collected a list of things to add, now we add them. We process
1772cb008830SSimon Glass        # each file from the largest line number to the smallest so that
1773cb008830SSimon Glass        # earlier additions do not affect our line numbers. E.g. if we added an
1774cb008830SSimon Glass        # imply at line 20 it would change the position of each line after
1775cb008830SSimon Glass        # that.
1776cb008830SSimon Glass        for fname, linenums in add_list.iteritems():
1777cb008830SSimon Glass            for linenum in sorted(linenums, reverse=True):
1778cb008830SSimon Glass                add_imply_rule(config[CONFIG_LEN:], fname, linenum)
177999b66605SSimon Glass
178099b66605SSimon Glass
17815a27c734SMasahiro Yamadadef main():
17825a27c734SMasahiro Yamada    try:
17835a27c734SMasahiro Yamada        cpu_count = multiprocessing.cpu_count()
17845a27c734SMasahiro Yamada    except NotImplementedError:
17855a27c734SMasahiro Yamada        cpu_count = 1
17865a27c734SMasahiro Yamada
17875a27c734SMasahiro Yamada    parser = optparse.OptionParser()
17885a27c734SMasahiro Yamada    # Add options here
1789cb008830SSimon Glass    parser.add_option('-a', '--add-imply', type='string', default='',
1790cb008830SSimon Glass                      help='comma-separated list of CONFIG options to add '
1791cb008830SSimon Glass                      "an 'imply' statement to for the CONFIG in -i")
1792cb008830SSimon Glass    parser.add_option('-A', '--skip-added', action='store_true', default=False,
1793cb008830SSimon Glass                      help="don't show options which are already marked as "
1794cb008830SSimon Glass                      'implying others')
1795d73fcb12SSimon Glass    parser.add_option('-b', '--build-db', action='store_true', default=False,
1796d73fcb12SSimon Glass                      help='build a CONFIG database')
17975a27c734SMasahiro Yamada    parser.add_option('-c', '--color', action='store_true', default=False,
17985a27c734SMasahiro Yamada                      help='display the log in color')
17999ede2123SSimon Glass    parser.add_option('-C', '--commit', action='store_true', default=False,
18009ede2123SSimon Glass                      help='Create a git commit for the operation')
180191040e85SJoe Hershberger    parser.add_option('-d', '--defconfigs', type='string',
1802ee4e61bdSSimon Glass                      help='a file containing a list of defconfigs to move, '
1803ee4e61bdSSimon Glass                      "one per line (for example 'snow_defconfig') "
1804ee4e61bdSSimon Glass                      "or '-' to read from stdin")
180599b66605SSimon Glass    parser.add_option('-i', '--imply', action='store_true', default=False,
180699b66605SSimon Glass                      help='find options which imply others')
18079b2a2e87SSimon Glass    parser.add_option('-I', '--imply-flags', type='string', default='',
18089b2a2e87SSimon Glass                      help="control the -i option ('help' for help")
18095a27c734SMasahiro Yamada    parser.add_option('-n', '--dry-run', action='store_true', default=False,
18105a27c734SMasahiro Yamada                      help='perform a trial run (show log with no changes)')
18115a27c734SMasahiro Yamada    parser.add_option('-e', '--exit-on-error', action='store_true',
18125a27c734SMasahiro Yamada                      default=False,
18135a27c734SMasahiro Yamada                      help='exit immediately on any error')
18148513dc04SMasahiro Yamada    parser.add_option('-s', '--force-sync', action='store_true', default=False,
18158513dc04SMasahiro Yamada                      help='force sync by savedefconfig')
181607913d1eSMasahiro Yamada    parser.add_option('-S', '--spl', action='store_true', default=False,
181707913d1eSMasahiro Yamada                      help='parse config options defined for SPL build')
18182144f880SJoe Hershberger    parser.add_option('-H', '--headers-only', dest='cleanup_headers_only',
18192144f880SJoe Hershberger                      action='store_true', default=False,
18202144f880SJoe Hershberger                      help='only cleanup the headers')
18215a27c734SMasahiro Yamada    parser.add_option('-j', '--jobs', type='int', default=cpu_count,
18225a27c734SMasahiro Yamada                      help='the number of jobs to run simultaneously')
18236b96c1a1SJoe Hershberger    parser.add_option('-r', '--git-ref', type='string',
18246b96c1a1SJoe Hershberger                      help='the git ref to clone for building the autoconf.mk')
18256b403dfdSSimon Glass    parser.add_option('-y', '--yes', action='store_true', default=False,
18266b403dfdSSimon Glass                      help="respond 'yes' to any prompts")
182795bf9c7eSJoe Hershberger    parser.add_option('-v', '--verbose', action='store_true', default=False,
182895bf9c7eSJoe Hershberger                      help='show any build errors as boards are built')
1829b6ef393aSMasahiro Yamada    parser.usage += ' CONFIG ...'
18305a27c734SMasahiro Yamada
1831b6ef393aSMasahiro Yamada    (options, configs) = parser.parse_args()
18325a27c734SMasahiro Yamada
183399b66605SSimon Glass    if len(configs) == 0 and not any((options.force_sync, options.build_db,
183499b66605SSimon Glass                                      options.imply)):
18355a27c734SMasahiro Yamada        parser.print_usage()
18365a27c734SMasahiro Yamada        sys.exit(1)
18375a27c734SMasahiro Yamada
1838b6ef393aSMasahiro Yamada    # prefix the option name with CONFIG_ if missing
1839b6ef393aSMasahiro Yamada    configs = [ config if config.startswith('CONFIG_') else 'CONFIG_' + config
1840b6ef393aSMasahiro Yamada                for config in configs ]
18415a27c734SMasahiro Yamada
18422144f880SJoe Hershberger    check_top_directory()
18432144f880SJoe Hershberger
184499b66605SSimon Glass    if options.imply:
18459b2a2e87SSimon Glass        imply_flags = 0
1846dee36c74SSimon Glass        if options.imply_flags == 'all':
1847dee36c74SSimon Glass            imply_flags = -1
1848dee36c74SSimon Glass
1849dee36c74SSimon Glass        elif options.imply_flags:
1850dee36c74SSimon Glass            for flag in options.imply_flags.split(','):
1851dee36c74SSimon Glass                bad = flag not in IMPLY_FLAGS
1852dee36c74SSimon Glass                if bad:
1853dee36c74SSimon Glass                    print "Invalid flag '%s'" % flag
1854dee36c74SSimon Glass                if flag == 'help' or bad:
18559b2a2e87SSimon Glass                    print "Imply flags: (separate with ',')"
18569b2a2e87SSimon Glass                    for name, info in IMPLY_FLAGS.iteritems():
18579b2a2e87SSimon Glass                        print ' %-15s: %s' % (name, info[1])
18589b2a2e87SSimon Glass                    parser.print_usage()
18599b2a2e87SSimon Glass                    sys.exit(1)
18609b2a2e87SSimon Glass                imply_flags |= IMPLY_FLAGS[flag][0]
18619b2a2e87SSimon Glass
1862cb008830SSimon Glass        do_imply_config(configs, options.add_imply, imply_flags,
1863cb008830SSimon Glass                        options.skip_added)
186499b66605SSimon Glass        return
186599b66605SSimon Glass
1866d73fcb12SSimon Glass    config_db = {}
1867d73fcb12SSimon Glass    db_queue = Queue.Queue()
1868d73fcb12SSimon Glass    t = DatabaseThread(config_db, db_queue)
1869d73fcb12SSimon Glass    t.setDaemon(True)
1870d73fcb12SSimon Glass    t.start()
1871d73fcb12SSimon Glass
18722144f880SJoe Hershberger    if not options.cleanup_headers_only:
1873f7536f79SMasahiro Yamada        check_clean_directory()
18746821a745SSimon Glass	bsettings.Setup('')
18756821a745SSimon Glass        toolchains = toolchain.Toolchains()
18766821a745SSimon Glass        toolchains.GetSettings()
18776821a745SSimon Glass        toolchains.Scan(verbose=False)
18786821a745SSimon Glass        move_config(toolchains, configs, options, db_queue)
1879d73fcb12SSimon Glass        db_queue.join()
18805a27c734SMasahiro Yamada
18816a9f79f7SMasahiro Yamada    if configs:
1882e9ea1221SMasahiro Yamada        cleanup_headers(configs, options)
18839ab0296aSMasahiro Yamada        cleanup_extra_options(configs, options)
1884ca43834dSChris Packham        cleanup_whitelist(configs, options)
1885f90df596SChris Packham        cleanup_readme(configs, options)
18862144f880SJoe Hershberger
18879ede2123SSimon Glass    if options.commit:
18889ede2123SSimon Glass        subprocess.call(['git', 'add', '-u'])
18899ede2123SSimon Glass        if configs:
18909ede2123SSimon Glass            msg = 'Convert %s %sto Kconfig' % (configs[0],
18919ede2123SSimon Glass                    'et al ' if len(configs) > 1 else '')
18929ede2123SSimon Glass            msg += ('\n\nThis converts the following to Kconfig:\n   %s\n' %
18939ede2123SSimon Glass                    '\n   '.join(configs))
18949ede2123SSimon Glass        else:
18959ede2123SSimon Glass            msg = 'configs: Resync with savedefconfig'
18969ede2123SSimon Glass            msg += '\n\nRsync all defconfig files using moveconfig.py'
18979ede2123SSimon Glass        subprocess.call(['git', 'commit', '-s', '-m', msg])
18989ede2123SSimon Glass
1899d73fcb12SSimon Glass    if options.build_db:
1900d73fcb12SSimon Glass        with open(CONFIG_DATABASE, 'w') as fd:
1901d73fcb12SSimon Glass            for defconfig, configs in config_db.iteritems():
1902c79d18c4SSimon Glass                fd.write('%s\n' % defconfig)
1903d73fcb12SSimon Glass                for config in sorted(configs.keys()):
1904c79d18c4SSimon Glass                    fd.write('   %s=%s\n' % (config, configs[config]))
1905c79d18c4SSimon Glass                fd.write('\n')
1906d73fcb12SSimon Glass
19075a27c734SMasahiro Yamadaif __name__ == '__main__':
19085a27c734SMasahiro Yamada    main()
1909