Archived
be013d2b42
Per the consolidation onto El: 'crates' is the Rust word, 'vessel' is El's (per spec/language.md §15). The directory rename is the structural marker that this slot holds an El buildable unit, even if its current contents are still Rust pending port. Mechanical: git mv crates vessels, sed workspace members and any path dependencies, update CI workflow paths, update README references. Cross-repo path dependencies (`../foo/crates/bar`) updated workspace- wide so cargo metadata still resolves where the Rust still builds.
95 lines
2.5 KiB
Rust
95 lines
2.5 KiB
Rust
//! Status API — project metadata and server health.
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
use axum::{extract::State, Json};
|
|
use serde::Serialize;
|
|
|
|
use crate::AppState;
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct StatusResponse {
|
|
pub project_name: String,
|
|
pub project_path: String,
|
|
pub file_count: usize,
|
|
pub el_file_count: usize,
|
|
pub version: String,
|
|
pub el_version: Option<String>,
|
|
}
|
|
|
|
/// GET /api/status
|
|
pub async fn status(State(state): State<AppState>) -> Json<StatusResponse> {
|
|
let project_path = state.config.project_path.clone();
|
|
let root = PathBuf::from(&project_path);
|
|
|
|
let project_name = root
|
|
.file_name()
|
|
.map(|n| n.to_string_lossy().to_string())
|
|
.unwrap_or_else(|| project_path.clone());
|
|
|
|
let (file_count, el_file_count) = count_files(&root);
|
|
let el_version = get_el_version(&state.config.el_binary);
|
|
|
|
Json(StatusResponse {
|
|
project_name,
|
|
project_path,
|
|
file_count,
|
|
el_file_count,
|
|
version: "0.1.0".into(),
|
|
el_version,
|
|
})
|
|
}
|
|
|
|
fn get_el_version(binary: &str) -> Option<String> {
|
|
let out = std::process::Command::new(binary)
|
|
.arg("--version")
|
|
.output()
|
|
.ok()?;
|
|
let text = String::from_utf8_lossy(&out.stdout).to_string();
|
|
let text = text.trim();
|
|
if text.is_empty() {
|
|
let err = String::from_utf8_lossy(&out.stderr).to_string();
|
|
let err = err.trim().to_string();
|
|
if err.is_empty() { None } else { Some(err) }
|
|
} else {
|
|
Some(text.to_string())
|
|
}
|
|
}
|
|
|
|
fn should_skip_dir(name: &str) -> bool {
|
|
matches!(name, "target" | ".git" | "node_modules" | "dist" | ".cargo")
|
|
}
|
|
|
|
fn count_files(root: &Path) -> (usize, usize) {
|
|
let mut total = 0usize;
|
|
let mut el_count = 0usize;
|
|
count_files_recursive(root, &mut total, &mut el_count);
|
|
(total, el_count)
|
|
}
|
|
|
|
fn count_files_recursive(dir: &Path, total: &mut usize, el_count: &mut usize) {
|
|
let rd = match std::fs::read_dir(dir) {
|
|
Ok(r) => r,
|
|
Err(_) => return,
|
|
};
|
|
|
|
for entry in rd.filter_map(|e| e.ok()) {
|
|
let path = entry.path();
|
|
let name = entry.file_name().to_string_lossy().to_string();
|
|
if name.starts_with('.') {
|
|
continue;
|
|
}
|
|
if path.is_dir() {
|
|
if should_skip_dir(&name) {
|
|
continue;
|
|
}
|
|
count_files_recursive(&path, total, el_count);
|
|
} else {
|
|
*total += 1;
|
|
if name.ends_with(".el") {
|
|
*el_count += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|