updated config format & cli

pull/17/head
ZSchoen 3 years ago
parent d6de41410b
commit 3c6d182109

@ -1,16 +1,27 @@
use serde::{Deserialize, Serialize};
use serde::Deserialize;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Clone)]
pub struct Remote {
pub name: String,
pub host: String,
pub user: String,
pub ssh_port: u16,
pub temp_dir: String,
}
#[derive(Debug, Deserialize)]
struct OptionRemote {
pub name: Option<String>,
pub host: String,
pub user: String,
pub ssh_port: Option<u16>,
pub temp_dir: Option<String>,
}
impl Default for Remote {
fn default() -> Self {
Self {
name: String::new(),
host: String::new(),
user: String::new(),
ssh_port: 22,
@ -19,25 +30,46 @@ impl Default for Remote {
}
}
impl From<OptionRemote> for Remote {
fn from(minimal_remote: OptionRemote) -> Self {
let default = Remote::default();
let name = minimal_remote.name.unwrap_or(default.name);
let ssh_port = minimal_remote.ssh_port.unwrap_or(default.ssh_port);
let temp_dir = minimal_remote.temp_dir.unwrap_or(default.temp_dir);
Remote {
name,
host: minimal_remote.host,
user: minimal_remote.user,
ssh_port,
temp_dir,
}
}
}
impl<'de> Deserialize<'de> for Remote {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
OptionRemote::deserialize(deserializer).map(Self::from)
}
}
impl Remote {
pub fn user_host(&self) -> String {
format!("{}@{}", self.user, self.host)
}
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[derive(Debug, Default, Deserialize)]
pub struct Config {
pub remote: Remote,
#[serde(rename = "remote")]
remotes: Option<Vec<Remote>>,
}
impl Config {
pub fn new(project_dir: &std::path::Path) -> Result<Self, config::ConfigError> {
let mut conf = config::Config::default();
conf.merge(config::File::from_str(
toml::to_string(&Config::default()).unwrap().as_str(),
config::FileFormat::Toml,
))?;
let mut conf = config::Config::new();
if let Some(config_file) = xdg::BaseDirectories::with_prefix("cargo-remote")
.ok()
@ -53,4 +85,37 @@ impl Config {
conf.try_into()
}
pub fn get_remote(&self, opts: &crate::Opts) -> Option<Remote> {
let remotes: Vec<_> = self.remotes.clone().unwrap_or_default();
let config_remote = match &opts.remote_name {
Some(remote_name) => remotes
.into_iter()
.find(|remote| remote.name == *remote_name),
None => remotes.into_iter().next(),
};
let blueprint_remote = match (
config_remote,
opts.remote_host.is_some() && opts.remote_user.is_some(),
) {
(Some(config_remote), _) => config_remote,
(None, true) => Remote::default(),
(None, false) => return None,
};
Some(Remote {
name: opts.remote_name.clone().unwrap_or(blueprint_remote.name),
host: opts.remote_host.clone().unwrap_or(blueprint_remote.host),
user: opts.remote_user.clone().unwrap_or(blueprint_remote.user),
ssh_port: opts
.remote_ssh_port
.clone()
.unwrap_or(blueprint_remote.ssh_port),
temp_dir: opts
.remote_temp_dir
.clone()
.unwrap_or(blueprint_remote.temp_dir),
})
}
}

@ -12,93 +12,91 @@ const PROGRESS_FLAG: &str = "--info=progress2";
#[derive(StructOpt, Debug)]
#[structopt(name = "cargo-remote", bin_name = "cargo")]
enum Opts {
#[structopt(name = "remote")]
Remote {
#[structopt(short = "r", long = "remote", help = "Remote ssh build server")]
remote: Option<String>,
#[structopt(
short = "b",
long = "build-env",
help = "Set remote environment variables. RUST_BACKTRACE, CC, LIB, etc. ",
default_value = "RUST_BACKTRACE=1"
)]
build_env: String,
#[structopt(
short = "d",
long = "rustup-default",
help = "Rustup default (stable|beta|nightly)",
default_value = "stable"
)]
rustup_default: String,
#[structopt(
short = "e",
long = "env",
help = "Environment profile. default_value = /etc/profile",
default_value = "/etc/profile"
)]
env: String,
#[structopt(
short = "c",
long = "copy-back",
help = "Transfer the target folder or specific file from that folder back to the local machine"
)]
copy_back: Option<Option<String>>,
#[structopt(
long = "no-copy-lock",
help = "don't transfer the Cargo.lock file back to the local machine"
)]
no_copy_lock: bool,
#[structopt(
long = "manifest-path",
help = "Path to the manifest to execute",
default_value = "Cargo.toml",
parse(from_os_str)
)]
manifest_path: PathBuf,
#[structopt(
short = "h",
long = "transfer-hidden",
help = "Transfer hidden files and directories to the build server"
)]
hidden: bool,
#[structopt(help = "cargo command that will be executed remotely")]
command: String,
#[structopt(
help = "cargo options and flags that will be applied remotely",
name = "remote options"
)]
options: Vec<String>,
},
pub struct Opts {
#[structopt(short = "r", long = "remote", help = "Remote ssh build server")]
remote_name: Option<String>,
#[structopt(short, long, help = "")]
remote_host: Option<String>,
#[structopt(short, long, help = "")]
remote_user: Option<String>,
#[structopt(short, long, help = "")]
remote_ssh_port: Option<u16>,
#[structopt(short, long, help = "")]
remote_temp_dir: Option<String>,
#[structopt(
short = "b",
long = "build-env",
help = "Set remote environment variables. RUST_BACKTRACE, CC, LIB, etc. ",
default_value = "RUST_BACKTRACE=1"
)]
build_env: String,
#[structopt(
short = "d",
long = "rustup-default",
help = "Rustup default (stable|beta|nightly)",
default_value = "stable"
)]
rustup_default: String,
#[structopt(
short = "e",
long = "env",
help = "Environment profile. default_value = /etc/profile",
default_value = "/etc/profile"
)]
env: String,
#[structopt(
short = "c",
long = "copy-back",
help = "Transfer the target folder or specific file from that folder back to the local machine"
)]
copy_back: Option<Option<String>>,
#[structopt(
long = "no-copy-lock",
help = "don't transfer the Cargo.lock file back to the local machine"
)]
no_copy_lock: bool,
#[structopt(
long = "manifest-path",
help = "Path to the manifest to execute",
default_value = "Cargo.toml",
parse(from_os_str)
)]
manifest_path: PathBuf,
#[structopt(
short = "h",
long = "transfer-hidden",
help = "Transfer hidden files and directories to the build server"
)]
hidden: bool,
#[structopt(help = "cargo command that will be executed remotely")]
command: String,
#[structopt(
help = "cargo options and flags that will be applied remotely",
name = "remote options"
)]
options: Vec<String>,
}
fn main() {
simple_logger::init().unwrap();
let Opts::Remote {
remote,
build_env,
rustup_default,
env,
copy_back,
no_copy_lock,
manifest_path,
hidden,
command,
options,
} = Opts::from_args();
let opts = Opts::from_args();
let mut metadata_cmd = cargo_metadata::MetadataCommand::new();
metadata_cmd.manifest_path(manifest_path).no_deps();
metadata_cmd.manifest_path(&opts.manifest_path).no_deps();
let project_metadata = metadata_cmd.exec().unwrap();
let project_dir = project_metadata.workspace_root;
@ -112,12 +110,32 @@ fn main() {
}
};
let build_server = remote.unwrap_or_else(|| conf.remote.user_host());
let remote = match conf.get_remote(&opts) {
Some(remote) => remote,
None => {
error!("No remote build server was defined (use config file or the --remote flags)");
exit(4);
}
};
let build_server = remote.user_host();
let Opts {
build_env,
rustup_default,
env,
copy_back,
no_copy_lock,
hidden,
command,
options,
..
} = opts;
// generate a unique build path by using the hashed project dir as folder on the remote machine
let mut hasher = DefaultHasher::new();
project_dir.hash(&mut hasher);
let build_path = format!("{}/{}/", conf.remote.temp_dir, hasher.finish());
let build_path = format!("{}/{}/", remote.temp_dir, hasher.finish());
info!("Transferring sources to build server.");
// transfer project to build server
@ -126,7 +144,7 @@ fn main() {
.arg("-a".to_owned())
.arg("--delete")
.arg("--compress")
.arg(format!("-e ssh -p {}", conf.remote.ssh_port))
.arg(format!("-e ssh -p {}", remote.ssh_port))
.arg("--info=progress2")
.arg("--exclude")
.arg("target");
@ -163,7 +181,7 @@ fn main() {
info!("Starting build process.");
let output = Command::new("ssh")
.arg(format!("-p {}", conf.remote.ssh_port))
.arg(format!("-p {}", remote.ssh_port))
.arg("-t")
.arg(&build_server)
.arg(build_command)
@ -183,7 +201,7 @@ fn main() {
.arg("-a")
.arg("--delete")
.arg("--compress")
.arg(format!("-e ssh -p {}", conf.remote.ssh_port))
.arg(format!("-e ssh -p {}", remote.ssh_port))
.arg("--info=progress2")
.arg(format!(
"{}:{}/target/{}",
@ -213,7 +231,7 @@ fn main() {
.arg("-a")
.arg("--delete")
.arg("--compress")
.arg(format!("-e ssh -p {}", conf.remote.ssh_port))
.arg(format!("-e ssh -p {}", remote.ssh_port))
.arg("--info=progress2")
.arg(format!("{}:{}/Cargo.lock", build_server, build_path))
.arg(format!("{}/Cargo.lock", project_dir.to_string_lossy()))

Loading…
Cancel
Save