docs: added documentation, enforced documentation
All checks were successful
CI / build (push) Successful in 7m21s
All checks were successful
CI / build (push) Successful in 7m21s
This commit is contained in:
@@ -10,6 +10,7 @@ use super::schroot::SchrootDriver;
|
||||
use super::ssh::SshDriver;
|
||||
use super::unshare::UnshareDriver;
|
||||
|
||||
/// A ContextDriver is the interface for the logic happening inside a context
|
||||
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<()>;
|
||||
@@ -41,34 +42,52 @@ pub trait ContextDriver {
|
||||
#[serde(tag = "type")]
|
||||
#[derive(Default)]
|
||||
pub enum ContextConfig {
|
||||
/// Local context: actions executed locally
|
||||
#[serde(rename = "local")]
|
||||
#[default]
|
||||
Local,
|
||||
/// SSH context: actions over an SSH connection
|
||||
#[serde(rename = "ssh")]
|
||||
Ssh {
|
||||
/// Host for the SSH connection
|
||||
host: String,
|
||||
/// User for the SSH connection
|
||||
user: Option<String>,
|
||||
/// TCP port for the SSH connection
|
||||
port: Option<u16>,
|
||||
},
|
||||
/// Schroot context: using `schroot`
|
||||
#[serde(rename = "schroot")]
|
||||
Schroot {
|
||||
/// Name of the schroot
|
||||
name: String,
|
||||
/// Optional parent context for the Schroot context
|
||||
parent: Option<String>,
|
||||
},
|
||||
/// Unshare context: chroot with dropped permissions (using `unshare`)
|
||||
#[serde(rename = "unshare")]
|
||||
Unshare {
|
||||
/// Path to use for chrooting
|
||||
path: String,
|
||||
/// Optional parent context for the Unshare context
|
||||
parent: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
/// A context, allowing to run commands, read and write files, etc
|
||||
pub struct Context {
|
||||
/// Configuration for the context
|
||||
pub config: ContextConfig,
|
||||
/// Parent context for the context
|
||||
///
|
||||
/// For example, you could have a chroot context over an ssh connection
|
||||
pub parent: Option<Arc<Context>>,
|
||||
/// ContextDriver for the context, implementing the logic for actions
|
||||
driver: Mutex<Option<Box<dyn ContextDriver + Send + Sync>>>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Create a context from configuration
|
||||
pub fn new(config: ContextConfig) -> Self {
|
||||
let parent = match &config {
|
||||
ContextConfig::Schroot {
|
||||
@@ -97,6 +116,7 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a context with an explicit parent context
|
||||
pub fn with_parent(config: ContextConfig, parent: Arc<Context>) -> Self {
|
||||
Self {
|
||||
config,
|
||||
@@ -105,6 +125,7 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
/// Make a command inside context
|
||||
pub fn command<S: AsRef<OsStr>>(&self, program: S) -> ContextCommand<'_> {
|
||||
ContextCommand {
|
||||
context: self,
|
||||
@@ -126,6 +147,7 @@ impl Context {
|
||||
.ensure_available(src, dest_root)
|
||||
}
|
||||
|
||||
/// Create a temp directory inside context
|
||||
pub fn create_temp_dir(&self) -> io::Result<String> {
|
||||
self.driver().as_ref().unwrap().create_temp_dir()
|
||||
}
|
||||
@@ -143,18 +165,22 @@ impl Context {
|
||||
self.driver().as_ref().unwrap().list_files(path)
|
||||
}
|
||||
|
||||
/// Copy a path inside context
|
||||
pub fn copy_path(&self, src: &Path, dest: &Path) -> io::Result<()> {
|
||||
self.driver().as_ref().unwrap().copy_path(src, dest)
|
||||
}
|
||||
|
||||
/// Read a file inside context
|
||||
pub fn read_file(&self, path: &Path) -> io::Result<String> {
|
||||
self.driver().as_ref().unwrap().read_file(path)
|
||||
}
|
||||
|
||||
/// Write a file inside context
|
||||
pub fn write_file(&self, path: &Path, content: &str) -> io::Result<()> {
|
||||
self.driver().as_ref().unwrap().write_file(path, content)
|
||||
}
|
||||
|
||||
/// Create and obtain a specific driver for the context
|
||||
pub fn driver(
|
||||
&self,
|
||||
) -> std::sync::MutexGuard<'_, Option<Box<dyn ContextDriver + Send + Sync>>> {
|
||||
@@ -182,6 +208,7 @@ impl Context {
|
||||
driver_lock
|
||||
}
|
||||
|
||||
/// Clone a context
|
||||
pub fn clone_raw(&self) -> Self {
|
||||
Self {
|
||||
config: self.config.clone(),
|
||||
@@ -207,12 +234,13 @@ pub struct ContextCommand<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ContextCommand<'a> {
|
||||
/// Add an argument to current command
|
||||
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
|
||||
self.args.push(arg.as_ref().to_string_lossy().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
// Support chaining args
|
||||
/// Add multiple command arguments
|
||||
pub fn args<I, S>(&mut self, args: I) -> &mut Self
|
||||
where
|
||||
I: IntoIterator<Item = S>,
|
||||
@@ -224,6 +252,7 @@ impl<'a> ContextCommand<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set environment variable for command
|
||||
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
|
||||
where
|
||||
K: AsRef<OsStr>,
|
||||
@@ -236,6 +265,7 @@ impl<'a> ContextCommand<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set multiple environment variables for command
|
||||
pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
|
||||
where
|
||||
I: IntoIterator<Item = (K, V)>,
|
||||
@@ -248,11 +278,13 @@ impl<'a> ContextCommand<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set current working directory for command
|
||||
pub fn current_dir<P: AsRef<OsStr>>(&mut self, dir: P) -> &mut Self {
|
||||
self.cwd = Some(dir.as_ref().to_string_lossy().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Run command and obtain exit status
|
||||
pub fn status(&mut self) -> io::Result<std::process::ExitStatus> {
|
||||
self.context.driver().as_ref().unwrap().run(
|
||||
&self.program,
|
||||
@@ -262,7 +294,7 @@ impl<'a> ContextCommand<'a> {
|
||||
)
|
||||
}
|
||||
|
||||
// Capture output
|
||||
/// Run command, capturing output
|
||||
pub fn output(&mut self) -> io::Result<std::process::Output> {
|
||||
self.context.driver().as_ref().unwrap().run_output(
|
||||
&self.program,
|
||||
|
||||
@@ -26,6 +26,7 @@ impl Default for Config {
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper managing contexts
|
||||
pub struct ContextManager {
|
||||
context: RwLock<Arc<Context>>,
|
||||
config_path: PathBuf,
|
||||
@@ -67,10 +68,12 @@ impl ContextManager {
|
||||
})
|
||||
}
|
||||
|
||||
/// Obtain current ContextManager configuration
|
||||
pub fn get_config(&self) -> std::sync::RwLockReadGuard<'_, Config> {
|
||||
self.config.read().unwrap()
|
||||
}
|
||||
|
||||
/// Make a ContextManager using a specific configuration path
|
||||
pub fn with_path(path: PathBuf) -> Self {
|
||||
let config = Config::default();
|
||||
Self {
|
||||
@@ -80,6 +83,7 @@ impl ContextManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// Save current context configuration to disk
|
||||
pub fn save(&self) -> io::Result<()> {
|
||||
let config = self.config.read().unwrap();
|
||||
let content = serde_json::to_string_pretty(&*config)
|
||||
@@ -97,6 +101,7 @@ impl ContextManager {
|
||||
Context::new(context_config)
|
||||
}
|
||||
|
||||
/// List contexts from configuration
|
||||
pub fn list_contexts(&self) -> Vec<String> {
|
||||
self.config
|
||||
.read()
|
||||
@@ -107,6 +112,7 @@ impl ContextManager {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Add a context to configuration
|
||||
pub fn add_context(&self, name: &str, config: ContextConfig) -> io::Result<()> {
|
||||
self.config
|
||||
.write()
|
||||
@@ -116,6 +122,7 @@ impl ContextManager {
|
||||
self.save()
|
||||
}
|
||||
|
||||
/// Remove context from configuration
|
||||
pub fn remove_context(&self, name: &str) -> io::Result<()> {
|
||||
let mut config = self.config.write().unwrap();
|
||||
if name == "local" {
|
||||
@@ -137,6 +144,7 @@ impl ContextManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set current context from name (modifying configuration)
|
||||
pub fn set_current(&self, name: &str) -> io::Result<()> {
|
||||
let mut config = self.config.write().unwrap();
|
||||
if config.contexts.contains_key(name) {
|
||||
@@ -153,14 +161,18 @@ impl ContextManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set current context, without modifying configuration
|
||||
pub fn set_current_ephemeral(&self, context: Context) {
|
||||
*self.context.write().unwrap() = context.into();
|
||||
}
|
||||
|
||||
/// Obtain current context handle
|
||||
pub fn current(&self) -> Arc<Context> {
|
||||
self.context.read().unwrap().clone()
|
||||
}
|
||||
|
||||
/// Obtain current context name
|
||||
/// Will not work for ephemeral context (obtained from config)
|
||||
pub fn current_name(&self) -> String {
|
||||
self.config.read().unwrap().context.clone()
|
||||
}
|
||||
|
||||
@@ -9,10 +9,12 @@ pub use api::{Context, ContextCommand, ContextConfig};
|
||||
pub use manager::ContextManager;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Obtain global context manager
|
||||
pub fn manager() -> &'static ContextManager {
|
||||
&manager::MANAGER
|
||||
}
|
||||
|
||||
/// Obtain current context
|
||||
pub fn current() -> Arc<Context> {
|
||||
manager::MANAGER.current()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user