cros_sdk: Add a non-interactive mode friendly flag `--working-dir`.

In some case, developers may prefer to use `cros_sdk` in
non-interactive mode (i.e. `cros_sdk -- some_command`) rather
than type the command on a shell in chroot in another terminal.
For example, the developers may have their own fancy working
environment outside chroot and the monitor is small.

This CL adds a new flag `--working-dir` for `cros_sdk` program to run
the command in the specific working directory in chroot.
Usage example:

   # Run factory repository's unttests.
   bash$ cd ~/chromiumos/src/platform/factory
   bash$ cros_sdk --working-dir . -- make test

   # View a file under /build/proj1/tmp
   bash$ cros_sdk --working-dir /build/proj1/tmp -- less file1

BUG=None
TEST=manually test `cros_sdk` command.
CQ-DEPEND=CL:903665

Change-Id: I0b9c5710b138862b6e6fe284675beb2acb0c965c
Reviewed-on: https://chromium-review.googlesource.com/904922
Commit-Ready: Yong Hong <yhong@google.com>
Tested-by: Yong Hong <yhong@google.com>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
diff --git a/scripts/cros_sdk.py b/scripts/cros_sdk.py
index b2492a7..3bb0fc8 100644
--- a/scripts/cros_sdk.py
+++ b/scripts/cros_sdk.py
@@ -32,6 +32,7 @@
 from chromite.lib import locking
 from chromite.lib import namespaces
 from chromite.lib import osutils
+from chromite.lib import path_util
 from chromite.lib import process_util
 from chromite.lib import retry_util
 from chromite.lib import toolchain
@@ -245,7 +246,8 @@
 
 
 def EnterChroot(chroot_path, cache_dir, chrome_root, chrome_root_mount,
-                workspace, goma_dir, goma_client_json, additional_args):
+                workspace, goma_dir, goma_client_json, working_dir,
+                additional_args):
   """Enters an existing SDK chroot"""
   st = os.statvfs(os.path.join(chroot_path, 'usr', 'bin', 'sudo'))
   # The os.ST_NOSUID constant wasn't added until python-3.2.
@@ -263,6 +265,8 @@
     cmd.extend(['--goma_dir', goma_dir])
   if goma_client_json:
     cmd.extend(['--goma_client_json', goma_client_json])
+  if working_dir is not None:
+    cmd.extend(['--working_dir', working_dir])
 
   if len(additional_args) > 0:
     cmd.append('--')
@@ -751,6 +755,15 @@
   parser.add_argument('--goma_client_json', type='path',
                       help='Service account json file to use goma on bot. '
                            'Mounted into the chroot.')
+
+  # Use type=str instead of type='path' to prevent the given path from being
+  # transfered to absolute path automatically.
+  parser.add_argument('--working-dir', type=str,
+                      help='Run the command in specific working directory in '
+                           'chroot.  If the given directory is a relative '
+                           'path, this program will transfer the path to '
+                           'the corresponding one inside chroot.')
+
   parser.add_argument('commands', nargs=argparse.REMAINDER)
 
   # SDK overlay tarball options (mutually exclusive).
@@ -902,6 +915,9 @@
     parser.error("Trying to enter or snapshot the chroot when --delete "
                  "was specified makes no sense.")
 
+  if options.working_dir is not None and not os.path.isabs(options.working_dir):
+    options.working_dir = path_util.ToChrootPath(options.working_dir)
+
   # Clean up potential leftovers from previous interrupted builds.
   # TODO(bmgordon): Remove this at the end of 2017.  That should be long enough
   # to get rid of them all.
@@ -1160,4 +1176,4 @@
         EnterChroot(options.chroot, options.cache_dir, options.chrome_root,
                     options.chrome_root_mount, options.workspace,
                     options.goma_dir, options.goma_client_json,
-                    chroot_command)
+                    options.working_dir, chroot_command)