pkh context allows to manage contexts (local, ssh) and run contextualized commands (deb) in other words, this allows building binary packages over ssh
This commit is contained in:
120
src/main.rs
120
src/main.rs
@@ -53,7 +53,31 @@ fn main() {
|
||||
Command::new("deb")
|
||||
.about("Build the binary package")
|
||||
.arg(arg!(-s --series <series> "Target distribution series").required(false))
|
||||
.arg(arg!(-a --arch <arch> "Target architecture").required(false))
|
||||
.arg(arg!(-a --arch <arch> "Target architecture").required(false)),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("context")
|
||||
.about("Manage contexts")
|
||||
.subcommand_required(true)
|
||||
.subcommand(
|
||||
Command::new("create")
|
||||
.about("Create a new context")
|
||||
.arg(arg!(<name> "Context name"))
|
||||
.arg(arg!(--type <type> "Context type: ssh (only type supported for now)"))
|
||||
.arg(arg!(--endpoint <endpoint> "Context endpoint (for example: ssh://user@host:port)"))
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("rm")
|
||||
.about("Remove a context")
|
||||
.arg(arg!(<name> "Context name"))
|
||||
)
|
||||
.subcommand(Command::new("ls").about("List contexts"))
|
||||
.subcommand(Command::new("show").about("Show current context"))
|
||||
.subcommand(
|
||||
Command::new("use")
|
||||
.about("Set current context")
|
||||
.arg(arg!(<name> "Context name"))
|
||||
)
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
@@ -124,6 +148,100 @@ fn main() {
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
Some(("context", sub_matches)) => {
|
||||
use pkh::context::{Context, ContextManager};
|
||||
|
||||
let mut mgr = match ContextManager::new() {
|
||||
Ok(mgr) => mgr,
|
||||
Err(e) => {
|
||||
error!("Failed to initialize context manager: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
match sub_matches.subcommand() {
|
||||
Some(("create", args)) => {
|
||||
let name = args.get_one::<String>("name").unwrap();
|
||||
let type_str = args
|
||||
.get_one::<String>("type")
|
||||
.map(|s| s.as_str())
|
||||
.unwrap_or("local");
|
||||
|
||||
let context = match type_str {
|
||||
"local" => Context::Local,
|
||||
"ssh" => {
|
||||
let endpoint = args
|
||||
.get_one::<String>("endpoint")
|
||||
.expect("Endpoint is required for ssh context");
|
||||
|
||||
// Parse host, user, port from endpoint
|
||||
// Formats: [ssh://][user@]host[:port]
|
||||
let endpoint_re = regex::Regex::new(r"^(?:ssh://)?(?:(?P<user>[^@]+)@)?(?P<host>[^:/]+)(?::(?P<port>\d+))?$").unwrap();
|
||||
let endpoint_cap = endpoint_re.captures(endpoint).unwrap_or_else(|| {
|
||||
error!("Invalid endpoint format: '{}'. Expected [ssh://][user@]host[:port]", endpoint);
|
||||
std::process::exit(1);
|
||||
});
|
||||
|
||||
let host = endpoint_cap.name("host").unwrap().as_str().to_string();
|
||||
let user = endpoint_cap.name("user").map(|m| m.as_str().to_string());
|
||||
let port = endpoint_cap.name("port").map(|m| {
|
||||
m.as_str().parse::<u16>().unwrap_or_else(|_| {
|
||||
error!("Invalid port number");
|
||||
std::process::exit(1);
|
||||
})
|
||||
});
|
||||
|
||||
Context::Ssh { host, user, port }
|
||||
}
|
||||
_ => {
|
||||
error!("Unknown context type: {}", type_str);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = mgr.add_context(name, context) {
|
||||
error!("Failed to create context: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
info!("Context '{}' created.", name);
|
||||
}
|
||||
Some(("rm", args)) => {
|
||||
let name = args.get_one::<String>("name").unwrap();
|
||||
if let Err(e) = mgr.remove_context(name) {
|
||||
error!("Failed to remove context: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
info!("Context '{}' removed.", name);
|
||||
}
|
||||
Some(("ls", _)) => {
|
||||
let contexts = mgr.list_contexts();
|
||||
let current = mgr.current_name();
|
||||
for ctx in contexts {
|
||||
if Some(&ctx) == current.as_ref() {
|
||||
println!("* {}", ctx);
|
||||
} else {
|
||||
println!(" {}", ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(("show", _)) => {
|
||||
if let Some(name) = mgr.current_name() {
|
||||
println!("{}", name);
|
||||
} else {
|
||||
println!("No context set (defaulting to local)");
|
||||
}
|
||||
}
|
||||
Some(("use", args)) => {
|
||||
let name = args.get_one::<String>("name").unwrap();
|
||||
if let Err(e) = mgr.set_current(name) {
|
||||
error!("Failed to set context: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
info!("Switched to context '{}'.", name);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
_ => unreachable!("Exhausted list of subcommands and subcommand_required prevents `None`"),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user