Merge "adb: allow multiple args to push/pull."
This commit is contained in:
commit
fe54c96ab2
3 changed files with 152 additions and 81 deletions
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <base/logging.h>
|
#include <base/logging.h>
|
||||||
#include <base/stringprintf.h>
|
#include <base/stringprintf.h>
|
||||||
|
|
@ -101,11 +102,11 @@ static void help() {
|
||||||
" will disconnect from all connected TCP/IP devices.\n"
|
" will disconnect from all connected TCP/IP devices.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"device commands:\n"
|
"device commands:\n"
|
||||||
" adb push <local> <remote>\n"
|
" adb push <local>... <remote>\n"
|
||||||
" - copy file/dir to device\n"
|
" - copy files/dirs to device\n"
|
||||||
" adb pull [-a] <remote> [<local>]\n"
|
" adb pull [-a] <remote>... <local>\n"
|
||||||
" - copy file/dir from device\n"
|
" - copy files/dirs from device\n"
|
||||||
" ('-a' means copy timestamp and mode)\n"
|
" (-a preserves file timestamp and mode)\n"
|
||||||
" adb sync [ <directory> ] - copy host->device only if changed\n"
|
" adb sync [ <directory> ] - copy host->device only if changed\n"
|
||||||
" (-l means list but don't copy)\n"
|
" (-l means list but don't copy)\n"
|
||||||
" adb shell [-Ttx] - run remote shell interactively\n"
|
" adb shell [-Ttx] - run remote shell interactively\n"
|
||||||
|
|
@ -1065,31 +1066,35 @@ static std::string find_product_out_path(const std::string& hint) {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_push_pull_args(const char **arg, int narg,
|
static void parse_push_pull_args(const char** arg, int narg,
|
||||||
char const **path1, char const **path2,
|
std::vector<const char*>* srcs,
|
||||||
int *copy_attrs) {
|
const char** dst, bool* copy_attrs) {
|
||||||
*copy_attrs = 0;
|
*copy_attrs = false;
|
||||||
|
|
||||||
|
srcs->clear();
|
||||||
|
bool ignore_flags = false;
|
||||||
while (narg > 0) {
|
while (narg > 0) {
|
||||||
if (!strcmp(*arg, "-p")) {
|
if (ignore_flags || *arg[0] != '-') {
|
||||||
// Silently ignore for backwards compatibility.
|
srcs->push_back(*arg);
|
||||||
} else if (!strcmp(*arg, "-a")) {
|
|
||||||
*copy_attrs = 1;
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
if (!strcmp(*arg, "-p")) {
|
||||||
|
// Silently ignore for backwards compatibility.
|
||||||
|
} else if (!strcmp(*arg, "-a")) {
|
||||||
|
*copy_attrs = true;
|
||||||
|
} else if (!strcmp(*arg, "--")) {
|
||||||
|
ignore_flags = true;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "adb: unrecognized option '%s'\n", *arg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
++arg;
|
++arg;
|
||||||
--narg;
|
--narg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (narg > 0) {
|
if (srcs->size() > 1) {
|
||||||
*path1 = *arg;
|
*dst = srcs->back();
|
||||||
++arg;
|
srcs->pop_back();
|
||||||
--narg;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (narg > 0) {
|
|
||||||
*path2 = *arg;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1561,20 +1566,22 @@ int adb_commandline(int argc, const char **argv) {
|
||||||
return do_sync_ls(argv[1]) ? 0 : 1;
|
return do_sync_ls(argv[1]) ? 0 : 1;
|
||||||
}
|
}
|
||||||
else if (!strcmp(argv[0], "push")) {
|
else if (!strcmp(argv[0], "push")) {
|
||||||
int copy_attrs = 0;
|
bool copy_attrs = false;
|
||||||
const char* lpath = NULL, *rpath = NULL;
|
std::vector<const char*> srcs;
|
||||||
|
const char* dst = nullptr;
|
||||||
|
|
||||||
parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, ©_attrs);
|
parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs);
|
||||||
if (!lpath || !rpath || copy_attrs != 0) return usage();
|
if (srcs.empty() || !dst) return usage();
|
||||||
return do_sync_push(lpath, rpath) ? 0 : 1;
|
return do_sync_push(srcs, dst) ? 0 : 1;
|
||||||
}
|
}
|
||||||
else if (!strcmp(argv[0], "pull")) {
|
else if (!strcmp(argv[0], "pull")) {
|
||||||
int copy_attrs = 0;
|
bool copy_attrs = false;
|
||||||
const char* rpath = NULL, *lpath = ".";
|
std::vector<const char*> srcs;
|
||||||
|
const char* dst = ".";
|
||||||
|
|
||||||
parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, ©_attrs);
|
parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs);
|
||||||
if (!rpath) return usage();
|
if (srcs.empty()) return usage();
|
||||||
return do_sync_pull(rpath, lpath, copy_attrs) ? 0 : 1;
|
return do_sync_pull(srcs, dst, copy_attrs) ? 0 : 1;
|
||||||
}
|
}
|
||||||
else if (!strcmp(argv[0], "install")) {
|
else if (!strcmp(argv[0], "install")) {
|
||||||
if (argc < 2) return usage();
|
if (argc < 2) return usage();
|
||||||
|
|
@ -1764,8 +1771,9 @@ static int install_app(TransportType transport, const char* serial, int argc, co
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = -1;
|
int result = -1;
|
||||||
const char* apk_file = argv[last_apk];
|
std::vector<const char*> apk_file = {argv[last_apk]};
|
||||||
std::string apk_dest = android::base::StringPrintf(where, adb_basename(apk_file).c_str());
|
std::string apk_dest = android::base::StringPrintf(
|
||||||
|
where, adb_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())) goto cleanup_apk;
|
||||||
argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
|
argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
|
||||||
result = pm_command(transport, serial, argc, argv);
|
result = pm_command(transport, serial, argc, argv);
|
||||||
|
|
|
||||||
|
|
@ -625,32 +625,55 @@ static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const c
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool do_sync_push(const char* lpath, const char* rpath) {
|
bool do_sync_push(const std::vector<const char*>& srcs, const char* dst) {
|
||||||
SyncConnection sc;
|
SyncConnection sc;
|
||||||
if (!sc.IsValid()) return false;
|
if (!sc.IsValid()) return false;
|
||||||
|
|
||||||
struct stat st;
|
bool success = true;
|
||||||
if (stat(lpath, &st)) {
|
|
||||||
sc.Error("cannot stat '%s': %s", lpath, strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
|
||||||
return copy_local_dir_remote(sc, lpath, rpath, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned mode;
|
unsigned mode;
|
||||||
if (!sync_stat(sc, rpath, nullptr, &mode, nullptr)) return false;
|
if (!sync_stat(sc, dst, nullptr, &mode, nullptr)) return false;
|
||||||
std::string path_holder;
|
bool dst_isdir = mode != 0 && S_ISDIR(mode);
|
||||||
if (mode != 0 && S_ISDIR(mode)) {
|
|
||||||
// If we're copying a local file to a remote directory,
|
if (!dst_isdir) {
|
||||||
// we really want to copy to remote_dir + "/" + local_filename.
|
if (srcs.size() > 1) {
|
||||||
path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
|
sc.Error("target '%s' is not a directory", dst);
|
||||||
rpath = path_holder.c_str();
|
return false;
|
||||||
|
} else {
|
||||||
|
size_t dst_len = strlen(dst);
|
||||||
|
if (dst[dst_len - 1] == '/') {
|
||||||
|
sc.Error("failed to access '%s': Not a directory", dst);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bool result = sync_send(sc, lpath, rpath, st.st_mtime, st.st_mode);
|
|
||||||
|
for (const char* src_path : srcs) {
|
||||||
|
const char* dst_path = dst;
|
||||||
|
struct stat st;
|
||||||
|
if (stat(src_path, &st)) {
|
||||||
|
sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
|
||||||
|
success = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
success &= copy_local_dir_remote(sc, src_path, dst, false, false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string path_holder;
|
||||||
|
if (mode != 0 && S_ISDIR(mode)) {
|
||||||
|
// If we're copying a local file to a remote directory,
|
||||||
|
// we really want to copy to remote_dir + "/" + local_filename.
|
||||||
|
path_holder = android::base::StringPrintf(
|
||||||
|
"%s/%s", dst_path, adb_basename(src_path).c_str());
|
||||||
|
dst_path = path_holder.c_str();
|
||||||
|
}
|
||||||
|
success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
sc.Print("\n");
|
sc.Print("\n");
|
||||||
return result;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sync_ls_build_list_cb_args {
|
struct sync_ls_build_list_cb_args {
|
||||||
|
|
@ -733,7 +756,7 @@ static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
|
static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
|
||||||
int copy_attrs) {
|
bool copy_attrs) {
|
||||||
// Make sure that both directory paths end in a slash.
|
// Make sure that both directory paths end in a slash.
|
||||||
std::string rpath_clean(rpath);
|
std::string rpath_clean(rpath);
|
||||||
std::string lpath_clean(lpath);
|
std::string lpath_clean(lpath);
|
||||||
|
|
@ -774,43 +797,80 @@ static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const c
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool do_sync_pull(const char* rpath, const char* lpath, int copy_attrs) {
|
bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
|
||||||
|
bool copy_attrs) {
|
||||||
SyncConnection sc;
|
SyncConnection sc;
|
||||||
if (!sc.IsValid()) return false;
|
if (!sc.IsValid()) return false;
|
||||||
|
|
||||||
|
bool success = true;
|
||||||
unsigned mode, time;
|
unsigned mode, time;
|
||||||
if (!sync_stat(sc, rpath, &time, &mode, nullptr)) return false;
|
struct stat st;
|
||||||
if (mode == 0) {
|
if (stat(dst, &st)) {
|
||||||
sc.Error("remote object '%s' does not exist", rpath);
|
// If we're only pulling one file, the destination path might point to
|
||||||
return false;
|
// a path that doesn't exist yet.
|
||||||
|
if (srcs.size() != 1 || errno != ENOENT) {
|
||||||
|
sc.Error("cannot stat '%s': %s", dst, strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
|
bool dst_isdir = S_ISDIR(st.st_mode);
|
||||||
std::string path_holder;
|
if (!dst_isdir) {
|
||||||
struct stat st;
|
if (srcs.size() > 1) {
|
||||||
if (stat(lpath, &st) == 0) {
|
sc.Error("target '%s' is not a directory", dst);
|
||||||
if (S_ISDIR(st.st_mode)) {
|
|
||||||
// If we're copying a remote file to a local directory,
|
|
||||||
// we really want to copy to local_dir + "/" + basename(remote).
|
|
||||||
path_holder = android::base::StringPrintf("%s/%s", lpath, adb_basename(rpath).c_str());
|
|
||||||
lpath = path_holder.c_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!sync_recv(sc, rpath, lpath)) {
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
|
size_t dst_len = strlen(dst);
|
||||||
|
if (dst[dst_len - 1] == '/') {
|
||||||
|
sc.Error("failed to access '%s': Not a directory", dst);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sc.Print("\n");
|
|
||||||
return true;
|
|
||||||
} else if (S_ISDIR(mode)) {
|
|
||||||
return copy_remote_dir_local(sc, rpath, lpath, copy_attrs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sc.Error("remote object '%s' not a file or directory", rpath);
|
for (const char* src_path : srcs) {
|
||||||
return false;
|
const char* dst_path = dst;
|
||||||
|
if (!sync_stat(sc, src_path, &time, &mode, nullptr)) return false;
|
||||||
|
if (mode == 0) {
|
||||||
|
sc.Error("remote object '%s' does not exist", src_path);
|
||||||
|
success = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
|
||||||
|
std::string path_holder;
|
||||||
|
struct stat st;
|
||||||
|
if (stat(dst_path, &st) == 0) {
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
// If we're copying a remote file to a local directory,
|
||||||
|
// we really want to copy to local_dir + "/" +
|
||||||
|
// basename(remote).
|
||||||
|
path_holder = android::base::StringPrintf(
|
||||||
|
"%s/%s", dst_path, adb_basename(src_path).c_str());
|
||||||
|
dst_path = path_holder.c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!sync_recv(sc, src_path, dst_path)) {
|
||||||
|
success = false;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
if (copy_attrs && set_time_and_mode(dst_path, time, mode)) {
|
||||||
|
success = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (S_ISDIR(mode)) {
|
||||||
|
success &= copy_remote_dir_local(sc, src_path, dst_path, copy_attrs);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
sc.Error("remote object '%s' not a file or directory", src_path);
|
||||||
|
success = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sc.Print("\n");
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
|
bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#define _FILE_SYNC_SERVICE_H_
|
#define _FILE_SYNC_SERVICE_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
|
#define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
|
||||||
|
|
||||||
|
|
@ -64,9 +65,11 @@ union syncmsg {
|
||||||
|
|
||||||
void file_sync_service(int fd, void* cookie);
|
void file_sync_service(int fd, void* cookie);
|
||||||
bool do_sync_ls(const char* path);
|
bool do_sync_ls(const char* path);
|
||||||
bool do_sync_push(const char* lpath, const char* rpath);
|
bool do_sync_push(const std::vector<const char*>& srcs, const char* dst);
|
||||||
|
bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
|
||||||
|
bool copy_attrs);
|
||||||
|
|
||||||
bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
|
bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
|
||||||
bool do_sync_pull(const char* rpath, const char* lpath, int copy_attrs);
|
|
||||||
|
|
||||||
#define SYNC_DATA_MAX (64*1024)
|
#define SYNC_DATA_MAX (64*1024)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue