Merge "Add --sync support to push." am: 62db5fcee0
am: d50b10544b
am: 141f9c46d5
am: 8572f515fd
Change-Id: I29fe1ae0cf6be95b7bd44aaaed87a06065229c16
This commit is contained in:
commit
dfc0ba92a8
4 changed files with 70 additions and 27 deletions
|
@ -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"
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
@ -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])
|
||||
|
||||
|
@ -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…
Reference in a new issue