diff --git a/Cargo.lock b/Cargo.lock index f1fd329..85c45de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -521,7 +521,7 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "paraglide-launch" -version = "0.2.2" +version = "0.3.1" dependencies = [ "aho-corasick", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 36b9202..78c1790 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "paraglide-launch" -version = "0.3.0" +version = "0.3.1" edition = "2024" description = "Analyze a project and detect deployable services, languages, frameworks, commands, and env vars" license = "MIT" diff --git a/src/discovery.rs b/src/discovery.rs index eb2755c..51f7029 100644 --- a/src/discovery.rs +++ b/src/discovery.rs @@ -132,11 +132,11 @@ pub fn walk_local(root: &Path, signals: &mut [Box]) -> Result<(), La }) }); - #[allow(clippy::expect_used)] // Arc has no other owners after run() returns - let entries = Arc::try_unwrap(collected) - .expect("all walker threads finished") - .into_inner() - .unwrap_or_else(|p| p.into_inner()); + // Drain the Vec directly from the Mutex. Avoids Arc::try_unwrap, which + // fails if any walker thread still holds the Arc when run() returns — + // that assumption doesn't hold under all scheduler conditions. + let entries = std::mem::take(&mut *collected.lock().unwrap_or_else(|p| p.into_inner())); + drop(collected); let mut by_dir: HashMap> = HashMap::new(); for (dir, entry) in entries { diff --git a/src/signals/health_check.rs b/src/signals/health_check.rs index 7f145d1..434217a 100644 --- a/src/signals/health_check.rs +++ b/src/signals/health_check.rs @@ -140,16 +140,16 @@ static HC_JS_TS_IMPORT_RE: LazyLock = LazyLock::new(|| { static HC_PYTHON_IMPORT_RE: LazyLock = LazyLock::new(|| { Regex::new(concat!( r#"health_check\.urls"#, - r#"|from\s+healthcheck\s+import"#, - r#"|from\s+fastapi_healthchecks\s+import"#, - r#"|from\s+fastapi_health\s+import"#, + r#"|from[ \t\n\r]+healthcheck[ \t\n\r]+import"#, + r#"|from[ \t\n\r]+fastapi_healthchecks[ \t\n\r]+import"#, + r#"|from[ \t\n\r]+fastapi_health[ \t\n\r]+import"#, )) .unwrap() }); static HC_PHP_IMPORT_RE: LazyLock = LazyLock::new(|| { Regex::new(concat!( - r#"use\s+(?:PragmaRX\\Health|Liip\\Monitor)"#, + r#"use[ \t\n\r]+(?:PragmaRX\\Health|Liip\\Monitor)"#, r#"|spatie/laravel-health"#, )) .unwrap() @@ -170,7 +170,7 @@ fn import_regex_for(lang: LangGroup) -> &'static Regex { // Exclude "." to avoid matching module paths like "health_check.urls". static HC_PATH_RE: LazyLock = LazyLock::new(|| { Regex::new( - r#"["'](/(?:health[^"'.\s]*|ready[^"'.\s]*|live[^"'.\s]*|ping|status|readiness|liveness))["']"#, + r#"["'](/(?:health[^"'. \t\n\r]*|ready[^"'. \t\n\r]*|live[^"'. \t\n\r]*|ping|status|readiness|liveness))["']"#, ) .unwrap() }); @@ -178,7 +178,7 @@ static HC_PATH_RE: LazyLock = LazyLock::new(|| { // Django-specific: path("prefix/", include("health_check.urls")) // Django URL conf never uses leading slashes, so we capture the prefix and prepend one. static HC_DJANGO_PATH_RE: LazyLock = LazyLock::new(|| { - Regex::new(r#"path\(\s*["']([^"']+)["']\s*,\s*include\(\s*["']health_check\.urls["']"#).unwrap() + Regex::new(r#"path\([ \t\n\r]*["']([^"']+)["'][ \t\n\r]*,[ \t\n\r]*include\([ \t\n\r]*["']health_check\.urls["']"#).unwrap() }); // -- is_test_file / is_test_dir (same logic as LibraryCallsSignal) --