installer: change TOOLKIT_VERSION when repacking

Currently we use the content of file MD5SUM to determine if toolkit
update is necessary. We want to use TOOLKIT_VERSION instead of MD5SUM in
the future, hence changing TOOLKIT_VERSION is needed when repacking.

BUG=b:36083439
TEST=manually
     1. # make a factory toolkit installer, with name "1.run"
     2. ./1.run --noexec --target 1
     3. ./1.run -- --repack 1 --pack-into 2.run
     4. ./2.run --noexec --target 2
     5. # check it shows "(modified 1 times)" in the previous step
     6. more [12]/usr/local/factory/TOOLKIT_VERSION

Change-Id: I8de9469021f60a9b6c51cd42217e504022ae3449
Reviewed-on: https://chromium-review.googlesource.com/483281
Commit-Ready: Youcheng Syu <youcheng@chromium.org>
Tested-by: Youcheng Syu <youcheng@chromium.org>
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
diff --git a/py/toolkit/installer.py b/py/toolkit/installer.py
index 69f645b..01ee4e3 100755
--- a/py/toolkit/installer.py
+++ b/py/toolkit/installer.py
@@ -14,23 +14,25 @@
 
 import argparse
 from contextlib import contextmanager
+import getpass
 import glob
 import os
 import shutil
 import sys
 import tempfile
+import time
 
 import factory_common  # pylint: disable=unused-import
 from cros.factory.test import event_log
 from cros.factory.test.env import paths
 from cros.factory.tools import install_symlinks
+from cros.factory.utils import file_utils
 from cros.factory.utils import sys_utils
 from cros.factory.utils.process_utils import Spawn
 
 
 INSTALLER_PATH = 'usr/local/factory/py/toolkit/installer.py'
-MAKESELF_SHELL = '/bin/sh'
-TOOLKIT_NAME = 'install_factory_toolkit.run'
+VERSION_PATH = 'usr/local/factory/TOOLKIT_VERSION'
 
 # Short and sweet help header for the executable generated by makeself.
 HELP_HEADER = """
@@ -165,8 +167,7 @@
           'This installer must be run from within the factory toolkit!')
 
   def WarningMessage(self, target_test_image=None):
-    with open(os.path.join(self._src, 'VERSION')) as f:
-      ret = f.read()
+    ret = file_utils.ReadFile(os.path.join(self._src, VERSION_PATH))
     if target_test_image:
       ret += (
           '\n'
@@ -205,8 +206,8 @@
 
   def _SetDeviceID(self):
     if self._device_id is not None:
-      with open(os.path.join(event_log.DEVICE_ID_PATH), 'w') as f:
-        f.write(self._device_id)
+      file_utils.WriteFile(os.path.join(event_log.DEVICE_ID_PATH),
+                           self._device_id)
 
   def _EnableApp(self, app, enabled):
     """Enable / disable @app.
@@ -332,25 +333,42 @@
   info_file = os.path.join(src_root, 'REPO_STATUS')
   if not os.path.exists(info_file):
     raise OSError('Build info file not found!')
-  with open(info_file, 'r') as f:
-    print f.read()
+  print file_utils.ReadFile(info_file)
 
 
-def PackFactoryToolkit(src_root, output_path, enable_device, enable_presenter):
+def PackFactoryToolkit(src_root, output_path, initial_version,
+                       enable_device, enable_presenter):
   """Packs the files containing this script into a factory toolkit."""
-  with open(os.path.join(src_root, 'VERSION'), 'r') as f:
-    version = f.read().strip()
+  if initial_version is None:
+    complete_version = '%s  repacked by %s@%s at %s\n' % (
+        file_utils.ReadFile(os.path.join(src_root, VERSION_PATH)),
+        getpass.getuser(), os.uname()[1], time.strftime('%Y-%m-%d %H:%M:%S'))
+    initial_version = complete_version.splitlines()[0]
+  else:
+    complete_version = initial_version + '\n'
+  modified_times = len(complete_version.splitlines()) - 1
+  if modified_times == 0:
+    modified_msg = ''
+  else:
+    modified_msg = ' (modified %d times)' % modified_times
   with tempfile.NamedTemporaryFile() as help_header:
-    help_header.write(version + '\n' + HELP_HEADER + HELP_HEADER_MAKESELF)
+    help_header.write(initial_version + '\n' +
+                      HELP_HEADER + HELP_HEADER_MAKESELF)
     help_header.flush()
     cmd = [os.path.join(src_root, 'makeself.sh'), '--bzip2', '--nox11',
            '--help-header', help_header.name,
-           src_root, output_path, version, INSTALLER_PATH, '--in-exe']
+           src_root, output_path, initial_version + modified_msg,
+           INSTALLER_PATH, '--in-exe']
     if not enable_device:
       cmd.append('--no-enable-device')
     if not enable_presenter:
       cmd.append('--no-enable-presenter')
     Spawn(cmd, check_call=True, log=True)
+  with file_utils.TempDirectory() as tmp_dir:
+    version_path = os.path.join(tmp_dir, VERSION_PATH)
+    os.makedirs(os.path.dirname(version_path))
+    file_utils.WriteFile(version_path, complete_version)
+    Spawn([cmd[0], '--append', tmp_dir, output_path], check_call=True, log=True)
   print ('\n'
          '  Factory toolkit generated at %s.\n'
          '\n'
@@ -414,6 +432,8 @@
                       help='Pack the files into a new factory toolkit')
   parser.add_argument('--repack', metavar='UNPACKED_TOOLKIT',
                       help='Repack from previously unpacked toolkit')
+  parser.add_argument('--version', metavar='VERSION',
+                      help='String to write into TOOLKIT_VERSION when packing')
 
   parser.add_argument('--enable-presenter', dest='enable_presenter',
                       action='store_true',
@@ -466,8 +486,8 @@
   # --pack-into may be called directly so this must be done before changing
   # working directory to OLDPWD.
   if args.pack_into and args.repack is None:
-    PackFactoryToolkit(src_root, args.pack_into, args.enable_device,
-                       args.enable_presenter)
+    PackFactoryToolkit(src_root, args.pack_into, args.version,
+                       args.enable_device, args.enable_presenter)
     return
 
   if not in_archive: