exp: cross
This commit is contained in:
@@ -1,16 +1,18 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::ffi::OsStr;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::local::LocalDriver;
|
||||
use super::ssh::SshDriver;
|
||||
use super::schroot::SchrootDriver;
|
||||
pub trait ContextDriver {
|
||||
fn ensure_available(&self, src: &Path, dest_root: &str) -> io::Result<PathBuf>;
|
||||
fn retrieve_path(&self, src: &Path, dest: &Path) -> io::Result<()>;
|
||||
fn list_files(&self, path: &Path) -> io::Result<Vec<PathBuf>>;
|
||||
fn run(&self, program: &str, args: &[String]) -> io::Result<std::process::ExitStatus>;
|
||||
fn run_output(&self, program: &str, args: &[String]) -> io::Result<std::process::Output>;
|
||||
fn run(&self, program: &str, args: &[String], env: &[(String, String)]) -> io::Result<std::process::ExitStatus>;
|
||||
fn run_output(&self, program: &str, args: &[String], env: &[(String, String)]) -> io::Result<std::process::Output>;
|
||||
fn prepare_work_dir(&self) -> io::Result<String>;
|
||||
}
|
||||
|
||||
@@ -20,7 +22,7 @@ pub trait ContextDriver {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(tag = "type")]
|
||||
#[derive(Default)]
|
||||
pub enum Context {
|
||||
pub enum ContextConfig {
|
||||
#[serde(rename = "local")]
|
||||
#[default]
|
||||
Local,
|
||||
@@ -30,14 +32,31 @@ pub enum Context {
|
||||
user: Option<String>,
|
||||
port: Option<u16>,
|
||||
},
|
||||
#[serde(rename = "schroot")]
|
||||
Schroot {
|
||||
name: String,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Context {
|
||||
config: ContextConfig,
|
||||
driver: RefCell<Option<Box<dyn ContextDriver>>>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn command<S: AsRef<OsStr>>(&self, program: S) -> ContextCommand {
|
||||
pub fn new(config: ContextConfig) -> Self {
|
||||
Self {
|
||||
config,
|
||||
driver: RefCell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn command<S: AsRef<OsStr>>(&self, program: S) -> ContextCommand<'_> {
|
||||
ContextCommand {
|
||||
driver: self.driver(),
|
||||
context: self,
|
||||
program: program.as_ref().to_string_lossy().to_string(),
|
||||
args: Vec::new(),
|
||||
env: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,15 +85,23 @@ impl Context {
|
||||
self.driver().list_files(path)
|
||||
}
|
||||
|
||||
fn driver(&self) -> Box<dyn ContextDriver> {
|
||||
match self {
|
||||
Context::Local => Box::new(LocalDriver),
|
||||
Context::Ssh { host, user, port } => Box::new(SshDriver {
|
||||
host: host.clone(),
|
||||
user: user.clone(),
|
||||
port: *port,
|
||||
}),
|
||||
fn driver(&self) -> Ref<Box<dyn ContextDriver>> {
|
||||
if self.driver.borrow().is_none() {
|
||||
let driver: Box<dyn ContextDriver> = match &self.config {
|
||||
ContextConfig::Local => Box::new(LocalDriver),
|
||||
ContextConfig::Ssh { host, user, port } => Box::new(SshDriver {
|
||||
host: host.clone(),
|
||||
user: user.clone(),
|
||||
port: *port,
|
||||
}),
|
||||
ContextConfig::Schroot { name } => Box::new(SchrootDriver {
|
||||
name: name.clone(),
|
||||
session: RefCell::new(None),
|
||||
}),
|
||||
};
|
||||
*self.driver.borrow_mut() = Some(driver);
|
||||
}
|
||||
Ref::map(self.driver.borrow(), |opt| opt.as_ref().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,13 +112,14 @@ impl Context {
|
||||
/// and call `status()` or `output()`.
|
||||
///
|
||||
/// It delegates the actual work to a `ContextDriver`.
|
||||
pub struct ContextCommand {
|
||||
driver: Box<dyn ContextDriver>,
|
||||
pub struct ContextCommand<'a> {
|
||||
context: &'a Context,
|
||||
program: String,
|
||||
args: Vec<String>,
|
||||
env: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
impl ContextCommand {
|
||||
impl<'a> ContextCommand<'a> {
|
||||
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
|
||||
self.args.push(arg.as_ref().to_string_lossy().to_string());
|
||||
self
|
||||
@@ -109,12 +137,36 @@ impl ContextCommand {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
|
||||
where
|
||||
K: AsRef<OsStr>,
|
||||
V: AsRef<OsStr>,
|
||||
{
|
||||
self.env.push((
|
||||
key.as_ref().to_string_lossy().to_string(),
|
||||
val.as_ref().to_string_lossy().to_string(),
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
|
||||
where
|
||||
I: IntoIterator<Item = (K, V)>,
|
||||
K: AsRef<OsStr>,
|
||||
V: AsRef<OsStr>,
|
||||
{
|
||||
for (key, val) in vars {
|
||||
self.env(key, val);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn status(&mut self) -> io::Result<std::process::ExitStatus> {
|
||||
self.driver.run(&self.program, &self.args)
|
||||
self.context.driver().run(&self.program, &self.args, &self.env)
|
||||
}
|
||||
|
||||
// Capture output
|
||||
pub fn output(&mut self) -> io::Result<std::process::Output> {
|
||||
self.driver.run_output(&self.program, &self.args)
|
||||
self.context.driver().run_output(&self.program, &self.args, &self.env)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user