Merge "adb: allow multiple args to push/pull." am: fe54c96ab2
am: 58ee99e454
am: 856afd9c26
* commit '856afd9c26f3f110c7c1baf249056835401e6744':
adb: allow multiple args to push/pull.
This commit is contained in:
commit
3a4429a590
3 changed files with 152 additions and 81 deletions
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <base/logging.h>
|
||||
#include <base/stringprintf.h>
|
||||
|
@ -101,11 +102,11 @@ static void help() {
|
|||
" will disconnect from all connected TCP/IP devices.\n"
|
||||
"\n"
|
||||
"device commands:\n"
|
||||
" adb push <local> <remote>\n"
|
||||
" - copy file/dir to device\n"
|
||||
" adb pull [-a] <remote> [<local>]\n"
|
||||
" - copy file/dir from device\n"
|
||||
" ('-a' means copy timestamp and mode)\n"
|
||||
" adb push <local>... <remote>\n"
|
||||
" - copy files/dirs to device\n"
|
||||
" adb pull [-a] <remote>... <local>\n"
|
||||
" - copy files/dirs from device\n"
|
||||
" (-a preserves file timestamp and mode)\n"
|
||||
" adb sync [ <directory> ] - copy host->device only if changed\n"
|
||||
" (-l means list but don't copy)\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;
|
||||
}
|
||||
|
||||
static void parse_push_pull_args(const char **arg, int narg,
|
||||
char const **path1, char const **path2,
|
||||
int *copy_attrs) {
|
||||
*copy_attrs = 0;
|
||||
static void parse_push_pull_args(const char** arg, int narg,
|
||||
std::vector<const char*>* srcs,
|
||||
const char** dst, bool* copy_attrs) {
|
||||
*copy_attrs = false;
|
||||
|
||||
srcs->clear();
|
||||
bool ignore_flags = false;
|
||||
while (narg > 0) {
|
||||
if (!strcmp(*arg, "-p")) {
|
||||
// Silently ignore for backwards compatibility.
|
||||
} else if (!strcmp(*arg, "-a")) {
|
||||
*copy_attrs = 1;
|
||||
if (ignore_flags || *arg[0] != '-') {
|
||||
srcs->push_back(*arg);
|
||||
} 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;
|
||||
--narg;
|
||||
}
|
||||
|
||||
if (narg > 0) {
|
||||
*path1 = *arg;
|
||||
++arg;
|
||||
--narg;
|
||||
}
|
||||
|
||||
if (narg > 0) {
|
||||
*path2 = *arg;
|
||||
if (srcs->size() > 1) {
|
||||
*dst = srcs->back();
|
||||
srcs->pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1561,20 +1566,22 @@ int adb_commandline(int argc, const char **argv) {
|
|||
return do_sync_ls(argv[1]) ? 0 : 1;
|
||||
}
|
||||
else if (!strcmp(argv[0], "push")) {
|
||||
int copy_attrs = 0;
|
||||
const char* lpath = NULL, *rpath = NULL;
|
||||
bool copy_attrs = false;
|
||||
std::vector<const char*> srcs;
|
||||
const char* dst = nullptr;
|
||||
|
||||
parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, ©_attrs);
|
||||
if (!lpath || !rpath || copy_attrs != 0) return usage();
|
||||
return do_sync_push(lpath, rpath) ? 0 : 1;
|
||||
parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs);
|
||||
if (srcs.empty() || !dst) return usage();
|
||||
return do_sync_push(srcs, dst) ? 0 : 1;
|
||||
}
|
||||
else if (!strcmp(argv[0], "pull")) {
|
||||
int copy_attrs = 0;
|
||||
const char* rpath = NULL, *lpath = ".";
|
||||
bool copy_attrs = false;
|
||||
std::vector<const char*> srcs;
|
||||
const char* dst = ".";
|
||||
|
||||
parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, ©_attrs);
|
||||
if (!rpath) return usage();
|
||||
return do_sync_pull(rpath, lpath, copy_attrs) ? 0 : 1;
|
||||
parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs);
|
||||
if (srcs.empty()) return usage();
|
||||
return do_sync_pull(srcs, dst, copy_attrs) ? 0 : 1;
|
||||
}
|
||||
else if (!strcmp(argv[0], "install")) {
|
||||
if (argc < 2) return usage();
|
||||
|
@ -1764,8 +1771,9 @@ static int install_app(TransportType transport, const char* serial, int argc, co
|
|||
}
|
||||
|
||||
int result = -1;
|
||||
const char* apk_file = argv[last_apk];
|
||||
std::string apk_dest = android::base::StringPrintf(where, adb_basename(apk_file).c_str());
|
||||
std::vector<const char*> apk_file = {argv[last_apk]};
|
||||
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;
|
||||
argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
if (!sc.IsValid()) return false;
|
||||
|
||||
struct stat st;
|
||||
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);
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
unsigned mode;
|
||||
if (!sync_stat(sc, rpath, nullptr, &mode, nullptr)) return false;
|
||||
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", rpath, adb_basename(lpath).c_str());
|
||||
rpath = path_holder.c_str();
|
||||
if (!sync_stat(sc, dst, nullptr, &mode, nullptr)) return false;
|
||||
bool dst_isdir = mode != 0 && S_ISDIR(mode);
|
||||
|
||||
if (!dst_isdir) {
|
||||
if (srcs.size() > 1) {
|
||||
sc.Error("target '%s' is not a directory", dst);
|
||||
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");
|
||||
return result;
|
||||
return success;
|
||||
}
|
||||
|
||||
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,
|
||||
int copy_attrs) {
|
||||
bool copy_attrs) {
|
||||
// Make sure that both directory paths end in a slash.
|
||||
std::string rpath_clean(rpath);
|
||||
std::string lpath_clean(lpath);
|
||||
|
@ -774,43 +797,80 @@ static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const c
|
|||
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;
|
||||
if (!sc.IsValid()) return false;
|
||||
|
||||
bool success = true;
|
||||
unsigned mode, time;
|
||||
if (!sync_stat(sc, rpath, &time, &mode, nullptr)) return false;
|
||||
if (mode == 0) {
|
||||
sc.Error("remote object '%s' does not exist", rpath);
|
||||
return false;
|
||||
struct stat st;
|
||||
if (stat(dst, &st)) {
|
||||
// If we're only pulling one file, the destination path might point to
|
||||
// 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)) {
|
||||
std::string path_holder;
|
||||
struct stat st;
|
||||
if (stat(lpath, &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", lpath, adb_basename(rpath).c_str());
|
||||
lpath = path_holder.c_str();
|
||||
}
|
||||
}
|
||||
if (!sync_recv(sc, rpath, lpath)) {
|
||||
bool dst_isdir = S_ISDIR(st.st_mode);
|
||||
if (!dst_isdir) {
|
||||
if (srcs.size() > 1) {
|
||||
sc.Error("target '%s' is not a directory", dst);
|
||||
return false;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
return false;
|
||||
for (const char* src_path : srcs) {
|
||||
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) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#define _FILE_SYNC_SERVICE_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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);
|
||||
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_pull(const char* rpath, const char* lpath, int copy_attrs);
|
||||
|
||||
#define SYNC_DATA_MAX (64*1024)
|
||||
|
||||
|
|
Loading…
Reference in a new issue