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