bisect-kit: migrate chromeos bisector to use codechange module

After this CL, chromeos localbuild bisector is more robust and can
handle following issues:
 - add and remove repo projects
 - manifest snapshot racing

Like android local build bisector, the setup step of chromeos checkout
is changed as well. Now you have to make a repo mirror and sync the
tree from the mirror. The exact steps are:

 1. setup a repo mirror
    $ cd $CHROMEOS_REPO_MIRROR_DIR
    $ repo init ...<original flags>... --mirror
    $ mkdir .repo/local_manifests
    $ cat << END > .repo/local_manifests/manifest-versions.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <manifest>
      <project name="chromeos/manifest-versions" remote="cros-internal" />
    </manifest>
    END
    $ repo sync

 2. checkout chromeos tree from the mirror
    $ cd $CHROMEOS_ROOT
    $ repo init ...<original flags>...  --reference=$CHROMEOS_REPO_MIRROR_DIR
    $ repo sync

 3. specify --chromeos_repo_mirror_dir $CHROMEOS_REPO_MIRROR_DIR when you
    use bisect_cros_repo.py and switch_cros_localbuild.py

Due to crbug.com/864886, this bisector can only work with version of
chromite after 2018-07-19. Workaround will be provided in separate CL
later.

BUG=chromium:827092
TEST=unit test and following commands
$ ./bisect_cros_repo.py init --old R69-10883.0.0 --new R69-10884.0.0 \
  --chromeos_root $CHROMEOS_ROOT \
  --chromeos_repo_mirror_dir $CHROMEOS_REPO_MIRROR_DIR \
  --board samus
$ ./switch_cros_localbuild.py samus-test R69-10883.0.0~R69-10884.0.0/10 \
  --chromeos_root $CHROMEOS_ROOT \
  --chromeos_repo_mirror_dir $CHROMEOS_REPO_MIRROR_DIR

Change-Id: I594d850f80a9ff05b7241106bdc7ff191cf12676
Reviewed-on: https://chromium-review.googlesource.com/1143114
Commit-Ready: Kuang-che Wu <kcwu@chromium.org>
Tested-by: Kuang-che Wu <kcwu@chromium.org>
Reviewed-by: Chi-Ngai Wan <cnwan@google.com>
diff --git a/bisect_cros_repo.py b/bisect_cros_repo.py
index 9ad9b3c..896fe5e 100755
--- a/bisect_cros_repo.py
+++ b/bisect_cros_repo.py
@@ -24,10 +24,11 @@
 import logging
 
 from bisect_kit import cli
-from bisect_kit import cros_util
-from bisect_kit import repo_util
+from bisect_kit import codechange
 from bisect_kit import configure
 from bisect_kit import core
+from bisect_kit import cros_util
+from bisect_kit import repo_util
 
 logger = logging.getLogger(__name__)
 
@@ -43,7 +44,7 @@
         '--dut',
         type=cli.argtype_notempty,
         metavar='DUT',
-        default=configure.get('DUT', ''),
+        default=configure.get('DUT'),
         help='DUT address')
     parser.add_argument(
         '--board',
@@ -57,6 +58,11 @@
         required=True,
         default=configure.get('CHROMEOS_ROOT'),
         help='ChromeOS tree root')
+    parser.add_argument(
+        '--chromeos_repo_mirror_dir',
+        type=cli.argtype_dir_path,
+        default=configure.get('CHROMEOS_REPO_MIRROR_DIR', ''),
+        help='ChromeOS repo mirror path')
 
   @staticmethod
   def init(opts):
@@ -82,12 +88,25 @@
     repo_util.abandon(opts.chromeos_root, 'stabilizing_branch')
 
     config = dict(
-        dut=opts.dut, board=opts.board, chromeos_root=opts.chromeos_root)
+        dut=opts.dut,
+        board=opts.board,
+        chromeos_root=opts.chromeos_root,
+        chromeos_repo_mirror_dir=opts.chromeos_repo_mirror_dir)
 
-    manifest_manager = cros_util.ChromeOSManifestManager(config)
-    dependency_manager = repo_util.DependencyManager(opts.chromeos_root,
-                                                     manifest_manager)
-    revlist = dependency_manager.get_revlist(opts.old, opts.new)
+    spec_manager = cros_util.ChromeOSSpecManager(config)
+    cache = repo_util.RepoMirror(opts.chromeos_repo_mirror_dir)
+
+    # Make sure all repos in between are cached
+    float_specs = spec_manager.collect_float_spec(opts.old, opts.new)
+    for spec in reversed(float_specs):
+      spec_manager.parse_spec(spec)
+      if cache.are_spec_commits_available(spec):
+        continue
+      spec_manager.sync_disk_state(spec.name)
+
+    code_manager = codechange.CodeManager(opts.chromeos_root, spec_manager,
+                                          cache)
+    revlist = code_manager.build_revlist(opts.old, opts.new)
     return config, revlist
 
   def __init__(self, config):
@@ -99,16 +118,18 @@
     if self.config['board']:
       env['BOARD'] = self.config['board']
     env['CHROMEOS_ROOT'] = self.config['chromeos_root']
+    env['CHROMEOS_REPO_MIRROR_DIR'] = self.config['chromeos_repo_mirror_dir']
     env['INTRA_REV'] = rev
 
   def view(self, old, new):
     print('old', old)
     print('new', new)
 
-    manifest_manager = cros_util.ChromeOSManifestManager(self.config)
-    dependency_manager = repo_util.DependencyManager(
-        self.config['chromeos_root'], manifest_manager)
-    dependency_manager.view_rev_diff(old, new)
+    spec_manager = cros_util.ChromeOSSpecManager(self.config)
+    cache = repo_util.RepoMirror(self.config['chromeos_repo_mirror_dir'])
+    code_manager = codechange.CodeManager(self.config['chromeos_root'],
+                                          spec_manager, cache)
+    code_manager.view_rev_diff(old, new)
 
 
 if __name__ == '__main__':