mirror of
https://github.com/nestriness/cdc-file-transfer.git
synced 2026-01-30 14:35:37 +02:00
[cdc_stream] Add a CLI client to start/stop asset streaming sessions (#4)
Implements the cdc_stream client and adjusts asset streaming in various places to work better outside of a GGP environment. This CL tries to get quoting for SSH commands right. It also brings back the ability to start a streaming session from asset_stream_manager. Also cleans up Bazel targets setup. Since the sln file is now in root, it is no longer necessary to prepend ../ to relative filenames to make clicking on errors work.
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include "absl/strings/match.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "common/path.h"
|
||||
@@ -46,6 +47,7 @@ void RemoteUtil::SetUserHostAndPort(std::string user_host, int port) {
|
||||
user_host_ = std::move(user_host);
|
||||
ssh_port_ = port;
|
||||
}
|
||||
|
||||
void RemoteUtil::SetScpCommand(std::string scp_command) {
|
||||
scp_command_ = std::move(scp_command);
|
||||
}
|
||||
@@ -56,7 +58,7 @@ void RemoteUtil::SetSshCommand(std::string ssh_command) {
|
||||
|
||||
absl::Status RemoteUtil::Scp(std::vector<std::string> source_filepaths,
|
||||
const std::string& dest, bool compress) {
|
||||
absl::Status status = CheckHostPort();
|
||||
absl::Status status = CheckUserHostPort();
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
@@ -64,7 +66,11 @@ absl::Status RemoteUtil::Scp(std::vector<std::string> source_filepaths,
|
||||
std::string source_args;
|
||||
for (const std::string& sourceFilePath : source_filepaths) {
|
||||
// Workaround for scp thinking that C is a host in C:\path\to\foo.
|
||||
source_args += QuoteArgument("//./" + sourceFilePath) + " ";
|
||||
if (absl::StrContains(path::GetDrivePrefix(sourceFilePath), ":")) {
|
||||
source_args += QuoteForWindows("//./" + sourceFilePath) + " ";
|
||||
} else {
|
||||
source_args += QuoteForWindows(sourceFilePath) + " ";
|
||||
}
|
||||
}
|
||||
|
||||
// -p preserves timestamps. This enables timestamp-based up-to-date checks.
|
||||
@@ -73,66 +79,27 @@ absl::Status RemoteUtil::Scp(std::vector<std::string> source_filepaths,
|
||||
"%s "
|
||||
"%s %s -p -T "
|
||||
"-P %i %s "
|
||||
"%s",
|
||||
scp_command_, quiet_ || verbosity_ < 2 ? "-q" : "", compress ? "-C" : "",
|
||||
ssh_port_, source_args, QuoteArgument(user_host_ + ":" + dest));
|
||||
"%s:%s",
|
||||
QuoteForWindows(scp_command_), quiet_ || verbosity_ < 2 ? "-q" : "",
|
||||
compress ? "-C" : "", ssh_port_, source_args, QuoteForWindows(user_host_),
|
||||
QuoteForWindows(dest));
|
||||
start_info.name = "scp";
|
||||
start_info.forward_output_to_log = forward_output_to_log_;
|
||||
|
||||
return process_factory_->Run(start_info);
|
||||
}
|
||||
|
||||
absl::Status RemoteUtil::Sync(std::vector<std::string> source_filepaths,
|
||||
const std::string& dest) {
|
||||
absl::Status status = CheckHostPort();
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
std::string source_args;
|
||||
for (const std::string& sourceFilePath : source_filepaths) {
|
||||
source_args += QuoteArgument(sourceFilePath) + " ";
|
||||
}
|
||||
|
||||
ProcessStartInfo start_info;
|
||||
start_info.command = absl::StrFormat(
|
||||
"cdc_rsync --ip=%s --port=%i -z "
|
||||
"%s %s%s",
|
||||
QuoteArgument(user_host_), ssh_port_,
|
||||
quiet_ || verbosity_ < 2 ? "-q " : " ", source_args, QuoteArgument(dest));
|
||||
start_info.name = "cdc_rsync";
|
||||
start_info.forward_output_to_log = forward_output_to_log_;
|
||||
|
||||
return process_factory_->Run(start_info);
|
||||
}
|
||||
|
||||
absl::Status RemoteUtil::Chmod(const std::string& mode,
|
||||
const std::string& remote_path, bool quiet) {
|
||||
std::string remote_command =
|
||||
absl::StrFormat("chmod %s %s %s", QuoteArgument(mode),
|
||||
EscapeForWindows(remote_path), quiet ? "-f" : "");
|
||||
absl::StrFormat("chmod %s %s %s", QuoteForSsh(mode),
|
||||
QuoteForSsh(remote_path), quiet ? "-f" : "");
|
||||
|
||||
return Run(remote_command, "chmod");
|
||||
}
|
||||
|
||||
absl::Status RemoteUtil::Rm(const std::string& remote_path, bool force) {
|
||||
std::string remote_command = absl::StrFormat("rm %s %s", force ? "-f" : "",
|
||||
EscapeForWindows(remote_path));
|
||||
|
||||
return Run(remote_command, "rm");
|
||||
}
|
||||
|
||||
absl::Status RemoteUtil::Mv(const std::string& old_remote_path,
|
||||
const std::string& new_remote_path) {
|
||||
std::string remote_command =
|
||||
absl::StrFormat("mv %s %s", EscapeForWindows(old_remote_path),
|
||||
EscapeForWindows(new_remote_path));
|
||||
|
||||
return Run(remote_command, "mv");
|
||||
}
|
||||
|
||||
absl::Status RemoteUtil::Run(std::string remote_command, std::string name) {
|
||||
absl::Status status = CheckHostPort();
|
||||
absl::Status status = CheckUserHostPort();
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
@@ -177,33 +144,61 @@ ProcessStartInfo RemoteUtil::BuildProcessStartInfoForSshInternal(
|
||||
"-oServerAliveCountMax=6 " // Number of lost msgs before ssh terminates
|
||||
"-oServerAliveInterval=5 " // Time interval between alive msgs
|
||||
"%s %s -p %i %s",
|
||||
ssh_command_, quiet_ || verbosity_ < 2 ? "-q" : "", forward_arg,
|
||||
QuoteArgument(user_host_), ssh_port_, remote_command_arg);
|
||||
QuoteForWindows(ssh_command_), quiet_ || verbosity_ < 2 ? "-q" : "",
|
||||
forward_arg, QuoteForWindows(user_host_), ssh_port_, remote_command_arg);
|
||||
start_info.forward_output_to_log = forward_output_to_log_;
|
||||
return start_info;
|
||||
}
|
||||
|
||||
std::string RemoteUtil::EscapeForWindows(const std::string& argument) {
|
||||
std::string str =
|
||||
std::string RemoteUtil::QuoteForWindows(const std::string& argument) {
|
||||
// Escape certain backslashes (see doc of this function).
|
||||
std::string escaped =
|
||||
std::regex_replace(argument, std::regex(R"(\\*(?="|$))"), "$&$&");
|
||||
return std::regex_replace(str, std::regex(R"(")"), R"(\")");
|
||||
// Escape " -> \".
|
||||
escaped = std::regex_replace(escaped, std::regex(R"(")"), R"(\")");
|
||||
// Quote.
|
||||
return absl::StrCat("\"", escaped, "\"");
|
||||
}
|
||||
|
||||
std::string RemoteUtil::QuoteArgument(const std::string& argument) {
|
||||
return absl::StrCat("\"", EscapeForWindows(argument), "\"");
|
||||
std::string RemoteUtil::QuoteForSsh(const std::string& argument) {
|
||||
// Escape \ ->: \\.
|
||||
std::string escaped =
|
||||
std::regex_replace(argument, std::regex(R"(\\)"), R"(\\)");
|
||||
// Escape " -> \".
|
||||
escaped = std::regex_replace(escaped, std::regex(R"(")"), R"(\")");
|
||||
|
||||
// Quote, but handle special case for ~.
|
||||
if (escaped.empty() || escaped[0] != '~') {
|
||||
return QuoteForWindows(absl::StrCat("\"", escaped, "\""));
|
||||
}
|
||||
|
||||
// Simple special cases. Quote() isn't required, but called for consistency.
|
||||
if (escaped == "~" || escaped == "~/") {
|
||||
return QuoteForWindows(escaped);
|
||||
}
|
||||
|
||||
// Check whether the username contains only valid characters.
|
||||
// E.g. ~user name/foo -> Quote(~user name/foo)
|
||||
size_t slash_pos = escaped.find('/');
|
||||
size_t username_end_pos =
|
||||
slash_pos == std::string::npos ? escaped.size() : slash_pos;
|
||||
if (username_end_pos > 1 &&
|
||||
!std::regex_match(escaped.substr(1, username_end_pos - 1),
|
||||
std::regex("^[a-z][-a-z0-9]*"))) {
|
||||
return QuoteForWindows(absl::StrCat("\"", escaped, "\""));
|
||||
}
|
||||
|
||||
if (slash_pos == std::string::npos) {
|
||||
// E.g. ~username -> Quote(~username)
|
||||
return QuoteForWindows(escaped);
|
||||
}
|
||||
|
||||
// E.g. or ~username/foo -> Quote(~username/"foo")
|
||||
return QuoteForWindows(absl::StrCat(escaped.substr(0, slash_pos + 1), "\"",
|
||||
escaped.substr(slash_pos + 1), "\""));
|
||||
}
|
||||
|
||||
std::string RemoteUtil::QuoteArgumentForSsh(const std::string& argument) {
|
||||
return absl::StrFormat(
|
||||
"'%s'", std::regex_replace(argument, std::regex("'"), "'\\''"));
|
||||
}
|
||||
|
||||
std::string RemoteUtil::QuoteAndEscapeArgumentForSsh(
|
||||
const std::string& argument) {
|
||||
return EscapeForWindows(QuoteArgumentForSsh(argument));
|
||||
}
|
||||
|
||||
absl::Status RemoteUtil::CheckHostPort() {
|
||||
absl::Status RemoteUtil::CheckUserHostPort() {
|
||||
if (user_host_.empty() || ssh_port_ == 0) {
|
||||
return MakeStatus("IP or port not set");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user