pub struct StackDetector { /* private fields */ }Expand description
Cache-owning detector for repeated stack and project lookups.
A detector is intentionally stateful. Cache entries are retained until the
detector is dropped or clear is called, so it is best used
for one coherent scan of process or project metadata. Call clear between
scans when filesystem changes should be observed.
§Home Ceiling
Upward project walks stop before testing the detector’s home directory, so
stray marker files directly in a user’s home do not claim unrelated
processes. new and Default use crate::home_dir;
with_home overrides it.
§Stack Priority
detect_stack resolves a label in this order:
- Image name via
crate::detect_from_image. - Process or executable name via
crate::detect_from_process_names, when that label is final:StackKind::Framework,StackKind::Database,StackKind::Service, or any future kind. - Project config, when the process label is a
StackKind::RuntimeorStackKind::Tool, or when the process is unknown but its executable belongs to the project: it lies inside the project root, it was built bygo runorgo testinto a temporarygo-build*directory (Go config only), or it lies in thetargetdirectory of a Cargo workspace that contains the root (Rust config only). - The process label, if any.
Config detection is ecosystem-aware. A known runtime or tool accepts only
config labels from its own ecosystem: a php or php-fpm process in a
Laravel project that also has vite.config.js is Laravel, a node or
vite process there is Vite, and a python process in a Next.js project
stays Python. Deno config has its own ecosystem, so a node or bun
process next to deno.json keeps its label, while a deno process also
accepts Node config. A Python process takes only framework labels from
config, so gunicorn in a Python project with no recognized framework
stays Gunicorn. An unknown process uses every rule, in the order of
crate::detect_from_config, except that when its executable lies inside
the project root, Rust, Go, .NET, and JVM config are tried first: a binary
at tmp/main in a repo with go.mod, package.json, and vite.config.js
is Go, not Vite. An executable under the project’s node_modules
(node_modules/@esbuild/linux-x64/bin/esbuild) is a Node build tool, so
Node config is tried first instead and the same repo gives Vite.
§Examples
use what_stack::{StackDetector, StackInput};
let mut detector = StackDetector::new();
let label = detector.detect_stack(StackInput::new("postgres").image("postgres:16"));
assert_eq!(label.expect("known image"), "PostgreSQL");Implementations§
Source§impl StackDetector
impl StackDetector
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a detector whose home ceiling is the current user’s home
directory, as returned by crate::home_dir.
Sourcepub fn with_home(home: Option<PathBuf>) -> Self
pub fn with_home(home: Option<PathBuf>) -> Self
Create a detector with an explicit home ceiling.
None disables the ceiling, so upward walks may reach the file system
root (bounded by crate::MAX_WALK_DEPTH).
Sourcepub fn clear(&mut self)
pub fn clear(&mut self)
Drop all cached project-root and config results.
The home ceiling is kept. Call this between scans when one detector is reused and filesystem changes should be observed.
Sourcepub fn detect_project_root(
&mut self,
input: ProjectInput<'_>,
) -> Option<PathBuf>
pub fn detect_project_root( &mut self, input: ProjectInput<'_>, ) -> Option<PathBuf>
Detect a project root from process-like path inputs.
Uses the same fallback order as crate::resolve_project_root with the
detector’s home ceiling. Results are cached by visited directory.
Positive hits cache the visited directories from the start up to the
discovered root; negative walks cache the visited directories as misses,
except when the walk stopped at crate::MAX_WALK_DEPTH, because a
walk from a shallower visited directory can reach further up.
This mirrors the process-enrichment hot path where many entries share a
working directory or project ancestor.
§Examples
use std::path::Path;
use what_stack::{ProjectInput, StackDetector};
let mut detector = StackDetector::new();
let root = detector.detect_project_root(ProjectInput::new().cwd(Path::new(".")));
println!("{root:?}");Sourcepub fn detect_stack(&mut self, input: StackInput<'_>) -> Option<StackLabel>
pub fn detect_stack(&mut self, input: StackInput<'_>) -> Option<StackLabel>
Detect a stack label from image, process, and project metadata.
Image and process matching are pure string operations. Config matching reads the given project-root directory on the first lookup and caches the result for future calls with the same path. See the type-level documentation for the priority and config guard.
Trait Implementations§
Source§impl Debug for StackDetector
impl Debug for StackDetector
Source§impl Default for StackDetector
impl Default for StackDetector
Source§fn default() -> Self
fn default() -> Self
Same as StackDetector::new.