Files
dockerbuild/src/docker_util.rs
2020-11-15 00:30:04 +08:00

143 lines
4.2 KiB
Rust

use std::fs;
use std::process::Command;
use rust_util::XResult;
use rust_util::util_cmd;
use crate::build_util;
use crate::build_util::Builder;
const DOCKER_CMD: &str = "docker";
const DCOLER_TEMP_CMD: &str = "temp_sub_cmd";
const DOCKER_WORK_DIR: &str = "/usr/src/app";
// $ docker run --rm --user "$(id -u)":"$(id -g)" \
// -v "$PWD":/usr/src/app -w /usr/src/app rust:1.47 \
// cargo build --release
#[derive(Default)]
pub struct DockerCmd {
docker_name: String,
docker_current_dir: Option<String>,
docker_run_uid: Option<u32>,
docker_run_gid: Option<u32>,
volumns: Vec<(String, String)>,
mirror: Option<String>,
}
impl DockerCmd {
pub fn new(docker_name: &str) -> Self {
Self {
docker_name: docker_name.into(),
..Default::default()
}
}
pub fn current_dir(&mut self, current_dir: &str) -> &mut Self {
self.docker_current_dir = Some(current_dir.into());
self
}
pub fn uid(&mut self, uid: u32) -> &mut Self {
self.docker_run_uid = Some(uid);
self
}
pub fn gid(&mut self, gid: u32) -> &mut Self {
self.docker_run_gid = Some(gid);
self
}
pub fn mirror(&mut self, mirror: &str) -> &mut Self {
self.mirror = Some(mirror.into());
self
}
pub fn add_volumn(&mut self, outer_vol: &str, docker_vol: &str) -> &mut Self {
self.volumns.push((outer_vol.into(), docker_vol.into()));
self
}
pub fn exec(self, cmds: &[String]) -> XResult<()> {
let mut cmd = Command::new(DOCKER_CMD);
cmd.arg("run");
cmd.arg("--rm");
cmd.arg("--user");
cmd.arg(&format!("{}:{}",
self.docker_run_uid.unwrap_or_else(|| users::get_current_uid() as u32),
self.docker_run_gid.unwrap_or_else(|| users::get_current_gid() as u32),
));
cmd.arg("-v");
cmd.arg(&format!("{}:{}", build_util::get_work_dir(&self.docker_current_dir)?, DOCKER_WORK_DIR));
for (outer_vol, docker_vol) in self.volumns {
cmd.arg("-v");
cmd.arg(&format!("{}:{}", outer_vol, docker_vol));
}
cmd.args(vec!["-w", DOCKER_WORK_DIR]);
cmd.arg(&self.docker_name);
let builder = Builder::from(&self.docker_current_dir)?;
let builder_name = match builder.get_name() {
Some(n) => n, None => {
warning!("Unknown builder, use default: cargo");
"cargo".into() // default use cargo?
},
};
let mut sub_cmd = String::with_capacity(1024);
if let Some(mirror) = self.mirror {
sub_cmd.push_str(&make_cmd(&mirror));
sub_cmd.push_str("\n");
}
let mut builder_cmd = builder_name;
let mut sub_build_cmd = vec![];
let mut cmds_iter = cmds.iter();
if let Some(cmd0) = cmds_iter.next() {
if cmd0.starts_with(":") {
builder_cmd = cmd0.chars().skip(1).collect::<String>();
} else {
sub_build_cmd.push(cmd0.clone());
}
} else {
warning!("Docker build param is empty!");
}
cmds_iter.for_each(|c| { sub_build_cmd.push(c.clone()); });
sub_cmd.push_str(&builder_cmd);
sub_cmd.push(' ');
sub_cmd.push_str(&sub_build_cmd.iter().map(|arg| escape_arg(arg)).collect::<Vec<_>>().join(" "));
fs::write(DCOLER_TEMP_CMD, &sub_cmd).ok();
cmd.args(vec!["bash", DCOLER_TEMP_CMD]);
success!("Docker cmd exec: {:?}", cmd);
success!("Docker temp sub cmd: {}", sub_cmd);
let r = util_cmd::run_command_and_wait(&mut cmd).map_err(|e| e.into());
fs::remove_file(DCOLER_TEMP_CMD).ok();
r
}
}
fn escape_arg(arg: &str) -> String {
let mut r = String::with_capacity(arg.len() + 10);
r.push('\'');
for c in arg.chars() {
if c == '\'' {
r.push('\\');
}
r.push(c);
}
r.push('\'');
r
}
fn make_cmd(mirror: &str) -> String {
let mut s = String::with_capacity(256);
s.push_str(&format!(r#"echo '[source.crates-io]
registry = "https://github.com/rust-lang/crates.io-index"
replace-with = "mirror"
[source.mirror]
registry = "{}"
' > /usr/local/cargo/config"#, mirror));
s
}