Refactor gooftool, eliminating boilerplate.

Eliminate gft_common, switch to use the python 2.7 argparse
with subcommands (like hwid_tool), and also use logging instead
of the home-made xxxMsg commands.  Also switch to using the
RunShellCmd (renamed Shell) from common instead of the
myriad versions in gft_common.

BUG=chrome-os-partner:9149
TEST=run all of the gooftool subcommands on a DUT

Change-Id: I50ad8a9e2e7cb760317e2b8c2e94531dcfd5c451
Reviewed-on: https://gerrit.chromium.org/gerrit/20052
Tested-by: Tammo Spalink <tammo@chromium.org>
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Commit-Ready: Tammo Spalink <tammo@chromium.org>
diff --git a/common.py b/common.py
index c914881..fdadc73 100644
--- a/common.py
+++ b/common.py
@@ -8,6 +8,7 @@
 import logging
 import re
 import time
+import yaml
 
 from subprocess import Popen, PIPE
 
@@ -27,8 +28,7 @@
     return repr(self.__dict__)
 
 
-# TODO(tammo): Combine this with gft_common.ShellExecution.
-def RunShellCmd(cmd):
+def Shell(cmd):
   """Run cmd in a shell, return Obj containing stdout, stderr, and status.
 
   The cmd stdout and stderr output is debug-logged.
@@ -42,7 +42,8 @@
   logging.debug('running %s' % repr(cmd) +
                 (', stdout: %s' % repr(stdout.strip()) if stdout else '') +
                 (', stderr: %s' % repr(stderr.strip()) if stderr else ''))
-  return Obj(stdout=stdout, stderr=stderr, success=(not process.poll()))
+  status = process.poll()
+  return Obj(stdout=stdout, stderr=stderr, status=status, success=(status == 0))
 
 
 def CompactStr(data):
@@ -75,3 +76,38 @@
       **({'filename': log_file_name} if log_file_name else {}))
   logging.Formatter.converter = time.gmtime
   logging.info(time.strftime('%Y.%m.%d %Z', time.gmtime()))
+
+
+def YamlWrite(structured_data):
+  """Wrap yaml.dump to make calling convention consistent."""
+  return yaml.dump(structured_data, default_flow_style=False)
+
+
+def YamlRead(serialized_data):
+  """Wrap yaml.load to make calling convention consistent."""
+  return yaml.safe_load(serialized_data)
+
+
+def ParseKeyValueData(pattern, data):
+  """Converts structured text into a {(key, value)} dict.
+
+  Args:
+    pattern: A regex pattern to decode key/value pairs
+    data: The text to be parsed.
+
+  Returns:
+    A { key: value, ... } dict.
+
+  Raises:
+    ValueError: When the input is invalid.
+  """
+  parsed_list = {}
+  for line in data.splitlines():
+    matched = re.match(pattern, line.strip())
+    if not matched:
+      raise ValueError('Invalid data: %s' % line)
+    (name, value) = (matched.group(1), matched.group(2))
+    if name in parsed_list:
+      raise ValueError('Duplicate key: %s' % name)
+    parsed_list[name] = value
+  return parsed_list
diff --git a/crosfw.py b/crosfw.py
index 8c70396..89f916f 100644
--- a/crosfw.py
+++ b/crosfw.py
@@ -18,9 +18,10 @@
 
 from tempfile import NamedTemporaryFile
 
-import common
 import fmap
 
+from common import Shell
+
 
 # Names to select target bus.
 TARGET_MAIN = 'main'
@@ -46,7 +47,7 @@
   def _InvokeCommand(self, param, ignore_status=False):
     command = ' '.join(['flashrom', self._TARGET_MAP[self._target], param])
     logging.debug('Flashrom._InvokeCommand: %s', command)
-    result = common.RunShellCmd(command)
+    result = Shell(command)
     if not (ignore_status or result.success):
       raise IOError, "Failed in command: %s\n%s" % (command, result.stderr)
     return result
@@ -202,7 +203,7 @@
 
 
 class FirmwareContent(object):
-  """Access to the firmware chip_id and content file for a specific target.
+  """Wrapper around flashrom for a specific firmware target.
 
   This class keeps track of all the instances of itself that exist.
   The goal being that only one instance ever gets created for each
@@ -227,7 +228,7 @@
   def GetChipId(self):
     """Caching get of flashrom chip identifier.  None if no chip is present."""
     if not hasattr(self, 'chip_id'):
-      info = flashrom.GetName()
+      info = self.flashrom.GetName()
       self.chip_id = ' '.join([info['vendor'], info['name']]) if info else None
     return self.chip_id
 
@@ -237,11 +238,15 @@
       return None
     if not hasattr(self, 'filename'):
       fileref = NamedTemporaryFile(prefix='fw_%s_' % self.target)
-      self.flashrom.Read(filename=fileref.filename)
+      self.flashrom.Read(filename=fileref.name)
       self.fileref = fileref
-      self.filename = fileref.filename
+      self.filename = fileref.name
     return self.filename
 
+  def Write(self, sections=None):
+    """Call flashrom write for specific sections."""
+    self.flashrom.Write(filename=self.GetFileName(), sections=sections)
+
 
 def LoadEcFirmware():
   """Returns flashrom data from Embedded Controller chipset."""
diff --git a/gft_common.py b/gft_common.py
deleted file mode 100644
index 8b36b6f..0000000
--- a/gft_common.py
+++ /dev/null
@@ -1,263 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Google Factory Tools Common Library
-
-This module includes several common utilities for Google Factory Tools
-A detailed description of gft_common.
-"""
-
-import os
-import re
-import subprocess
-import sys
-import tempfile
-import threading
-import time
-
-
-########################################################################
-# Global Variables
-
-
-_debug = False
-_verbose = False
-_log_path = None
-
-DEFAULT_CONSOLE_LOG_PATH = '/var/log/factory.log'
-
-
-########################################################################
-# Common Utilities
-
-
-class GFTError(Exception):
-  """ Exception for unrecoverable errors for GFT related functions. """
-
-  def __init__(self, value):
-    self.value = value
-
-  def __str__(self):
-    return repr(self.value)
-
-
-def SetDebugLevel(level):
-  """ Sets the debugging level. """
-  global _debug
-  _debug = level
-
-
-def SetVerboseLevel(level, log_path=None):
-  """ Sets the verbosity level and log output path. """
-  global _verbose, _log_path
-  _verbose = level
-  if log_path:
-    DebugMsg("Set log path to: " + log_path, log=False)
-    _log_path = log_path
-
-
-def Log(msg):
-  """ Writes a message to pre-configured log file. """
-  if not _log_path:
-    return
-  try:
-    with open(_log_path, "at") as log_handle:
-      lines = ["(GFT) %s %s\n" % (time.strftime("%Y%m%d %H:%M:%S"), entry)
-               for entry in msg.splitlines()]
-      log_handle.writelines(lines)
-  except:
-    sys.stderr.write("FAILED TO WRITE TO LOG FILE %s.\n" % _log_path)
-
-
-def WarningMsg(msg):
-  """ Prints warning messages (to stderr) as-is. """
-  sys.stderr.write("%s\n" % msg)
-  Log(msg)
-
-
-def VerboseMsg(msg):
-  """ Prints verbose message, if SetVerboseLevel was called with True. """
-  if _verbose:
-    WarningMsg(msg)
-  else:
-    Log(msg)
-
-
-def DebugMsg(msg, log=True):
-  """ Prints message when debug is enabled. """
-  for entry in msg.splitlines():
-    if _debug:
-      WarningMsg("(DEBUG) %s" % entry)
-    elif log:
-      Log("(DEBUG) %s" % entry)
-
-
-def ErrorMsg(msg):
-  """ Prints messages to stderr with prefix "ERROR". """
-  for entry in msg.splitlines():
-    WarningMsg("ERROR: %s" % entry)
-
-
-def ErrorDie(msg):
-  """ Raises a GFTError exception. """
-  raise GFTError(msg)
-
-
-def GFTConsole(f):
-  """Decorator for all Google Factory Test Tools console programs.
-
-  log path will be redirectd to DEFAULT_CONSOLE_LOG_PATH by default,
-  and all GFTError will be catched, logged, and exit as failure.
-  """
-  def main_wrapper(*args, **kw):
-    # override the default log path
-    global _log_path
-    _log_path = DEFAULT_CONSOLE_LOG_PATH
-    try:
-      return f(*args, **kw)
-    except GFTError, e:
-      ErrorMsg(e.value)
-      sys.exit(1)
-  return main_wrapper
-
-
-def GetTemporaryFileName(prefix='gft', suffix=''):
-  """ Gets a unique file name for temporary usage. """
-  (fd, filename) = tempfile.mkstemp(prefix=prefix, suffix=suffix)
-  os.close(fd)
-  return filename
-
-
-def ShellExecution(command,
-                   ignore_status=False,
-                   show_progress=False,
-                   progress_message=None):
-  """ Executes a shell command, and return the results.
-
-  Args:
-    ignore_status: False to raise exectopion when execution result is not zero
-    show_progress: Shows progress by messages and dots
-    progress_message: Messages printed before starting.
-
-  Returns:
-    (exit_code, stdout_messages, stderr_messages)
-  """
-  DebugMsg("ShellExecution: %s" % command, log=False)
-  temp_stderr = tempfile.TemporaryFile()
-  temp_stdout = tempfile.TemporaryFile()
-  proc = subprocess.Popen(command,
-                          stderr=temp_stderr,
-                          stdout=temp_stdout,
-                          shell=True)
-  if show_progress:
-    sys.stdout.flush()
-    if progress_message:
-      sys.stderr.write(progress_message)
-    while proc.poll() is None:
-      sys.stderr.write('.')
-      time.sleep(1)
-    if progress_message:
-      sys.stderr.write('\n')
-  else:
-    proc.communicate()
-
-  # collect output
-  temp_stdout.seek(0)
-  out = temp_stdout.read()
-  temp_stdout.close()
-
-  temp_stderr.seek(0)
-  err = temp_stderr.read()
-  temp_stderr.close()
-
-  exit_code = proc.wait()
-  if exit_code:
-    # prepare to log the error message.
-    message = ('Failed executing command: %s\n'
-               'Output and Error Messages: %s\n%s' % (command, out, err))
-    if ignore_status:
-      DebugMsg(message)
-    else:
-      ErrorDie(message)
-  return (exit_code, out, err)
-
-
-def SystemOutput(command,
-                 ignore_status=False,
-                 show_progress=False,
-                 progress_message=None):
-  """ Returns the stdout results from a shell command execution. """
-  return ShellExecution(command, ignore_status, show_progress,
-                        progress_message)[1].rstrip('\n')
-
-
-def System(command,
-           ignore_status=False,
-           show_progress=False,
-           progress_message=None):
-  """ Returns the exit code from a shell command execution. """
-  return ShellExecution(command, ignore_status, show_progress,
-                        progress_message)[0]
-
-
-def ReadOneLine(filename):
-  """ Reads one line from file. """
-  with open(filename) as opened_file:
-    return opened_file.readline().strip()
-
-
-def ReadFile(filename):
-  """ Reads whole file. """
-  with open(filename) as opened_file:
-    return opened_file.read().strip()
-
-
-def ReadBinaryFile(filename):
-  """ Reads whole binary file. """
-  with open(filename, "rb") as opened_file:
-    return opened_file.read()
-
-
-def WriteFile(filename, data):
-  """ Writes one file and exit. """
-  with open(filename, "w") as opened_file:
-    opened_file.write(data)
-
-def WriteBinaryFile(filename, data):
-  """ Writes one binary file and exit. """
-  with open(filename, "wb") as opened_file:
-    opened_file.write(data)
-
-
-def ThreadSafe(f):
-  """ Decorator for functions that need synchronoization. """
-  lock = threading.Lock()
-  def threadsafe_call(*args):
-    try:
-      lock.acquire()
-      return f(*args)
-    finally:
-      lock.release()
-  return threadsafe_call
-
-
-def Memorize(f):
-  """ Decorator for functions that need memorization. """
-  memorize_data = {}
-  def memorize_call(*args):
-    index = repr(args)
-    if index in memorize_data:
-      value = memorize_data[index]
-      # DebugMsg('Memorize: using cached value for: %s %s' % (repr(f), index))
-      return value
-    value = f(*args)
-    memorize_data[index] = value
-    return value
-  return memorize_call
-
-
-if __name__ == '__main__':
-  print "Google Factory Tool Common Library."
diff --git a/gft_report.py b/gft_report.py
deleted file mode 100755
index 61acb6b..0000000
--- a/gft_report.py
+++ /dev/null
@@ -1,424 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-""" gft_report.py: Device detail reports for factory process.
-
-The reports for factory is currently a python native dict.
-
-You can use CreateReport() to create a native report,
-ValidateReport() to check if a native report is valid,
-FormatReport() to print a native report in text form,
-EncodeReport() to transform a report to ASCII-safe format,
-DecodeReport() to covert from an encoded string.
-"""
-
-import base64
-import gzip
-import os
-import pprint
-import re
-import StringIO
-import sys
-import time
-
-import crosfw
-import gft_common
-from gft_common import ErrorMsg, VerboseMsg, DebugMsg, ErrorDie
-
-
-# TODO(tammo): It would be nice to be less python-centric, and maybe
-# to be more flexible.  Consider using YAML for the primary structured
-# portion of the data.  Also consider collecting log data
-# incrementally on disk.  The routines here could be called by other
-# modules to add log data (either structured or non-structured), and
-# then the final log creation just serializes the collection.
-# Consider using MIME for this serialization (and MIME types could be
-# indicated when data is registered to be included).
-
-
-# Update this if any field names (or formats) have been changed.
-REPORT_VERSION = 4
-
-# Keys in decoding results
-KEY_INFO_DECODERS = 'decoders'
-
-
-def ParseKeyValueData(pattern, data):
-  """Converts a given key-value style into [(key, value)] format.
-
-  Args:
-    pattern: A regex pattern to decode key/value pairs
-    data: The data to be parsed.
-
-  Returns:
-    A { key: value, ... } dict.
-
-  Raises:
-    ValueError: When the input is invalid.
-  """
-  parsed_list = {}
-  for line in data.splitlines():
-    matched = re.match(pattern, line.strip())
-    if not matched:
-      raise ValueError("Invalid data: %s" % line)
-    (name, value) = (matched.group(1), matched.group(2))
-    if name in parsed_list:
-      raise ValueError("Duplicated entry: %s" % name)
-    parsed_list[name] = value
-  return parsed_list
-
-
-def ParseVPDOutput(output):
-  """ Converts "a"="b"\n list into [(a, b)] """
-  return ParseKeyValueData('"(.*)"="(.*)"$', output)
-
-
-def ParseCrossystemOutput(output):
-  """ Converts [a   = b  # comment] into [(a, b)] """
-  return ParseKeyValueData("^([^ =]*) *= *(.*[^ ]) *# [^#]*$", output)
-
-
-def EncodeReport(native_report, text_armed=True):
-  """ Encodes a native python-dict report into ASCII friendly form. """
-  buf = StringIO.StringIO()
-  zbuf = gzip.GzipFile(fileobj=buf, mode='wb')
-  zbuf.write(FormatReport(native_report) + "\n")
-  zbuf.close()
-  buf.seek(0)  # prepare for read
-  data = buf.read()
-  if text_armed:
-    data = base64.encodestring(data)
-  return data
-
-
-def DecodeReport(blob, info={}):
-  """Decodes a report in blob (or ASCII) form into native python dict.
-
-  Args:
-    blob: A data containing encoded report.
-    info: Dictionary object to receive information collected during decode.
-  """
-  # The report may be encoded in gzipped/base64 formats.
-
-  def Base64Decoder(data):
-    info[KEY_INFO_DECODERS] += ['b64']
-    return base64.decodestring(data)
-  def GunzipDecoder(data):
-    info[KEY_INFO_DECODERS] += ['gz']
-    buf = StringIO.StringIO()
-    buf.write(data)
-    buf.seek(0)  # prepare for read
-    zbuf = gzip.GzipFile(fileobj=buf, mode='rb')
-    return zbuf.read()
-  def ReportDecoder(data):
-    info[KEY_INFO_DECODERS] += ['rpt']
-    return eval(data)
-
-  decoders = [
-    lambda(x): ReportDecoder(GunzipDecoder(Base64Decoder(x))),
-    lambda(x): ReportDecoder(GunzipDecoder(x)),
-    lambda(x): ReportDecoder(x),
-  ]
-
-  for decoder in decoders:
-    try:
-      info[KEY_INFO_DECODERS] = []
-      decoded = decoder(blob)
-      return decoded
-    except:
-      pass
-  raise ValueError, "Invalid report."
-
-
-def FormatReport(native_report):
-  """ Returns a pretty-formatted text presentation of the report. """
-  return pprint.pformat(native_report)
-
-
-def ValidateReport(native_report):
-  '''Type check the details data.
-
-  Args:
-    native_report: A dict object containing the detail report.
-
-  Returns:
-    None if validation passed, otherwise a string of reason for failure.
-  '''
-  mandatory_string_keys = ['version',
-                           'create_params',
-                           'device_timestamp',
-                           'platform_name',
-                           'hwid',
-                           'tag',
-                           ]
-  mandatory_dict_keys = ['crossystem',
-                         'hwid_properties',
-                         'cooked_probe_results',
-                         'ro_vpd',
-                         'rw_vpd',
-                         ]
-  mandatory_list_keys = ['modem_status',
-                         'verbose_log',
-                         'wp_status',
-                         ]
-  if not isinstance(native_report, dict):
-    return 'native_report must be a dict'
-
-  # populate key difference
-  mandatory_key_set = (set(mandatory_string_keys) |
-                       set(mandatory_dict_keys) |
-                       set(mandatory_list_keys))
-  detail_key_set = set(native_report.keys())
-  key_set_delta = detail_key_set ^ mandatory_key_set
-  if key_set_delta:
-    err_msg = 'detail key sets differ'
-    extra = detail_key_set - mandatory_key_set
-    if extra:
-      err_msg += ', extra keys [%s]' % ', '.join([repr(x) for x in extra])
-    missing = mandatory_key_set - detail_key_set
-    if missing:
-      err_msg += ', missing keys [%s]' % ', '.join([repr(x) for x in missing])
-    return err_msg
-
-  # validate value attributes
-  for key in mandatory_string_keys:
-    if not isinstance(native_report[key], str):
-      return 'property %s in report should be a simple string.' % key
-
-  for key in mandatory_dict_keys:
-    value = native_report[key]
-    if not isinstance(value, dict):
-      return 'property %s in report should be a dict.' % key
-    # TODO(tammo): Either fix the check below (which currently forces
-    # each dict value to be simple string, and thus is not compatible
-    # with the deeper nesting used by the hwid_properties and cooked_*
-    # fields) or switch to a YAML/etc report format w/o checks.
-    # for subkey in value:
-    #   if not isinstance(value[subkey], str):
-    #     return ('property %s.%s in report should be a simple string.' %
-    #            (key, subkey))
-  for key in mandatory_list_keys:
-    value = native_report[key]
-    if not isinstance(value, list):
-      return 'property %s in report should be a list.' % key
-    # each elements in value should be simple string
-    for subvalue in value:
-      if not isinstance(subvalue, str):
-        return 'property %s in report should be a list of simple strings.' % key
-  return None
-
-
-def CreateReport(create_params,
-                 system_details,
-                 verbose_log_path=gft_common.DEFAULT_CONSOLE_LOG_PATH,
-                 vpd_source=None,
-                 tag='',
-                 verbose=False):
-  """Creates a detail report for current device.
-
-  Collects hwid, vpd, probed components, and attach a timestamp.
-
-  Args:
-    create_params: the original command line that creates the report.
-    probed_components: A match result from gft_hwcomp.HardwareComponents
-    vpd_source: Optional input image for VPD values (None for system)
-
-  Returns:
-    A dict mapping keys to details. Example:
-    {'hwid': 'ABC',
-     'device_timestamp': '20111031-175023',  # UTC
-     ...}
-  """
-  report = {}
-
-  # TODO(tammo): Consider adding /var/log/messages* and /etc/lsb-release.
-
-  # TODO(hungte) we may also add in future:
-  #   rootfs hash, dump_kernel_config, lsb-release from release image,
-  #   gooftool version, result of dev_vboot_debug,
-  #   /var/log/factory.log and any other customized data
-
-  # General information
-  report['version'] = '%s' % REPORT_VERSION
-  report['create_params'] = ' '.join(create_params)
-  report['tag'] = tag
-
-  # System Hardware ID
-  report['hwid'] = gft_common.SystemOutput("crossystem hwid").strip()
-  report['platform_name'] = gft_common.SystemOutput(
-      "mosys platform name").strip()
-
-  # crossystem reports many system configuration data
-  report['crossystem'] = ParseCrossystemOutput(
-      gft_common.SystemOutput("crossystem").strip())
-
-  # Vital Product Data
-  vpd_cmd = '-f %s' % vpd_source if vpd_source else ''
-  report['ro_vpd'] = ParseVPDOutput(
-      gft_common.SystemOutput("vpd -i RO_VPD -l %s" % vpd_cmd,
-                              progress_message="Reading RO VPD",
-                              show_progress=verbose).strip())
-  report['rw_vpd'] = ParseVPDOutput(
-      gft_common.SystemOutput("vpd -i RW_VPD -l %s" % vpd_cmd,
-                              progress_message="Reading RW VPD",
-                              show_progress=verbose).strip())
-
-  # HWID-related Device Data
-  report['hwid_properties'] = system_details.hwid_properties.__dict__
-  report['cooked_probe_results'] = system_details.cooked_results.__dict__
-
-  # Firmware write protection status
-  # TODO(hungte) Replace by crosfw.Flashrom.
-  ec_wp_status = gft_common.SystemOutput(
-      'flashrom -p internal:bus=lpc --get-size 2>/dev/null && '
-      'flashrom -p internal:bus=lpc --wp-status || '
-      'echo "EC is not available."',
-      ignore_status=True)
-  bios_wp_status = gft_common.SystemOutput(
-      'flashrom -p internal:bus=spi --wp-status')
-
-  wp_status_message = 'main: %s\nec: %s' % (bios_wp_status, ec_wp_status)
-  report['wp_status'] = wp_status_message.splitlines()
-
-  # Cellular status
-  modem_status = gft_common.SystemOutput('modem status', ignore_status=True)
-  report['modem_status'] = modem_status.splitlines()
-
-  # Verbose log. Should be prepared before the last step.
-  if verbose_log_path and os.path.exists(verbose_log_path):
-    verbose_log = gft_common.ReadFile(verbose_log_path).splitlines()
-  else:
-    verbose_log = ['(Not available)']
-  report['verbose_log'] = verbose_log
-
-  # Finally, attach a timestamp. This must be the last entry.
-  report['device_timestamp'] = time.strftime("%Y%m%d-%H%M%S", time.gmtime())
-  return report
-
-
-def GetReportName(report_blob):
-  """Returns the proper report file name according to report content.
-
-  Args:
-    report_path: Path to report file.
-  Returns:
-    File name according to provided report.
-  """
-  def quote_atom(atom, delimiter=''):
-    return re.sub(r'[^a-zA-Z0-9]+', delimiter, atom).strip(delimiter)
-
-  info = {}
-  report = DecodeReport(report_blob, info)
-  error = ValidateReport(report)
-  if error:
-    ErrorDie("Failed decoding report: %s" % error)
-  platform = report['platform_name'].lower()
-  serial = report['ro_vpd'].get('serial_number', 'unknown')
-  date = report['device_timestamp']
-  ext = info[KEY_INFO_DECODERS]
-  ext.reverse()
-
-  return '%s_%s_%s.%s' % (quote_atom(platform), quote_atom(serial),
-                          quote_atom(date, '-'), '.'.join(ext))
-
-
-#############################################################################
-# Console main entry
-@gft_common.GFTConsole
-def main():
-  """ Main entry as a utility. """
-  # Only load optparse when running as a stand-alone command.
-  import glob
-  import optparse
-
-  parser = optparse.OptionParser()
-  parser.add_option('--debug', action='store_true',
-                    help='provide debug messages.')
-  parser.add_option('--decode', action='store_true',
-                    help='decode a encoded report to human readable format.')
-  parser.add_option('--log_path', metavar='PATH',
-                    default=gft_common.DEFAULT_CONSOLE_LOG_PATH,
-                    help='use the given path for getting verbose logs.')
-  parser.add_option('--report_path', metavar='PATH', default='report.gz',
-                    help='use this path to read / write reports.')
-  parser.add_option('--report_format', metavar='FORMAT', default='gz',
-                    help='format of the generated report; '
-                         'currently supported values: gz, base64')
-  parser.add_option('--db_path', metavar='DB_PATH',
-                    help='path pattern for hardware components databases')
-  (options, args) = parser.parse_args()
-  if args:
-    parser.error('Un-expected parameter(s): %s\n' % ' '.join(args))
-  if options.debug:
-    gft_common.SetDebugLevel(options.debug)
-
-  # Decode
-  if options.decode:
-    if not options.report_path:
-      parser.error('Need --report_path to assign target for decoding.')
-    data = gft_common.ReadFile(options.report_path)
-    if options.report_format == 'gz':
-      text_armed = False
-    elif options.report_format == 'base64':
-      text_armed = True
-    else:
-      ErrorDie('gft_report: invalid report format: %s' % options.report_format)
-    print FormatReport(DecodeReport(data))
-    print "Report name: %s" % GetReportName(data)
-    return
-
-  # Encode
-  if not options.db_path:
-    parser.error('Need --db_path.')
-
-  # populate db_path
-  db_files = glob.glob(options.db_path)
-  if not db_files:
-    parser.error('No valid files in --db_path (%s)' % options.db_path)
-
-  best_match = None
-  for db_file in db_files:
-    VerboseMsg("gft_report: Matching for %s..." % db_file)
-    (probed, failure) = hwcomp.match_current_system(db_file)
-    if not failure:
-      best_match = probed
-      break
-  if not best_match:
-    best_match = probed
-  VerboseMsg('gft_report: Found hardware components: %s' %
-             hwcomp.pformat(best_match))
-
-  # create the native report
-  main_fw_file = crosfw.LoadMainFirmware().path
-  native_report = CreateReport(sys.argv,
-                               best_match,
-                               verbose_log_path=options.log_path,
-                               vpd_source=main_fw_file,
-                               verbose=True)
-  invalid_message = ValidateReport(native_report)
-  assert not invalid_message, "Invalid report: %s" % invalid_message
-
-  # write the text report into stderr, without being logged.
-  sys.stdout.flush()
-  sys.stderr.write(FormatReport(native_report) + '\n')
-
-  if options.report_format == 'gz':
-    data = EncodeReport(native_report, text_armed=False)
-  elif options.report_format == 'base64':
-    data = EncodeReport(native_report, text_armed=True)
-  else:
-    ErrorDie('gft_report: invalid report format: %s' % options.report_format)
-
-  if options.report_path:
-    print "Saved report to: %s" % options.report_path
-    with open(options.report_path, "wb") as report_handle:
-      report_handle.write(data)
-  else:
-    print data
-  print "Report name: %s" % GetReportName(data)
-
-
-if __name__ == "__main__":
-  main()
diff --git a/gft_vpd.py b/gft_vpd.py
deleted file mode 100755
index f6de023..0000000
--- a/gft_vpd.py
+++ /dev/null
@@ -1,398 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-#
-# This is a required test to check all VPD related information.
-
-""" gft_vpd.py: Check if the VPD data is valid for ChromeOS. """
-
-
-import bmpblk
-import crosfw
-import gft_common
-import gft_report
-import os
-import sys
-
-from gft_common import ErrorMsg, WarningMsg, VerboseMsg, DebugMsg, ErrorDie
-
-# Required VPD Keys. See http://go/vpdspec
-KEY_KEYBOARD_LAYOUT = 'keyboard_layout'
-KEY_INITIAL_LOCALE = 'initial_locale'
-KEY_INITIAL_TIMEZONE = 'initial_timezone'
-KEY_SERIAL_NUMBER = 'serial_number'
-
-# keyboard_layout: http://gerrit.chromium.org/gerrit/gitweb?p=chromium/src.git;a=blob;f=chrome/browser/chromeos/input_method/ibus_input_methods.txt
-CHROMEOS_KEYBOARD_LAYOUT = [
-  'xkb:nl::nld',
-  'xkb:be::nld',
-  'xkb:fr::fra',
-  'xkb:be::fra',
-  'xkb:ca::fra',
-  'xkb:ch:fr:fra',
-  'xkb:de::ger',
-  'xkb:de:neo:ger',
-  'xkb:be::ger',
-  'xkb:ch::ger',
-  'xkb:jp::jpn',
-  'xkb:ru::rus',
-  'xkb:ru:phonetic:rus',
-  'xkb:us::eng',
-  'xkb:us:intl:eng',
-  'xkb:us:altgr-intl:eng',
-  'xkb:us:dvorak:eng',
-  'xkb:us:colemak:eng',
-  'xkb:br::por',
-  'xkb:bg::bul',
-  'xkb:bg:phonetic:bul',
-  'xkb:ca:eng:eng',
-  'xkb:cz::cze',
-  'xkb:ee::est',
-  'xkb:es::spa',
-  'xkb:es:cat:cat',
-  'xkb:dk::dan',
-  'xkb:gr::gre',
-  'xkb:il::heb',
-  'xkb:kr:kr104:kor',
-  'xkb:latam::spa',
-  'xkb:lt::lit',
-  'xkb:lv:apostrophe:lav',
-  'xkb:hr::scr',
-  'xkb:gb:extd:eng',
-  'xkb:gb:dvorak:eng',
-  'xkb:fi::fin',
-  'xkb:hu::hun',
-  'xkb:it::ita',
-  'xkb:no::nob',
-  'xkb:pl::pol',
-  'xkb:pt::por',
-  'xkb:ro::rum',
-  'xkb:se::swe',
-  'xkb:sk::slo',
-  'xkb:si::slv',
-  'xkb:rs::srp',
-  'xkb:tr::tur',
-  'xkb:ua::ukr',
-]
-
-# initial_locale: http://git.chromium.org/gitweb/?p=chromium.git;a=blob;f=ui/base/l10n/l10n_util.cc
-CHROMEOS_INITIAL_LOCALE = [
-  "af",
-  "am",
-  "ar",
-  "az",
-  "be",
-  "bg",
-  "bh",
-  "bn",
-  "br",
-  "bs",
-  "ca",
-  "co",
-  "cs",
-  "cy",
-  "da",
-  "de",
-  "de-AT",
-  "de-CH",
-  "de-DE",
-  "el",
-  "en",
-  "en-AU",
-  "en-CA",
-  "en-GB",
-  "en-NZ",
-  "en-US",
-  "en-ZA",
-  "eo",
-  "es",
-  "es-419",
-  "et",
-  "eu",
-  "fa",
-  "fi",
-  "fil",
-  "fo",
-  "fr",
-  "fr-CA",
-  "fr-CH",
-  "fr-FR",
-  "fy",
-  "ga",
-  "gd",
-  "gl",
-  "gn",
-  "gu",
-  "ha",
-  "haw",
-  "he",
-  "hi",
-  "hr",
-  "hu",
-  "hy",
-  "ia",
-  "id",
-  "is",
-  "it",
-  "it-CH",
-  "it-IT",
-  "ja",
-  "jw",
-  "ka",
-  "kk",
-  "km",
-  "kn",
-  "ko",
-  "ku",
-  "ky",
-  "la",
-  "ln",
-  "lo",
-  "lt",
-  "lv",
-  "mk",
-  "ml",
-  "mn",
-  "mo",
-  "mr",
-  "ms",
-  "mt",
-  "nb",
-  "ne",
-  "nl",
-  "nn",
-  "no",
-  "oc",
-  "om",
-  "or",
-  "pa",
-  "pl",
-  "ps",
-  "pt",
-  "pt-BR",
-  "pt-PT",
-  "qu",
-  "rm",
-  "ro",
-  "ru",
-  "sd",
-  "sh",
-  "si",
-  "sk",
-  "sl",
-  "sn",
-  "so",
-  "sq",
-  "sr",
-  "st",
-  "su",
-  "sv",
-  "sw",
-  "ta",
-  "te",
-  "tg",
-  "th",
-  "ti",
-  "tk",
-  "to",
-  "tr",
-  "tt",
-  "tw",
-  "ug",
-  "uk",
-  "ur",
-  "uz",
-  "vi",
-  "xh",
-  "yi",
-  "yo",
-  "zh",
-  "zh-CN",
-  "zh-TW",
-  "zu",
-]
-
-# initial_timezone: http://git.chromium.org/gitweb/?p=chromium.git;a=blob;f=chrome/browser/chromeos/dom_ui/system_settings_provider.cc
-CHROMEOS_INITIAL_TIMEZONE = [
-  "Pacific/Majuro",
-  "Pacific/Midway",
-  "Pacific/Honolulu",
-  "America/Anchorage",
-  "America/Los_Angeles",
-  "America/Tijuana",
-  "America/Denver",
-  "America/Phoenix",
-  "America/Chihuahua",
-  "America/Chicago",
-  "America/Mexico_City",
-  "America/Costa_Rica",
-  "America/Regina",
-  "America/New_York",
-  "America/Bogota",
-  "America/Caracas",
-  "America/Barbados",
-  "America/Manaus",
-  "America/Santiago",
-  "America/St_Johns",
-  "America/Sao_Paulo",
-  "America/Araguaina",
-  "America/Argentina/Buenos_Aires",
-  "America/Godthab",
-  "America/Montevideo",
-  "Atlantic/South_Georgia",
-  "Atlantic/Azores",
-  "Atlantic/Cape_Verde",
-  "Africa/Casablanca",
-  "Europe/London",
-  "Europe/Amsterdam",
-  "Europe/Belgrade",
-  "Europe/Brussels",
-  "Europe/Sarajevo",
-  "Africa/Windhoek",
-  "Africa/Brazzaville",
-  "Asia/Amman",
-  "Europe/Athens",
-  "Asia/Beirut",
-  "Africa/Cairo",
-  "Europe/Helsinki",
-  "Asia/Jerusalem",
-  "Europe/Minsk",
-  "Africa/Harare",
-  "Asia/Baghdad",
-  "Europe/Moscow",
-  "Asia/Kuwait",
-  "Africa/Nairobi",
-  "Asia/Tehran",
-  "Asia/Baku",
-  "Asia/Tbilisi",
-  "Asia/Yerevan",
-  "Asia/Dubai",
-  "Asia/Kabul",
-  "Asia/Karachi",
-  "Asia/Oral",
-  "Asia/Yekaterinburg",
-  "Asia/Calcutta",
-  "Asia/Colombo",
-  "Asia/Katmandu",
-  "Asia/Almaty",
-  "Asia/Rangoon",
-  "Asia/Krasnoyarsk",
-  "Asia/Bangkok",
-  "Asia/Shanghai",
-  "Asia/Hong_Kong",
-  "Asia/Irkutsk",
-  "Asia/Kuala_Lumpur",
-  "Australia/Perth",
-  "Asia/Taipei",
-  "Asia/Seoul",
-  "Asia/Tokyo",
-  "Asia/Yakutsk",
-  "Australia/Adelaide",
-  "Australia/Darwin",
-  "Australia/Brisbane",
-  "Australia/Hobart",
-  "Australia/Sydney",
-  "Asia/Vladivostok",
-  "Pacific/Guam",
-  "Asia/Magadan",
-  "Pacific/Auckland",
-  "Pacific/Fiji",
-  "Pacific/Tongatapu",
-]
-
-
-def ParseRoVpdData(vpd_source=None, verbose=False):
-  vpd_cmd = '-f %s' % vpd_source if vpd_source else ''
-  ro_vpd = gft_report.ParseVPDOutput(
-      gft_common.SystemOutput("vpd -i RO_VPD -l %s" % vpd_cmd,
-                              progress_message="Reading RO VPD",
-                              show_progress=verbose).strip())
-  return ro_vpd
-
-
-def ValidateVpdData(vpd_source=None, verbose=False):
-  mandatory_fields = {
-      KEY_KEYBOARD_LAYOUT: CHROMEOS_KEYBOARD_LAYOUT,
-      KEY_INITIAL_LOCALE: CHROMEOS_INITIAL_LOCALE,
-      KEY_INITIAL_TIMEZONE: CHROMEOS_INITIAL_TIMEZONE,
-      KEY_SERIAL_NUMBER: None,
-  }
-  ro_vpd = ParseRoVpdData(vpd_source, verbose)
-  for field, valid_list in mandatory_fields.items():
-    if field not in ro_vpd:
-      ErrorDie('Missing required VPD value: %s' % field)
-    if valid_list is not None and ro_vpd[field] not in valid_list:
-      ErrorDie('Invalid value in VPD [%s]: %s' % (field, ro_vpd[field]))
-  return True
-
-
-def SetFirmwareBitmapLocale(image_file):
-  ro_vpd = ParseRoVpdData(image_file, False)
-  if KEY_INITIAL_LOCALE not in ro_vpd:
-    ErrorDie('SetFirmwareBitmapLocale: missing initial_locale in VPD data.')
-  locale = ro_vpd[KEY_INITIAL_LOCALE]
-  bitmap_locales = []
-  bmpblk_file = None
-  try:
-    bmpblk_file = gft_common.GetTemporaryFileName()
-    gft_common.System("gbb_utility -g --bmpfv=%s %s" %
-                      (bmpblk_file, image_file))
-    with open(bmpblk_file, "rb") as bmp_handle:
-      bmpblk_data = bmpblk.unpack_bmpblock(bmp_handle.read())
-      bitmap_locales = bmpblk_data.get('locales', bitmap_locales)
-  finally:
-    if bmpblk_file:
-      os.remove(bmpblk_file)
-  locale_lang = locale if locale in bitmap_locales else locale.split('-')[0]
-  if locale_lang not in bitmap_locales:
-    WarningMsg('SetFirmwareBitmapLocale: Warning: locale (%s) '
-               'not in bitmap (%s), resetting index to zero.' %
-               (locale, bitmap_locales))
-    # Reset locale index if the specified locale is not found.
-    gft_common.System('crossystem loc_idx=0')
-    return False
-  else:
-    locale_index = bitmap_locales.index(locale_lang)
-    VerboseMsg('SetFirmwareBitmapLocale: initial locale set to %d (%s).' %
-               (locale_index, bitmap_locales[locale_index]))
-    gft_common.System('crossystem loc_idx=%d' % locale_index)
-    return True
-
-
-# TODO(tammo): In the factory, we should be validating that any
-# keyboard value specified as part of the HWID data matches keyboard
-# data in the VPD.  Determine if this function is useful or necessary
-# for that, and if not, delete.
-def ProbeKeyboard(data):
-  # VPD value "keyboard_layout"="xkb:gb:extd:eng" should be listed.
-  # TODO(tammo): Try using ParseRoVpdData or "vpd -i -g
-  # keyboard_layout -f %s" instead of running grep + cut -- the latter
-  # is slower, undeterministic, and harder to maintain.
-  cmd = ('vpd -i RO_VPD -l -f "%s" | grep keyboard_layout | cut -f4 -d\\"' %
-         data.main_fw.image_path)
-  part_id = RunShellCmd(cmd).stdout.strip()
-  return part_id if part_id else None
-
-
-#############################################################################
-# Console main entry
-@gft_common.GFTConsole
-def main():
-  """ Main entry as a utility. """
-  vpd_source = None
-  verbose = True
-  if len(sys.argv) > 2:
-    ErrorDie('Usage: %s [vpd_source]' % sys.argv[0])
-  elif len(sys.argv) == 2:
-    vpd_source = sys.argv[1]
-    verbose = False
-  ValidateVpdData(vpd_source, verbose)
-  if not vpd_source:
-    vpd_source = crosfw.LoadMainFirmware().path
-  SetFirmwareBitmapLocale(vpd_source)
-  print "VPD verified OK."
-
-if __name__ == "__main__":
-  main()
diff --git a/gft_wpfw.py b/gft_wpfw.py
deleted file mode 100755
index 9620865..0000000
--- a/gft_wpfw.py
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Google Factory Tool: Write Protection for Firmware
-
-This module enables or verifies that firmware write protection is properly
-activated.
-
-WARNING: THE RO SECTIONS OF YOUR EEPROM WILL BECOME READONLY AFTER RUNNING THIS.
-"""
-
-import sys
-
-import crosfw
-import gft_common
-
-from gft_common import DebugMsg, VerboseMsg, ErrorDie
-
-
-def EnableWriteProtect(target, image=None):
-  """ Enables and verifies firmware write protection status.
-  ARGS
-      target: the crosfw target code (crosfw.TARGET_*).
-      image: a reference image for layout detection.
-  """
-
-  if image is None:
-    with open(crosfw.LoadFirmware(target).path, 'rb') as f:
-      image = f.read()
-
-  # The EEPROM in FMAP are mapped as:
-  #   (MAIN) [RO_SECTION | RW_SECTION_*]
-  #   (EC)   [EC_RW | EC_RO]
-  # Each part of RW/RO section occupies half of the EEPROM.
-
-  ro_section_names = {
-      crosfw.TARGET_MAIN: 'RO_SECTION',
-      crosfw.TARGET_EC: 'EC_RO',
-  }
-
-  ro_name = ro_section_names[target]
-  image_map = crosfw.FirmwareImage(image)
-  if not image_map.has_section(ro_name):
-    raise IOError, "Failed to find section %s in target %s." % (ro_name, target)
-  area = image_map.get_section_area(ro_name)
-
-  flashrom = crosfw.Flashrom(target)
-  # Verify layout has valid size.  Most chips support only setting
-  # write protection on half of the total size, so we always divide the flash
-  # chipset space into 2 slots.
-  slot_size = len(image) / 2
-  ro_begin = int(area[0] / slot_size)
-  ro_end = int((area[0] + area[1] - 1) / slot_size)
-  if ro_begin != ro_end:
-    raise ValueError, "Section %s exceeds write protection boundary." % ro_name
-  ro_offset = ro_begin * slot_size
-  ro_size = slot_size
-
-  VerboseMsg(' - Enable Write Protection for ' + target)
-  flashrom.EnableWriteProtection(ro_offset, ro_size)
-  return True
-
-
-#############################################################################
-# Console main entry
-@gft_common.GFTConsole
-def _main():
-  """ Main entry for console mode """
-  if len(sys.argv) != 2:
-    sys.stderr.write('Usage: %s %s\n' %
-                     (sys.argv[0], '|'.join((crosfw.TARGET_MAIN,
-                                             crosfw.TARGET_EC))))
-    sys.exit(1)
-
-  gft_common.SetDebugLevel(True)
-  gft_common.SetVerboseLevel(True)
-  EnableWriteProtect(sys.argv[1])
-
-
-if __name__ == '__main__':
-  _main()
diff --git a/gooftool b/gooftool
deleted file mode 100755
index 4520a43..0000000
--- a/gooftool
+++ /dev/null
@@ -1,612 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-gooftool: Google Factory Tool, providing all Google Required Test
-          functionality.
-"""
-
-
-# TODO(tammo): Refactor to match Chromium style.
-
-
-import copy
-import glob
-import logging
-import optparse
-import os
-import re
-import sys
-import tempfile
-import yaml
-
-########################################################################
-# cros/gft modules
-
-import crosfw
-import gft_common
-import gft_report
-import gft_upload
-import gft_vpd
-import gft_wpfw
-import gpio
-import hwid_tool
-import probe
-
-from common import Obj, SetupLogging
-from gft_common import WarningMsg, VerboseMsg, DebugMsg, ErrorMsg, ErrorDie
-
-
-#######################################################################r
-# global variables and cached objects
-
-g_options = None
-g_args = None
-
-# list of commands
-g_commands = []
-
-# gooftool version
-VERSION = 2
-
-# cached objects
-g_cached_device_data = None
-
-
-########################################################################
-# factory utilities
-
-
-def GetPrimaryDevicePath(partition=None):
-  def isfixed(dev):
-    sysfs_path = '/sys/block/%s/removable' % dev
-    return (os.path.exists(sysfs_path) and
-            open(sysfs_path).read().strip() == '0')
-  alpha_re = re.compile(r'^/dev/([a-zA-Z]+)[0-9]+$')
-  alnum_re = re.compile(r'^/dev/([a-zA-Z]+[0-9]+)p[0-9]+$')
-  dev_set = set(
-      dev
-      for path in gft_common.SystemOutput('cgpt find -t rootfs').split()
-      for dev in alpha_re.findall(path) + alnum_re.findall(path)
-      if isfixed(dev))
-  if len(dev_set) != 1:
-    ErrorDie('zero or multiple primary devs: %s' % dev_set)
-  dev_path = '/dev/' + dev_set.pop()
-  if partition is None:
-    return dev_path
-  fmt_str = '%sp%d' if alnum_re.match(dev_path) else '%s%d'
-  return fmt_str % (dev_path, partition)
-
-
-def GetReleaseRootPartitionPath():
-  return GetPrimaryDevicePath(5)
-
-
-def GetReleaseKernelPartitionPath():
-  return GetPrimaryDevicePath(4)
-
-
-def VerifySwitch(name, value):
-  """ Verifies if hardware switches are in correct states. """
-  my_gpio = gpio.Gpio()
-  my_gpio.setup()
-  try:
-    DebugMsg('reading GPIO %s (expected %s)' % (name, value))
-    if value != my_gpio.read(name):
-      VerboseMsg('VerifySwitch: %s is not in proper state.' % name)
-      return False
-  except:
-    ErrorDie('VerifySwitch: cannot read: ' + name)
-  return True
-
-
-def EnableWriteProtect(target, image):
-  """ Enables and verifies firmware write protection. """
-  return gft_wpfw.EnableWriteProtect(target, image)
-
-
-def VerboseSystemCommand(command, prompt=None):
-  """ Invokes command and put stdout/stderr messages into verbose log. """
-  VerboseMsg(" # Executing command: %s" % command)
-  (_, stdout, stderr) = gft_common.ShellExecution(
-      command, show_progress=g_options.verbose, progress_message=prompt)
-  message = '\n'.join((stdout.strip(), stderr.strip())).strip()
-  if message:
-    VerboseMsg(message)
-
-
-def GFTCommand(f):
-  """ Decorator for gooftool base commands. """
-  def wrapper(*args, **kw):
-    try:
-      DebugMsg('@Starting to execute command: %s.' % f.__name__)
-      result = f(*args, **kw)
-      DebugMsg('@Executed command: %s. Result: %s' %
-                 (f.__name__, "SUCCESS"
-                  if result is not False else "NOT SUCCESS"))
-      return result
-    except gft_common.GFTError, e:
-      DebugMsg('@Executed command: %s. Result: ERROR - %s' %
-               (f.__name__, e.value))
-      raise
-    except:
-      DebugMsg('@Executed command: %s. Result: FAILED.' % f.__name__)
-      raise
-  wrapper.__name__ = f.__name__
-  wrapper.__doc__ = re.sub(r'\s+', ' ', f.__doc__).strip()
-  g_commands.append(wrapper)
-  return wrapper
-
-
-def GFTCommandDependency(command_list):
-  """Decorator to define the depenedncy of a gooftool command.
-
-  Args
-    command_list: a list or tuple of command functions to be executed in order.
-
-  Raises
-    GFTError if any of the commands in dependency return False.
-  """
-  def meta_wrapper(f):
-
-    def wrapper(*args, **kargs):
-      for command in command_list:
-        if not command():
-          ErrorDie('%s: failed in sub-command: %s.' %
-                   (f.__name__, command.__name__))
-      return f(*args, **kargs)
-
-    wrapper.__name__ = f.__name__
-    wrapper.__doc__ = ('Runs: %s. %s' %
-                       (', '.join(['--%s' % command.__name__
-                                   for command in command_list]),
-                        f.__doc__))
-    return wrapper
-  return meta_wrapper
-
-
-########################################################################
-# standard procedure
-# (function names are used for self-reflection to command line parameters)
-
-# HWID, GBB, and hardware components validation
-
-
-@GFTCommand
-def write_hwid():
-  """Write specified HWID value into the system GBB."""
-  if not g_options.hwid:
-    ErrorDie('write_hwid: No HWID specified (must specify using --hwid arg).')
-  hwid = g_options.hwid
-  DebugMsg('write_hwid: using hwid string %r' % hwid)
-  main_fw_file = crosfw.LoadMainFirmware().GetFileName()
-  cmd = ('gbb_utility --set --hwid="%s" "%s"' % (hwid, main_fw_file))
-  gft_common.System(cmd)
-  flashrom = crosfw.Flashrom(crosfw.TARGET_MAIN)
-  flashrom.Write(filename=main_fw_file, sections=['GBB'])
-  return True
-
-
-@GFTCommand
-def run_probe():
-  """Print yaml-formatted breakdown of probed device properties."""
-  SetupLogging(logging.DEBUG, g_options.probe_log)
-  probe_results = probe.Probe()
-  print yaml.dump(probe_results.__dict__, default_flow_style=False)
-  return True
-
-
-@GFTCommand
-def verify_hwid():
-  """Verify system HWID properties match probed device properties.
-
-  First probe components, volatile and initial_config parameters for
-  the DUT.  Then use the available device data to produce a list of
-  candidate HWIDs.  Then verify the HWID from the DUT is present in
-  that list.  Finally, verify that the DUT initial config values match
-  those specified for its HWID.
-  """
-  main_fw_file = crosfw.LoadMainFirmware().GetFileName()
-  gbb_result = gft_common.SystemOutput(
-      'gbb_utility -g --hwid %s' % main_fw_file)
-  hwid = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
-  DebugMsg('system HWID: %r\n' % hwid)
-  try:
-    data = hwid_tool.ReadDatastore(g_options.db_path)
-    hwid_properties = hwid_tool.LookupHwidProperties(data, hwid)
-    board = hwid_properties.board
-    DebugMsg('expected system properties:\n%s' %
-             yaml.dump(hwid_properties.__dict__, default_flow_style=False))
-    probe_results = probe.Probe()
-    cooked_results = hwid_tool.CookProbeResults(data, probe_results, board)
-    DebugMsg('found system properties:\n%s' %
-             yaml.dump(cooked_results.__dict__, default_flow_style=False))
-    global g_cached_device_data
-    g_cached_device_data = Obj(
-        hwid_properties=hwid_properties,
-        cooked_results=cooked_results)
-  except hwid_tool.Error, e:
-    ErrorDie('verify_hwid: FAILED.\n%s' % e)
-  match_errors = []
-  for comp_class, expected_name in hwid_properties.component_map.items():
-    if expected_name == 'ANY':
-      continue
-    if expected_name == cooked_results.matched_components.get(comp_class, None):
-      continue
-    if comp_class in probe_results.missing_components:
-      match_errors.append('  %s component mismatch, expected %s, found nothing'
-                          % (comp_class, expected_name))
-    else:
-      probe_value = probe_results.found_components.get(comp_class, None)
-      match_errors.append('  %s component mismatch, expected %s, found  %r' %
-                          (comp_class, expected_name, probe_value))
-  if match_errors:
-    ErrorDie('verify_hwid: FAILED.\n%s' % '\n'.join(match_errors))
-  if hwid_properties.volatile not in cooked_results.matched_volatile_tags:
-    msg = ('  HWID specified volatile %s, but found match only for %s' %
-           (hwid_properties.volatile,
-            ', '.join(cooked_results.matched_volatile_tags)))
-    ErrorDie('verify_hwid: FAILED.\n%s' % msg)
-  if (hwid_properties.initial_config is not None and
-      hwid_properties.initial_config not in
-      cooked_results.matched_initial_config_tags):
-    msg = ('  HWID specified initial_config %s, but found match only for %s' %
-           (hwid_properties.initial_config,
-            ', '.join(cooked_results.matched_initial_config_tags)))
-    ErrorDie('verify_hwid: FAILED.\n%s' % msg)
-  # TODO(tammo): Verify HWID status is supported (or deprecated for RMA).
-  # TODO(tammo): Verify VPD here, using hwid_properties.vpd_ro_field_list.
-  print 'Verified: %s' % hwid
-  return True
-
-
-@GFTCommand
-def verify_keys():
-  """ Verifies if the keys in firmware and SSD are matched. """
-  script = os.path.join(os.path.split(sys.argv[0])[0], 'gft_verify_keys.sh')
-  if not os.path.exists(script):
-    ErrorDie('verify_keys: cannot find script to verify.')
-  kernel_device = GetReleaseKernelPartitionPath()
-  main_fw_path = crosfw.LoadMainFirmware().GetFileName()
-  command = '%s %s %s' % (script, kernel_device, main_fw_path)
-  try:
-    VerboseSystemCommand(command, prompt='verify_keys: ')
-  except gft_common.GFTError, e:
-    ErrorDie('verify_keys: FAILED.\n%s' % e.value)
-  return True
-
-
-@GFTCommand
-def verify_vpd():
-  """ Verifies if the VPD contains valid required data. """
-  try:
-    # TODO(tammo): Verify that all of the VPD fields specified for the
-    # board (using hwid properties) have values.
-    image_file = crosfw.LoadMainFirmware().GetFileName()
-    gft_vpd.ValidateVpdData(image_file, g_options.verbose)
-    gft_vpd.SetFirmwareBitmapLocale(image_file)
-  except gft_common.GFTError, e:
-    ErrorDie('verify_vpd: FAILED.\n%s' % e.value)
-  return True
-
-
-@GFTCommand
-def verify_system_time():
-  """Verifies if system time is later than release filesystem creation time."""
-  script = os.path.join(os.path.split(sys.argv[0])[0],
-                        'gft_verify_system_time.sh')
-  if not os.path.exists(script):
-    ErrorDie('verify_system_time: cannot find script to verify.')
-  rootfs_device = GetReleaseRootPartitionPath()
-  command = '%s %s' % (script, rootfs_device)
-  try:
-    VerboseSystemCommand(command, prompt='verify_system_time: ')
-  except gft_common.GFTError, e:
-    ErrorDie('verify_system_time: FAILED.\n%s' % e.value)
-  return True
-
-
-@GFTCommand
-def verify_rootfs():
-  """ Verifies if the rootfs on SSD is valid (by checking hash). """
-  script = os.path.join(os.path.split(sys.argv[0])[0], 'gft_verify_rootfs.sh')
-  if not os.path.exists(script):
-    ErrorDie('verify_rootfs: cannot find script to verify.')
-  rootfs_device = GetReleaseRootPartitionPath()
-  command = '%s %s' % (script, rootfs_device)
-  try:
-    VerboseSystemCommand(command, prompt='verify_rootfs: ')
-  except gft_common.GFTError, e:
-    ErrorDie('verify_rootfs: FAILED.\n%s' % e.value)
-  return True
-
-
-# Hardware Switches
-
-@GFTCommand
-def verify_switch_wp():
-  """ Verifies if hardware write protection switch is enabled. """
-  if VerifySwitch('write_protect', 1):
-    return True
-  ErrorDie('verify_switch_wp: failed')
-
-
-@GFTCommand
-def verify_switch_dev():
-  """ Verifies if developer switch is disabled. """
-  if VerifySwitch('developer_switch', 0):
-    return True
-  ErrorDie('verify_switch_dev: failed')
-
-
-# Report Creation
-
-@GFTCommand
-def create_report():
-  """ Creates the report (with vpd, hwid, date, ...) for uploading. """
-  # decide log format
-  if g_options.report_format == 'gz':
-    text_armed = False
-  elif g_options.report_format == 'base64':
-    text_armed = True
-  else:
-    ErrorDie('create_report: invalid format: %s' % g_options.report_format)
-
-  tag = g_options.report_tag if g_options.report_tag else ''
-
-  if g_cached_device_data is None:
-    # TODO(tammo): Refactor verify_hwid to extract the probing and
-    # cooking from the actual validation, so that we can generate
-    # reports for machines where the hwid validation fails.
-    ErrorDie('create_report: must run verify_hwid first')
-
-  vpd_source = crosfw.LoadMainFirmware().GetFileName()
-  report = gft_report.CreateReport(sys.argv,
-                                   system_details=g_cached_device_data,
-                                   verbose_log_path=g_options.log_path,
-                                   vpd_source=vpd_source,
-                                   tag=tag,
-                                   verbose=g_options.debug)
-
-  data = gft_report.EncodeReport(report, text_armed=text_armed)
-  if not g_options.report_path:
-    g_options.report_path = os.path.join(tempfile.gettempdir(),
-                                         gft_report.GetReportName(data))
-
-  gft_common.WriteFile(g_options.report_path, data)
-  report_saved_message = 'Report saved in: %s' % g_options.report_path
-  # To help scripting, the message must be printed to console and logged.
-  print report_saved_message
-  gft_common.Log(report_saved_message)
-  return True
-
-
-@GFTCommand
-def upload_report():
-  """ Uploads a report (by --create_report) for tracking factory process. """
-  report_path = g_options.report_path
-  if not (report_path and os.path.exists(report_path)):
-    ErrorDie('upload_report: need an existing report file '
-             '(--report_path or --create_report)')
-  if not g_options.upload_method:
-    ErrorDie('upload_report: need proper --upload_method.')
-
-  # Always report in standard naming scheme.
-  report_blob = gft_common.ReadBinaryFile(report_path)
-  report_name = gft_report.GetReportName(report_blob)
-  local_file = os.path.join(tempfile.gettempdir(), report_name)
-  if local_file != report_path:
-    gft_common.WriteBinaryFile(local_file, report_blob)
-  if not gft_upload.Upload(local_file, g_options.upload_method):
-    ErrorDie('upload_report: failed to upload.')
-  return True
-
-
-@GFTCommand
-def wpfw():
-  """ Enables and verifies firmware write protection status. """
-  if g_options.debug_dryrun_wpfw:
-    ErrorMsg('wpfw is by-passed. This device CANNOT be qualified.')
-    return True
-  read_binary = gft_common.ReadBinaryFile
-  ec_fw = crosfw.LoadEcFirmware()
-  main_fw = crosfw.LoadMainFirmware()
-  target_set = [('bios', main_fw.GetFileName())]
-  if ec_fw.GetChipId() is not None:
-    target_set.insert(0, ('ec', ec_fw.path))
-    assert target_set[0][0] == 'ec'
-  else:
-    VerboseMsg('wpfw: current platform does not have EC. Ignored.')
-  assert len(target_set) > 0
-  for target_name, loader_api in target_set:
-    if not EnableWriteProtect(target_name, read_binary(loader_api())):
-      ErrorDie('wpfw: failed to enable firmware write protection.')
-  return True
-
-
-@GFTCommand
-def clear_gbb_flags():
-  """ Clears GBB Header Flags for shipping devices. """
-  script = os.path.join(os.path.split(sys.argv[0])[0],
-                        'gft_clear_gbb_flags.sh')
-  command = '%s' % script
-  try:
-    VerboseSystemCommand(command, prompt='clear_gbb_flags: ')
-  except gft_common.GFTError, e:
-    ErrorDie('clear_gbb_flags: FAILED.\n%s' % e.value)
-  return True
-
-
-@GFTCommand
-def prepare_wipe():
-  """ Prepares the system for transitioning to release state in next reboot. """
-  if g_options.debug_dryrun_prepare_wipe:
-    ErrorMsg('prepare_wipe is by-passed. This device CANNOT be qualified.')
-    return True
-  wipe_script = os.path.join(os.path.split(sys.argv[0])[0],
-                             'gft_prepare_wipe.sh')
-  if not os.path.exists(wipe_script):
-    ErrorDie('prepare_wipe: cannot find script to prepare for wiping.')
-  wipe_method_map = {
-      'fast': 'fast',
-      'secure': '',
-  }
-  method = g_options.wipe_method
-  if method not in wipe_method_map:
-    ErrorDie('prepare_wipe: unknown wipe method: %s' % method)
-  tag = wipe_method_map[method]
-  rootfs_device = GetReleaseRootPartitionPath()
-  command = 'FACTORY_WIPE_TAGS=%s %s %s' % (tag, wipe_script, rootfs_device)
-  try:
-    VerboseSystemCommand(command, prompt='prepare_wipe: ')
-  except gft_common.GFTError, e:
-    ErrorDie('prepare_wipe: FAILED.\n%s' % e.value)
-  return True
-
-
-@GFTCommand
-@GFTCommandDependency((verify_switch_dev,
-                       verify_switch_wp,
-                       verify_hwid,
-                       verify_vpd,
-                       verify_system_time,
-                       verify_keys,
-                       verify_rootfs))
-def verify():
-  """ Verifies if whole factory process is ready for finalization. """
-  # See the dependency list for the real commands to be executed.
-  return True
-
-
-@GFTCommand
-@GFTCommandDependency((clear_gbb_flags,
-                       verify,
-                       wpfw,
-                       create_report,
-                       upload_report,
-                       prepare_wipe))
-def finalize():
-  """ Finalizes all factory tests and transit system into release state. """
-  # See the dependency list for the real commands to be executed.
-  return True
-
-
-@GFTCommand
-@GFTCommandDependency((clear_gbb_flags,
-                       verify_hwid,
-                       verify_vpd,
-                       verify_system_time,
-                       verify_keys,
-                       verify_rootfs,
-                       create_report,
-                       upload_report,
-                       prepare_wipe))
-def developer_finalize():
-  """ Finalizes tests and leave the system in developer-friendly mode.
-
-  This is similar to 'finalize' command but not enforcing commands that would
-  prevent developers to restart factory process, for example write protection
-  (wpfw) and non-developer mode (verify_switch_dev).
-  """
-  # See the dependency list for the real commands to be executed.
-  return True
-
-
-########################################################################
-# console command line options
-
-def ConsoleParser():
-  """ command line option parser """
-  parser = optparse.OptionParser()
-
-  # Message control
-  parser.add_option('-d', '--debug', action='store_true',
-                    help='provide debug messages')
-  parser.add_option('-v', '--verbose', action='store_true', default=False,
-                    help='provide verbose messages')
-  parser.add_option('--log_path', metavar='PATH',
-                    default=gft_common.DEFAULT_CONSOLE_LOG_PATH,
-                    help='use the given path for verbose logs.')
-  # TODO(tammo): Remove this when gooftool converts to use logging module.
-  parser.add_option('--probe_log', metavar='PATH',
-                    default='/var/log/factory_probe.log',
-                    help='probe process details')
-  # Debugging
-  parser.add_option('--debug_dryrun_wpfw', action='store_true',
-                    help='make --wpfw in dry-run mode (debugging only)')
-  parser.add_option('--debug_dryrun_prepare_wipe', action='store_true',
-                    help='make --prepare_wipe in dry-run mode (debugging only)')
-  parser.add_option('--ignore_factory_initial', action='store_true',
-                    help='ignore components in config_factory_initial.')
-  # Configuration
-  parser.add_option('--config', metavar='PATH',
-                    help='path to the config file (TBD)')
-  # TODO(tammo): Consider removing db_path option once the hwid_tool
-  # has meaningful default path searching.
-  parser.add_option('--db_path', metavar='PATH',
-                    default=hwid_tool.DEFAULT_HWID_DATA_PATH,
-                    help='path to the HWID component database')
-  # TODO(tammo): Add proper support for per-command required positional args.
-  parser.add_option('--hwid', metavar='HWID', help='HWID string')
-  # Reports
-  parser.add_option('--report_path', metavar='PATH',
-                    help='override the path for report file')
-  parser.add_option('--report_format', metavar='FORMAT', default='gz',
-                    help='format of the generated report (see gft_report.py)')
-  parser.add_option('--report_tag', metavar='TAG', default='',
-                    help='tag to be included in report (see gft_report.py), '
-                         'current possible values may include rma, mp, pvt.')
-  parser.add_option('--upload_method', metavar='METHOD:PARAM',
-                    help='assign the upload method (see gft_upload).')
-  # Wiping
-  parser.add_option('--wipe_method', metavar='METHOD', default='secure',
-                    help='assign the wipe method (secure/fast).')
-
-  for command in g_commands:
-    parser.add_option('--%s' % command.__name__,
-                      action='store_true',
-                      help=command.__doc__)
-  return parser
-
-
-########################################################################
-# main entry
-
-
-@gft_common.GFTConsole
-def _main():
-  """ main entry """
-  global g_options, g_args
-  parser = ConsoleParser()
-  (g_options, g_args) = parser.parse_args()
-  if g_args:
-    parser.error('Un-expected parameter(s): %s\n' % ' '.join(g_args))
-
-  if g_options.debug:
-    g_options.verbose = True
-  gft_common.SetDebugLevel(g_options.debug)
-  gft_common.SetVerboseLevel(g_options.verbose, g_options.log_path)
-  DebugMsg('options: ' + repr(g_options) + '\nargs: ' + repr(g_args), log=False)
-
-  # execute commands by order.
-  executed_commands = 0
-  return_value = 0
-  for command in g_commands:
-    command_name = command.__name__
-    if not getattr(g_options, command_name):
-      continue
-    DebugMsg('COMMAND: ' + command_name, log=False)
-    if not command():
-      return_value = 1
-    executed_commands = executed_commands + 1
-
-  if executed_commands == 0:
-    parser.print_help()
-  return return_value
-
-
-if __name__ == '__main__':
-  sys.exit(_main())
diff --git a/gooftool b/gooftool
new file mode 120000
index 0000000..efdb529
--- /dev/null
+++ b/gooftool
@@ -0,0 +1 @@
+gooftool.py
\ No newline at end of file
diff --git a/gooftool.py b/gooftool.py
new file mode 100755
index 0000000..b7bb0be
--- /dev/null
+++ b/gooftool.py
@@ -0,0 +1,383 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Google Factory Tool.
+
+This tool is indended to be used on factory assembly lines.  It
+provides all of the Google required test functionality and must be run
+on each device as part of the assembly process.
+"""
+
+
+import logging
+import os
+import re
+import sys
+
+import bmpblk
+import crosfw
+import hwid_tool
+import probe
+import report
+import report_upload
+import vpd_data
+
+from common import Error, ParseKeyValueData, SetupLogging, Shell, YamlWrite
+from hacked_argparse import CmdArg, Command, ParseCmdline, verbosity_cmd_arg
+from tempfile import NamedTemporaryFile
+
+
+def GetPrimaryDevicePath(partition=None):
+  def IsFixed(dev):
+    sysfs_path = '/sys/block/%s/removable' % dev
+    return (os.path.exists(sysfs_path) and
+            open(sysfs_path).read().strip() == '0')
+  alpha_re = re.compile(r'^/dev/([a-zA-Z]+)[0-9]+$')
+  alnum_re = re.compile(r'^/dev/([a-zA-Z]+[0-9]+)p[0-9]+$')
+  dev_set = set(
+      dev
+      for path in Shell('cgpt find -t rootfs').stdout.strip().split()
+      for dev in alpha_re.findall(path) + alnum_re.findall(path)
+      if IsFixed(dev))
+  if len(dev_set) != 1:
+    raise Error('zero or multiple primary devs: %s' % dev_set)
+  dev_path = os.path.join('/dev', dev_set.pop())
+  if partition is None:
+    return dev_path
+  fmt_str = '%sp%d' if alnum_re.match(dev_path) else '%s%d'
+  return fmt_str % (dev_path, partition)
+
+
+def GetReleaseRootPartitionPath():
+  return GetPrimaryDevicePath(5)
+
+
+def GetReleaseKernelPartitionPath():
+  return GetPrimaryDevicePath(4)
+
+
+def FindScript(script_name):
+  script_path = os.path.join(sys.path[0], script_name)
+  if not os.path.exists(script_path):
+    raise Error('Needed script %s does not exist.' % script_path)
+  return script_path
+
+
+def ReadRoVpd(fw_image_file):
+  raw_vpd_data = Shell('vpd -i RO_VPD -l -f %s' % fw_image_file).stdout
+  return ParseKeyValueData('"(.*)"="(.*)"$', raw_vpd_data)
+
+
+@Command('write_hwid',
+         CmdArg('hwid', metavar='HWID', help='HWID string'))
+def WriteHwid(options):
+  """Write specified HWID value into the system BB."""
+  logging.debug('writing hwid string %r', options.hwid)
+  main_fw = crosfw.LoadMainFirmware()
+  Shell('gbb_utility --set --hwid="%s" "%s"' %
+        (options.hwid, main_fw.GetFileName()))
+  main_fw.Write(sections=['GBB'])
+
+
+@Command('probe',
+         CmdArg('--comps', nargs='*',
+                help='List of keys from the component_db registry.'),
+         CmdArg('--no_vol', action='store_true',
+                help='Do not probe volatile data.'),
+         CmdArg('--no_ic', action='store_true',
+                help='Do not probe initial_config data.'))
+def RunProbe(options):
+  """Print yaml-formatted breakdown of probed device properties."""
+  probe_results = probe.Probe(target_comp_classes=options.comps,
+                              probe_volatile=not options.no_vol,
+                              probe_initial_config=not options.no_ic)
+  print YamlWrite(probe_results.__dict__)
+
+
+_hwdb_path_cmd_arg = CmdArg(
+    '--hwdb_path', metavar='PATH',
+    default=hwid_tool.DEFAULT_HWID_DATA_PATH,
+    help='Path to the HWID database.')
+
+
+@Command('verify_hwid',
+         _hwdb_path_cmd_arg)
+def VerifyHwid(options):
+  """Verify system HWID properties match probed device properties.
+
+  First probe components, volatile and initial_config parameters for
+  the DUT.  Then use the available device data to produce a list of
+  candidate HWIDs.  Then verify the HWID from the DUT is present in
+  that list.  Then verify that the DUT initial config values match
+  those specified for its HWID.  Finally, verify that VPD contains all
+  the necessary fields as specified by the board data, and when
+  possible verify that values are legitimate.
+  """
+  hwdb = hwid_tool.ReadDatastore(options.hwdb_path)
+  main_fw_file = crosfw.LoadMainFirmware().GetFileName()
+  gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
+  hwid = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
+  hwid_properties = hwid_tool.LookupHwidProperties(hwdb, hwid)
+  logging.info('Verifying system HWID: %r', hwid_properties.hwid)
+  logging.debug('expected system properties:\n%s',
+                YamlWrite(hwid_properties.__dict__))
+  probe_results = probe.Probe()
+  cooked_results = hwid_tool.CookProbeResults(
+      hwdb, probe_results, hwid_properties.board)
+  logging.debug('found system properties:\n%s',
+                YamlWrite(cooked_results.__dict__))
+  # TODO(tammo): Output a new-style log event with device details here.
+  match_errors = []
+  for comp_class, expected_name in hwid_properties.component_map.items():
+    if expected_name == 'ANY':
+      continue
+    if expected_name == cooked_results.matched_components.get(comp_class, None):
+      continue
+    if comp_class in probe_results.missing_components:
+      match_errors.append('  %s component mismatch, expected %s, found nothing'
+                          % (comp_class, expected_name))
+    else:
+      probe_value = probe_results.found_components.get(comp_class, None)
+      match_errors.append('  %s component mismatch, expected %s, found  %r' %
+                          (comp_class, expected_name, probe_value))
+  if match_errors:
+    raise Error('HWID verification FAILED.\n%s' % '\n'.join(match_errors))
+  if hwid_properties.volatile not in cooked_results.matched_volatile_tags:
+    msg = ('  HWID specified volatile %s, but found match only for %s' %
+           (hwid_properties.volatile,
+            ', '.join(cooked_results.matched_volatile_tags)))
+    raise Error('HWID verification FAILED.\n%s' % msg)
+  if (hwid_properties.initial_config is not None and
+      hwid_properties.initial_config not in
+      cooked_results.matched_initial_config_tags):
+    msg = ('  HWID specified initial_config %s, but only found match for [%s]' %
+           (hwid_properties.initial_config,
+            ', '.join(cooked_results.matched_initial_config_tags)))
+    raise Error('HWID verification FAILED.\n%s' % msg)
+  # TODO(tammo): Verify HWID status is supported (or deprecated for RMA).
+  ro_vpd = ReadRoVpd(main_fw_file)
+  for field in hwid_properties.vpd_ro_field_list:
+    if field not in ro_vpd:
+      raise Error('Missing required VPD field: %s' % field)
+    known_valid_values = vpd_data.KNOWN_VPD_FIELD_DATA.get(field, None)
+    value = ro_vpd[field]
+    if known_valid_values is not None and value not in known_valid_values:
+      raise Error('Invalid VPD entry : field %r, value %r' % (field, value))
+
+
+@Command('verify_keys')
+def VerifyKeys(options):
+  """Verify keys in firmware and SSD match."""
+  script = FindScript('gft_verify_keys.sh')
+  kernel_device = GetReleaseKernelPartitionPath()
+  main_fw_file = crosfw.LoadMainFirmware().GetFileName()
+  result = Shell('%s %s %s' % (script, kernel_device, main_fw_file))
+  if not result.success:
+    raise Error, '%r failed, stderr: %r' % (script, result.stderr)
+
+
+@Command('set_fw_bitmap_locale')
+def SetFirmwareBitmapLocale(options):
+  """Use VPD locale value to set firmware bitmap default language."""
+  image_file = crosfw.LoadMainFirmware().GetFileName()
+  locale = ReadRoVpd(image_file).get('initial_locale', None)
+  if locale is None:
+    raise Error, 'Missing initial_locale VPD.'
+  bitmap_locales = []
+  with NamedTemporaryFile() as f:
+    Shell('gbb_utility -g --bmpfv=%s %s' % (f.name, image_file))
+    bmpblk_data = bmpblk.unpack_bmpblock(f.read())
+    bitmap_locales = bmpblk_data.get('locales', bitmap_locales)
+  # Some locale values are just a language code and others are a
+  # hyphen-separated language code and country code pair.  We care
+  # only about the language code part.
+  language_code = locale.partition('-')[0]
+  if language_code not in bitmap_locales:
+    raise Error, ('Firmware bitmaps do not contain support for the specified '
+                  'initial locale language %r' % language_code)
+  else:
+    locale_index = bitmap_locales.index(language_code)
+    logging.info('Firmware bitmap initial locale set to %d (%s).',
+                 locale_index, bitmap_locales[locale_index])
+    Shell('crossystem loc_idx=%d' % locale_index)
+
+
+@Command('verify_system_time')
+def VerifySystemTime(options):
+  """Verify system time is later than release filesystem creation time."""
+  script = FindScript('gft_verify_system_time.sh')
+  rootfs_device = GetReleaseRootPartitionPath()
+  result = Shell('%s %s' % (script, rootfs_device))
+  if not result.success:
+    raise Error, '%r failed, stderr: %r' % (script, result.stderr)
+
+
+@Command('verify_rootfs')
+def VerifyRootFs(options):
+  """Verify rootfs on SSD is valid by checking hash."""
+  script = FindScript('gft_verify_rootfs.sh')
+  rootfs_device = GetReleaseRootPartitionPath()
+  result = Shell('%s %s' % (script, rootfs_device))
+  if not result.success:
+    raise Error, '%r failed, stderr: %r' % (script, result.stderr)
+
+
+@Command('verify_switch_wp')
+def VerifyWpSwitch(options):
+  """Verify hardware write protection switch is enabled."""
+  if Shell('crossystem wpsw_cur').stdout.strip() != '1':
+    raise Error, 'write protection is disabled'
+
+
+@Command('verify_switch_dev')
+def VerifyDevSwitch(options):
+  """Verify developer switch is disabled."""
+  if Shell('crossystem devsw_cur').stdout.strip() != '0':
+    raise Error, 'developer mode is enabled'
+
+
+@Command('write_protect')
+def EnableFwWp(options):
+  """Enable then verify firmware write protection."""
+
+  def WriteProtect(fw_file_path, fw_type, section):
+    """Calculate protection size, then invoke flashrom.
+
+    Our supported chips only allow write protecting half their total
+    size, so we parition the flash chipset space accordingly.
+    """
+    raw_image = open(fw_file_path, 'rb').read()
+    image = crosfw.FirmwareImage(raw_image)
+    if not image.has_section(section):
+      raise Error('could not find %s firmware section %s' % (fw_type, section))
+    section_data = image.get_section_area(section)
+    protectable_size = len(raw_image) / 2
+    ro_a = int(section_data[0] / protectable_size)
+    ro_b = int((section_data[0] + section_data[1] - 1) / protectable_size)
+    if ro_a != ro_b:
+      raise Error("%s firmware section %s has illegal size" %
+                  (fw_type, section))
+    ro_offset = ro_a * protectable_size
+    logging.debug('write protecting %s', fw_type)
+    crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, protectable_size)
+
+  WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
+  ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
+  if ec_fw_file is not None:
+    WriteProtect(ec_fw_file, 'ec', 'EC_RO')
+  else:
+    logging.warning('EC not write protected (seems there is no EC flash).')
+
+
+@Command('clear_gbb_flags')
+def ClearGbbFlags(options):
+  """Zero out the GBB flags, in preparation for transition to release state.
+
+  No GBB flags are set in release/shipping state, but they are useful
+  for factory/development.  See "gbb_utility --flags" for details.
+  """
+  script = FindScript('gft_clear_gbb_flags.sh')
+  result = Shell(script)
+  if not result.success:
+    raise Error, '%r failed, stderr: %r' % (script, result.stderr)
+
+
+@Command('prepare_wipe',
+         CmdArg('--fast', action='store_true',
+                help='use non-secure but faster wipe method.'))
+def PrepareWipe(options):
+  """Prepare system for transition to release state in next reboot."""
+  script = FindScript('gft_prepare_wipe.sh')
+  tag = 'fast' if options.fast else ''
+  rootfs_device = GetReleaseRootPartitionPath()
+  result = Shell('FACTORY_WIPE_TAGS=%s %s %s' % (tag, script, rootfs_device))
+  if not result.success:
+    raise Error, '%r failed, stderr: %r' % (script, result.stderr)
+
+
+@Command('verify',
+         CmdArg('--dev', action='store_true',
+                help='Do not verify switch state (dev mode and fw wp).'),
+         _hwdb_path_cmd_arg)
+def Verify(options):
+  """Verifies if whole factory process is ready for finalization.
+
+  This routine performs all the necessary checks to make sure the
+  device is ready to be finalized, but does not modify state.  These
+  checks include dev switch, firmware write protection switch, hwid,
+  system time, keys, and root file system.
+  """
+  if not options.dev:
+    VerifyDevSwitch({})
+    VerifyWpSwitch({})
+  VerifyHwid(options)
+  VerifySystemTime({})
+  VerifyKeys({})
+  VerifyRootFs({})
+
+
+_upload_method_cmd_arg = CmdArg(
+    '--upload_method', metavar='METHOD:PARAM',
+    help=('How to perform the upload.  METHOD should be one of '
+          '{ftp, shopfloor, curl, cpfe, custom}.'))
+
+
+@Command('upload_report',
+         _upload_method_cmd_arg)
+def UploadReport(options):
+  """Create and a report containing key device details."""
+  report_upload.Upload(report.Create(options.log), options.upload_method)
+
+
+@Command('finalize',
+         CmdArg('--dev', action='store_true',
+                help='Do not verify or alter write protection or dev mode.'),
+         CmdArg('--fast', action='store_true',
+                help='use non-secure but faster wipe method.'),
+         _hwdb_path_cmd_arg,
+         _upload_method_cmd_arg)
+def Finalize(options):
+  """Verify system readiness and trigger transition into release state.
+
+  This routine first verifies system state (see verify command), then
+  clears all of the testing flags from the GBB, then modifies firmware
+  bitmaps to match locale.  Then it enables firmware write protection
+  and sets the necessary boot flags to cause wipe of the factory image
+  on the next boot.
+  """
+  ClearGbbFlags({})
+  Verify(options)
+  SetFirmwareBitmapLocale({})
+  if not options.dev:
+    EnableFwWp({})
+  UploadReport(options)
+  PrepareWipe(options)
+
+
+def Main():
+  """Run sub-command specified by the command line args."""
+  options = ParseCmdline(
+      'Perform Google required factory tests.',
+      CmdArg('-l', '--log', metavar='PATH',
+             help='Write logs to this file.'),
+      verbosity_cmd_arg
+      )
+  SetupLogging(options.verbosity, options.log)
+  logging.debug('gooftool options: %s', repr(options))
+  try:
+    logging.debug('GOOFTOOL command %r', options.command_name)
+    options.command(options)
+    logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
+  except Error, e:
+    logging.exception(e)
+    sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
+  except Exception, e:
+    logging.exception(e)
+    sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
+
+
+if __name__ == '__main__':
+  Main()
diff --git a/gpio.py b/gpio.py
deleted file mode 100644
index 7321b8a..0000000
--- a/gpio.py
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# THIS FILE IS COPIED FROM AUTOTEST LIBRARY AND FOLLOWING PEP8 CODING STYLE RULE
-# FOR BACKWARD COMPATIBLE, WE'RE NOT CHANGING ITS INDENTATION AND FUNCTION NAMES
-
-'''Chrome OS device GPIO library
-
-This module provides a convenient way to detect, setup, and access to GPIO
-values on a Chrome OS compatible device.
-
-See help(Gpio) for more information.
-
-'''
-
-import os
-import shutil
-import sys
-import tempfile
-
-
-class Gpio(object):
-    '''
-    Utility to access GPIO values.
-
-    Usage:
-        gpio = Gpio()
-        try:
-            gpio.setup()
-            print gpio.read(gpio.DEVELOPER_SWITCH_CURRENT)
-        except:
-            print "gpio failed"
-    '''
-
-    # GPIO property names (by "crossystem"):
-    DEVELOPER_SWITCH_CURRENT = 'devsw_cur'
-    RECOVERY_BUTTON_CURRENT = 'recoverysw_cur'
-    WRITE_PROTECT_CURRENT = 'wpsw_cur'
-
-    DEVELOPER_SWITCH_BOOT = 'devsw_boot'
-    RECOVERY_BUTTON_BOOT = 'recoverysw_boot'
-    WRITE_PROTECT_BOOT = 'wpsw_boot'
-
-    def __init__(self, exception_type=IOError):
-        self._exception_type = exception_type
-
-        # list of property conversions, usually str2int.
-        self._override_map = {
-                self.DEVELOPER_SWITCH_CURRENT: int,
-                self.DEVELOPER_SWITCH_BOOT: int,
-                self.RECOVERY_BUTTON_CURRENT: int,
-                self.RECOVERY_BUTTON_BOOT: int,
-                self.WRITE_PROTECT_CURRENT: int,
-                self.WRITE_PROTECT_BOOT: int,
-        }
-
-        # list of legacy (chromeos_acpi) property names.
-        self._legacy_map = {
-                'developer_switch': self.DEVELOPER_SWITCH_CURRENT,
-                'recovery_button': self.RECOVERY_BUTTON_CURRENT,
-                'write_protect': self.WRITE_PROTECT_CURRENT,
-        }
-
-    def setup(self):
-        '''Configures system for processing GPIO.
-
-        Returns:
-            Raises an exception if gpio_setup execution failed.
-        '''
-        # This is the place to do any configuration / system detection.
-        # Currently "crossystem" handles everything so we don't need to do
-        # anything now.
-        pass
-
-    def read(self, name):
-        '''Reads a GPIO property value.
-           Check "crossystem" command for the list of available property names.
-
-        Parameters:
-            name: the name of property to read.
-
-        Returns: current value, or raise exceptions.
-        '''
-        debug_title = "Gpio.read('%s'): " % name
-
-        # convert legacy names
-        if name in self._legacy_map:
-            name = self._legacy_map[name]
-
-        temp_fd, temp_file = tempfile.mkstemp()
-        os.close(temp_fd)
-        command = "crossystem %s 2>%s" % (name, temp_file)
-        pipe = os.popen(command, 'r')
-        value = pipe.read()
-        exit_status = pipe.close()
-        if exit_status:
-            with open(temp_file, 'r') as temp_handle:
-                debug_info = temp_handle.read()
-            value = value.strip()
-            debug_info = debug_info.strip()
-            if value:
-                debug_info = value + '\n' + debug_info
-            if debug_info:
-                debug_info = '\nInformation: ' + debug_info
-            raise self._exception_type(
-                    debug_title + "Command failed (%d): %s%s" %
-                    (exit_status, command, debug_info))
-        # convert values
-        if name in self._override_map:
-            try:
-                value = self._override_map[name](value)
-            except:
-                raise self._exception_type(debug_title +
-                                           'Conversion failed: %s' % value)
-        return value
-
-
-def main():
-    gpio = Gpio()
-    try:
-        gpio.setup()
-        print ("developer switch current status: %s" %
-               gpio.read(gpio.DEVELOPER_SWITCH_CURRENT))
-    except Exception, e:
-        print "GPIO failed. %s" % e
-        sys.exit(1)
-
-if __name__ == '__main__':
-    main()
diff --git a/hacked_argparse.py b/hacked_argparse.py
new file mode 100644
index 0000000..6bdc089
--- /dev/null
+++ b/hacked_argparse.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+import inspect
+import logging
+import re
+
+from argparse import ArgumentParser, Action
+
+
+class HackedArgParser(ArgumentParser):
+  """Replace the usage and help strings to better format command names.
+
+  The default formatting is terrible, cramming all the command names
+  into one line with no spacing so that they are very hard to
+  copy-paste.  Instead format command names one-per-line.  For
+  simplicity make usage just return the help message text.
+
+  Reformatting is done using regexp-substitution because the argparse
+  formatting internals are explicitly declared to be private, and so
+  doing things this way should be no less fragile than trying to
+  replace the relevant argparse internals.
+  """
+
+  def __init__(self, subcommands={}, **kvargs):
+    self.subcommands = subcommands
+    ArgumentParser.__init__(self, **kvargs)
+
+  def format_sub_cmd_menu(self):
+    """Return str with aligned list of 'cmd-name : first-doc-line' strs."""
+    max_cmd_len = (max(len(c) for c in self.subcommands) if self.subcommands
+                   else 0)
+    def format_item(cmd_name):
+      doc = self.subcommands[cmd_name][1]
+      doc = '' if doc is None else ' : ' + doc.split('\n')[0]
+      return (max_cmd_len - len(cmd_name) + 2) * ' ' + cmd_name + doc
+    return '\n'.join(
+        format_item(cmd_name) for cmd_name in sorted(self.subcommands))
+
+  def format_help(self):
+    s = ArgumentParser.format_help(self)
+    s = re.sub(r'(?ms)\].*{.*}.*\.\.\.', r'] <sub-command>', s)
+    s = re.sub(r'(?ms)(positional.*)(optional arguments:)',
+               r'sub-commands:\n%s\n\n\2' % self.format_sub_cmd_menu(), s)
+    return s
+
+  def format_usage(self):
+    return self.format_help() + '\n'
+
+
+def CmdArg(*tags, **kvargs):
+  """Allow decorator arg specification using real argparse syntax."""
+  return (tags, kvargs)
+
+
+class VerbosityAction(Action):
+  def __call__(self, parser, namespace, values, option_string=None):
+    logging_level = {4: logging.DEBUG, 3: logging.INFO, 2: logging.WARNING,
+                     1: logging.ERROR, 0: logging.CRITICAL}[int(values)]
+    setattr(namespace, self.dest, logging_level)
+
+
+verbosity_cmd_arg = CmdArg(
+    '-v', '--verbosity', choices='01234', default=logging.WARNING,
+    action=VerbosityAction)
+
+
+# Per-module attribute to contain dict of (sub-command-name : function) pairs.
+SUB_CMD_LIST_ATTR = 'G_subcommands'
+
+
+def Command(cmd_name, *arg_list):
+  """Decorator to populate the per-module sub-command list.
+
+  If not already present, a SUB_CMD_LIST_ATTR attribute is created in
+  the caller module.  This attribute is then populated with the list
+  of subcommands.
+
+  Function doc strings are extracted and shown to users as part of the
+  help message for each command.
+  """
+  caller_module = inspect.getmodule((inspect.stack()[1])[0])
+  def Decorate(fun):
+    doc = fun.__doc__ if fun.__doc__ else None
+    subcommands = getattr(caller_module, SUB_CMD_LIST_ATTR, {})
+    subcommands[cmd_name] = (fun, doc, arg_list)
+    setattr(caller_module, SUB_CMD_LIST_ATTR, subcommands)
+    return fun
+  return Decorate
+
+
+def ParseCmdline(top_level_description, *common_args):
+  """Return object containing all argparse-processed command line data.
+
+  The list of subcommands is taken from the SUB_CMD_LIST_ATTR
+  attribute of the caller module.
+  """
+  caller_module = inspect.getmodule((inspect.stack()[1])[0])
+  subcommands = getattr(caller_module, SUB_CMD_LIST_ATTR, {})
+  parser = HackedArgParser(
+      subcommands=subcommands,
+      description=top_level_description)
+  for (tags, kvargs) in common_args:
+    parser.add_argument(*tags, **kvargs)
+  subparsers = parser.add_subparsers(dest='command_name')
+  for cmd_name, (fun, doc, arg_list) in subcommands.items():
+    subparser = subparsers.add_parser(cmd_name, description=doc)
+    subparser.set_defaults(command_name=cmd_name, command=fun)
+    for (tags, kvargs) in arg_list:
+      subparser.add_argument(*tags, **kvargs)
+  return parser.parse_args()
diff --git a/hwid_database.py b/hwid_database.py
index f67a462..696878d 100644
--- a/hwid_database.py
+++ b/hwid_database.py
@@ -5,15 +5,7 @@
 import inspect
 import yaml
 
-
-def YamlWrite(structured_data):
-  """Wrap yaml.dump to make calling convention consistent."""
-  return yaml.dump(structured_data, default_flow_style=False)
-
-
-def YamlRead(serialized_data):
-  """Wrap yaml.load to make calling convention consistent."""
-  return yaml.safe_load(serialized_data)
+from common import YamlWrite, YamlRead
 
 
 class InvalidDataError(ValueError):
diff --git a/hwid_tool.py b/hwid_tool.py
index c5605dc..aaea6ca 100755
--- a/hwid_tool.py
+++ b/hwid_tool.py
@@ -3,25 +3,28 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+"""Visualize and/or modify HWID and related component data."""
+
 
 import difflib
 import logging
 import os
 import random
-import re
 import string
 import sys
 import zlib
 
-from argparse import ArgumentParser, Action
-from common import Error, Obj, SetupLogging
 from bom_names import BOM_NAME_SET
-from hwid_database import InvalidDataError, MakeDatastoreSubclass, YamlRead
+from common import Error, Obj, SetupLogging, YamlWrite, YamlRead
+from hacked_argparse import CmdArg, Command, ParseCmdline, verbosity_cmd_arg
+from hwid_database import InvalidDataError, MakeDatastoreSubclass
 
 
 # The expected location of HWID data within a factory image.
 DEFAULT_HWID_DATA_PATH = '/usr/local/factory/hwid'
 
+
+# File that contains component data shared by all boards.
 COMPONENT_DB_FILENAME = 'component_db'
 
 
@@ -104,6 +107,12 @@
 # any early termination (no calls to return), to make sure that the
 # database does not get written.
 
+# TODO(tammo): Get rid of the 'ANY' and/or 'NONE' special values in
+# Hwid.component_map.  Instead add not_present_components and
+# (optionally) anything_goes_components lists.  If component classes
+# are not in either the map or the not_present list, they are
+# implicitly in anything_goes.
+
 
 def HwidChecksum(text):
   return ('%04u' % (zlib.crc32(text) & 0xffffffffL))[-4:]
@@ -132,7 +141,8 @@
   board, bom = parts
   if not all(x.isalpha() for x in [board, bom, variant, volatile]):
     raise Error, 'bad (non-alpha) part for hwid %r' % hwid
-  return Obj(board=board, bom=bom, variant=variant, volatile=volatile)
+  return Obj(hwid=hwid, board=board, bom=bom,
+             variant=variant, volatile=volatile)
 
 
 def AlphaIndex(num):
@@ -230,7 +240,7 @@
       try:
         data.device_db[entry] = Device.Decode(f.read())
       except InvalidDataError, e:
-        logging.error('%r decode failed: %s' % (entry_path, e))
+        logging.error('%r decode failed: %s', entry_path, e)
   return data
 
 
@@ -246,10 +256,9 @@
       diff = [line for line in difflib.unified_diff(file_data, internal_data)]
       if not diff:
         return
-      logging.info('updating %s with changes:\n%s' %
-                   (filename, '\n'.join(diff)))
+      logging.info('updating %s with changes:\n%s', filename, '\n'.join(diff))
     else:
-      logging.info('creating new data file %s' % filename)
+      logging.info('creating new data file %s', filename)
     with open(full_path, 'w') as f:
       f.write('%s\n' % '\n'.join(internal_data))
   WriteOnDiff(COMPONENT_DB_FILENAME, data.comp_db.Encode())
@@ -580,30 +589,6 @@
   return props
 
 
-# List of sub-commands that can be specified as command line
-# arguments.  This list is populated by the @Command decorators around
-# the corresponding command implementation functions.
-G_commands = {}
-
-
-def Command(cmd_name, *arg_list):
-  """Decorator to populate the global command list.
-
-  Function doc strings are extracted and shown to users as part of the
-  help message for each command.
-  """
-  def Decorate(fun):
-    doc = fun.__doc__ if fun.__doc__ else None
-    G_commands[cmd_name] = (fun, doc, arg_list)
-    return fun
-  return Decorate
-
-
-def CmdArg(*tags, **kvargs):
-  """Allow decorator arg specification using real argparse syntax."""
-  return (tags, kvargs)
-
-
 @Command('create_hwids',
          CmdArg('-b', '--board', required=True),
          CmdArg('-c', '--comps', nargs='*', required=True),
@@ -750,7 +735,7 @@
   registry = data.comp_db.registry
   if not set(components) <= set(registry):
     logging.critical('data contains component classes that are not preset in '
-                     'the component_db, specifically %r' %
+                     'the component_db, specifically %r',
                      sorted(set(components) - set(registry)))
   reverse_registry = CalcCompDbProbeValMap(data.comp_db)
   component_match_dict = {}
@@ -1026,67 +1011,16 @@
           hwid.component_map[comp_class] = new_name
 
 
-class HackedArgumentParser(ArgumentParser):
-  """Replace the usage and help strings to better format command names.
-
-  The default formatting is terrible, cramming all the command names
-  into one line with no spacing so that they are very hard to
-  copy-paste.  Instead format command names one-per-line.  For
-  simplicity make usage just return the help message text.
-
-  Reformatting is done using regexp-substitution because the argparse
-  formatting internals are explicitly declared to be private, and so
-  doing things this way should be no less fragile than trying to
-  replace the relevant argparse internals.
-  """
-
-  def format_sub_cmd_menu(self):
-    """Return str with aligned list of 'cmd-name : first-doc-line' strs."""
-    max_cmd_len = max(len(c) for c in G_commands)
-    def format_item(cmd_name):
-      doc = G_commands[cmd_name][1]
-      doc = '' if doc is None else ' : ' + doc.split('\n')[0]
-      return (max_cmd_len - len(cmd_name) + 2) * ' ' + cmd_name + doc
-    return '\n'.join(format_item(cmd_name) for cmd_name in sorted(G_commands))
-
-  def format_help(self):
-    s = ArgumentParser.format_help(self)
-    s = re.sub(r'(?ms)\].*{.*}.*\.\.\.', r'] <sub-command>', s)
-    s = re.sub(r'(?ms)(positional.*)(optional arguments:)',
-               r'sub-commands:\n%s\n\n\2' % self.format_sub_cmd_menu(), s)
-    return s
-
-  def format_usage(self):
-    return self.format_help() + '\n'
-
-
-def ParseCmdline():
-  """Return object containing all argparse-processed command line data."""
-  parser = HackedArgumentParser(
-      description='Visualize and/or modify HWID and related component data.')
-  parser.add_argument('-p', '--data_path', metavar='PATH',
-                      default=DEFAULT_HWID_DATA_PATH)
-  class VerbosityAction(Action):
-    def __call__(self, parser, namespace, values, option_string=None):
-      logging_level = {4: logging.DEBUG, 3: logging.INFO, 2: logging.WARNING,
-                       1: logging.ERROR, 0: logging.CRITICAL}[int(values)]
-      setattr(namespace, self.dest, logging_level)
-  parser.add_argument('-v', '--verbosity', choices='01234', default='2',
-                      action=VerbosityAction)
-  parser.add_argument('-l', '--log_file')
-  subparsers = parser.add_subparsers(dest='command_name')
-  for cmd_name, (fun, doc, arg_list) in G_commands.items():
-    subparser = subparsers.add_parser(cmd_name, description=doc)
-    subparser.set_defaults(command=fun)
-    for (tags, kvargs) in arg_list:
-      subparser.add_argument(*tags, **kvargs)
-  return parser.parse_args()
-
-
 def Main():
   """Run sub-command specified by the command line args."""
-  config = ParseCmdline()
-  SetupLogging(config.verbosity, config.log_file)
+  config = ParseCmdline(
+      'Visualize and/or modify HWID and related component data.',
+      CmdArg('-p', '--data_path', metavar='PATH',
+             default=DEFAULT_HWID_DATA_PATH),
+      CmdArg('-l', '--log', metavar='PATH',
+             help='Write logs to this file.'),
+      verbosity_cmd_arg)
+  SetupLogging(config.verbosity, config.log)
   data = ReadDatastore(config.data_path)
   try:
     config.command(config, data)
diff --git a/probe.py b/probe.py
index 672c108..30b8639 100644
--- a/probe.py
+++ b/probe.py
@@ -33,7 +33,7 @@
 sys.path.append('/usr/local/lib/flimflam/test')
 import flimflam
 
-from common import CompactStr, Error, Obj, RunShellCmd
+from common import CompactStr, Error, Obj, Shell
 
 
 # TODO(tammo): Some tests look for multiple components, some tests
@@ -56,9 +56,9 @@
 def _LoadKernelModule(name):
   """Ensure kernel module is loaded.  If not already loaded, do the load."""
   # TODO(tammo): Maybe lift into shared data for performance reasons.
-  loaded = RunShellCmd('lsmod | grep -q %s' % name).success
+  loaded = Shell('lsmod | grep -q %s' % name).success
   if not loaded:
-    loaded = RunShellCmd('modprobe %s' % name).success
+    loaded = Shell('modprobe %s' % name).success
     if not loaded:
       raise Error('Cannot load kernel module: %s' % name)
 
@@ -201,13 +201,13 @@
     detect_program = '/opt/Synaptics/bin/syndetect'
     if not os.path.exists(detect_program):
       return None
-    lock_check = RunShellCmd('lsof /dev/serio_raw0 | grep -q "^X"')
+    lock_check = Shell('lsof /dev/serio_raw0 | grep -q "^X"')
     if lock_check.success and not os.getenv('DISPLAY'):
       logging.error('Synaptics touchpad detection with X in the '
                     'foreground requires DISPLAY and XAUTHORITY '
                     'to be set properly.')
       return None
-    result = RunShellCmd(detect_program)
+    result = Shell(detect_program)
     if not result.success:
       return None
     properties = dict(map(str.strip, line.split('=', 1))
@@ -239,7 +239,7 @@
     # format: N: Name="???_trackpad"
     input_file = '/proc/bus/input/devices'
     cmd = 'grep -iE "^N.*(touch *pad|track *pad)" %s' % input_file
-    info = RunShellCmd(cmd).stdout.splitlines()
+    info = Shell(cmd).stdout.splitlines()
     info = [re.sub('^[^"]*"(.*)"$', r'\1', device) for device in info]
     return Obj(ident_str=(', '.join(info) if info else None), fw_version=None)
 
@@ -293,7 +293,7 @@
 @_ComponentProbe('audio_codec')
 def _ProbeAudioCodec():
   """Looks for codec strings in /proc/asound then at PCM details."""
-  grep_result = RunShellCmd('grep -R "Codec:" /proc/asound/*')
+  grep_result = Shell('grep -R "Codec:" /proc/asound/*')
   match_list = [re.findall(r'.*Codec:(.*)', line)
                 for line in grep_result.stdout.splitlines()]
   result_set = set(CompactStr(match) for match in match_list if match)
@@ -380,7 +380,7 @@
           dev_chrontel = os.path.basename(dev_path)
           break
     cmd = 'ch7036_monitor -d %s -p' % dev_chrontel
-    if os.path.exists(dev_chrontel) and RunShellCmd(cmd).success:
+    if os.path.exists(dev_chrontel) and Shell(cmd).success:
       return 'ch7036'
     return None
   part_id_gen = (probe_fun() for probe_fun in [ProbeChrontel])
@@ -412,7 +412,7 @@
   #   model name : Intel(R) Atom(TM) CPU ???
   #   model name : Intel(R) Atom(TM) CPU ???
   cmd = r'sed -nr "s/^model name\s*: (.*)/\1/p" /proc/cpuinfo'
-  stdout = RunShellCmd(cmd).stdout.splitlines()
+  stdout = Shell(cmd).stdout.splitlines()
   return CompactStr(stdout[0] + ' [%d cores]' % len(stdout))
 
 
@@ -426,7 +426,7 @@
   #   processor : 0
   #   processor : 1
   cmd = r'sed -nr "s/^[Pp]rocessor\s*: (.*)/\1/p" /proc/cpuinfo'
-  stdout = RunShellCmd(cmd).stdout.splitlines()
+  stdout = Shell(cmd).stdout.splitlines()
   return CompactStr(stdout[0] + ' [%d cores]' % len(stdout) - 1)
 
 
@@ -447,8 +447,8 @@
   """Combine mosys memory timing and geometry information."""
   # TODO(tammo): Document why mosys cannot load i2c_dev itself.
   _LoadKernelModule('i2c_dev')
-  time_data = RunShellCmd('mosys -k memory spd print timings').stdout
-  size_data = RunShellCmd('mosys -k memory spd print geometry').stdout
+  time_data = Shell('mosys -k memory spd print timings').stdout
+  size_data = Shell('mosys -k memory spd print geometry').stdout
   times = dict(re.findall('dimm="([^"]*)".*speeds="([^"]*)"', time_data))
   sizes = dict(re.findall('dimm="([^"]*)".*size_mb="([^"]*)"', size_data))
   return CompactStr(['%s|%s|%s' % (i, sizes[i], times[i].replace(' ', ''))
@@ -475,7 +475,7 @@
   # Example mosys command output:
   # vendor="VENDOR" name="CHIPNAME" fw_version="ECFWVER"
   ecinfo = re.findall(r'\bvendor="([^"]*)".*\bname="([^"]*)"',
-                      RunShellCmd('mosys -k ec info').stdout)
+                      Shell('mosys -k ec info').stdout)
   if ecinfo:
     return CompactStr(*ecinfo)
   return None
@@ -522,7 +522,7 @@
 def _ProbeTpm():
   """Return Manufacturer_info : Chip_Version string from tpm_version output."""
   tpm_data = [line.partition(':') for line in
-              RunShellCmd('tpm_version').stdout.splitlines()]
+              Shell('tpm_version').stdout.splitlines()]
   tpm_dict = dict((key.strip(), value.strip()) for
                   key, _, value in tpm_data)
   mfg = tpm_dict.get('Manufacturer Info', None)
@@ -582,7 +582,7 @@
       return CompactStr([dev_attrs[key] for key in version_format])
     # If nothing available, try 'modem status'.
     cmd = 'modem status | grep firmware_revision'
-    modem_status = RunShellCmd(cmd).stdout.strip()
+    modem_status = Shell(cmd).stdout.strip()
     info = re.findall('^\s*firmware_revision:\s*(.*)', modem_status)
     if info and info[0]:
       return info[0]
@@ -617,7 +617,7 @@
   """Algorithm: sha256(GBB[-HWID]); GBB without HWID."""
   with NamedTemporaryFile('wb') as f:
     f.write(image.get_section('GBB'))
-    RunShellCmd('gbb_utility -s --hwid="ChromeOS" "%s"' % f.name)
+    Shell('gbb_utility -s --hwid="ChromeOS" "%s"' % f.name)
     hash_src = f.read()
   return hashlib.sha256(hash_src).hexdigest()
 
@@ -643,11 +643,10 @@
 def _FwKeyHash(main_fw_file, key_name):
   """Hash specified GBB key, extracted by vbutil_key."""
   with NamedTemporaryFile(prefix='gbb_%s_' % key_name) as f:
-    if not RunShellCmd('gbb_utility -g --%s=%s %s' %
-                       (key_name, f.name, main_fw_file)).success:
+    if not Shell('gbb_utility -g --%s=%s %s' %
+                 (key_name, f.name, main_fw_file)).success:
       raise Error('cannot get %s from GBB' % key_name)
-
-    key_info = RunShellCmd('vbutil_key --unpack %s' % f.name).stdout
+    key_info = Shell('vbutil_key --unpack %s' % f.name).stdout
     sha1sum = re.findall(r'Key sha1sum:[\s]+([\w]+)', key_info)
     if len(sha1sum) != 1:
       logging.error("Failed calling vbutil_key for firmware key hash.")
@@ -714,7 +713,6 @@
     arch_probes = ref_probe_map.get(arch, {})
     if not probe_class_white_list:
       probe_class_white_list = set(generic_probes) | set(arch_probes)
-    print probe_class_white_list, generic_probes, arch_probes
     return dict((probe_class, (arch_probes[probe_class]
                                if probe_class in arch_probes
                                else generic_probes[probe_class]))
@@ -724,7 +722,7 @@
       missing_components=[],
       volatiles={},
       initial_configs={})
-  arch = RunShellCmd('crossystem arch').stdout.strip()
+  arch = Shell('crossystem arch').stdout.strip()
   comp_probes = FilterProbes(_COMPONENT_PROBE_MAP, arch, target_comp_classes)
   if probe_initial_config:
     ic_probes = FilterProbes(_INITIAL_CONFIG_PROBE_MAP, arch, [])
@@ -737,7 +735,9 @@
     else:
       results.missing_components.append(comp_class)
   for ic_class, probe_fun in ic_probes.items():
-    results.initial_configs[ic_class] = RunProbe(probe_fun)
+    probe_value = RunProbe(probe_fun)
+    if probe_value is not None:
+      results.initial_configs[ic_class] = probe_value
   if probe_volatile:
     main_fw_file = crosfw.LoadMainFirmware().GetFileName()
     results.volatiles.update(CalculateFirmwareHashes(main_fw_file))
diff --git a/report.py b/report.py
new file mode 100755
index 0000000..9e81fa7
--- /dev/null
+++ b/report.py
@@ -0,0 +1,82 @@
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Device detail reports for factory process."""
+
+
+import os
+import tempfile
+import time
+import uuid
+
+import crosfw
+from common import Shell, YamlWrite
+
+
+# Update this if any field names (or formats) have been changed.
+REPORT_VERSION = 6
+
+
+def Create(log_path):
+  """Creates a detail report for current device.
+
+  Collects hwid, vpd, and attach a timestamp.
+
+  Args:
+    log_path: Filename of log to include in the report.
+
+  Returns:
+    The created report filename.
+  """
+  report = {}
+
+  # TODO(tammo): Consider adding /var/log/messages* and /etc/lsb-release.
+
+  # TODO(hungte) we may also add in future:
+  #   rootfs hash, dump_kernel_config, lsb-release from release image,
+  #   gooftool version, result of dev_vboot_debug,
+  #   /var/log/factory.log and any other customized data
+
+  # General information
+  report['version'] = '%s' % REPORT_VERSION
+
+  # System Hardware ID
+  report['hwid'] = Shell('crossystem hwid').stdout.strip()
+  report['platform_name'] = Shell('mosys platform name').stdout.strip()
+
+  # crossystem reports many system configuration data
+  report['crossystem'] = Shell('crossystem').stdout.strip().splitlines()
+
+  # Vital Product Data
+  main_fw_file = crosfw.LoadMainFirmware().GetFileName()
+  vpd_cmd = '-f %s' % main_fw_file
+  report['ro_vpd'] = Shell('vpd -i RO_VPD -l %s' % vpd_cmd).stdout.splitlines()
+  report['rw_vpd'] = Shell('vpd -i RW_VPD -l %s' % vpd_cmd).stdout.splitlines()
+
+  # Firmware write protection status
+  # TODO(hungte) Replace by crosfw.Flashrom.
+  ec_wp_status = Shell(
+      'flashrom -p internal:bus=lpc --get-size 2>/dev/null && '
+      'flashrom -p internal:bus=lpc --wp-status || '
+      'echo "EC is not available."').stdout
+  bios_wp_status = Shell(
+      'flashrom -p internal:bus=spi --wp-status').stdout
+
+  wp_status_message = 'main: %s\nec: %s' % (bios_wp_status, ec_wp_status)
+  report['wp_status'] = wp_status_message.splitlines()
+
+  # Cellular status
+  modem_status = Shell('modem status').stdout
+  report['modem_status'] = modem_status.splitlines()
+
+  # Verbose log. Should be prepared before the last step.
+  if log_path is not None:
+    report['verbose_log'] = open(log_path).read().splitlines()
+
+  # Finally, attach a timestamp. This must be the last entry.
+  report['device_timestamp'] = time.strftime('%Y%m%d-%H%M%S', time.gmtime())
+
+  filename = os.path.join(tempfile.gettempdir(), uuid.uuid4().hex)
+  open(filename, 'w').write(YamlWrite(report))
+  return filename
diff --git a/gft_upload.py b/report_upload.py
similarity index 69%
rename from gft_upload.py
rename to report_upload.py
index a1f6ed4..4b658e8 100755
--- a/gft_upload.py
+++ b/report_upload.py
@@ -1,6 +1,4 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
@@ -9,6 +7,7 @@
 """
 
 import ftplib
+import logging
 import os
 import re
 import sys
@@ -17,8 +16,7 @@
 import urlparse
 import xmlrpclib
 
-import gft_common
-from gft_common import DebugMsg, ErrorDie, ErrorMsg, VerboseMsg, WarningMsg
+from common import Error, Shell
 
 
 # Constants
@@ -43,8 +41,8 @@
     message = results.get('message', 'unknown')
     abort = results.get('abort', False)
     if (not interval) or abort:
-      ErrorDie('%s: %s' % (message_prefix, message))
-    ErrorMsg('%s: %s' % (message_prefix, message))
+      raise Error('%s: %s' % message_prefix, message)
+    logging.error('%s: %s', message_prefix, message)
     for i in range(interval, 0, -1):
       if i % 10 == 0:
         sys.stderr.write(" Retry in %d seconds...\n" % i)
@@ -60,30 +58,28 @@
     custom_command: A shell script command to invoke.
   """
   if not custom_command:
