OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Provides an interface to communicate with the device via the adb command. | 5 """Provides an interface to communicate with the device via the adb command. |
6 | 6 |
7 Assumes adb binary is currently on system path. | 7 Assumes adb binary is currently on system path. |
8 """ | 8 """ |
9 | 9 |
10 import collections | 10 import collections |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 utc_delta = datetime.timedelta(hours=int(utc_offset[1:3]), | 165 utc_delta = datetime.timedelta(hours=int(utc_offset[1:3]), |
166 minutes=int(utc_offset[3:5])) | 166 minutes=int(utc_offset[3:5])) |
167 if utc_offset[0:1] == '-': | 167 if utc_offset[0:1] == '-': |
168 utc_delta = -utc_delta | 168 utc_delta = -utc_delta |
169 lastmod -= utc_delta | 169 lastmod -= utc_delta |
170 files[filename] = (int(file_match.group('size')), lastmod) | 170 files[filename] = (int(file_match.group('size')), lastmod) |
171 return files | 171 return files |
172 | 172 |
173 | 173 |
174 def _ComputeFileListHash(md5sum_output): | 174 def _ComputeFileListHash(md5sum_output): |
175 """Returns a list of MD5 strings from the provided md5sum output.""" | 175 """Returns a list of tuples from the provided md5sum output. |
176 return [line.split(' ')[0] for line in md5sum_output] | 176 |
| 177 Args: |
| 178 md5sum_output: output directly from md5sum binary. |
| 179 |
| 180 Returns: |
| 181 List of namedtuples (hash, path). |
| 182 """ |
| 183 HashAndPath = collections.namedtuple('HashAndPath', ['hash', 'path']) |
| 184 split_lines = [line.split(' ') for line in md5sum_output] |
| 185 assert all(len(s) == 2 for s in split_lines), 'Invalid md5sum output' |
| 186 return [HashAndPath._make(s) for s in split_lines] |
177 | 187 |
178 | 188 |
179 def _HasAdbPushSucceeded(command_output): | 189 def _HasAdbPushSucceeded(command_output): |
180 """Returns whether adb push has succeeded from the provided output.""" | 190 """Returns whether adb push has succeeded from the provided output.""" |
181 # TODO(frankf): We should look at the return code instead of the command | 191 # TODO(frankf): We should look at the return code instead of the command |
182 # output for many of the commands in this file. | 192 # output for many of the commands in this file. |
183 if not command_output: | 193 if not command_output: |
184 return True | 194 return True |
185 # Success looks like this: "3035 KB/s (12512056 bytes in 4.025s)" | 195 # Success looks like this: "3035 KB/s (12512056 bytes in 4.025s)" |
186 # Errors look like this: "failed to copy ... " | 196 # Errors look like this: "failed to copy ... " |
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
720 if not os.path.exists(md5sum_dist_path): | 730 if not os.path.exists(md5sum_dist_path): |
721 build_dir = '%s/Release/' % cmd_helper.OutDirectory().get() | 731 build_dir = '%s/Release/' % cmd_helper.OutDirectory().get() |
722 md5sum_dist_path = '%s/md5sum_dist' % build_dir | 732 md5sum_dist_path = '%s/md5sum_dist' % build_dir |
723 assert os.path.exists(md5sum_dist_path), 'Please build md5sum.' | 733 assert os.path.exists(md5sum_dist_path), 'Please build md5sum.' |
724 command = 'push %s %s' % (md5sum_dist_path, MD5SUM_DEVICE_FOLDER) | 734 command = 'push %s %s' % (md5sum_dist_path, MD5SUM_DEVICE_FOLDER) |
725 assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) | 735 assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) |
726 self._md5sum_build_dir = build_dir | 736 self._md5sum_build_dir = build_dir |
727 | 737 |
728 cmd = (MD5SUM_LD_LIBRARY_PATH + ' ' + self._util_wrapper + ' ' + | 738 cmd = (MD5SUM_LD_LIBRARY_PATH + ' ' + self._util_wrapper + ' ' + |
729 MD5SUM_DEVICE_PATH + ' ' + device_path) | 739 MD5SUM_DEVICE_PATH + ' ' + device_path) |
730 hashes_on_device = _ComputeFileListHash( | 740 device_hash_tuples = _ComputeFileListHash( |
731 self.RunShellCommand(cmd, timeout_time=2 * 60)) | 741 self.RunShellCommand(cmd, timeout_time=2 * 60)) |
732 assert os.path.exists(local_path), 'Local path not found %s' % local_path | 742 assert os.path.exists(local_path), 'Local path not found %s' % local_path |
733 md5sum_output = cmd_helper.GetCmdOutput( | 743 md5sum_output = cmd_helper.GetCmdOutput( |
734 ['%s/md5sum_bin_host' % self._md5sum_build_dir, local_path]) | 744 ['%s/md5sum_bin_host' % self._md5sum_build_dir, local_path]) |
735 hashes_on_host = _ComputeFileListHash(md5sum_output.splitlines()) | 745 host_hash_tuples = _ComputeFileListHash(md5sum_output.splitlines()) |
736 | 746 |
737 if ignore_paths: | 747 # Ignore extra files on the device. |
738 hashes_on_device = [h.split()[0] for h in hashes_on_device] | 748 if len(device_hash_tuples) > len(host_hash_tuples): |
739 hashes_on_host = [h.split()[0] for h in hashes_on_host] | 749 host_files = [os.path.relpath(os.path.normpath(p.path), |
| 750 os.path.normpath(local_path)) for p in host_hash_tuples] |
740 | 751 |
| 752 def _host_has(fname): |
| 753 return any(path in fname for path in host_files) |
| 754 |
| 755 hashes_on_device = [h.hash for h in device_hash_tuples if |
| 756 _host_has(h.path)] |
| 757 else: |
| 758 hashes_on_device = [h.hash for h in device_hash_tuples] |
| 759 |
| 760 # Compare md5sums between host and device files. |
| 761 hashes_on_host = [h.hash for h in host_hash_tuples] |
| 762 hashes_on_device.sort() |
| 763 hashes_on_host.sort() |
741 return hashes_on_device == hashes_on_host | 764 return hashes_on_device == hashes_on_host |
742 | 765 |
743 def PushIfNeeded(self, local_path, device_path): | 766 def PushIfNeeded(self, local_path, device_path): |
744 """Pushes |local_path| to |device_path|. | 767 """Pushes |local_path| to |device_path|. |
745 | 768 |
746 Works for files and directories. This method skips copying any paths in | 769 Works for files and directories. This method skips copying any paths in |
747 |test_data_paths| that already exist on the device with the same hash. | 770 |test_data_paths| that already exist on the device with the same hash. |
748 | 771 |
749 All pushed files can be removed by calling RemovePushedFiles(). | 772 All pushed files can be removed by calling RemovePushedFiles(). |
750 """ | 773 """ |
(...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1368 """ | 1391 """ |
1369 def __init__(self, output): | 1392 def __init__(self, output): |
1370 self._output = output | 1393 self._output = output |
1371 | 1394 |
1372 def write(self, data): | 1395 def write(self, data): |
1373 data = data.replace('\r\r\n', '\n') | 1396 data = data.replace('\r\r\n', '\n') |
1374 self._output.write(data) | 1397 self._output.write(data) |
1375 | 1398 |
1376 def flush(self): | 1399 def flush(self): |
1377 self._output.flush() | 1400 self._output.flush() |
OLD | NEW |