Skip to main content

codeberg_cli/actions/auth/
list.rs

1use crate::actions::GlobalArgs;
2use crate::paths::berg_data_dir;
3use crate::render::json::JsonToStdout;
4use crate::types::context::BergContext;
5use crate::types::output::OutputMode;
6use miette::IntoDiagnostic;
7
8use clap::Parser;
9
10/// List all forgejo instances you're authenticated for
11#[derive(Parser, Debug)]
12pub struct ListArgs {}
13
14impl ListArgs {
15    pub async fn run(self, global_args: GlobalArgs) -> miette::Result<()> {
16        let ctx = BergContext::new(self, global_args).await?;
17        let data_dir = berg_data_dir()?;
18
19        let instances = data_dir
20            .read_dir()
21            .into_diagnostic()?
22            .filter_map(|dir| {
23                let entry = dir.ok()?;
24
25                let logged_in = entry.metadata().is_ok_and(|metadata| metadata.is_dir())
26                    && entry
27                        .path()
28                        .read_dir()
29                        .into_iter()
30                        .flatten()
31                        .any(|content| content.is_ok_and(|content| content.file_name() == "TOKEN"));
32
33                Some(Instance {
34                    base_url: entry.file_name().display().to_string(),
35                    logged_in,
36                })
37            })
38            .collect::<Vec<_>>();
39
40        match ctx.global_args.output_mode {
41            OutputMode::Pretty => {
42                present_instance_list(ctx, instances);
43            }
44            OutputMode::Json => {
45                instances.print_json()?;
46            }
47        }
48
49        Ok(())
50    }
51}
52
53#[derive(Debug, Clone, serde::Serialize)]
54struct Instance {
55    base_url: String,
56    logged_in: bool,
57}
58
59fn present_instance_list(ctx: BergContext<ListArgs>, instances: Vec<Instance>) {
60    let issues_empty = instances.is_empty();
61
62    let table = ctx
63        .make_table()
64        .set_header(vec!["Base URL", "Logged In"])
65        .add_rows(instances.into_iter().map(|instance| {
66            let Instance {
67                base_url,
68                logged_in,
69            } = instance;
70            vec![base_url, String::from(if logged_in { "Yes" } else { "No" })]
71        }));
72
73    let header = format!(
74        "Instances{}",
75        if issues_empty {
76            " (empty)"
77        } else {
78            Default::default()
79        }
80    );
81
82    let underscore = "=".repeat(header.len());
83    let out = [header, underscore, table.show()].join("\n");
84
85    println!("{out}");
86}