Skip to main content

gobby_code/commands/status/
current.rs

1use std::fmt::Write as _;
2use std::path::Path;
3
4use crate::config::Context;
5use crate::db;
6use crate::models::IndexedProject;
7use crate::output::{self, Format};
8use crate::utils::short_id;
9use crate::visibility;
10
11use super::shared::{format_coverage, format_timestamp, indexed_project_from_row};
12
13pub fn run(ctx: &Context, format: Format) -> anyhow::Result<()> {
14    let mut conn = db::connect_readonly(&ctx.database_url)?;
15
16    let stats: Option<IndexedProject> = conn
17        .query_opt(
18            "SELECT id,
19                    root_path,
20                    total_files::BIGINT AS total_files,
21                    total_symbols::BIGINT AS total_symbols,
22                    last_indexed_at::TEXT AS last_indexed_at,
23                    COALESCE(index_duration_ms, 0)::BIGINT AS index_duration_ms,
24                    NULL::BIGINT AS total_eligible_files
25             FROM code_indexed_projects WHERE id = $1",
26            &[&ctx.project_id],
27        )
28        .ok()
29        .flatten()
30        .and_then(|row| indexed_project_from_row(&row).ok());
31
32    match stats {
33        Some(s) => match format {
34            Format::Json => {
35                let mut value = serde_json::to_value(&s)?;
36                if let Some(overlay) = overlay_status_json(ctx, &mut conn) {
37                    value["overlay"] = overlay;
38                }
39                output::print_json(&value)
40            }
41            Format::Text => {
42                let name = Path::new(&s.root_path)
43                    .file_name()
44                    .map(|n| n.to_string_lossy().to_string())
45                    .unwrap_or_else(|| s.id.clone());
46                let mut text = String::new();
47                writeln!(text, "{} ({})", name, short_id(&s.id))?;
48                writeln!(text, "  Root:     {}", s.root_path)?;
49                writeln!(
50                    text,
51                    "  Files:    {}",
52                    format_coverage(s.total_files, s.total_eligible_files)
53                )?;
54                writeln!(text, "  Symbols:  {}", s.total_symbols)?;
55                writeln!(text, "  Indexed:  {}", format_timestamp(&s.last_indexed_at))?;
56                write!(text, "  Duration: {}ms", s.index_duration_ms)?;
57                if let crate::config::ProjectIndexScope::Overlay {
58                    parent_project_id,
59                    parent_root,
60                    ..
61                } = &ctx.index_scope
62                {
63                    writeln!(text)?;
64                    write!(
65                        text,
66                        "  Overlay:  parent {} ({})",
67                        parent_root.display(),
68                        short_id(parent_project_id)
69                    )?;
70                    let tombstones = visibility::tombstone_count(&mut conn, ctx);
71                    if tombstones > 0 {
72                        writeln!(text)?;
73                        write!(text, "  Deletes:  {tombstones}")?;
74                    }
75                }
76                output::print_text(&text)
77            }
78        },
79        None => {
80            eprintln!(
81                "No index found for project {}. Run `gcode index` first.",
82                ctx.project_id
83            );
84            Ok(())
85        }
86    }
87}
88
89fn overlay_status_json(ctx: &Context, conn: &mut postgres::Client) -> Option<serde_json::Value> {
90    let crate::config::ProjectIndexScope::Overlay {
91        overlay_project_id,
92        overlay_root,
93        parent_project_id,
94        parent_root,
95    } = &ctx.index_scope
96    else {
97        return None;
98    };
99
100    let tombstones = visibility::tombstone_count(conn, ctx);
101    let mut overlay = serde_json::json!({
102        "overlay_project_id": overlay_project_id,
103        "overlay_root": overlay_root,
104        "parent_project_id": parent_project_id,
105        "parent_root": parent_root,
106    });
107    if tombstones > 0 {
108        overlay["tombstones"] = serde_json::json!(tombstones);
109    }
110    Some(overlay)
111}