Chromium Code Reviews| Index: build/android/pylib/android_commands.py |
| diff --git a/build/android/pylib/android_commands.py b/build/android/pylib/android_commands.py |
| index 4cf070d0711a9626edf1ba6eae35efe0f7bb7e40..b9cb085cad1d21095edb3e3480daa88d45d7a818 100644 |
| --- a/build/android/pylib/android_commands.py |
| +++ b/build/android/pylib/android_commands.py |
| @@ -738,15 +738,16 @@ class AndroidCommands(object): |
| """ |
| self.RunShellCommand('input keyevent %d' % keycode) |
| - def CheckMd5Sum(self, local_path, device_path): |
| - """Compares the md5sum of a local path against a device path. |
| + def _RunMd5Sum(self, host_path, device_path): |
|
frankf
2013/08/06 00:17:23
Why not inline this in GetFilesChanged?
craigdh
2013/08/06 21:17:29
Could, this seems reusable and keeps the functions
|
| + """Gets the md5sum of a host path and device path. |
| Args: |
| - local_path: Path (file or directory) on the host. |
| + host_path: Path (file or directory) on the host. |
| device_path: Path on the device. |
| Returns: |
| - True if the md5sums match. |
| + A tuple containing lists of the host and device md5sum results as |
| + created by _ComputeFileListHash(). |
| """ |
| if not self._md5sum_build_dir: |
| default_build_type = os.environ.get('BUILD_TYPE', 'Debug') |
| @@ -765,71 +766,122 @@ class AndroidCommands(object): |
| MD5SUM_DEVICE_PATH + ' ' + device_path) |
| device_hash_tuples = _ComputeFileListHash( |
| self.RunShellCommand(cmd, timeout_time=2 * 60)) |
| - assert os.path.exists(local_path), 'Local path not found %s' % local_path |
| + assert os.path.exists(host_path), 'Local path not found %s' % host_path |
| md5sum_output = cmd_helper.GetCmdOutput( |
| - ['%s/md5sum_bin_host' % self._md5sum_build_dir, local_path]) |
| + ['%s/md5sum_bin_host' % self._md5sum_build_dir, host_path]) |
| host_hash_tuples = _ComputeFileListHash(md5sum_output.splitlines()) |
| + return (host_hash_tuples, device_hash_tuples) |
| + |
| + def GetFilesChanged(self, host_path, device_path): |
| + """Compares the md5sum of a host path against a device path. |
| + |
| + Note: Ignores extra files on the device. |
| + |
| + Args: |
| + host_path: Path (file or directory) on the host. |
| + device_path: Path on the device. |
| + |
| + Returns: |
| + A list of tuples of the form (host_path, device_path) for files whose |
| + md5sums do not match. |
| + """ |
| + host_hash_tuples, device_hash_tuples = self._RunMd5Sum( |
| + host_path, device_path) |
| # Ignore extra files on the device. |
| if len(device_hash_tuples) > len(host_hash_tuples): |
| host_files = [os.path.relpath(os.path.normpath(p.path), |
| - os.path.normpath(local_path)) for p in host_hash_tuples] |
| + os.path.normpath(host_path)) for p in host_hash_tuples] |
| - def _host_has(fname): |
| + def HostHas(fname): |
| return any(path in fname for path in host_files) |
| - hashes_on_device = [h.hash for h in device_hash_tuples if |
| - _host_has(h.path)] |
| - else: |
| - hashes_on_device = [h.hash for h in device_hash_tuples] |
| + device_hash_tuples = [h for h in device_hash_tuples if HostHas(h.path)] |
| - # Compare md5sums between host and device files. |
| - hashes_on_host = [h.hash for h in host_hash_tuples] |
| - hashes_on_device.sort() |
| - hashes_on_host.sort() |
| - return hashes_on_device == hashes_on_host |
| + # Constructs the target device path from a given host path. Don't use when |
| + # only a single file is given as the base name given in device_path may |
| + # differ from that in host_path. |
| + def HostToDevicePath(host_path): |
| + return os.path.join(os.path.dirname(device_path), os.path.relpath( |
| + host_path, os.path.dirname(os.path.normpath(host_path)))) |
| - def PushIfNeeded(self, local_path, device_path): |
| - """Pushes |local_path| to |device_path|. |
| + device_hashes = [h.hash for h in device_hash_tuples] |
| + return [(t.path, HostToDevicePath(t.path) if os.path.isdir(host_path) else |
| + device_path) |
| + for t in host_hash_tuples if t.hash not in device_hashes] |
| + |
| + def CheckMd5Sum(self, host_path, device_path): |
|
frankf
2013/08/06 00:17:23
Can you get rid of this and just call GetFilesChan
craigdh
2013/08/06 21:17:29
Done.
|
| + """Compares the md5sum of a host path against a device path. |
| + |
| + Args: |
| + host_path: Path (file or directory) on the host. |
| + device_path: Path on the device. |
| + |
| + Returns: |
| + True if the md5sums match. |
| + """ |
| + return not self.GetFilesChanged(host_path, device_path) |
| + |
| + def PushIfNeeded(self, host_path, device_path): |
| + """Pushes |host_path| to |device_path|. |
| Works for files and directories. This method skips copying any paths in |
| |test_data_paths| that already exist on the device with the same hash. |
| All pushed files can be removed by calling RemovePushedFiles(). |
| """ |
| - assert os.path.exists(local_path), 'Local path not found %s' % local_path |
| - size = int(cmd_helper.GetCmdOutput(['du', '-sb', local_path]).split()[0]) |
| + MAX_INDIVIDUAL_PUSHES = 50 |
| + assert os.path.exists(host_path), 'Local path not found %s' % host_path |
| + |
| + def GetHostSize(path): |
| + return int(cmd_helper.GetCmdOutput(['du', '-sb', path]).split()[0]) |
| + |
| + size = GetHostSize(host_path) |
| self._pushed_files.append(device_path) |
| self._potential_push_size += size |
| - if self.CheckMd5Sum(local_path, device_path): |
| + missing_files = self.GetFilesChanged(host_path, device_path) |
|
frankf
2013/08/06 00:17:23
this is misleading -> changed_files
craigdh
2013/08/06 21:17:29
Done.
|
| + if not missing_files: |
| return |
| - self._actual_push_size += size |
| - # They don't match, so remove everything first and then create it. |
| - if os.path.isdir(local_path): |
| - self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60) |
| - self.RunShellCommand('mkdir -p %s' % device_path) |
| - |
| - # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of |
| - # 60 seconds which isn't sufficient for a lot of users of this method. |
| - push_command = 'push %s %s' % (local_path, device_path) |
| - self._LogShell(push_command) |
| - |
| - # Retry push with increasing backoff if the device is busy. |
| - retry = 0 |
| - while True: |
| - output = self._adb.SendCommand(push_command, timeout_time=30 * 60) |
| - if _HasAdbPushSucceeded(output): |
| - return |
| - if 'resource busy' in output and retry < 3: |
| - retry += 1 |
| - wait_time = 5 * retry |
| - logging.error('Push failed, retrying in %d seconds: %s' % |
| - (wait_time, output)) |
| - time.sleep(wait_time) |
| - else: |
| - raise Exception('Push failed: %s' % output) |
| + def Push(host, device): |
| + # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout |
| + # of 60 seconds which isn't sufficient for a lot of users of this method. |
| + push_command = 'push %s %s' % (host, device) |
| + self._LogShell(push_command) |
| + |
| + # Retry push with increasing backoff if the device is busy. |
| + retry = 0 |
| + while True: |
| + output = self._adb.SendCommand(push_command, timeout_time=30 * 60) |
| + if _HasAdbPushSucceeded(output): |
| + return |
| + if 'resource busy' in output and retry < 3: |
| + retry += 1 |
| + wait_time = 5 * retry |
| + logging.error('Push failed, retrying in %d seconds: %s' % |
| + (wait_time, output)) |
| + time.sleep(wait_time) |
| + else: |
| + raise Exception('Push failed: %s' % output) |
| + |
| + diff_size = 0 |
| + if len(missing_files) <= MAX_INDIVIDUAL_PUSHES: |
| + diff_size = sum(GetHostSize(f[0]) for f in missing_files) |
| + |
| + # TODO(craigdh): Replace this educated guess with a heuristic that |
| + # approximates the push time for each method. |
|
frankf
2013/08/06 00:17:23
Can you look how adb sync operates: https://androi
craigdh
2013/08/06 21:17:29
Seems to just compare the timestamps. From what I
|
| + if len(missing_files) > MAX_INDIVIDUAL_PUSHES or diff_size > 0.5 * size: |
| + # We're pushing everything, remove everything first and then create it. |
| + self._actual_push_size += size |
| + if os.path.isdir(host_path): |
| + self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60) |
| + self.RunShellCommand('mkdir -p %s' % device_path) |
| + Push(host_path, device_path) |
| + else: |
| + for f in missing_files: |
| + Push(f[0], f[1]) |
| + self._actual_push_size += diff_size |
| def GetPushSizeInfo(self): |
| """Get total size of pushes to the device done via PushIfNeeded() |