noosphere_cli/native/
mod.rs

1//! Functions for invoking the CLI imperatively
2
3pub mod cli;
4pub mod commands;
5pub mod content;
6pub mod extension;
7pub mod paths;
8pub mod render;
9pub mod workspace;
10
11#[cfg(any(test, feature = "helpers"))]
12pub mod helpers;
13
14use std::path::{Path, PathBuf};
15
16use self::{
17    cli::{AuthCommand, Cli, ConfigCommand, FollowCommand, KeyCommand, OrbCommand, SphereCommand},
18    commands::{
19        key::{key_create, key_list},
20        serve::serve,
21        sphere::{
22            auth_add, auth_list, auth_revoke, config_get, config_set, follow_add, follow_list,
23            follow_remove, follow_rename, history, save, sphere_create, sphere_join, status, sync,
24        },
25    },
26    workspace::Workspace,
27};
28use anyhow::Result;
29use clap::Parser;
30use noosphere_core::tracing::initialize_tracing;
31use noosphere_storage::StorageConfig;
32use vergen_pretty::{vergen_pretty_env, PrettyBuilder};
33
34/// Additional context used to invoke a [Cli] command.
35pub struct CliContext<'a> {
36    /// Path to the current working directory.
37    cwd: PathBuf,
38    /// Path to the global configuration directory, if provided.
39    global_config_directory: Option<&'a Path>,
40}
41
42#[cfg(not(doc))]
43#[allow(missing_docs)]
44pub async fn main() -> Result<()> {
45    initialize_tracing(None);
46    let context = CliContext {
47        cwd: std::env::current_dir()?,
48        global_config_directory: None,
49    };
50    invoke_cli(Cli::parse(), &context).await
51}
52
53/// Invoke the CLI implementation imperatively.
54///
55/// This is the entrypoint used by orb when handling a command line invocation.
56/// The [Cli] is produced by parsing the command line arguments, and internally
57/// creates a new [Workspace] from the current working directory.
58///
59/// Use [invoke_cli_with_workspace] if using your own [Workspace].
60pub async fn invoke_cli<'a>(cli: Cli, context: &CliContext<'a>) -> Result<()> {
61    let storage_config = if let OrbCommand::Serve {
62        storage_memory_cache_limit,
63        ..
64    } = &cli.command
65    {
66        Some(StorageConfig {
67            memory_cache_limit: *storage_memory_cache_limit,
68        })
69    } else {
70        None
71    };
72    let workspace = Workspace::new(
73        &context.cwd,
74        context.global_config_directory,
75        storage_config,
76    )?;
77
78    invoke_cli_with_workspace(cli, workspace).await
79}
80
81/// Same as [invoke_cli], but enables the caller to provide their own
82/// initialized [Workspace]
83pub async fn invoke_cli_with_workspace(cli: Cli, mut workspace: Workspace) -> Result<()> {
84    match cli.command {
85        OrbCommand::Key { command } => match command {
86            KeyCommand::Create { name } => key_create(&name, &workspace).await?,
87            KeyCommand::List { as_json } => key_list(as_json, &workspace).await?,
88        },
89        OrbCommand::Version { verbose } => {
90            let version = env!("CARGO_PKG_VERSION");
91
92            if verbose {
93                let mut out = Vec::new();
94                PrettyBuilder::default()
95                    .env(vergen_pretty_env!())
96                    .build()?
97                    .display(&mut out)?;
98
99                info!("{:>28}: {}", "Version (  orb)", version);
100                info!("{}", std::str::from_utf8(&out)?);
101            } else {
102                info!("{}", version);
103            }
104        }
105        OrbCommand::Sphere { command } => match command {
106            SphereCommand::Create { owner_key } => {
107                sphere_create(&owner_key, &mut workspace).await?;
108            }
109            SphereCommand::Join {
110                local_key,
111                authorization,
112                id,
113                gateway_url,
114                render_depth,
115            } => {
116                sphere_join(
117                    &local_key,
118                    authorization,
119                    &id,
120                    &gateway_url,
121                    render_depth,
122                    &mut workspace,
123                )
124                .await?;
125            }
126            SphereCommand::Auth { command } => match command {
127                AuthCommand::Add { did, name } => {
128                    auth_add(&did, name, &workspace).await?;
129                }
130                AuthCommand::List { tree, as_json } => auth_list(tree, as_json, &workspace).await?,
131                AuthCommand::Revoke { name } => auth_revoke(&name, &workspace).await?,
132                AuthCommand::Rotate {} => unimplemented!(),
133            },
134            SphereCommand::Config { command } => match command {
135                ConfigCommand::Set { command } => config_set(command, &workspace).await?,
136                ConfigCommand::Get { command } => config_get(command, &workspace).await?,
137            },
138
139            SphereCommand::Status { id } => status(id, &workspace).await?,
140            SphereCommand::Save { render_depth } => save(render_depth, &workspace).await?,
141            SphereCommand::Sync {
142                auto_retry,
143                render_depth,
144            } => sync(auto_retry, render_depth, &workspace).await?,
145            SphereCommand::Follow { command } => match command {
146                FollowCommand::Add { name, sphere_id } => {
147                    follow_add(name, sphere_id, &workspace).await?;
148                }
149                FollowCommand::Remove {
150                    by_name,
151                    by_sphere_id,
152                } => follow_remove(by_name, by_sphere_id, &workspace).await?,
153                FollowCommand::Rename { from, to } => follow_rename(from, to, &workspace).await?,
154                FollowCommand::List { as_json } => follow_list(as_json, &workspace).await?,
155            },
156            SphereCommand::Render { render_depth } => {
157                commands::sphere::render(render_depth, &workspace).await?
158            }
159            SphereCommand::History => {
160                history(&workspace).await?;
161            }
162        },
163
164        OrbCommand::Serve {
165            cors_origin,
166            ipfs_api,
167            name_resolver_api,
168            interface,
169            port,
170            ..
171        } => {
172            serve(
173                interface,
174                port,
175                ipfs_api,
176                name_resolver_api,
177                cors_origin,
178                &mut workspace,
179            )
180            .await?;
181        }
182    }
183
184    Ok(())
185}