Loading adb/commandline.cpp +13 −8 Original line number Diff line number Diff line Loading @@ -126,8 +126,9 @@ static void help() { " reverse --remove-all remove all reverse socket connections from device\n" "\n" "file transfer:\n" " push LOCAL... REMOTE\n" " push [--sync] LOCAL... REMOTE\n" " copy local files/directories to device\n" " --sync: only push files that are newer on the host than the device\n" " pull [-a] REMOTE... LOCAL\n" " copy files/dirs from device\n" " -a: preserve file timestamp and mode\n" Loading Loading @@ -1233,9 +1234,8 @@ static int restore(int argc, const char** argv) { return 0; } static void parse_push_pull_args(const char** arg, int narg, std::vector<const char*>* srcs, const char** dst, bool* copy_attrs) { static void parse_push_pull_args(const char** arg, int narg, std::vector<const char*>* srcs, const char** dst, bool* copy_attrs, bool* sync) { *copy_attrs = false; srcs->clear(); Loading @@ -1248,6 +1248,10 @@ static void parse_push_pull_args(const char** arg, int narg, // Silently ignore for backwards compatibility. } else if (!strcmp(*arg, "-a")) { *copy_attrs = true; } else if (!strcmp(*arg, "--sync")) { if (sync != nullptr) { *sync = true; } } else if (!strcmp(*arg, "--")) { ignore_flags = true; } else { Loading Loading @@ -1654,19 +1658,20 @@ int adb_commandline(int argc, const char** argv) { } else if (!strcmp(argv[0], "push")) { bool copy_attrs = false; bool sync = false; std::vector<const char*> srcs; const char* dst = nullptr; parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs); parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, &sync); if (srcs.empty() || !dst) return syntax_error("push requires an argument"); return do_sync_push(srcs, dst) ? 0 : 1; return do_sync_push(srcs, dst, sync) ? 0 : 1; } else if (!strcmp(argv[0], "pull")) { bool copy_attrs = false; std::vector<const char*> srcs; const char* dst = "."; parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs); parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, nullptr); if (srcs.empty()) return syntax_error("pull requires an argument"); return do_sync_pull(srcs, dst, copy_attrs) ? 0 : 1; } Loading Loading @@ -2086,7 +2091,7 @@ static int install_app_legacy(TransportType transport, const char* serial, int a std::vector<const char*> apk_file = {argv[last_apk]}; std::string apk_dest = android::base::StringPrintf( where, android::base::Basename(argv[last_apk]).c_str()); if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk; if (!do_sync_push(apk_file, apk_dest.c_str(), false)) goto cleanup_apk; argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */ result = pm_command(transport, serial, argc, argv); Loading adb/file_sync_client.cpp +18 −7 Original line number Diff line number Diff line Loading @@ -674,11 +674,22 @@ static bool sync_stat_fallback(SyncConnection& sc, const char* path, struct stat return true; } static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, unsigned mtime, mode_t mode) { static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, unsigned mtime, mode_t mode, bool sync) { std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode); if (sync) { struct stat st; if (sync_lstat(sc, rpath, &st)) { // For links, we cannot update the atime/mtime. if ((S_ISREG(mode & st.st_mode) && st.st_mtime == static_cast<time_t>(mtime)) || (S_ISLNK(mode & st.st_mode) && st.st_mtime >= static_cast<time_t>(mtime))) { sc.RecordFilesSkipped(1); return true; } } } if (S_ISLNK(mode)) { #if !defined(_WIN32) char buf[PATH_MAX]; Loading Loading @@ -902,7 +913,7 @@ static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath, if (list_only) { sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str()); } else { if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode)) { if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode, false)) { return false; } } Loading @@ -916,7 +927,7 @@ static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath, return true; } bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync) { SyncConnection sc; if (!sc.IsValid()) return false; Loading Loading @@ -981,7 +992,7 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { dst_dir.append(android::base::Basename(src_path)); } success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), false, false); success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), sync, false); continue; } else if (!should_push_file(st.st_mode)) { sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode); Loading @@ -1002,7 +1013,7 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { sc.NewTransfer(); sc.SetExpectedTotalBytes(st.st_size); success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode); success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode, sync); sc.ReportTransferRate(src_path, TransferDirection::push); } Loading adb/file_sync_service.h +1 −1 Original line number Diff line number Diff line Loading @@ -81,7 +81,7 @@ union syncmsg { void file_sync_service(int fd, void* cookie); bool do_sync_ls(const char* path); bool do_sync_push(const std::vector<const char*>& srcs, const char* dst); bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync); bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs, const char* name=nullptr); Loading adb/test_device.py +38 −11 Original line number Diff line number Diff line Loading @@ -1130,8 +1130,18 @@ class FileOperationsTest(DeviceTest): if host_dir is not None: shutil.rmtree(host_dir) def verify_sync(self, device, temp_files, device_dir): """Verifies that a list of temp files was synced to the device.""" # Confirm that every file on the device mirrors that on the host. for temp_file in temp_files: device_full_path = posixpath.join( device_dir, temp_file.base_name) dev_md5, _ = device.shell( [get_md5_prog(self.device), device_full_path])[0].split() self.assertEqual(temp_file.checksum, dev_md5) def test_sync(self): """Sync a randomly generated directory of files to specified device.""" """Sync a host directory to the data partition.""" try: base_dir = tempfile.mkdtemp() Loading @@ -1141,9 +1151,10 @@ class FileOperationsTest(DeviceTest): os.makedirs(full_dir_path) # Create 32 random files within the host mirror. temp_files = make_random_host_files(in_dir=full_dir_path, num_files=32) temp_files = make_random_host_files( in_dir=full_dir_path, num_files=32) # Clean up any trash on the device. # Clean up any stale files on the device. device = adb.get_device() # pylint: disable=no-member device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) Loading @@ -1155,19 +1166,35 @@ class FileOperationsTest(DeviceTest): else: os.environ['ANDROID_PRODUCT_OUT'] = old_product_out # Confirm that every file on the device mirrors that on the host. for temp_file in temp_files: device_full_path = posixpath.join(self.DEVICE_TEMP_DIR, temp_file.base_name) dev_md5, _ = device.shell( [get_md5_prog(self.device), device_full_path])[0].split() self.assertEqual(temp_file.checksum, dev_md5) self.verify_sync(device, temp_files, self.DEVICE_TEMP_DIR) self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) #self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) finally: if base_dir is not None: shutil.rmtree(base_dir) def test_push_sync(self): """Sync a host directory to a specific path.""" try: temp_dir = tempfile.mkdtemp() temp_files = make_random_host_files(in_dir=temp_dir, num_files=32) device_dir = posixpath.join(self.DEVICE_TEMP_DIR, 'sync_src_dst') # Clean up any stale files on the device. device = adb.get_device() # pylint: disable=no-member device.shell(['rm', '-rf', device_dir]) device.push(temp_dir, device_dir, sync=True) self.verify_sync(device, temp_files, device_dir) self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) finally: if temp_dir is not None: shutil.rmtree(temp_dir) def test_unicode_paths(self): """Ensure that we can support non-ASCII paths, even on Windows.""" name = u'로보카 폴리' Loading Loading
adb/commandline.cpp +13 −8 Original line number Diff line number Diff line Loading @@ -126,8 +126,9 @@ static void help() { " reverse --remove-all remove all reverse socket connections from device\n" "\n" "file transfer:\n" " push LOCAL... REMOTE\n" " push [--sync] LOCAL... REMOTE\n" " copy local files/directories to device\n" " --sync: only push files that are newer on the host than the device\n" " pull [-a] REMOTE... LOCAL\n" " copy files/dirs from device\n" " -a: preserve file timestamp and mode\n" Loading Loading @@ -1233,9 +1234,8 @@ static int restore(int argc, const char** argv) { return 0; } static void parse_push_pull_args(const char** arg, int narg, std::vector<const char*>* srcs, const char** dst, bool* copy_attrs) { static void parse_push_pull_args(const char** arg, int narg, std::vector<const char*>* srcs, const char** dst, bool* copy_attrs, bool* sync) { *copy_attrs = false; srcs->clear(); Loading @@ -1248,6 +1248,10 @@ static void parse_push_pull_args(const char** arg, int narg, // Silently ignore for backwards compatibility. } else if (!strcmp(*arg, "-a")) { *copy_attrs = true; } else if (!strcmp(*arg, "--sync")) { if (sync != nullptr) { *sync = true; } } else if (!strcmp(*arg, "--")) { ignore_flags = true; } else { Loading Loading @@ -1654,19 +1658,20 @@ int adb_commandline(int argc, const char** argv) { } else if (!strcmp(argv[0], "push")) { bool copy_attrs = false; bool sync = false; std::vector<const char*> srcs; const char* dst = nullptr; parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs); parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, &sync); if (srcs.empty() || !dst) return syntax_error("push requires an argument"); return do_sync_push(srcs, dst) ? 0 : 1; return do_sync_push(srcs, dst, sync) ? 0 : 1; } else if (!strcmp(argv[0], "pull")) { bool copy_attrs = false; std::vector<const char*> srcs; const char* dst = "."; parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs); parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, nullptr); if (srcs.empty()) return syntax_error("pull requires an argument"); return do_sync_pull(srcs, dst, copy_attrs) ? 0 : 1; } Loading Loading @@ -2086,7 +2091,7 @@ static int install_app_legacy(TransportType transport, const char* serial, int a std::vector<const char*> apk_file = {argv[last_apk]}; std::string apk_dest = android::base::StringPrintf( where, android::base::Basename(argv[last_apk]).c_str()); if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk; if (!do_sync_push(apk_file, apk_dest.c_str(), false)) goto cleanup_apk; argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */ result = pm_command(transport, serial, argc, argv); Loading
adb/file_sync_client.cpp +18 −7 Original line number Diff line number Diff line Loading @@ -674,11 +674,22 @@ static bool sync_stat_fallback(SyncConnection& sc, const char* path, struct stat return true; } static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, unsigned mtime, mode_t mode) { static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, unsigned mtime, mode_t mode, bool sync) { std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode); if (sync) { struct stat st; if (sync_lstat(sc, rpath, &st)) { // For links, we cannot update the atime/mtime. if ((S_ISREG(mode & st.st_mode) && st.st_mtime == static_cast<time_t>(mtime)) || (S_ISLNK(mode & st.st_mode) && st.st_mtime >= static_cast<time_t>(mtime))) { sc.RecordFilesSkipped(1); return true; } } } if (S_ISLNK(mode)) { #if !defined(_WIN32) char buf[PATH_MAX]; Loading Loading @@ -902,7 +913,7 @@ static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath, if (list_only) { sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str()); } else { if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode)) { if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode, false)) { return false; } } Loading @@ -916,7 +927,7 @@ static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath, return true; } bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync) { SyncConnection sc; if (!sc.IsValid()) return false; Loading Loading @@ -981,7 +992,7 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { dst_dir.append(android::base::Basename(src_path)); } success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), false, false); success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), sync, false); continue; } else if (!should_push_file(st.st_mode)) { sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode); Loading @@ -1002,7 +1013,7 @@ bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) { sc.NewTransfer(); sc.SetExpectedTotalBytes(st.st_size); success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode); success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode, sync); sc.ReportTransferRate(src_path, TransferDirection::push); } Loading
adb/file_sync_service.h +1 −1 Original line number Diff line number Diff line Loading @@ -81,7 +81,7 @@ union syncmsg { void file_sync_service(int fd, void* cookie); bool do_sync_ls(const char* path); bool do_sync_push(const std::vector<const char*>& srcs, const char* dst); bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync); bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs, const char* name=nullptr); Loading
adb/test_device.py +38 −11 Original line number Diff line number Diff line Loading @@ -1130,8 +1130,18 @@ class FileOperationsTest(DeviceTest): if host_dir is not None: shutil.rmtree(host_dir) def verify_sync(self, device, temp_files, device_dir): """Verifies that a list of temp files was synced to the device.""" # Confirm that every file on the device mirrors that on the host. for temp_file in temp_files: device_full_path = posixpath.join( device_dir, temp_file.base_name) dev_md5, _ = device.shell( [get_md5_prog(self.device), device_full_path])[0].split() self.assertEqual(temp_file.checksum, dev_md5) def test_sync(self): """Sync a randomly generated directory of files to specified device.""" """Sync a host directory to the data partition.""" try: base_dir = tempfile.mkdtemp() Loading @@ -1141,9 +1151,10 @@ class FileOperationsTest(DeviceTest): os.makedirs(full_dir_path) # Create 32 random files within the host mirror. temp_files = make_random_host_files(in_dir=full_dir_path, num_files=32) temp_files = make_random_host_files( in_dir=full_dir_path, num_files=32) # Clean up any trash on the device. # Clean up any stale files on the device. device = adb.get_device() # pylint: disable=no-member device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) Loading @@ -1155,19 +1166,35 @@ class FileOperationsTest(DeviceTest): else: os.environ['ANDROID_PRODUCT_OUT'] = old_product_out # Confirm that every file on the device mirrors that on the host. for temp_file in temp_files: device_full_path = posixpath.join(self.DEVICE_TEMP_DIR, temp_file.base_name) dev_md5, _ = device.shell( [get_md5_prog(self.device), device_full_path])[0].split() self.assertEqual(temp_file.checksum, dev_md5) self.verify_sync(device, temp_files, self.DEVICE_TEMP_DIR) self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) #self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) finally: if base_dir is not None: shutil.rmtree(base_dir) def test_push_sync(self): """Sync a host directory to a specific path.""" try: temp_dir = tempfile.mkdtemp() temp_files = make_random_host_files(in_dir=temp_dir, num_files=32) device_dir = posixpath.join(self.DEVICE_TEMP_DIR, 'sync_src_dst') # Clean up any stale files on the device. device = adb.get_device() # pylint: disable=no-member device.shell(['rm', '-rf', device_dir]) device.push(temp_dir, device_dir, sync=True) self.verify_sync(device, temp_files, device_dir) self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR]) finally: if temp_dir is not None: shutil.rmtree(temp_dir) def test_unicode_paths(self): """Ensure that we can support non-ASCII paths, even on Windows.""" name = u'로보카 폴리' Loading