Organize the public CLI with clap
This commit is contained in:
parent
e7dd95aea6
commit
d08d931b5f
1 changed files with 445 additions and 255 deletions
|
|
@ -1,8 +1,6 @@
|
|||
use std::ffi::OsString;
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Write};
|
||||
use std::os::unix::ffi::OsStringExt;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Mutex;
|
||||
|
||||
|
|
@ -22,6 +20,7 @@ use sha2::{Digest, Sha256};
|
|||
|
||||
use crate::terminal::{HostTerminal, InteractiveSessionTransport, run_interactive_session};
|
||||
|
||||
pub mod cli;
|
||||
pub mod coordinator_backend;
|
||||
pub mod state;
|
||||
pub mod terminal;
|
||||
|
|
@ -34,82 +33,6 @@ pub struct ClientCommand {
|
|||
pub argv: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ArgumentError(&'static str);
|
||||
|
||||
impl fmt::Display for ArgumentError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ArgumentError {}
|
||||
|
||||
/// Parses `--profile`, optional host paths, and the exact command following `--`.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns a concise usage error for missing values, unknown options, or a missing command.
|
||||
pub fn parse_command_line(
|
||||
arguments: impl IntoIterator<Item = OsString>,
|
||||
current_workspace: PathBuf,
|
||||
) -> Result<ClientCommand, ArgumentError> {
|
||||
let mut arguments = arguments.into_iter();
|
||||
let mut profile = None;
|
||||
let mut workspace = None;
|
||||
let mut configuration = None;
|
||||
let mut argv = Vec::new();
|
||||
while let Some(argument) = arguments.next() {
|
||||
match argument.to_str() {
|
||||
Some("--profile") => profile = Some(required_utf8(&mut arguments, "--profile")?),
|
||||
Some("--workspace") => {
|
||||
workspace = Some(PathBuf::from(required_value(
|
||||
&mut arguments,
|
||||
"--workspace",
|
||||
)?));
|
||||
}
|
||||
Some("--config") => {
|
||||
configuration = Some(PathBuf::from(required_value(&mut arguments, "--config")?));
|
||||
}
|
||||
Some("--") => {
|
||||
argv.extend(arguments.map(OsString::into_vec));
|
||||
break;
|
||||
}
|
||||
Some(_) | None => return Err(ArgumentError("unknown option before `--`")),
|
||||
}
|
||||
}
|
||||
let profile = profile.ok_or(ArgumentError("`--profile <name>` is required"))?;
|
||||
if argv.is_empty() {
|
||||
return Err(ArgumentError("a command is required after `--`"));
|
||||
}
|
||||
Ok(ClientCommand {
|
||||
profile,
|
||||
workspace: workspace.unwrap_or(current_workspace),
|
||||
configuration,
|
||||
argv,
|
||||
})
|
||||
}
|
||||
|
||||
fn required_value(
|
||||
arguments: &mut impl Iterator<Item = OsString>,
|
||||
option: &'static str,
|
||||
) -> Result<OsString, ArgumentError> {
|
||||
arguments.next().ok_or(match option {
|
||||
"--profile" => ArgumentError("`--profile` requires a value"),
|
||||
"--workspace" => ArgumentError("`--workspace` requires a path"),
|
||||
"--config" => ArgumentError("`--config` requires a path"),
|
||||
_ => ArgumentError("option requires a value"),
|
||||
})
|
||||
}
|
||||
|
||||
fn required_utf8(
|
||||
arguments: &mut impl Iterator<Item = OsString>,
|
||||
option: &'static str,
|
||||
) -> Result<String, ArgumentError> {
|
||||
required_value(arguments, option)?
|
||||
.into_string()
|
||||
.map_err(|_| ArgumentError("profile name must be UTF-8"))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum DomainStatus<E> {
|
||||
Absent,
|
||||
|
|
|
|||
Loading…
Reference in a new issue