tools: mkimage: use common ALIGN to do the size align
[oweals/u-boot.git] / tools / moveconfig.py
index 6f549a51c16d0c2d81c3effbd8f62f8d255f45a5..d8bf7fd0717fe1c405317e9e5ea95698a50ecefc 100755 (executable)
@@ -1,9 +1,8 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0+
 #
 # Author: Masahiro Yamada <yamada.masahiro@socionext.com>
 #
-# SPDX-License-Identifier:     GPL-2.0+
-#
 
 """
 Move config options from headers to defconfig files.
@@ -296,6 +295,7 @@ To see the complete list of supported options, run
 
 """
 
+import asteval
 import collections
 import copy
 import difflib
@@ -305,7 +305,7 @@ import glob
 import multiprocessing
 import optparse
 import os
-import Queue
+import queue
 import re
 import shutil
 import subprocess
@@ -355,6 +355,26 @@ CONFIG_DATABASE = 'moveconfig.db'
 
 CONFIG_LEN = len('CONFIG_')
 
+SIZES = {
+    "SZ_1":    0x00000001, "SZ_2":    0x00000002,
+    "SZ_4":    0x00000004, "SZ_8":    0x00000008,
+    "SZ_16":   0x00000010, "SZ_32":   0x00000020,
+    "SZ_64":   0x00000040, "SZ_128":  0x00000080,
+    "SZ_256":  0x00000100, "SZ_512":  0x00000200,
+    "SZ_1K":   0x00000400, "SZ_2K":   0x00000800,
+    "SZ_4K":   0x00001000, "SZ_8K":   0x00002000,
+    "SZ_16K":  0x00004000, "SZ_32K":  0x00008000,
+    "SZ_64K":  0x00010000, "SZ_128K": 0x00020000,
+    "SZ_256K": 0x00040000, "SZ_512K": 0x00080000,
+    "SZ_1M":   0x00100000, "SZ_2M":   0x00200000,
+    "SZ_4M":   0x00400000, "SZ_8M":   0x00800000,
+    "SZ_16M":  0x01000000, "SZ_32M":  0x02000000,
+    "SZ_64M":  0x04000000, "SZ_128M": 0x08000000,
+    "SZ_256M": 0x10000000, "SZ_512M": 0x20000000,
+    "SZ_1G":   0x40000000, "SZ_2G":   0x80000000,
+    "SZ_4G":  0x100000000
+}
+
 ### helper functions ###
 def get_devnull():
     """Get the file object of '/dev/null' device."""
@@ -431,8 +451,8 @@ def get_matched_defconfigs(defconfigs_file):
             line = line.split(' ')[0]  # handle 'git log' input
         matched = get_matched_defconfig(line)
         if not matched:
-            print >> sys.stderr, "warning: %s:%d: no defconfig matched '%s'" % \
-                                                 (defconfigs_file, i + 1, line)
+            print("warning: %s:%d: no defconfig matched '%s'" % \
+                                                 (defconfigs_file, i + 1, line), file=sys.stderr)
 
         defconfigs += matched
 
@@ -475,11 +495,11 @@ def show_diff(a, b, file_path, color_enabled):
 
     for line in diff:
         if line[0] == '-' and line[1] != '-':
-            print color_text(color_enabled, COLOR_RED, line),
+            print(color_text(color_enabled, COLOR_RED, line), end=' ')
         elif line[0] == '+' and line[1] != '+':
-            print color_text(color_enabled, COLOR_GREEN, line),
+            print(color_text(color_enabled, COLOR_GREEN, line), end=' ')
         else:
-            print line,
+            print(line, end=' ')
 
 def extend_matched_lines(lines, matched, pre_patterns, post_patterns, extend_pre,
                          extend_post):
