use std::cmp::Ordering;
use anyhow::bail;
use anyhow::Result;
use argh::FromArgs;
use lium::chroot::Chroot;
use lium::cros::ensure_testing_rsa_is_there;
use lium::dut::SshInfo;
use lium::repo::get_repo_dir;
use once_cell::sync::Lazy;
use regex::Regex;
static RE_CROS_KERNEL: Lazy<Regex> = Lazy::new(|| Regex::new("chromeos-kernel-").unwrap());
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "deploy")]
pub struct Args {
#[argh(option)]
repo: Option<String>,
#[argh(option)]
dut: String,
#[argh(positional)]
packages: Vec<String>,
#[argh(switch)]
skip_reboot: bool,
#[argh(switch)]
ab_update: bool,
}
#[tracing::instrument(level = "trace")]
pub fn run(args: &Args) -> Result<()> {
ensure_testing_rsa_is_there()?;
let target = {
let t = SshInfo::new(&args.dut)?;
if t.needs_port_forwarding_in_chroot() {
let port = t.start_ssh_forwarding_range_background(4100..4200)?;
SshInfo::new_host_and_port("localhost", port)?
} else {
t
}
};
println!("Target DUT is {:?}", target);
let board = target.get_board()?;
let packages_str = args.packages.join(" ");
let chroot = Chroot::new(&get_repo_dir(&args.repo)?)?;
let kernel_pkg = extract_kernel_pkg(&args.packages)?;
cros_workon_user_packages(&chroot, &board, &args.packages, &packages_str, &target)?;
if kernel_pkg.is_some() {
chroot.run_bash_script_in_chroot(
"update_kernel",
&format!(
r###"
cros-workon-{board} start {packages_str}
~/trunk/src/scripts/update_kernel.sh {} --remote={} --ssh_port {} --remote_bootargs
"###,
if args.ab_update { "--ab_update" } else { "" },
target.host(),
target.port()
),
None,
)?;
return Ok(());
}
if !args.skip_reboot {
println!("Rebooting DUT...");
target.run_cmd_piped(&["reboot; exit"])?;
}
Ok(())
}
fn extract_kernel_pkg(packages: &[String]) -> Result<Option<String>> {
let kernel_packages: Vec<_> = packages
.iter()
.filter(|&s| RE_CROS_KERNEL.is_match(s))
.collect();
match kernel_packages.len().cmp(&1) {
Ordering::Greater => {
bail!("There are more than 2 kernel packages. Please specify one of them.");
}
Ordering::Equal => Ok(Some(kernel_packages[0].to_string())),
_ => Ok(None),
}
}
fn cros_workon_user_packages(
chroot: &Chroot,
board: &str,
packages: &[String],
packages_str: &str,
target: &SshInfo,
) -> Result<()> {
let user_pkgs: String = packages
.iter()
.filter(|&s| !RE_CROS_KERNEL.is_match(s))
.map(|s| s.to_string())
.collect::<Vec<_>>()
.join(" ");
if !user_pkgs.is_empty() {
chroot.run_bash_script_in_chroot(
"deploy",
&format!(
r"cros-workon-{board} start {packages_str} && cros deploy {} {user_pkgs}",
target.host_and_port()
),
None,
)?;
}
Ok(())
}