Merge "ginstall:  Output progress to /tmp/ginstall/progress."
diff --git a/ginstall/ginstall.py b/ginstall/ginstall.py
index 0140e81..affd475 100755
--- a/ginstall/ginstall.py
+++ b/ginstall/ginstall.py
@@ -59,6 +59,7 @@
 HNVRAM = 'hnvram'
 NANDDUMP = ['nanddump']
 SGDISK = 'sgdisk'
+PROGRESS_EXPORT_PATH = '/tmp/ginstall'
 
 F = {
     'ETCPLATFORM': '/etc/platform',
@@ -761,19 +762,37 @@
 class ProgressBar(object):
   """Progress bar that prints one dot per 1MB."""
 
+  # Can be overridden by unit tests.
+  DOTSIZE = 1024 * 1024
+
   def __init__(self):
     self.bytes = 0
+    if not os.path.exists(PROGRESS_EXPORT_PATH):
+      try:
+        os.makedirs(PROGRESS_EXPORT_PATH)
+      except OSError as e:
+        VerbosePrint('Could not create %r: %s', PROGRESS_EXPORT_PATH, e)
 
   def MadeProgress(self, b):
     self.bytes += b
-    dotsize = 1024 * 1024
-    if self.bytes > dotsize:
+    if self.bytes >= self.DOTSIZE:
       VerbosePrint('.')
-      self.bytes -= dotsize
+      self.ExportProgress('.')
+      self.bytes -= self.DOTSIZE
 
   def Done(self):
+    self.ExportProgress('\n')
     VerbosePrint('\n')
 
+  def _ProgressExportFile(self):
+    return os.path.join(PROGRESS_EXPORT_PATH, 'progress')
+
+  def ExportProgress(self, msg):
+    try:
+      open(self._ProgressExportFile(), 'a').write(msg)
+    except (OSError, IOError) as e:
+      VerbosePrint('Failed to write progress bar to file: %s', e)
+
 
 class FileWithSecureHash(object):
   """A file-like object paired with a SHA-1 hash."""
diff --git a/ginstall/ginstall_test.py b/ginstall/ginstall_test.py
index 5b335ea..1bbdb14 100755
--- a/ginstall/ginstall_test.py
+++ b/ginstall/ginstall_test.py
@@ -71,6 +71,7 @@
         self.tmpdir + '/mmcblk0boot0/force_ro')
     ginstall.MMC_RO_LOCK['MMCBLK0BOOT1'] = (
         self.tmpdir + '/mmcblk0boot1/force_ro')
+    ginstall.PROGRESS_EXPORT_PATH = os.path.join(self.tmpdir, 'ginstall')
 
     # default OS to 'fiberos'
     self.WriteOsFile('fiberos')
@@ -115,11 +116,26 @@
         open('testdata/img/loader_bad.sig'),
         open('testdata/etc/google_public.der')))
 
-  def testIsIdentical(self):
+  def testIsIdenticalAndProgressBar(self):
+    ginstall.BUFSIZE = 1
+    ginstall.ProgressBar.DOTSIZE = 1
+    loader = 'testdata/img/loader.bin'
+    loader1 = 'testdata/img/loader1.bin'
+    self.assertTrue(ginstall.IsIdentical(
+        'testloader', open(loader), open(loader)))
     self.assertFalse(ginstall.IsIdentical(
-        'testloader',
-        open('testdata/img/loader.bin'),
-        open('testdata/img/loader1.bin')))
+        'testloader', open(loader), open(loader1)))
+
+    # Test exported progress bar.
+    success_line = '.' * (len(open(loader).read()) - 1) + '\n'
+    failure_line = ''
+    for a, b in zip(open(loader).read(), open(loader1).read()):
+      if a != b:
+        break
+      failure_line += '.'
+    progress_file = open(
+        os.path.join(ginstall.PROGRESS_EXPORT_PATH, 'progress')).read()
+    self.assertEqual(progress_file, success_line + failure_line)
 
   def testVerifyAndIsIdentical(self):
     loader = open('testdata/img/loader.bin')