-    ErrorDie('CustomUpload: need a shell command for customized uploading.')
+    raise Error('CustomUpload: need a shell command for customized uploading.')
   cmd = '%s %s' % (custom_command, source_path)
-  DebugMsg('CustomUpload: custom: %s' % cmd)
+  logging.debug('CustomUpload: custom: %s', cmd)
   if os.system(cmd) != 0:
-    ErrorDie('CustomUpload: failed: %s' % cmd)
-  VerboseMsg('CustomUpload: successfully invoked command: %s.' % cmd)
+    raise Error('CustomUpload: failed: %s' % cmd)
+  logging.info('CustomUpload: successfully invoked command: %s.', cmd)
   return True
 
 
 def ShopFloorUpload(source_path, remote_spec,
                     retry_interval=DEFAULT_RETRY_INTERVAL):
   if '#' not in remote_spec:
-    ErrorDie('ShopFloorUpload: need a valid parameter in URL#SN format.')
+    raise Error('ShopFloorUpload: need a valid parameter in URL#SN format.')
   (server_url, _, serial_number) = remote_spec.partition('#')
-  DebugMsg("ShopFloorUpload: [%s].UploadReport(%s, %s)" %
-           (server_url, serial_number, source_path))
+  logging.debug("ShopFloorUpload: [%s].UploadReport(%s, %s)",
+                server_url, serial_number, source_path)
   instance = xmlrpclib.ServerProxy(server_url, allow_none=True, verbose=False)
   remote_name = os.path.basename(source_path)
   with open(source_path, 'rb') as source_handle:
     blob = xmlrpclib.Binary(source_handle.read())
 
   def ShopFloorCallback(result):