@@ -535,9 +555,9 @@ def extend_matched_lines(lines, matched, pre_patterns, post_patterns, extend_pre
 def confirm(options, prompt):
     if not options.yes:
         while True:
-            choice = raw_input('{} [y/n]: '.format(prompt))
+            choice = input('{} [y/n]: '.format(prompt))
             choice = choice.lower()
-            print choice
+            print(choice)
             if choice == 'y' or choice == 'n':
                 break
 
@@ -546,6 +566,28 @@ def confirm(options, prompt):
 
     return True
 
+def cleanup_empty_blocks(header_path, options):
+    """Clean up empty conditional blocks
+
+    Arguments:
+      header_path: path to the cleaned file.
+      options: option flags.
+    """
+    pattern = re.compile(r'^\s*#\s*if.*$\n^\s*#\s*endif.*$\n*', flags=re.M)
+    with open(header_path) as f:
+        data = f.read()
+
+    new_data = pattern.sub('\n', data)
+
+    show_diff(data.splitlines(True), new_data.splitlines(True), header_path,
+              options.color)
+
+    if options.dry_run:
+        return
+
+    with open(header_path, 'w') as f:
+        f.write(new_data)
+
 def cleanup_one_header(header_path, patterns, options):
     """Clean regex-matched lines away from a file.
 
@@ -626,9 +668,13 @@ def cleanup_headers(configs, options):
             if dirpath == os.path.join('include', 'generated'):
                 continue
             for filename in filenames:
-                if not fnmatch.fnmatch(filename, '*~'):
-                    cleanup_one_header(os.path.join(dirpath, filename),
-                                       patterns, options)
+                if not filename.endswith(('~', '.dts', '.dtsi')):
+                    header_path = os.path.join(dirpath, filename)
+                    # This file contains UTF-16 data and no CONFIG symbols
+                    if header_path == 'include/video_font_data.h':
+                        continue
+                    cleanup_one_header(header_path, patterns, options)
+                    cleanup_empty_blocks(header_path, options)
 
 def cleanup_one_extra_option(defconfig_path, configs, options):
     """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in one defconfig file.
@@ -755,6 +801,26 @@ def cleanup_readme(configs, options):
     with open('README', 'w') as f:
         f.write(''.join(newlines))
 
+def try_expand(line):
+    """If value looks like an expression, try expanding it
+    Otherwise just return the existing value
+    """
+    if line.find('=') == -1:
+        return line
+
+    try:
+        aeval = asteval.Interpreter( usersyms=SIZES, minimal=True )
+        cfg, val = re.split("=", line)
+        val= val.strip('\"')
+        if re.search("[*+-/]|<<|SZ_+|\(([^\)]+)\)", val):
+            newval = hex(aeval(val))
+            print("\tExpanded expression %s to %s" % (val, newval))
+            return cfg+'='+newval
+    except:
+        print("\tFailed to expand expression in %s" % line)
+
+    return line
+
 
 ### classes ###
 class Progress:
@@ -777,7 +843,7 @@ class Progress:
 
     def show(self):
         """Display the progress."""
-        print ' %d defconfigs out of %d\r' % (self.current, self.total),
+        print(' %d defconfigs out of %d\r' % (self.current, self.total), end=' ')
         sys.stdout.flush()
 
 
@@ -790,7 +856,7 @@ class KconfigScanner:
         os.environ['srctree'] = os.getcwd()
         os.environ['UBOOTVERSION'] = 'dummy'
         os.environ['KCONFIG_OBJDIR'] = ''
-        self.conf = kconfiglib.Config()
+        self.conf = kconfiglib.Kconfig()
 
 
 class KconfigParser:
@@ -869,6 +935,8 @@ class KconfigParser:
         else:
             new_val = not_set
 
+        new_val = try_expand(new_val)
+
         for line in dotconfig_lines:
             line = line.rstrip()
             if line.startswith(config + '=') or line == not_set:
@@ -1149,7 +1217,7 @@ class Slot:
                                "Failed to process.\n")
         if self.options.verbose:
             self.log += color_text(self.options.color, COLOR_LIGHT_CYAN,
-                                   self.ps.stderr.read())
+                                   self.ps.stderr.read().decode())
         self.finish(False)
 
     def do_defconfig(self):
@@ -1170,10 +1238,10 @@ class Slot:
             toolchain = self.toolchains.Select(arch)
         except ValueError:
             self.log += color_text(self.options.color, COLOR_YELLOW,
-                    "Tool chain for '%s' is missing.  Do nothing.\n % arch")
+                    "Tool chain for '%s' is missing.  Do nothing.\n" % arch)
             self.finish(False)
             return
-       env = toolchain.MakeEnvironment(False)
+        env = toolchain.MakeEnvironment(False)
 
         cmd = list(self.make_cmd)
         cmd.append('KCONFIG_IGNORE_DUPLICATES=1')
@@ -1249,7 +1317,7 @@ class Slot:
         log += '\n'.join([ '    ' + s for s in self.log.split('\n') ])
         # Some threads are running in parallel.
         # Print log atomically to not mix up logs from different threads.
-        print >> (sys.stdout if success else sys.stderr), log
+        print(log, file=(sys.stdout if success else sys.stderr))
 
         if not success:
             if self.options.exit_on_error:
