]> git.sur5r.net Git - u-boot/blobdiff - tools/moveconfig.py
dm: Add a more efficient libfdt library
[u-boot] / tools / moveconfig.py
index 9bbcead2eb9131c6ad41c197d4a637c92923abed..d362923b221b7ef5ed3c2b5f7a74f61f5551b705 100755 (executable)
@@ -143,6 +143,14 @@ Available options
    Specify the number of threads to run simultaneously.  If not specified,
    the number of threads is the same as the number of CPU cores.
 
+ -r, --git-ref
+   Specify the git ref to clone for building the autoconf.mk. If unspecified
+   use the CWD. This is useful for when changes to the Kconfig affect the
+   default values and you want to capture the state of the defconfig from
+   before that change was in effect. If in doubt, specify a ref pre-Kconfig
+   changes (use HEAD if Kconfig changes are not committed). Worst case it will
+   take a bit longer to run, but will always do the right thing.
+
  -v, --verbose
    Show any build errors as boards are built
 
@@ -479,9 +487,6 @@ class KconfigParser:
         else:
             new_val = not_set
 
-        if old_val == new_val:
-            return (ACTION_NO_CHANGE, new_val)
-
         # If this CONFIG is neither bool nor trisate
         if old_val[-2:] != '=y' and old_val[-2:] != '=m' and old_val != not_set:
             # tools/scripts/define2mk.sed changes '1' to 'y'.
@@ -490,7 +495,8 @@ class KconfigParser:
             if new_val[-2:] == '=y':
                 new_val = new_val[:-1] + '1'
 
-        return (ACTION_MOVE, new_val)
+        return (ACTION_NO_CHANGE if old_val == new_val else ACTION_MOVE,
+                new_val)
 
     def update_dotconfig(self):
         """Parse files for the config options and update the .config.
@@ -584,7 +590,7 @@ class Slot:
     for faster processing.
     """
 
-    def __init__(self, configs, options, progress, devnull, make_cmd):
+    def __init__(self, configs, options, progress, devnull, make_cmd, reference_src_dir):
         """Create a new process slot.
 
         Arguments:
@@ -593,22 +599,26 @@ class Slot:
           progress: A progress indicator.
           devnull: A file object of '/dev/null'.
           make_cmd: command name of GNU Make.
+          reference_src_dir: Determine the true starting config state from this
+                             source tree.
         """
         self.options = options
         self.progress = progress
         self.build_dir = tempfile.mkdtemp()
         self.devnull = devnull
         self.make_cmd = (make_cmd, 'O=' + self.build_dir)
+        self.reference_src_dir = reference_src_dir
         self.parser = KconfigParser(configs, options, self.build_dir)
         self.state = STATE_IDLE
         self.failed_boards = []
+        self.suspicious_boards = []
 
     def __del__(self):
         """Delete the working directory
 
         This function makes sure the temporary directory is cleaned away
         even if Python suddenly dies due to error.  It should be done in here
-        because it is guranteed the destructor is always invoked when the
+        because it is guaranteed the destructor is always invoked when the
         instance of the class gets unreferenced.
 
         If the subprocess is still running, wait until it finishes.
@@ -636,6 +646,7 @@ class Slot:
 
         self.defconfig = defconfig
         self.log = ''
+        self.current_src_dir = self.reference_src_dir
         self.do_defconfig()
         return True
 
@@ -664,9 +675,16 @@ class Slot:
         if self.ps.poll() != 0:
             self.handle_error()
         elif self.state == STATE_DEFCONFIG:
-            self.do_autoconf()
+            if self.reference_src_dir and not self.current_src_dir:
+                self.do_savedefconfig()
+            else:
+                self.do_autoconf()
         elif self.state == STATE_AUTOCONF:
-            self.do_savedefconfig()
+            if self.current_src_dir:
+                self.current_src_dir = None
+                self.do_defconfig()
+            else:
+                self.do_savedefconfig()
         elif self.state == STATE_SAVEDEFCONFIG:
             self.update_defconfig()
         else:
@@ -690,7 +708,8 @@ class Slot:
         cmd = list(self.make_cmd)
         cmd.append(self.defconfig)
         self.ps = subprocess.Popen(cmd, stdout=self.devnull,
-                                   stderr=subprocess.PIPE)
+                                   stderr=subprocess.PIPE,
+                                   cwd=self.current_src_dir)
         self.state = STATE_DEFCONFIG
 
     def do_autoconf(self):
@@ -709,7 +728,8 @@ class Slot:
         cmd.append('KCONFIG_IGNORE_DUPLICATES=1')
         cmd.append('include/config/auto.conf')
         self.ps = subprocess.Popen(cmd, stdout=self.devnull,
-                                   stderr=subprocess.PIPE)
+                                   stderr=subprocess.PIPE,
+                                   cwd=self.current_src_dir)
         self.state = STATE_AUTOCONF
 
     def do_savedefconfig(self):
@@ -736,13 +756,16 @@ class Slot:
     def update_defconfig(self):
         """Update the input defconfig and go back to the idle state."""
 
-        self.log += self.parser.check_defconfig()
+        log = self.parser.check_defconfig()
+        if log:
+            self.suspicious_boards.append(self.defconfig)
+            self.log += log
         orig_defconfig = os.path.join('configs', self.defconfig)
         new_defconfig = os.path.join(self.build_dir, 'defconfig')
         updated = not filecmp.cmp(orig_defconfig, new_defconfig)
 
         if updated:
-            self.log += color_text(self.options.color, COLOR_LIGHT_GREEN,
+            self.log += color_text(self.options.color, COLOR_LIGHT_BLUE,
                                    "defconfig was updated.\n")
 
         if not self.options.dry_run and updated:
@@ -780,17 +803,24 @@ class Slot:
         """
         return self.failed_boards
 
