use std::path::PathBuf;
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub enum Operation {
CreateDataLink {
pack: String,
handler: String,
source: PathBuf,
},
CreateUserLink {
pack: String,
handler: String,
datastore_path: PathBuf,
user_path: PathBuf,
},
RunCommand {
pack: String,
handler: String,
executable: String,
arguments: Vec<String>,
sentinel: String,
},
CheckSentinel {
pack: String,
handler: String,
sentinel: String,
},
}
impl Operation {
pub fn pack(&self) -> &str {
match self {
Self::CreateDataLink { pack, .. }
| Self::CreateUserLink { pack, .. }
| Self::RunCommand { pack, .. }
| Self::CheckSentinel { pack, .. } => pack,
}
}
pub fn handler(&self) -> &str {
match self {
Self::CreateDataLink { handler, .. }
| Self::CreateUserLink { handler, .. }
| Self::RunCommand { handler, .. }
| Self::CheckSentinel { handler, .. } => handler,
}
}
pub fn kind(&self) -> &'static str {
match self {
Self::CreateDataLink { .. } => "CreateDataLink",
Self::CreateUserLink { .. } => "CreateUserLink",
Self::RunCommand { .. } => "RunCommand",
Self::CheckSentinel { .. } => "CheckSentinel",
}
}
}
#[derive(Debug, Clone, Serialize)]
pub enum HandlerIntent {
Link {
pack: String,
handler: String,
source: PathBuf,
user_path: PathBuf,
},
Stage {
pack: String,
handler: String,
source: PathBuf,
},
Run {
pack: String,
handler: String,
executable: String,
arguments: Vec<String>,
sentinel: String,
},
}
impl HandlerIntent {
pub fn pack(&self) -> &str {
match self {
Self::Link { pack, .. } | Self::Stage { pack, .. } | Self::Run { pack, .. } => pack,
}
}
pub fn handler(&self) -> &str {
match self {
Self::Link { handler, .. }
| Self::Stage { handler, .. }
| Self::Run { handler, .. } => handler,
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct OperationResult {
pub operation: Operation,
pub success: bool,
pub message: String,
}
impl OperationResult {
pub fn ok(operation: Operation, message: impl Into<String>) -> Self {
Self {
operation,
success: true,
message: message.into(),
}
}
pub fn fail(operation: Operation, message: impl Into<String>) -> Self {
Self {
operation,
success: false,
message: message.into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn operation_accessors() {
let op = Operation::CreateDataLink {
pack: "vim".into(),
handler: "symlink".into(),
source: PathBuf::from("/src/vimrc"),
};
assert_eq!(op.pack(), "vim");
assert_eq!(op.handler(), "symlink");
assert_eq!(op.kind(), "CreateDataLink");
}
#[test]
fn handler_intent_accessors() {
let intent = HandlerIntent::Link {
pack: "git".into(),
handler: "symlink".into(),
source: PathBuf::from("/src/gitconfig"),
user_path: PathBuf::from("/home/.gitconfig"),
};
assert_eq!(intent.pack(), "git");
assert_eq!(intent.handler(), "symlink");
}
#[test]
fn operation_result_constructors() {
let op = Operation::CheckSentinel {
pack: "vim".into(),
handler: "install".into(),
sentinel: "abc".into(),
};
let ok = OperationResult::ok(op.clone(), "done");
assert!(ok.success);
let fail = OperationResult::fail(op, "oops");
assert!(!fail.success);
}
#[test]
fn operation_serializes() {
let op = Operation::RunCommand {
pack: "vim".into(),
handler: "install".into(),
executable: "echo".into(),
arguments: vec!["hi".into()],
sentinel: "s1".into(),
};
let json = serde_json::to_string(&op).unwrap();
assert!(json.contains("RunCommand"));
assert!(json.contains("echo"));
assert!(json.contains("hi"));
}
}