pray-cli 1.12.0

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

pub(crate) fn run_token_command(arguments: Vec<String>) -> PrayResult<()> {
    let mut iter = arguments.into_iter();
    let subcommand = iter
        .next()
        .ok_or_else(|| PrayError::Unsupported("token requires a subcommand".to_string()))?;
    match subcommand.as_str() {
        "create" => token_create_command(iter),
        "revoke" => token_revoke_command(iter),
        other => Err(PrayError::Unsupported(format!(
            "unknown token command: {other}"
        ))),
    }
}

fn token_create_command(mut arguments: std::vec::IntoIter<String>) -> PrayResult<()> {
    let mut root = None;
    let mut email = None;
    let mut scopes = Vec::new();
    while let Some(argument) = arguments.next() {
        match argument.as_str() {
            "--root" => {
                root = Some(PathBuf::from(arguments.next().ok_or_else(|| {
                    PrayError::Unsupported("token create requires a path after --root".into())
                })?));
            }
            "--email" => {
                email = Some(arguments.next().ok_or_else(|| {
                    PrayError::Unsupported("token create requires a value after --email".into())
                })?);
            }
            "--scope" => {
                scopes.push(arguments.next().ok_or_else(|| {
                    PrayError::Unsupported("token create requires a value after --scope".into())
                })?);
            }
            other => {
                return Err(PrayError::Unsupported(format!(
                    "unknown token create flag: {other}"
                )))
            }
        }
    }
    let root = root
        .ok_or_else(|| PrayError::Unsupported("token create requires --root PATH".to_string()))?;
    let email = email
        .ok_or_else(|| PrayError::Unsupported("token create requires --email EMAIL".to_string()))?;
    if scopes.is_empty() {
        scopes.push(PUBLISH_SCOPE.to_string());
    }
    let store = RegistryAuthStore::open(&root)?;
    let record = store.issue_publish_token(&email, &scopes)?;
    println!("{}", record.token);
    eprintln!(
        "created publish token for {} with scopes {}",
        record.email,
        record.scopes.join(",")
    );
    eprintln!("set PRAY_PUBLISH_TOKEN to this value for pray publish --server");
    Ok(())
}

fn token_revoke_command(mut arguments: std::vec::IntoIter<String>) -> PrayResult<()> {
    let mut root = None;
    let mut token = None;
    while let Some(argument) = arguments.next() {
        match argument.as_str() {
            "--root" => {
                root = Some(PathBuf::from(arguments.next().ok_or_else(|| {
                    PrayError::Unsupported("token revoke requires a path after --root".into())
                })?));
            }
            other if !other.starts_with('-') => token = Some(other.to_string()),
            other => {
                return Err(PrayError::Unsupported(format!(
                    "unknown token revoke flag: {other}"
                )))
            }
        }
    }
    let root = root
        .ok_or_else(|| PrayError::Unsupported("token revoke requires --root PATH".to_string()))?;
    let token =
        token.ok_or_else(|| PrayError::Unsupported("token revoke requires TOKEN".to_string()))?;
    let store = RegistryAuthStore::open(&root)?;
    store.revoke_publish_token(&token)?;
    println!("revoked publish token");
    Ok(())
}