Archived
rename crates/ → vessels/ — El's word for buildable units
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.
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
//! 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user