@@ -1348,8 +1416,8 @@ class Slots:
             msg = "The following boards were not processed due to error:\n"
             msg += boards
             msg += "(the list has been saved in %s)\n" % output_file
-            print >> sys.stderr, color_text(self.options.color, COLOR_LIGHT_RED,
-                                            msg)
+            print(color_text(self.options.color, COLOR_LIGHT_RED,
+                                            msg), file=sys.stderr)
 
             with open(output_file, 'w') as f:
                 f.write(boards)
@@ -1368,8 +1436,8 @@ class Slots:
             msg += "It is highly recommended to check them manually:\n"
             msg += boards
             msg += "(the list has been saved in %s)\n" % output_file
-            print >> sys.stderr, color_text(self.options.color, COLOR_YELLOW,
-                                            msg)
+            print(color_text(self.options.color, COLOR_YELLOW,
+                                            msg), file=sys.stderr)
 
             with open(output_file, 'w') as f:
                 f.write(boards)
@@ -1385,11 +1453,11 @@ class ReferenceSource:
           commit: commit to git-clone
         """
         self.src_dir = tempfile.mkdtemp()
-        print "Cloning git repo to a separate work directory..."
+        print("Cloning git repo to a separate work directory...")
         subprocess.check_output(['git', 'clone', os.getcwd(), '.'],
                                 cwd=self.src_dir)
-        print "Checkout '%s' to build the original autoconf.mk." % \
-            subprocess.check_output(['git', 'rev-parse', '--short', commit]).strip()
+        print("Checkout '%s' to build the original autoconf.mk." % \
+            subprocess.check_output(['git', 'rev-parse', '--short', commit]).strip())
         subprocess.check_output(['git', 'checkout', commit],
                                 stderr=subprocess.STDOUT, cwd=self.src_dir)
 
@@ -1417,14 +1485,14 @@ def move_config(toolchains, configs, options, db_queue):
     """
     if len(configs) == 0:
         if options.force_sync:
-            print 'No CONFIG is specified. You are probably syncing defconfigs.',
+            print('No CONFIG is specified. You are probably syncing defconfigs.', end=' ')
         elif options.build_db:
-            print 'Building %s database' % CONFIG_DATABASE
+            print('Building %s database' % CONFIG_DATABASE)
         else:
-            print 'Neither CONFIG nor --force-sync is specified. Nothing will happen.',
+            print('Neither CONFIG nor --force-sync is specified. Nothing will happen.', end=' ')
     else:
-        print 'Move ' + ', '.join(configs),
-    print '(jobs: %d)\n' % options.jobs
+        print('Move ' + ', '.join(configs), end=' ')
+    print('(jobs: %d)\n' % options.jobs)
 
     if options.git_ref:
         reference_src = ReferenceSource(options.git_ref)
@@ -1454,7 +1522,7 @@ def move_config(toolchains, configs, options, db_queue):
     while not slots.empty():
         time.sleep(SLEEP_TIME)
 
-    print ''
+    print('')
     slots.show_failed_boards()
     slots.show_suspicious_boards()
 
@@ -1462,7 +1530,7 @@ def find_kconfig_rules(kconf, config, imply_config):
     """Check whether a config has a 'select' or 'imply' keyword
 
     Args:
-        kconf: Kconfig.Config object
+        kconf: Kconfiglib.Kconfig object
         config: Name of config to check (without CONFIG_ prefix)
         imply_config: Implying config (without CONFIG_ prefix) which may or
             may not have an 'imply' for 'config')
@@ -1470,9 +1538,9 @@ def find_kconfig_rules(kconf, config, imply_config):
     Returns:
         Symbol object for 'config' if found, else None
     """
-    sym = kconf.get_symbol(imply_config)
+    sym = kconf.syms.get(imply_config)
     if sym:
-        for sel in sym.get_selected_symbols():
+        for sel in sym.get_selected_symbols() | sym.get_implied_symbols():
             if sel.get_name() == config:
                 return sym
     return None
@@ -1484,7 +1552,7 @@ def check_imply_rule(kconf, config, imply_config):
     to add an 'imply' for 'config' to that part of the Kconfig.
 
     Args:
-        kconf: Kconfig.Config object
+        kconf: Kconfiglib.Kconfig object
         config: Name of config to check (without CONFIG_ prefix)
         imply_config: Implying config (without CONFIG_ prefix) which may or
             may not have an 'imply' for 'config')
