Skip to main content

aws_context_switcher/
matching.rs

1/// Matching logic untuk AWS profile ↔ kubectl context
2pub fn normalize_name(name: &str) -> String {
3    name.to_lowercase().replace('_', "-")
4}
5
6pub fn tokenize(name: &str) -> Vec<&str> {
7    name.split(|c: char| c == '-' || c == '_' || c == '.')
8        .filter(|s| !s.is_empty())
9        .collect()
10}
11
12pub fn match_score(profile: &str, kube_ctx: &str) -> u32 {
13    let pn = normalize_name(profile);
14    let kn = normalize_name(kube_ctx);
15
16    if pn == kn {
17        return 100;
18    }
19
20    let p_tokens = tokenize(&pn);
21    let k_tokens = tokenize(&kn);
22
23    if p_tokens.is_empty() || k_tokens.is_empty() {
24        return 0;
25    }
26
27    let matched: usize = p_tokens.iter().filter(|t| k_tokens.contains(t)).count();
28    let total = p_tokens.len().max(k_tokens.len());
29
30    let shorter = p_tokens.len().min(k_tokens.len());
31    let shorter_matched = if p_tokens.len() <= k_tokens.len() {
32        p_tokens.iter().filter(|t| k_tokens.contains(t)).count()
33    } else {
34        k_tokens.iter().filter(|t| p_tokens.contains(t)).count()
35    };
36
37    if shorter_matched < shorter {
38        return 0;
39    }
40
41    ((matched as f64 / total as f64) * 100.0) as u32
42}
43
44pub fn find_kube_match(profile: &str, kube_contexts: &[String]) -> Option<String> {
45    find_kube_match_threshold(profile, kube_contexts, 50)
46}
47
48pub fn find_kube_match_threshold(profile: &str, kube_contexts: &[String], threshold: u32) -> Option<String> {
49    if kube_contexts.contains(&profile.to_string()) {
50        return Some(profile.to_string());
51    }
52    let mut best: Option<(String, u32)> = None;
53    for kctx in kube_contexts {
54        let score = match_score(profile, kctx);
55        if score >= threshold {
56            if best.as_ref().map_or(true, |(_, s)| score > *s) {
57                best = Some((kctx.clone(), score));
58            }
59        }
60    }
61    best.map(|(ctx, _)| ctx)
62}
63
64pub fn detect_environment(name: &str) -> Option<String> {
65    let lower = name.to_lowercase();
66    if lower.contains("prd") || lower.contains("prod") {
67        Some("production".to_string())
68    } else if lower.contains("stg") || lower.contains("staging") {
69        Some("staging".to_string())
70    } else if lower.contains("dev") {
71        Some("development".to_string())
72    } else {
73        None
74    }
75}