Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Side by Side Diff: build/android/pylib/android_commands.py

Issue 21307002: [android] Push only updated files in PushIfNeeded when few files have changed. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix issue when pushing a single file with a different destination name Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 720 matching lines...) Expand 10 before | Expand all | Expand 10 after
731 self.RunShellCommand('pm clear ' + package) 731 self.RunShellCommand('pm clear ' + package)
732 732
733 def SendKeyEvent(self, keycode): 733 def SendKeyEvent(self, keycode):
734 """Sends keycode to the device. 734 """Sends keycode to the device.
735 735
736 Args: 736 Args:
737 keycode: Numeric keycode to send (see "enum" at top of file). 737 keycode: Numeric keycode to send (see "enum" at top of file).
738 """ 738 """
739 self.RunShellCommand('input keyevent %d' % keycode) 739 self.RunShellCommand('input keyevent %d' % keycode)
740 740
741 def CheckMd5Sum(self, local_path, device_path): 741 def _RunMd5Sum(self, local_path, device_path):
742 """Compares the md5sum of a local path against a device path. 742 """Gets the md5sum of a local path and device path.
743 743
744 Args: 744 Args:
745 local_path: Path (file or directory) on the host. 745 local_path: Path (file or directory) on the host.
746 device_path: Path on the device. 746 device_path: Path on the device.
747 747
748 Returns: 748 Returns:
749 True if the md5sums match. 749 A tuple containing lists of the local and device md5sum results.
frankf 2013/07/31 22:58:19 Define exactly what tuple is.
craigdh 2013/08/05 23:55:43 Done.
750 """ 750 """
751 if not self._md5sum_build_dir: 751 if not self._md5sum_build_dir:
752 default_build_type = os.environ.get('BUILD_TYPE', 'Debug') 752 default_build_type = os.environ.get('BUILD_TYPE', 'Debug')
753 build_dir = '%s/%s/' % ( 753 build_dir = '%s/%s/' % (
754 cmd_helper.OutDirectory().get(), default_build_type) 754 cmd_helper.OutDirectory().get(), default_build_type)
755 md5sum_dist_path = '%s/md5sum_dist' % build_dir 755 md5sum_dist_path = '%s/md5sum_dist' % build_dir
756 if not os.path.exists(md5sum_dist_path): 756 if not os.path.exists(md5sum_dist_path):
757 build_dir = '%s/Release/' % cmd_helper.OutDirectory().get() 757 build_dir = '%s/Release/' % cmd_helper.OutDirectory().get()
758 md5sum_dist_path = '%s/md5sum_dist' % build_dir 758 md5sum_dist_path = '%s/md5sum_dist' % build_dir
759 assert os.path.exists(md5sum_dist_path), 'Please build md5sum.' 759 assert os.path.exists(md5sum_dist_path), 'Please build md5sum.'
760 command = 'push %s %s' % (md5sum_dist_path, MD5SUM_DEVICE_FOLDER) 760 command = 'push %s %s' % (md5sum_dist_path, MD5SUM_DEVICE_FOLDER)
761 assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) 761 assert _HasAdbPushSucceeded(self._adb.SendCommand(command))
762 self._md5sum_build_dir = build_dir 762 self._md5sum_build_dir = build_dir
763 763
764 cmd = (MD5SUM_LD_LIBRARY_PATH + ' ' + self._util_wrapper + ' ' + 764 cmd = (MD5SUM_LD_LIBRARY_PATH + ' ' + self._util_wrapper + ' ' +
765 MD5SUM_DEVICE_PATH + ' ' + device_path) 765 MD5SUM_DEVICE_PATH + ' ' + device_path)
766 device_hash_tuples = _ComputeFileListHash( 766 device_hash_tuples = _ComputeFileListHash(
767 self.RunShellCommand(cmd, timeout_time=2 * 60)) 767 self.RunShellCommand(cmd, timeout_time=2 * 60))
768 assert os.path.exists(local_path), 'Local path not found %s' % local_path 768 assert os.path.exists(local_path), 'Local path not found %s' % local_path
769 md5sum_output = cmd_helper.GetCmdOutput( 769 md5sum_output = cmd_helper.GetCmdOutput(
770 ['%s/md5sum_bin_host' % self._md5sum_build_dir, local_path]) 770 ['%s/md5sum_bin_host' % self._md5sum_build_dir, local_path])
771 host_hash_tuples = _ComputeFileListHash(md5sum_output.splitlines()) 771 host_hash_tuples = _ComputeFileListHash(md5sum_output.splitlines())
772 return (host_hash_tuples, device_hash_tuples)
773
774 def GetFileDiff(self, local_path, device_path):
frankf 2013/07/31 22:58:19 GetFileDiff -> GetFilesChanged
craigdh 2013/08/05 23:55:43 Done.
775 """Compares the md5sum of a local path against a device path.
776
777 Note: Ignores extra files on the device.
778
779 Args:
780 local_path: Path (file or directory) on the host.
781 device_path: Path on the device.
782
783 Returns:
784 A list of files whose md5sums do not match.
785 """
786 host_hash_tuples, device_hash_tuples = self._RunMd5Sum(
787 local_path, device_path)
772 788
773 # Ignore extra files on the device. 789 # Ignore extra files on the device.
774 if len(device_hash_tuples) > len(host_hash_tuples): 790 if len(device_hash_tuples) > len(host_hash_tuples):
775 host_files = [os.path.relpath(os.path.normpath(p.path), 791 host_files = [os.path.relpath(os.path.normpath(p.path),
776 os.path.normpath(local_path)) for p in host_hash_tuples] 792 os.path.normpath(local_path)) for p in host_hash_tuples]
777 793
778 def _host_has(fname): 794 def _host_has(fname):
frankf 2013/07/31 22:58:19 naming issue
craigdh 2013/08/05 23:55:43 Done.
779 return any(path in fname for path in host_files) 795 return any(path in fname for path in host_files)
780 796
781 hashes_on_device = [h.hash for h in device_hash_tuples if 797 device_hash_tuples = [h for h in device_hash_tuples if _host_has(h.path)]
782 _host_has(h.path)]
783 else:
784 hashes_on_device = [h.hash for h in device_hash_tuples]
785 798
786 # Compare md5sums between host and device files. 799 # Constructs the target device path from a given host path. Don't use when
787 hashes_on_host = [h.hash for h in host_hash_tuples] 800 # only a single file is given as the device_path may specify a rename.
frankf 2013/07/31 22:58:19 What rename?
craigdh 2013/08/05 23:55:43 If the local_path and device_path refer to a file
788 hashes_on_device.sort() 801 def _h2d_path(host_path):
frankf 2013/07/31 22:58:19 Use our naming convention
craigdh 2013/08/05 23:55:43 Done.
789 hashes_on_host.sort() 802 return os.path.join(os.path.dirname(device_path), os.path.relpath(
790 return hashes_on_device == hashes_on_host 803 host_path, os.path.dirname(os.path.normpath(local_path))))
804
805 device_hashes = [h.hash for h in device_hash_tuples]
806 return [(t.path,
807 _h2d_path(t.path) if os.path.isdir(local_path) else device_path)
frankf 2013/07/31 22:58:19 You're returning a list of tuples, this doesn't ma
craigdh 2013/08/05 23:55:43 Done.
808 for t in host_hash_tuples if t.hash not in device_hashes]
809
810 def CheckMd5Sum(self, local_path, device_path):
811 """Compares the md5sum of a local path against a device path.
812
813 Args:
814 local_path: Path (file or directory) on the host.
815 device_path: Path on the device.
816
817 Returns:
818 True if the md5sums match.
819 """
820 return not self.GetFileDiff(local_path, device_path)
791 821
792 def PushIfNeeded(self, local_path, device_path): 822 def PushIfNeeded(self, local_path, device_path):
793 """Pushes |local_path| to |device_path|. 823 """Pushes |local_path| to |device_path|.
frankf 2013/07/31 22:58:19 rename local to host everywhere
craigdh 2013/08/05 23:55:43 Done.
794 824
795 Works for files and directories. This method skips copying any paths in 825 Works for files and directories. This method skips copying any paths in
796 |test_data_paths| that already exist on the device with the same hash. 826 |test_data_paths| that already exist on the device with the same hash.
797 827
798 All pushed files can be removed by calling RemovePushedFiles(). 828 All pushed files can be removed by calling RemovePushedFiles().
799 """ 829 """
800 assert os.path.exists(local_path), 'Local path not found %s' % local_path 830 assert os.path.exists(local_path), 'Local path not found %s' % local_path
801 size = int(cmd_helper.GetCmdOutput(['du', '-sb', local_path]).split()[0]) 831
832 def _get_local_size(path):
833 return int(cmd_helper.GetCmdOutput(['du', '-sb', path]).split()[0])
834
835 size = _get_local_size(local_path)
802 self._pushed_files.append(device_path) 836 self._pushed_files.append(device_path)
803 self._potential_push_size += size 837 self._potential_push_size += size
804 838
805 if self.CheckMd5Sum(local_path, device_path): 839 missing_files = self.GetFileDiff(local_path, device_path)
840 if not missing_files:
806 return 841 return
807 842
808 self._actual_push_size += size 843 def _push(local, device):
frankf 2013/07/31 22:58:19 Naming
craigdh 2013/08/05 23:55:43 Done.
809 # They don't match, so remove everything first and then create it. 844 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout
810 if os.path.isdir(local_path): 845 # of 60 seconds which isn't sufficient for a lot of users of this method.
811 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60) 846 push_command = 'push %s %s' % (local, device)
812 self.RunShellCommand('mkdir -p %s' % device_path) 847 self._LogShell(push_command)
813 848
814 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of 849 # Retry push with increasing backoff if the device is busy.
815 # 60 seconds which isn't sufficient for a lot of users of this method. 850 retry = 0
816 push_command = 'push %s %s' % (local_path, device_path) 851 while True:
817 self._LogShell(push_command) 852 output = self._adb.SendCommand(push_command, timeout_time=30 * 60)
853 if _HasAdbPushSucceeded(output):
854 return
855 if 'resource busy' in output and retry < 3:
856 retry += 1
857 wait_time = 5 * retry
858 logging.error('Push failed, retrying in %d seconds: %s' %
859 (wait_time, output))
860 time.sleep(wait_time)
861 else:
862 raise Exception('Push failed: %s' % output)
818 863
819 # Retry push with increasing backoff if the device is busy. 864 # Above a small number of files it's likely faster to push everything.
820 retry = 0 865 if len(missing_files) > 20:
frankf 2013/07/31 22:58:19 This is very arbitrary. Why number of files instea
craigdh 2013/08/05 23:55:43 Based on size for now with a cutoff and added a TO
821 while True: 866 # We're pushing everything, remove everything first and then create it.
822 output = self._adb.SendCommand(push_command, timeout_time=30 * 60) 867 self._actual_push_size += size
823 if _HasAdbPushSucceeded(output): 868 if os.path.isdir(local_path):
824 return 869 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60)
825 if 'resource busy' in output and retry < 3: 870 self.RunShellCommand('mkdir -p %s' % device_path)
826 retry += 1 871 _push(local_path, device_path)
827 wait_time = 5 * retry 872 else:
828 logging.error('Push failed, retrying in %d seconds: %s' % 873 for f in missing_files:
829 (wait_time, output)) 874 self._actual_push_size += _get_local_size(f[0])
830 time.sleep(wait_time) 875 _push(f[0], f[1])
831 else:
832 raise Exception('Push failed: %s' % output)
833 876
834 def GetPushSizeInfo(self): 877 def GetPushSizeInfo(self):
835 """Get total size of pushes to the device done via PushIfNeeded() 878 """Get total size of pushes to the device done via PushIfNeeded()
836 879
837 Returns: 880 Returns:
838 A tuple: 881 A tuple:
839 1. Total size of push requests to PushIfNeeded (MB) 882 1. Total size of push requests to PushIfNeeded (MB)
840 2. Total size that was actually pushed (MB) 883 2. Total size that was actually pushed (MB)
841 """ 884 """
842 return (self._potential_push_size, self._actual_push_size) 885 return (self._potential_push_size, self._actual_push_size)
(...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after
1472 """ 1515 """
1473 def __init__(self, output): 1516 def __init__(self, output):
1474 self._output = output 1517 self._output = output
1475 1518
1476 def write(self, data): 1519 def write(self, data):
1477 data = data.replace('\r\r\n', '\n') 1520 data = data.replace('\r\r\n', '\n')
1478 self._output.write(data) 1521 self._output.write(data)
1479 1522
1480 def flush(self): 1523 def flush(self):
1481 self._output.flush() 1524 self._output.flush()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698