[U-Boot] [PATCH 5/7] tools/genboardscfg.py: fix minor problems on termination

Simon Glass sjg at chromium.org
Wed Aug 20 21:10:52 CEST 2014


HI Masahiro,

On 20 August 2014 05:47, Masahiro Yamada <yamada.m at jp.panasonic.com> wrote:
> This tool deletes the incomplete boards.cfg
> if it encounters an error or is is terminated by the user.
>
> I notice some problems even though they rarely happen.
>
> [1] The boards.cfg is removed if the program is terminated
> during __gen_boards_cfg() function but before boards.cfg
> is actually touched.  In this case, the previous boards.cfg
> should be kept as it is.
>
> [2] If an error occurs while deleting the incomplete boards.cfg,
> the program throws another exception.  This hides the privious
> exception and we will not be able to know the real cause.
>
> Signed-off-by: Masahiro Yamada <yamada.m at jp.panasonic.com>

Acked-by: Simon Glass <sjg at chromium.org>

A few suggestions below (please ignore as you wish, they are not important)

> ---
>
>  tools/genboardscfg.py | 156 +++++++++++++++++++++++++++++---------------------
>  1 file changed, 90 insertions(+), 66 deletions(-)
>
> diff --git a/tools/genboardscfg.py b/tools/genboardscfg.py
> index 9b3a9bf..13bb424 100755
> --- a/tools/genboardscfg.py
> +++ b/tools/genboardscfg.py
> @@ -417,63 +417,95 @@ class Indicator:
>          sys.stdout.write('\r' + msg)
>          sys.stdout.flush()
>
> -def __gen_boards_cfg(jobs):
> -    """Generate boards.cfg file.
> +class BoardsFileGenerator:
>
> -    Arguments:
> -      jobs: The number of jobs to run simultaneously
> +    """Generator of boards.cfg."""
>
> -    Note:
> -      The incomplete boards.cfg is left over when an error (including
> -      the termination by the keyboard interrupt) occurs on the halfway.
> -    """
> -    check_top_directory()
> -    print 'Generating %s ...  (jobs: %d)' % (BOARD_FILE, jobs)
> -
> -    # All the defconfig files to be processed
> -    defconfigs = []
> -    for (dirpath, dirnames, filenames) in os.walk(CONFIG_DIR):
> -        dirpath = dirpath[len(CONFIG_DIR) + 1:]
> -        for filename in fnmatch.filter(filenames, '*_defconfig'):
> -            if fnmatch.fnmatch(filename, '.*'):
> -                continue
> -            defconfigs.append(os.path.join(dirpath, filename))
> -
> -    # Parse all the MAINTAINERS files
> -    maintainers_database = MaintainersDatabase()
> -    for (dirpath, dirnames, filenames) in os.walk('.'):
> -        if 'MAINTAINERS' in filenames:
> -            maintainers_database.parse_file(os.path.join(dirpath,
> -                                                         'MAINTAINERS'))
> -
> -    # Output lines should be piped into the reformat tool
> -    reformat_process = subprocess.Popen(REFORMAT_CMD, stdin=subprocess.PIPE,
> -                                        stdout=open(BOARD_FILE, 'w'))
> -    pipe = reformat_process.stdin
> -    pipe.write(COMMENT_BLOCK)
> -
> -    indicator = Indicator(len(defconfigs))
> -    slots = Slots(jobs, pipe, maintainers_database)
> -
> -    # Main loop to process defconfig files:
> -    #  Add a new subprocess into a vacant slot.
> -    #  Sleep if there is no available slot.
> -    for defconfig in defconfigs:
> -        while not slots.add(defconfig):
> -            while not slots.available():
> -                # No available slot: sleep for a while
> -                time.sleep(SLEEP_TIME)
> -        indicator.inc()
> -
> -    # wait until all the subprocesses finish
> -    while not slots.empty():
> -        time.sleep(SLEEP_TIME)
> -    print ''
> -
> -    # wait until the reformat tool finishes
> -    reformat_process.communicate()
> -    if reformat_process.returncode != 0:
> -        sys.exit('"%s" failed' % REFORMAT_CMD[0])
> +    def __init__(self):
> +        """Prepare basic things for generating boards.cfg."""
> +        # All the defconfig files to be processed
> +        defconfigs = []
> +        for (dirpath, dirnames, filenames) in os.walk(CONFIG_DIR):
> +            dirpath = dirpath[len(CONFIG_DIR) + 1:]
> +            for filename in fnmatch.filter(filenames, '*_defconfig'):
> +                if fnmatch.fnmatch(filename, '.*'):
> +                    continue
> +                defconfigs.append(os.path.join(dirpath, filename))
> +        self.defconfigs = defconfigs
> +        self.indicator = Indicator(len(defconfigs))

