- Decompose main.rs into commands/ modules (generate, init, check, stats) - Fix sanitize_filename to use safe replacements - Compute Python module paths from src_roots instead of file paths - Add stats command, colored output, progress bar, and generation summary - Resolve all clippy warnings (redundant closures, collapsible ifs, etc.) - Replace last unwrap() with proper error handling - Add target/ to .gitignore, remove target/ artifacts from git tracking
169 lines
4.1 KiB
Rust
169 lines
4.1 KiB
Rust
use anyhow::Result;
|
||
use colored::Colorize;
|
||
|
||
pub fn init_project(root: &str, out: &str) -> Result<()> {
|
||
println!("{}", "Initializing archdoc project...".cyan().bold());
|
||
|
||
let out_path = std::path::Path::new(out);
|
||
std::fs::create_dir_all(out_path)?;
|
||
std::fs::create_dir_all(out_path.join("modules"))?;
|
||
std::fs::create_dir_all(out_path.join("files"))?;
|
||
|
||
let layout_md_path = out_path.join("layout.md");
|
||
let layout_md_content = r#"# Repository layout
|
||
|
||
<!-- MANUAL:BEGIN -->
|
||
## Manual overrides
|
||
- `src/app/` — <FILL_MANUALLY>
|
||
<!-- MANUAL:END -->
|
||
|
||
---
|
||
|
||
## Detected structure
|
||
<!-- ARCHDOC:BEGIN section=layout_detected -->
|
||
> Generated. Do not edit inside this block.
|
||
<!-- ARCHDOC:END section=layout_detected -->
|
||
"#;
|
||
std::fs::write(&layout_md_path, layout_md_content)?;
|
||
|
||
let architecture_md_content = r#"# ARCHITECTURE — <PROJECT_NAME>
|
||
|
||
<!-- MANUAL:BEGIN -->
|
||
## Project summary
|
||
**Name:** <PROJECT_NAME>
|
||
**Description:** <FILL_MANUALLY: what this project does in 3–7 lines>
|
||
|
||
## Key decisions (manual)
|
||
- <FILL_MANUALLY>
|
||
|
||
## Non-goals (manual)
|
||
- <FILL_MANUALLY>
|
||
<!-- MANUAL:END -->
|
||
|
||
---
|
||
|
||
## Document metadata
|
||
- **Created:** <AUTO_ON_INIT: YYYY-MM-DD>
|
||
- **Updated:** <AUTO_ON_CHANGE: YYYY-MM-DD>
|
||
- **Generated by:** archdoc (cli) v0.1
|
||
|
||
---
|
||
|
||
## Rails / Tooling
|
||
<!-- ARCHDOC:BEGIN section=rails -->
|
||
> Generated. Do not edit inside this block.
|
||
<AUTO: rails summary + links to config files>
|
||
<!-- ARCHDOC:END section=rails -->
|
||
|
||
---
|
||
|
||
## Repository layout (top-level)
|
||
<!-- ARCHDOC:BEGIN section=layout -->
|
||
> Generated. Do not edit inside this block.
|
||
<AUTO: table of top-level folders + heuristic purpose + link to layout.md>
|
||
<!-- ARCHDOC:END section=layout -->
|
||
|
||
---
|
||
|
||
## Modules index
|
||
<!-- ARCHDOC:BEGIN section=modules_index -->
|
||
> Generated. Do not edit inside this block.
|
||
<AUTO: table modules + deps counts + links to module docs>
|
||
<!-- ARCHDOC:END section=modules_index -->
|
||
|
||
---
|
||
|
||
## Critical dependency points
|
||
<!-- ARCHDOC:BEGIN section=critical_points -->
|
||
> Generated. Do not edit inside this block.
|
||
<AUTO: top fan-in/out symbols + cycles>
|
||
<!-- ARCHDOC:END section=critical_points -->
|
||
|
||
---
|
||
|
||
<!-- MANUAL:BEGIN -->
|
||
## Change notes (manual)
|
||
- <FILL_MANUALLY>
|
||
<!-- MANUAL:END -->
|
||
"#;
|
||
|
||
let architecture_md_path = std::path::Path::new(root).join("ARCHITECTURE.md");
|
||
std::fs::write(&architecture_md_path, architecture_md_content)?;
|
||
|
||
let config_toml_content = r#"[project]
|
||
root = "."
|
||
out_dir = "docs/architecture"
|
||
entry_file = "ARCHITECTURE.md"
|
||
language = "python"
|
||
|
||
[scan]
|
||
include = ["src", "app", "tests"]
|
||
exclude = [
|
||
".venv", "venv", "__pycache__", ".git", "dist", "build",
|
||
".mypy_cache", ".ruff_cache", ".pytest_cache", "*.egg-info"
|
||
]
|
||
follow_symlinks = false
|
||
max_file_size = "10MB"
|
||
|
||
[python]
|
||
src_roots = ["src", "."]
|
||
include_tests = true
|
||
parse_docstrings = true
|
||
max_parse_errors = 10
|
||
|
||
[analysis]
|
||
resolve_calls = true
|
||
resolve_inheritance = false
|
||
detect_integrations = true
|
||
integration_patterns = [
|
||
{ type = "http", patterns = ["requests", "httpx", "aiohttp"] },
|
||
{ type = "db", patterns = ["sqlalchemy", "psycopg", "mysql", "sqlite3"] },
|
||
{ type = "queue", patterns = ["celery", "kafka", "pika", "redis"] }
|
||
]
|
||
|
||
[output]
|
||
single_file = false
|
||
per_file_docs = true
|
||
create_directories = true
|
||
overwrite_manual_sections = false
|
||
|
||
[diff]
|
||
update_timestamp_on_change_only = true
|
||
hash_algorithm = "sha256"
|
||
preserve_manual_content = true
|
||
|
||
[thresholds]
|
||
critical_fan_in = 20
|
||
critical_fan_out = 20
|
||
high_complexity = 50
|
||
|
||
[rendering]
|
||
template_engine = "handlebars"
|
||
max_table_rows = 100
|
||
truncate_long_descriptions = true
|
||
description_max_length = 200
|
||
|
||
[logging]
|
||
level = "info"
|
||
file = "archdoc.log"
|
||
format = "compact"
|
||
|
||
[caching]
|
||
enabled = true
|
||
cache_dir = ".archdoc/cache"
|
||
max_cache_age = "24h"
|
||
"#;
|
||
|
||
let config_toml_path = std::path::Path::new(root).join("archdoc.toml");
|
||
if !config_toml_path.exists() {
|
||
std::fs::write(&config_toml_path, config_toml_content)?;
|
||
}
|
||
|
||
println!("{} Project initialized!", "✓".green().bold());
|
||
println!(" {} {}", "→".dimmed(), architecture_md_path.display());
|
||
println!(" {} {}", "→".dimmed(), config_toml_path.display());
|
||
println!(" {} {} (directory)", "→".dimmed(), out_path.display());
|
||
|
||
Ok(())
|
||
}
|