You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cargo-remote/src/main.rs

115 lines
3.7 KiB
Rust

extern crate structopt;
#[macro_use]
extern crate structopt_derive;
extern crate cargo_metadata;
#[macro_use] extern crate log;
extern crate simple_logger;
extern crate toml;
use std::process::{exit, Command, Stdio};
use std::ffi::OsString;
use std::path::Path;
use std::fs::File;
use std::io::{BufReader, Read};
use structopt::StructOpt;
use toml::Value;
#[derive(StructOpt, Debug)]
#[structopt(name = "cargo remote")]
struct Opts {
// workaround for "remote" argument when calling "cargo remote"
_unused: String,
command: String,
#[structopt(short = "r", long = "remote", help = "remote ssh build server")]
remote: Option<String>
}
fn main() {
simple_logger::init().unwrap();
let options = Opts::from_args();
// TODO: add manifest_path option
let project_metadata = cargo_metadata::metadata(None).unwrap_or_else(|e| {
error!("Could not read cargo metadata: {}", e);
exit(-1);
});
// for now, assume that there is only one project and find it's root directory
let (project_dir, project_name) = project_metadata.packages.first().map_or_else(|| {
error!("No project found.");
exit(-2);
}, |project| {
(
Path::new(&project.manifest_path)
.parent()
.expect("Cargo.toml seems to have no parent directory?"),
&project.name
)
});
let build_server = options.remote.unwrap_or_else(|| {
let config_path = project_dir.join(".cargo-remote.toml");
File::open(config_path).ok().and_then(|mut file| {
let mut config_file_string = "".to_owned();
file.read_to_string(&mut config_file_string);
config_file_string.parse::<Value>().ok()
}).and_then(|value| {
value["remote"].as_str().map(str::to_owned)
}).unwrap_or_else(|| {
error!("No remote build server was defined (use config file or --remote flag)");
exit(-3);
})
});
match options.command {
Build => {
info!("Transferring sources to build server.");
// transfer project to build server
Command::new("rsync")
.arg("-a")
.arg("--delete")
.arg("--info=progress2")
.arg("--exclude")
.arg("target")
.arg(format!("{}/", project_dir.to_string_lossy()))
.arg(format!("{}:/tmp/remote-build-{}/", build_server, project_name))
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.stdin(Stdio::inherit())
.output()
.expect("failed to transfer project to build server");
let build_command = format!("cd /tmp/remote-build-{}/; $HOME/.cargo/bin/cargo build", project_name);
info!("Starting build process.");
Command::new("ssh")
.arg(&build_server)
.arg(build_command)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.stdin(Stdio::inherit())
.output()
.expect("failed to build project");
info!("Transferring artifacts back to client.");
Command::new("rsync")
.arg("-a")
.arg("--delete")
.arg("--info=progress2")
.arg(format!("{}:/tmp/remote-build-{}/target/", build_server, project_name))
.arg(format!("{}/target/", project_dir.to_string_lossy()))
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.stdin(Stdio::inherit())
.output()
.expect("failed to transfer built project to client");
}
}
}