I try to put an _ before private members to indicate that they should
not be used outside the class. But It is not particularly important -
just thought I'd mention it.

> +
> +        # Parse all the MAINTAINERS files
> +        maintainers_database = MaintainersDatabase()
> +        for (dirpath, dirnames, filenames) in os.walk('.'):
> +            if 'MAINTAINERS' in filenames:
> +                maintainers_database.parse_file(os.path.join(dirpath,
> +                                                             'MAINTAINERS'))
> +        self.maintainers_database = maintainers_database
> +
> +    def __del__(self):
> +        """Delete the incomplete boards.cfg
> +
> +        This destructor deletes boards.cfg if the private member 'in_progress'
> +        is defined as True.  The 'in_progress' member is set to True at the
> +        beginning of the generate() method and set to False at its end.
> +        So, in_progress==True means generating boards.cfg was terminated
> +        on the way.
> +        """
> +
> +        if hasattr(self, 'in_progress') and self.in_progress:

Would it be better to initialise in_progress to None in the constructor?

> +            try:
> +                os.remove(BOARD_FILE)
> +            except OSError, exception:
> +                # Ignore 'No such file or directory' error
> +                if exception.errno != errno.ENOENT:
> +                    raise
> +            print 'Removed incomplete %s' % BOARD_FILE
> +
> +    def generate(self, jobs):
> +        """Generate boards.cfg
> +
> +        This method sets the 'in_progress' member to True at the beginning
> +        and sets it to False on success.  The boards.cfg should not be
> +        touched before/after this method because 'in_progress' is used
> +        to detect the incomplete boards.cfg.
> +
> +        Arguments:
> +          jobs: The number of jobs to run simultaneously
> +        """
> +
> +        self.in_progress = True
> +        print 'Generating %s ...  (jobs: %d)' % (BOARD_FILE, jobs)
> +
> +        # Output lines should be piped into the reformat tool
> +        reformat_process = subprocess.Popen(REFORMAT_CMD,
> +                                            stdin=subprocess.PIPE,
> +                                            stdout=open(BOARD_FILE, 'w'))
> +        pipe = reformat_process.stdin
> +        pipe.write(COMMENT_BLOCK)
> +
> +        slots = Slots(jobs, pipe, self.maintainers_database)
> +
> +        # Main loop to process defconfig files:
> +        #  Add a new subprocess into a vacant slot.
> +        #  Sleep if there is no available slot.
> +        for defconfig in self.defconfigs:
> +            while not slots.add(defconfig):
> +                while not slots.available():
> +                    # No available slot: sleep for a while
> +                    time.sleep(SLEEP_TIME)
> +            self.indicator.inc()
> +
> +        # wait until all the subprocesses finish
> +        while not slots.empty():
> +            time.sleep(SLEEP_TIME)
> +        print ''
> +
> +        # wait until the reformat tool finishes
> +        reformat_process.communicate()
> +        if reformat_process.returncode != 0:
> +            sys.exit('"%s" failed' % REFORMAT_CMD[0])
> +
> +        self.in_progress = False
>
>  def gen_boards_cfg(jobs):
>      """Generate boards.cfg file.
> @@ -484,17 +516,9 @@ def gen_boards_cfg(jobs):
>      Arguments:
>        jobs: The number of jobs to run simultaneously
>      """
> -    try:
> -        __gen_boards_cfg(jobs)
> -    except:
> -        # We should remove incomplete boards.cfg
> -        try:
> -            os.remove(BOARD_FILE)
> -        except OSError, exception:
> -            # Ignore 'No such file or directory' error
> -            if exception.errno != errno.ENOENT:
> -                raise
> -        raise
> +    check_top_directory()
> +    generator = BoardsFileGenerator()
> +    generator.generate(jobs)
>
>  def main():
>      parser = optparse.OptionParser()
> --
> 1.9.1
>

Regards,
Simon


More information about the U-Boot mailing list