pub mod args;
pub mod bundle;
pub mod checkout;
pub mod client;
pub mod commands;
pub mod config;
pub mod credentials;
pub mod docref;
pub mod exit;
pub mod output;
pub mod project_link;
pub mod remember;
use clap::Parser;
use crate::args::{Cli, Cmd};
use crate::config::{Flags, Settings};
pub struct Ctx {
pub settings: Settings,
pub json: bool,
pub store: credentials::Store,
}
impl Ctx {
pub fn client(&self) -> anyhow::Result<client::Client> {
client::Client::new(&self.settings)
}
}
pub async fn main_entry() -> i32 {
config::load_dotenv();
let cli = match Cli::try_parse() {
Ok(cli) => cli,
Err(e) => {
print_banner(&e);
e.exit()
}
};
let env = |k: &str| std::env::var(k).ok();
let result = async {
let ctx = build_ctx(&cli, &env)?;
run(ctx, cli.cmd).await
}
.await;
match result {
Ok(code) => code,
Err(e) => {
match e.downcast_ref::<exit::Exit>() {
Some(x) => output::error(&x.message),
None => output::error(format!("{e:#}")),
}
exit::code_of(&e)
}
}
}
fn print_banner(e: &clap::Error) {
use std::io::IsTerminal;
if e.kind() == clap::error::ErrorKind::DisplayVersion {
if std::io::stdout().is_terminal() {
anstream::println!("{}", output::banner(output::out()));
}
} else if std::env::args_os().len() == 1 && std::io::stderr().is_terminal() {
anstream::eprintln!("{}\n", output::banner(output::err()));
}
}
fn build_ctx(cli: &Cli, env: &dyn Fn(&str) -> Option<String>) -> anyhow::Result<Ctx> {
let dir = config::config_dir(env);
let file = config::read_file_config(&dir)?;
let no_keyring = env("SEMORA_NO_KEYRING").is_some_and(|v| !v.is_empty() && v != "0");
let store = credentials::Store::new(&dir, !no_keyring);
let flags = Flags {
server: cli.server.clone(),
api_key: cli.api_key.clone(),
};
let settings = config::resolve(&flags, env, &file, store.default_server(), &|u| {
store.get(&config::origin(u))
})?;
Ok(Ctx {
settings,
json: cli.json,
store,
})
}
async fn run(ctx: Ctx, cmd: Cmd) -> anyhow::Result<i32> {
use commands::*;
match cmd {
Cmd::Push(a) => push::run(&ctx, a).await,
Cmd::Watch(a) => watch::run(&ctx, a).await,
Cmd::Pull(a) => pull::pull(&ctx, a).await,
Cmd::Status { path } => pull::status(&ctx, path).await,
Cmd::Wait(a) => wait::run(&ctx, a).await,
Cmd::Say {
doc,
text,
reply_to,
} => events::say(&ctx, &doc, &text, reply_to).await,
Cmd::Ls {
query,
tag,
kind,
project,
limit,
} => docs::ls(&ctx, query, tag, kind, project, limit).await,
Cmd::Show { doc } => docs::show(&ctx, &doc).await,
Cmd::Get {
doc,
path,
rev,
output,
} => docs::get(&ctx, &doc, path, rev, output).await,
Cmd::Tag { doc, changes } => docs::tag(&ctx, &doc, &changes).await,
Cmd::Rm { doc } => docs::rm(&ctx, &doc).await,
Cmd::Open { doc } => docs::open(&ctx, &doc).await,
Cmd::Whoami => account::whoami(&ctx).await,
Cmd::Login { no_browser, name } => login::login(&ctx, no_browser, name).await,
Cmd::Logout => login::logout(&ctx).await,
Cmd::Keys(k) => account::keys(&ctx, k).await,
Cmd::Project(p) => project::run(&ctx, p).await,
Cmd::Skill => skill::run(&ctx),
}
}