+    def get_suspicious_boards(self):
+        """Returns a list of boards (defconfigs) with possible misconversion.
+        """
+        return self.suspicious_boards
+
 class Slots:
 
     """Controller of the array of subprocess slots."""
 
-    def __init__(self, configs, options, progress):
+    def __init__(self, configs, options, progress, reference_src_dir):
         """Create a new slots controller.
 
         Arguments:
           configs: A list of CONFIGs to move.
           options: option flags.
           progress: A progress indicator.
+          reference_src_dir: Determine the true starting config state from this
+                             source tree.
         """
         self.options = options
         self.slots = []
@@ -798,7 +828,7 @@ class Slots:
         make_cmd = get_make_cmd()
         for i in range(options.jobs):
             self.slots.append(Slot(configs, options, progress, devnull,
-                                   make_cmd))
+                                   make_cmd, reference_src_dir))
 
     def add(self, defconfig):
         """Add a new subprocess if a vacant slot is found.
@@ -839,21 +869,76 @@ class Slots:
 
     def show_failed_boards(self):
         """Display all of the failed boards (defconfigs)."""
-        failed_boards = []
+        boards = []
+        output_file = 'moveconfig.failed'
+
+        for slot in self.slots:
+            boards += slot.get_failed_boards()
+
+        if boards:
+            boards = '\n'.join(boards) + '\n'
+            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)
+
+            with open(output_file, 'w') as f:
+                f.write(boards)
+
+    def show_suspicious_boards(self):
+        """Display all boards (defconfigs) with possible misconversion."""
+        boards = []
+        output_file = 'moveconfig.suspicious'
 
         for slot in self.slots:
-            failed_boards += slot.get_failed_boards()
+            boards += slot.get_suspicious_boards()
+
+        if boards:
+            boards = '\n'.join(boards) + '\n'
+            msg = "The following boards might have been converted incorrectly.\n"
+            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)
+
+            with open(output_file, 'w') as f:
+                f.write(boards)
 
-        if len(failed_boards) > 0:
-            msg = [ "The following boards were not processed due to error:" ]
-            msg += failed_boards
-            for line in msg:
-                print >> sys.stderr, color_text(self.options.color,
-                                                COLOR_LIGHT_RED, line)
+class ReferenceSource:
 
-            with open('moveconfig.failed', 'w') as f:
-                for board in failed_boards:
-                    f.write(board + '\n')
+    """Reference source against which original configs should be parsed."""
+
+    def __init__(self, commit):
+        """Create a reference source directory based on a specified commit.
+
+        Arguments:
+          commit: commit to git-clone
+        """
+        self.src_dir = tempfile.mkdtemp()
+        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()
+        subprocess.check_output(['git', 'checkout', commit],
+                                stderr=subprocess.STDOUT, cwd=self.src_dir)
+
+    def __del__(self):
+        """Delete the reference source directory
+
+        This function makes sure the temporary directory is cleaned away
+        even if Python suddenly dies due to error.  It should be done in here
+        because it is guaranteed the destructor is always invoked when the
+        instance of the class gets unreferenced.
+        """
+        shutil.rmtree(self.src_dir)
+
+    def get_dir(self):
+        """Return the absolute path to the reference source directory."""
+
+        return self.src_dir
 
 def move_config(configs, options):
     """Move config options to defconfig files.
@@ -871,6 +956,12 @@ def move_config(configs, options):
         print 'Move ' + ', '.join(configs),
     print '(jobs: %d)\n' % options.jobs
 
+    if options.git_ref:
+        reference_src = ReferenceSource(options.git_ref)
+        reference_src_dir = reference_src.get_dir()
+    else:
+        reference_src_dir = None
+
     if options.defconfigs:
         defconfigs = [line.strip() for line in open(options.defconfigs)]
         for i, defconfig in enumerate(defconfigs):
@@ -888,7 +979,7 @@ def move_config(configs, options):
                 defconfigs.append(os.path.join(dirpath, filename))
 
     progress = Progress(len(defconfigs))
-    slots = Slots(configs, options, progress)
+    slots = Slots(configs, options, progress, reference_src_dir)
 
     # Main loop to process defconfig files:
     #  Add a new subprocess into a vacant slot.
@@ -905,6 +996,7 @@ def move_config(configs, options):
 
     print ''
     slots.show_failed_boards()
+    slots.show_suspicious_boards()
 
 def main():
     try:
@@ -930,6 +1022,8 @@ def main():
                       help='only cleanup the headers')
     parser.add_option('-j', '--jobs', type='int', default=cpu_count,
                       help='the number of jobs to run simultaneously')
+    parser.add_option('-r', '--git-ref', type='string',
+                      help='the git ref to clone for building the autoconf.mk')
     parser.add_option('-v', '--verbose', action='store_true', default=False,
                       help='show any build errors as boards are built')
     parser.usage += ' CONFIG ...'