-    abort = False
-    message = None
     try:
       instance.UploadReport(serial_number, blob, remote_name)
       return True
@@ -96,7 +92,7 @@
       result['abort'] = False
 
   RetryCommand(ShopFloorCallback, 'ShopFloorUpload', interval=retry_interval)
-  VerboseMsg('ShopFloorUpload: successfully uploaded to: %s' % remote_spec)
+  logging.info('ShopFloorUpload: successfully uploaded to: %s', remote_spec)
   return True
 
 
@@ -109,37 +105,38 @@
     success_string: String to be recognized as "uploaded successfully".
   """
   if not curl_command:
-    ErrorDie('CurlCommand: need parameters for curl.')
+    raise Error('CurlCommand: need parameters for curl.')
 
   cmd = 'curl -s -S %s' % curl_command
-  DebugMsg('CurlCommand: %s' % cmd)
+  logging.debug('CurlCommand: %s', cmd)
 
   # man curl(1) for EXIT CODES not related to temporary network failure.
   curl_abort_exit_codes = [1, 2, 3, 27, 37, 43, 45, 53, 54, 58, 59, 63]
 
   def CurlCallback(result):
-    (exit_code, stdout, stderr) = (
-        gft_common.ShellExecution(cmd, ignore_status=True))
+    cmd_result = Shell(cmd)
     abort = False
     message = None
-    if exit_code == 0:
-      if abort_string and stdout.find(abort_string) >= 0:
+    if cmd_result.success:
+      if abort_string and cmd_result.stdout.find(abort_string) >= 0:
         message = "Abort: Found abort pattern: %s" % abort_string
-      elif (not success_string) or (stdout.find(success_string) >= 0):
+      elif ((not success_string) or
+            (cmd_result.stdout.find(success_string) >= 0)):
         return True
       else:
         message = "Retry: No valid pattern (%s) in response." % success_string
-      DebugMsg("CurlCallback: original response: %s" %
-               ' '.join(stdout.splitlines()))
+      logging.debug("CurlCallback: original response: %s",
+                    ' '.join(cmd_result.stdout.splitlines()))
     else:
-      message = '#%d %s' % (exit_code, stderr if stderr else stdout)
-      if exit_code in curl_abort_exit_codes:
+      message = '#%d %s' % (cmd_result.status, cmd_result.stderr
+                            if cmd_result.stderr else cmd_result.stdout)
+      if cmd_result.status in curl_abort_exit_codes:
         abort = True
     result['abort'] = abort
     result['message'] = message
 
   RetryCommand(CurlCallback, 'CurlCommand', interval=retry_interval)
-  VerboseMsg('CurlCommand: successfully executed: %s' % cmd)
+  logging.info('CurlCommand: successfully executed: %s', cmd)
   return True
 
 
@@ -191,7 +188,7 @@
 
   # Check and specify default parameters
   if not host:
-    ErrorDie('FtpUpload: invalid ftp url: %s' % ftp_url)
+    raise Error('FtpUpload: invalid ftp url: %s' % ftp_url)
   if not port:
     port = ftplib.FTP_PORT
   if not userid:
@@ -207,14 +204,14 @@
 
   source_name = os.path.split(source_path)[1]
   dest_name = os.path.split(path)[1]
-  DebugMsg('source name: %s, dest_name: %s -> %s' % (source_name, path,
-                                                     dest_name))
+  logging.debug('source name: %s, dest_name: %s -> %s',
+                source_name, path, dest_name)
   if source_name and (not dest_name):
     path = os.path.join(path, source_name)
 
   ftp = ftplib.FTP()
   url = 'ftp://%s:%s@%s:%s/ %s' % (userid, passwd, host, port, path)
-  VerboseMsg('FtpUpload: target is %s' % url)
+  logging.info('FtpUpload: target is %s', url)
 
   def FtpCallback(result):
     try:
@@ -226,19 +223,19 @@
   RetryCommand(FtpCallback, 'FtpUpload', interval=retry_interval)
 
   # Ready for copying files
-  DebugMsg('FtpUpload: connected, uploading to %s...' % path)
+  logging.debug('FtpUpload: connected, uploading to %s...', path)
   ftp.login(user=userid, passwd=passwd)
   with open(source_path, 'rb') as fileobj:
     ftp.storbinary('STOR %s' % path, fileobj)
-  DebugMsg('FtpUpload: upload complete.')
+  logging.debug('FtpUpload: upload complete.')
   ftp.quit()
-  VerboseMsg('FtpUpload: successfully uploaded to %s' % ftp_url)
+  logging.info('FtpUpload: successfully uploaded to %s', ftp_url)
   return True
 
 
 def NoneUpload(source_path, **kargs):
   """ Dummy function for bypassing uploads """
-  WarningMsg('NoneUpload%s: skipped uploading %s' % (kargs, source_path))
+  logging.warning('NoneUpload%s: skipped uploading %s', kargs, source_path)
   return True
 
 
@@ -270,49 +267,5 @@
   elif method == 'cpfe':
     return CpfeUpload(path, param, **kargs)
   else:
-    ErrorDie('Upload: unknown method: %s' % method)
+    raise Error('Upload: unknown method: %s' % method)
   return False
-
-
-#############################################################################
-# Console main entry
-@gft_common.GFTConsole
-def main():
-  gft_common.SetVerboseLevel(True)
-  # gft_common.SetDebugLevel(True)
-  if len(sys.argv) != 3:
-    print "Usage: %s upload_file_path upload_method" % sys.argv[0]
-    print """
-    Supported values for upload_method:
-
-    none
-        Do nothing.
-
-    ftp://userid:passwd@host:port/path
-        Upload to a FTP site using python ftplib (for backward compatible and
-        better connection status checking).
-
-    ftps://userid:passwd@host:port/path [curl_options]
-        Upload by FTP-SSL protocol using curl.
-
-    curl:ftp[s]://userid:passwd@host:port/path [curl_options]
-        Upload by FTP(s) protocol using curl, allowing customized curl
-        parameters like --ftp-create-dirs.
-
-    cpfe:cpfe_url [curl_options]
-        Upload to Google ChromeOS Partner Front End.
-
-    shopfloor:shopfloor_url#serial_number
-        Upload to ChromeOS factory shop floor XMLRPC interface (more info in
-        src/platform/factory-utils/factory_setup/shopfloor*)
-
-    custom:shell_command
-        Invoke a shell command to upload the file.
-    """
-    sys.exit(1)
-
-  if not Upload(sys.argv[1], sys.argv[2]):
-    ErrorDie('ftp_upload: FAILED.')
-
-if __name__ == '__main__':
-  main()
diff --git a/vpd_data.py b/vpd_data.py
new file mode 100755
index 0000000..938cbe4
--- /dev/null
+++ b/vpd_data.py
@@ -0,0 +1,295 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# This is a required test to check all VPD related information.
+
+
+"""Collection of valid VPD values for ChromeOS."""
+
+
+# keyboard_layout: http://gerrit.chromium.org/gerrit/gitweb?p=chromium/src.git;a=blob;f=chrome/browser/chromeos/input_method/ibus_input_methods.txt
+KEYBOARD_LAYOUT = [
+  'xkb:nl::nld',
+  'xkb:be::nld',
+  'xkb:fr::fra',
+  'xkb:be::fra',
+  'xkb:ca::fra',
+  'xkb:ch:fr:fra',
+  'xkb:de::ger',
+  'xkb:de:neo:ger',
+  'xkb:be::ger',
+  'xkb:ch::ger',
+  'xkb:jp::jpn',
+  'xkb:ru::rus',
+  'xkb:ru:phonetic:rus',
+  'xkb:us::eng',
+  'xkb:us:intl:eng',
+  'xkb:us:altgr-intl:eng',
+  'xkb:us:dvorak:eng',
+  'xkb:us:colemak:eng',
+  'xkb:br::por',
+  'xkb:bg::bul',
+  'xkb:bg:phonetic:bul',
+  'xkb:ca:eng:eng',
+  'xkb:cz::cze',
+  'xkb:ee::est',
+  'xkb:es::spa',
+  'xkb:es:cat:cat',
+  'xkb:dk::dan',
+  'xkb:gr::gre',
+  'xkb:il::heb',
+  'xkb:kr:kr104:kor',
+  'xkb:latam::spa',
+  'xkb:lt::lit',
+  'xkb:lv:apostrophe:lav',
+  'xkb:hr::scr',
+  'xkb:gb:extd:eng',
+  'xkb:gb:dvorak:eng',
+  'xkb:fi::fin',
+  'xkb:hu::hun',
+  'xkb:it::ita',
+  'xkb:no::nob',
+  'xkb:pl::pol',
+  'xkb:pt::por',
+  'xkb:ro::rum',
+  'xkb:se::swe',
+  'xkb:sk::slo',
+  'xkb:si::slv',
+  'xkb:rs::srp',
+  'xkb:tr::tur',
+  'xkb:ua::ukr',
+  ]
+
+# initial_locale: http://git.chromium.org/gitweb/?p=chromium.git;a=blob;f=ui/base/l10n/l10n_util.cc
+INITIAL_LOCALE = [
+  "af",
+  "am",
+  "ar",
+  "az",
+  "be",
+  "bg",
+  "bh",
+  "bn",
+  "br",
+  "bs",
+  "ca",
+  "co",
+  "cs",
+  "cy",
+  "da",
+  "de",
+  "de-AT",
+  "de-CH",
+  "de-DE",
+  "el",
+  "en",
+  "en-AU",
+  "en-CA",
+  "en-GB",
+  "en-NZ",
+  "en-US",
+  "en-ZA",
+  "eo",
+  "es",
+  "es-419",
+  "et",
+  "eu",
+  "fa",
+  "fi",
+  "fil",
+  "fo",
+  "fr",
+  "fr-CA",
+  "fr-CH",
+  "fr-FR",
+  "fy",
+  "ga",
+  "gd",
+  "gl",
+  "gn",
+  "gu",
+  "ha",
+  "haw",
+  "he",
+  "hi",
+  "hr",
+  "hu",
+  "hy",
+  "ia",
+  "id",
+  "is",
+  "it",
+  "it-CH",
+  "it-IT",
+  "ja",
+  "jw",
+  "ka",
+  "kk",
+  "km",
+  "kn",
+  "ko",
+  "ku",
+  "ky",
+  "la",
+  "ln",
+  "lo",
+  "lt",
+  "lv",
+  "mk",
+  "ml",
+  "mn",
+  "mo",
+  "mr",
+  "ms",
+  "mt",
+  "nb",
+  "ne",
+  "nl",
+  "nn",
+  "no",
+  "oc",
+  "om",
+  "or",
+  "pa",
+  "pl",
+  "ps",
+  "pt",
+  "pt-BR",
+  "pt-PT",
+  "qu",
+  "rm",
+  "ro",
+  "ru",
+  "sd",
+  "sh",
+  "si",
+  "sk",
+  "sl",
+  "sn",
+  "so",
+  "sq",
+  "sr",
+  "st",
+  "su",
+  "sv",
+  "sw",
+  "ta",
+  "te",
+  "tg",
+  "th",
+  "ti",
+  "tk",
+  "to",
+  "tr",
+  "tt",
+  "tw",
+  "ug",
+  "uk",
+  "ur",
+  "uz",
+  "vi",
+  "xh",
+  "yi",
+  "yo",
+  "zh",
+  "zh-CN",
+  "zh-TW",
+  "zu",
+  ]
+
+# initial_timezone: http://git.chromium.org/gitweb/?p=chromium.git;a=blob;f=chrome/browser/chromeos/dom_ui/system_settings_provider.cc
+INITIAL_TIMEZONE = [
+  "Pacific/Majuro",
+  "Pacific/Midway",
+  "Pacific/Honolulu",
+  "America/Anchorage",
+  "America/Los_Angeles",
+  "America/Tijuana",
+  "America/Denver",
+  "America/Phoenix",
+  "America/Chihuahua",
+  "America/Chicago",
+  "America/Mexico_City",
+  "America/Costa_Rica",
+  "America/Regina",
+  "America/New_York",
+  "America/Bogota",
+  "America/Caracas",
+  "America/Barbados",
+  "America/Manaus",
+  "America/Santiago",
+  "America/St_Johns",
+  "America/Sao_Paulo",
+  "America/Araguaina",
+  "America/Argentina/Buenos_Aires",
+  "America/Godthab",
+  "America/Montevideo",
+  "Atlantic/South_Georgia",
+  "Atlantic/Azores",
+  "Atlantic/Cape_Verde",
+  "Africa/Casablanca",
+  "Europe/London",
+  "Europe/Amsterdam",
+  "Europe/Belgrade",
+  "Europe/Brussels",
+  "Europe/Sarajevo",
+  "Africa/Windhoek",
+  "Africa/Brazzaville",
+  "Asia/Amman",
+  "Europe/Athens",
+  "Asia/Beirut",
+  "Africa/Cairo",
+  "Europe/Helsinki",
+  "Asia/Jerusalem",
+  "Europe/Minsk",
+  "Africa/Harare",
+  "Asia/Baghdad",
+  "Europe/Moscow",
+  "Asia/Kuwait",
+  "Africa/Nairobi",
+  "Asia/Tehran",
+  "Asia/Baku",
+  "Asia/Tbilisi",
+  "Asia/Yerevan",
+  "Asia/Dubai",
+  "Asia/Kabul",
+  "Asia/Karachi",
+  "Asia/Oral",
+  "Asia/Yekaterinburg",
+  "Asia/Calcutta",
+  "Asia/Colombo",
+  "Asia/Katmandu",
+  "Asia/Almaty",
+  "Asia/Rangoon",
+  "Asia/Krasnoyarsk",
+  "Asia/Bangkok",
+  "Asia/Shanghai",
+  "Asia/Hong_Kong",
+  "Asia/Irkutsk",
+  "Asia/Kuala_Lumpur",
+  "Australia/Perth",
+  "Asia/Taipei",
+  "Asia/Seoul",
+  "Asia/Tokyo",
+  "Asia/Yakutsk",
+  "Australia/Adelaide",
+  "Australia/Darwin",
+  "Australia/Brisbane",
+  "Australia/Hobart",
+  "Australia/Sydney",
+  "Asia/Vladivostok",
+  "Pacific/Guam",
+  "Asia/Magadan",
+  "Pacific/Auckland",
+  "Pacific/Fiji",
+  "Pacific/Tongatapu",
+  ]
+
+KNOWN_VPD_FIELD_DATA = {
+  'keyboard_layout': KEYBOARD_LAYOUT,
+  'initial_locale': INITIAL_LOCALE,
+  'initial_timezone': INITIAL_TIMEZONE,
+  }