1pub mod args;
7pub mod bundle;
8pub mod client;
9pub mod commands;
10pub mod config;
11pub mod credentials;
12pub mod docref;
13pub mod exit;
14pub mod output;
15pub mod remember;
16
17use clap::Parser;
18
19use crate::args::{Cli, Cmd};
20use crate::config::{Flags, Settings};
21
22pub struct Ctx {
24 pub settings: Settings,
25 pub json: bool,
26 pub store: credentials::Store,
27}
28
29impl Ctx {
30 pub fn client(&self) -> anyhow::Result<client::Client> {
31 client::Client::new(&self.settings)
32 }
33}
34
35pub async fn main_entry() -> i32 {
37 config::load_dotenv();
38 let cli = Cli::parse();
39 let env = |k: &str| std::env::var(k).ok();
40 let result = async {
41 let ctx = build_ctx(&cli, &env)?;
42 run(ctx, cli.cmd).await
43 }
44 .await;
45 match result {
46 Ok(code) => code,
47 Err(e) => {
48 match e.downcast_ref::<exit::Exit>() {
49 Some(x) => eprintln!("error: {}", x.message),
50 None => eprintln!("error: {e:#}"),
51 }
52 exit::code_of(&e)
53 }
54 }
55}
56
57fn build_ctx(cli: &Cli, env: &dyn Fn(&str) -> Option<String>) -> anyhow::Result<Ctx> {
58 let dir = config::config_dir(env);
59 let file = config::read_file_config(&dir)?;
60 let no_keyring = env("SEMORA_NO_KEYRING").is_some_and(|v| !v.is_empty() && v != "0");
61 let store = credentials::Store::new(&dir, !no_keyring);
62 let flags = Flags {
63 server: cli.server.clone(),
64 api_key: cli.api_key.clone(),
65 };
66 let settings = config::resolve(&flags, env, &file, store.default_server(), &|u| {
67 store.get(&config::origin(u))
68 })?;
69 Ok(Ctx {
70 settings,
71 json: cli.json,
72 store,
73 })
74}
75
76async fn run(ctx: Ctx, cmd: Cmd) -> anyhow::Result<i32> {
77 use commands::*;
78 match cmd {
79 Cmd::Push(a) => push::run(&ctx, a).await,
80 Cmd::Watch(a) => watch::run(&ctx, a).await,
81 Cmd::Wait(a) => wait::run(&ctx, a).await,
82 Cmd::Say {
83 doc,
84 text,
85 reply_to,
86 } => events::say(&ctx, &doc, &text, reply_to).await,
87 Cmd::Ls {
88 query,
89 tag,
90 kind,
91 limit,
92 } => docs::ls(&ctx, query, tag, kind, limit).await,
93 Cmd::Show { doc } => docs::show(&ctx, &doc).await,
94 Cmd::Get {
95 doc,
96 path,
97 rev,
98 output,
99 } => docs::get(&ctx, &doc, path, rev, output).await,
100 Cmd::Tag { doc, changes } => docs::tag(&ctx, &doc, &changes).await,
101 Cmd::Rm { doc } => docs::rm(&ctx, &doc).await,
102 Cmd::Open { doc } => docs::open(&ctx, &doc).await,
103 Cmd::Whoami => account::whoami(&ctx).await,
104 Cmd::Login { no_browser, name } => login::login(&ctx, no_browser, name).await,
105 Cmd::Logout => login::logout(&ctx).await,
106 Cmd::Keys(k) => account::keys(&ctx, k).await,
107 Cmd::Skill => skill::run(&ctx),
108 }
109}