pray-cli 1.9.1

Package manager for the language placed before inference — Prayfile CLI (binary: pray)
use crate::Command;
use pray_core::{PrayError, PrayResult};
use std::path::PathBuf;

pub(crate) fn parse_login_command(
    mut arguments: std::vec::IntoIter<String>,
) -> PrayResult<Command> {
    let mut servers = Vec::new();
    let mut email = None;
    let mut credential_id = None;
    let mut passkey_key = None;
    let mut public_key = None;
    let mut ssh_agent = false;
    while let Some(argument) = arguments.next() {
        match argument.as_str() {
            "--server" => {
                let Some(value) = arguments.next() else {
                    return Err(PrayError::Unsupported(
                        "login requires a URL after --server".to_string(),
                    ));
                };
                servers.push(value);
            }
            "--email" => {
                let Some(value) = arguments.next() else {
                    return Err(PrayError::Unsupported(
                        "login requires an email after --email".to_string(),
                    ));
                };
                email = Some(value);
            }
            "--credential-id" => {
                let Some(value) = arguments.next() else {
                    return Err(PrayError::Unsupported(
                        "login requires a credential id after --credential-id".to_string(),
                    ));
                };
                credential_id = Some(value);
            }
            "--passkey-key" => {
                let Some(value) = arguments.next() else {
                    return Err(PrayError::Unsupported(
                        "login requires a path after --passkey-key".to_string(),
                    ));
                };
                passkey_key = Some(PathBuf::from(value));
            }
            "--public-key" => {
                let Some(value) = arguments.next() else {
                    return Err(PrayError::Unsupported(
                        "login requires a path after --public-key".to_string(),
                    ));
                };
                public_key = Some(PathBuf::from(value));
            }
            "--ssh-agent" => ssh_agent = true,
            other if other.starts_with("--") => {
                return Err(PrayError::Unsupported(format!(
                    "unknown login flag: {other}"
                )))
            }
            other => {
                return Err(PrayError::Unsupported(format!(
                    "unexpected login argument: {other}"
                )))
            }
        }
    }
    if servers.is_empty() {
        return Err(PrayError::Unsupported(
            "login requires at least one --server URL".to_string(),
        ));
    }
    let email = email
        .ok_or_else(|| PrayError::Unsupported("login requires --email ADDRESS".to_string()))?;
    if passkey_key.is_some() == ssh_agent || (passkey_key.is_none() && public_key.is_none()) {
        return Err(PrayError::Unsupported(
            "login requires exactly one authentication mode".to_string(),
        ));
    }
    if passkey_key.is_some() && credential_id.is_none() {
        return Err(PrayError::Unsupported(
            "passkey login requires --credential-id".to_string(),
        ));
    }
    if ssh_agent && public_key.is_none() {
        return Err(PrayError::Unsupported(
            "ssh-agent login requires --public-key".to_string(),
        ));
    }
    Ok(Command::Login {
        servers,
        email,
        credential_id,
        passkey_key,
        public_key,
        ssh_agent,
    })
}

#[cfg(feature = "auth")]
pub(crate) fn parse_serve_command(
    mut arguments: std::vec::IntoIter<String>,
) -> PrayResult<Command> {
    let mut root = PathBuf::from(".");
    let mut host = "127.0.0.1".to_string();
    let mut port = 7429u16;
    let mut stdio = false;
    let mut allow_open_push = false;
    while let Some(argument) = arguments.next() {
        match argument.as_str() {
            "--root" => {
                let Some(value) = arguments.next() else {
                    return Err(PrayError::Unsupported(
                        "serve requires a path after --root".to_string(),
                    ));
                };
                root = PathBuf::from(value);
            }
            "--host" => {
                let Some(value) = arguments.next() else {
                    return Err(PrayError::Unsupported(
                        "serve requires a host after --host".to_string(),
                    ));
                };
                host = value;
            }
            "--port" => {
                let Some(value) = arguments.next() else {
                    return Err(PrayError::Unsupported(
                        "serve requires a port after --port".to_string(),
                    ));
                };
                port = value
                    .parse::<u16>()
                    .map_err(|error| PrayError::Unsupported(error.to_string()))?;
            }
            "--stdio" => stdio = true,
            "--allow-open-push" => allow_open_push = true,
            other if other.starts_with("--") => {
                return Err(PrayError::Unsupported(format!(
                    "unknown serve flag: {other}"
                )))
            }
            other => {
                return Err(PrayError::Unsupported(format!(
                    "unexpected serve argument: {other}"
                )))
            }
        }
    }
    Ok(Command::Serve {
        root,
        host,
        port,
        stdio,
        allow_open_push,
    })
}