Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 2 additions & 64 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ serde_json = "1.0"
tower-service = "0.3"

# Utilities
thiserror = "2.0"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
futures-util = "0.3"
Expand Down
7 changes: 3 additions & 4 deletions crates/cargo-rustapi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ indicatif = { workspace = true }
console = { workspace = true }

# File system
walkdir = "2.5"
toml_edit = "0.22"
notify = "8.0"
notify-debouncer-mini = "0.7"
notify = { version = "8.0", optional = true }
notify-debouncer-mini = { version = "0.7", optional = true }

# Async
tokio = { workspace = true, features = ["process", "fs", "macros", "rt-multi-thread", "time", "signal", "sync"] }
Expand All @@ -42,7 +41,6 @@ toml = "1.1"
reqwest = { version = "0.12", features = ["json", "rustls-tls"], default-features = false, optional = true }

# Utilities
thiserror = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
anyhow = "1.0"
Expand All @@ -54,5 +52,6 @@ predicates = "3.1"

[features]
default = ["remote-spec", "replay"]
native-watch = ["dep:notify", "dep:notify-debouncer-mini"]
remote-spec = ["dep:reqwest"]
replay = ["dep:reqwest"]
116 changes: 70 additions & 46 deletions crates/cargo-rustapi/src/commands/doctor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use console::{style, Emoji};
use std::fs;
use std::path::{Path, PathBuf};
use tokio::process::Command;
use walkdir::WalkDir;

#[derive(Args, Debug, Clone)]
pub struct DoctorArgs {
Expand Down Expand Up @@ -382,61 +381,86 @@ fn build_project_checks(workspace_root: &Path) -> Result<Vec<DoctorCheck>> {
fn scan_workspace_signals(workspace_root: &Path) -> Result<WorkspaceSignals> {
let mut signals = WorkspaceSignals::default();

for entry in WalkDir::new(workspace_root)
.into_iter()
.filter_entry(|entry| should_scan(entry.path()))
{
scan_workspace_dir(workspace_root, &mut signals)?;

Ok(signals)
}

fn scan_workspace_dir(dir: &Path, signals: &mut WorkspaceSignals) -> Result<()> {
if !should_scan(dir) {
return Ok(());
}

for entry in fs::read_dir(dir).with_context(|| format!("failed to read {}", dir.display()))? {
let entry = entry?;
if !entry.file_type().is_file() || !is_scannable_file(entry.path()) {
let path = entry.path();

if !should_scan(&path) {
continue;
}

let file_type = match entry.file_type() {
Ok(file_type) => file_type,
Err(_) => continue,
};

if file_type.is_dir() {
scan_workspace_dir(&path, signals)?;
continue;
}

let contents = match fs::read_to_string(entry.path()) {
if !file_type.is_file() || !is_scannable_file(&path) {
continue;
}

let contents = match fs::read_to_string(&path) {
Ok(contents) => contents,
Err(_) => continue,
};

signals.production_defaults |= contains_any(
&contents,
&[".production_defaults(", ".production_defaults_with_config("],
);
signals.health_endpoints |= contains_any(
&contents,
&[
".health_endpoints(",
".health_endpoint_config(",
"HealthEndpointConfig",
],
);
signals.health_checks |= contents.contains(".with_health_check(");
signals.request_id |= contents.contains("RequestIdLayer");
signals.tracing |= contains_any(&contents, &["TracingLayer", "tracing_subscriber"]);
signals.shutdown |= contents.contains("run_with_shutdown(");
signals.shutdown_hooks |= contents.contains(".on_shutdown(");
signals.structured_logging |= contains_any(
&contents,
&["StructuredLoggingLayer", "structured_logging("],
);
signals.otel |= contains_any(&contents, &["OtelLayer", "otel("]);
signals.rate_limit |= contains_any(&contents, &["RateLimitLayer", "rate_limit("]);
signals.security_headers |=
contains_any(&contents, &["SecurityHeadersLayer", "security_headers("]);
signals.timeout |= contains_any(&contents, &["TimeoutLayer", "timeout("]);
signals.cors |= contains_any(&contents, &["CorsLayer", "cors("]);
signals.body_limit |= contains_any(&contents, &["BodyLimitLayer", ".body_limit("]);
signals.env_production |= contains_any(
&contents,
&[
"RUSTAPI_ENV=production",
"RUSTAPI_ENV: production",
"RUSTAPI_ENV = \"production\"",
"RUSTAPI_ENV','production",
"RUSTAPI_ENV\", \"production\"",
],
);
apply_workspace_signals(signals, &contents);
}

Ok(signals)
Ok(())
}

fn apply_workspace_signals(signals: &mut WorkspaceSignals, contents: &str) {
signals.production_defaults |= contains_any(
contents,
&[".production_defaults(", ".production_defaults_with_config("],
);
signals.health_endpoints |= contains_any(
contents,
&[
".health_endpoints(",
".health_endpoint_config(",
"HealthEndpointConfig",
],
);
signals.health_checks |= contents.contains(".with_health_check(");
signals.request_id |= contents.contains("RequestIdLayer");
signals.tracing |= contains_any(contents, &["TracingLayer", "tracing_subscriber"]);
signals.shutdown |= contents.contains("run_with_shutdown(");
signals.shutdown_hooks |= contents.contains(".on_shutdown(");
signals.structured_logging |=
contains_any(contents, &["StructuredLoggingLayer", "structured_logging("]);
signals.otel |= contains_any(contents, &["OtelLayer", "otel("]);
signals.rate_limit |= contains_any(contents, &["RateLimitLayer", "rate_limit("]);
signals.security_headers |=
contains_any(contents, &["SecurityHeadersLayer", "security_headers("]);
signals.timeout |= contains_any(contents, &["TimeoutLayer", "timeout("]);
signals.cors |= contains_any(contents, &["CorsLayer", "cors("]);
signals.body_limit |= contains_any(contents, &["BodyLimitLayer", ".body_limit("]);
signals.env_production |= contains_any(
contents,
&[
"RUSTAPI_ENV=production",
"RUSTAPI_ENV: production",
"RUSTAPI_ENV = \"production\"",
"RUSTAPI_ENV','production",
"RUSTAPI_ENV\", \"production\"",
],
);
}

fn find_workspace_root(start: &Path) -> Option<PathBuf> {
Expand Down
Loading
Loading