cros deploy: optimize installed package check further

Our desktops are most likely faster than the DUT, so cat the bzip2
data locally and decompress it here.

BUG=None
TEST=`cros deploy` with uninstalled & installed packages still work

Change-Id: I835981e0c41445749a0d74d2afb88887d7f06281
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/2653782
Reviewed-by: Jae Hoon Kim <kimjae@chromium.org>
Tested-by: Mike Frysinger <vapier@chromium.org>
Commit-Queue: Mike Frysinger <vapier@chromium.org>
diff --git a/cli/deploy.py b/cli/deploy.py
index 9f04443..4def3ac 100644
--- a/cli/deploy.py
+++ b/cli/deploy.py
@@ -1073,21 +1073,20 @@
   if from_dut:
     # On DUT, |pkg_path| is the directory which contains environment file.
     environment_path = os.path.join(pkg_path, _ENVIRONMENT_FILENAME)
-    result = device.run(['bzip2', '-d', '-c', environment_path], check=False,
-                        encoding=None)
-    if result.returncode:
+    try:
+      environment_data = device.CatFile(
+          environment_path, max_size=None, encoding=None)
+    except remote_access.CatFileError:
       # The package is not installed on DUT yet. Skip extracting info.
-      if not result.stdout and b'No such file or directory' in result.stderr:
-        return None, None
-      result.check_returncode()
-    environment_content = result.output
+      return None, None
   else:
     # On host, pkg_path is tbz2 file which contains environment file.
     # Extract the metadata of the package file.
     data = portage.xpak.tbz2(pkg_path).get_data()
-    # Extract the environment metadata.
-    environment_content = bz2.decompress(
-        data[_ENVIRONMENT_FILENAME.encode('utf-8')])
+    environment_data = data[_ENVIRONMENT_FILENAME.encode('utf-8')]
+
+  # Extract the environment metadata.
+  environment_content = bz2.decompress(environment_data)
 
   with tempfile.NamedTemporaryFile() as f:
     # Dumps content into a file so we can use osutils.SourceEnvironment.
diff --git a/lib/remote_access.py b/lib/remote_access.py
index f8461f0..4699de1 100644
--- a/lib/remote_access.py
+++ b/lib/remote_access.py
@@ -1039,13 +1039,14 @@
     result = self.BaseRunCommand(cmd, remote_sudo=True, capture_output=True)
     return int(result.output.split()[0])
 
-  def CatFile(self, path, max_size=1000000):
+  def CatFile(self, path, max_size=1000000, encoding='utf-8'):
     """Reads the file on device to string if its size is less than |max_size|.
 
     Args:
       path: The full path to the file on the device to read.
       max_size: Read the file only if its size is less than |max_size| in bytes.
         If None, do not check its size and always cat the path.
+      encoding: Encoding for return value.  Use None to get bytes.
 
     Returns:
       A string of the file content.
@@ -1063,8 +1064,8 @@
         raise CatFileError('File "%s" is larger than %d bytes' %
                            (path, max_size))
 
-    result = self.BaseRunCommand(['cat', path], remote_sudo=True,
-                                 check=False, capture_output=True)
+    result = self.base_run(['cat', path], remote_sudo=True, check=False,
+                           capture_output=True, encoding=encoding)
     if result.returncode:
       raise CatFileError('Failed to read file "%s" on the device' % path)
     return result.output