@@ -1495,7 +1563,7 @@ def check_imply_rule(kconf, config, imply_config):
             line number within the Kconfig file, or 0 if none
             message indicating the result
     """
-    sym = kconf.get_symbol(imply_config)
+    sym = kconf.syms.get(imply_config)
     if not sym:
         return 'cannot find sym'
     locs = sym.get_def_locations()
@@ -1628,15 +1696,15 @@ def do_imply_config(config_list, add_imply, imply_flags, skip_added,
     for config in config_list:
         defconfigs = defconfig_db.get(config)
         if not defconfigs:
-            print '%s not found in any defconfig' % config
+            print('%s not found in any defconfig' % config)
             continue
 
         # Get the set of defconfigs without this one (since a config cannot
         # imply itself)
         non_defconfigs = all_defconfigs - defconfigs
         num_defconfigs = len(defconfigs)
-        print '%s found in %d/%d defconfigs' % (config, num_defconfigs,
-                                                len(all_configs))
+        print('%s found in %d/%d defconfigs' % (config, num_defconfigs,
+                                                len(all_configs)))
 
         # This will hold the results: key=config, value=defconfigs containing it
         imply_configs = {}
@@ -1673,7 +1741,7 @@ def do_imply_config(config_list, add_imply, imply_flags, skip_added,
             if common_defconfigs:
                 skip = False
                 if find_superset:
-                    for prev in imply_configs.keys():
+                    for prev in list(imply_configs.keys()):
                         prev_count = len(imply_configs[prev])
                         count = len(common_defconfigs)
                         if (prev_count > count and
@@ -1721,7 +1789,7 @@ def do_imply_config(config_list, add_imply, imply_flags, skip_added,
                         if skip_added:
                             show = False
                 else:
-                    sym = kconf.get_symbol(iconfig[CONFIG_LEN:])
+                    sym = kconf.syms.get(iconfig[CONFIG_LEN:])
                     fname = ''
                     if sym:
                         locs = sym.get_def_locations()
@@ -1743,15 +1811,15 @@ def do_imply_config(config_list, add_imply, imply_flags, skip_added,
                             add_list[fname].append(linenum)
 
             if show and kconfig_info != 'skip':
-                print '%5d : %-30s%-25s %s' % (num_common, iconfig.ljust(30),
-                                              kconfig_info, missing_str)
+                print('%5d : %-30s%-25s %s' % (num_common, iconfig.ljust(30),
+                                              kconfig_info, missing_str))
 
         # Having collected a list of things to add, now we add them. We process
         # each file from the largest line number to the smallest so that
         # earlier additions do not affect our line numbers. E.g. if we added an
         # imply at line 20 it would change the position of each line after
         # that.
-        for fname, linenums in add_list.iteritems():
+        for fname, linenums in add_list.items():
             for linenum in sorted(linenums, reverse=True):
                 add_imply_rule(config[CONFIG_LEN:], fname, linenum)
 
@@ -1828,11 +1896,11 @@ def main():
             for flag in options.imply_flags.split(','):
                 bad = flag not in IMPLY_FLAGS
                 if bad:
-                    print "Invalid flag '%s'" % flag
+                    print("Invalid flag '%s'" % flag)
                 if flag == 'help' or bad:
-                    print "Imply flags: (separate with ',')"
-                    for name, info in IMPLY_FLAGS.iteritems():
-                        print ' %-15s: %s' % (name, info[1])
+                    print("Imply flags: (separate with ',')")
+                    for name, info in IMPLY_FLAGS.items():
+                        print(' %-15s: %s' % (name, info[1]))
                     parser.print_usage()
                     sys.exit(1)
                 imply_flags |= IMPLY_FLAGS[flag][0]
@@ -1842,14 +1910,14 @@ def main():
         return
 
     config_db = {}
-    db_queue = Queue.Queue()
+    db_queue = queue.Queue()
     t = DatabaseThread(config_db, db_queue)
     t.setDaemon(True)
     t.start()
 
     if not options.cleanup_headers_only:
         check_clean_directory()
-       bsettings.Setup('')
+        bsettings.Setup('')
         toolchains = toolchain.Toolchains()
         toolchains.GetSettings()
         toolchains.Scan(verbose=False)
@@ -1876,7 +1944,7 @@ def main():
 
     if options.build_db:
         with open(CONFIG_DATABASE, 'w') as fd:
-            for defconfig, configs in config_db.iteritems():
+            for defconfig, configs in config_db.items():
                 fd.write('%s\n' % defconfig)
                 for config in sorted(configs.keys()):
                     fd.write('   %s=%s\n' % (config, configs[config]))