• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kdash-rs / kdash / 12205394102

06 Dec 2024 08:06PM UTC coverage: 58.458% (+21.7%) from 36.747%
12205394102

push

github

deepu105
fix CI

4337 of 7419 relevant lines covered (58.46%)

7.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

17.27
/src/cmd/mod.rs
1
use std::sync::Arc;
2

3
use anyhow::anyhow;
4
use duct::cmd;
5
use log::{error, info};
6
use regex::Regex;
7
use serde_json::Value as JValue;
8
use tokio::sync::Mutex;
9

10
use crate::app::{self, models::ScrollableTxt, App, Cli};
11

12
#[derive(Debug, Eq, PartialEq)]
13
pub enum IoCmdEvent {
14
  GetCliInfo,
15
  GetDescribe {
16
    kind: String,
17
    value: String,
18
    ns: Option<String>,
19
  },
20
}
21

22
#[derive(Clone)]
23
pub struct CmdRunner<'a> {
24
  pub app: &'a Arc<Mutex<App>>,
25
}
26

27
static NOT_FOUND: &str = "Not found";
28

29
impl<'a> CmdRunner<'a> {
30
  pub fn new(app: &'a Arc<Mutex<App>>) -> Self {
×
31
    CmdRunner { app }
×
32
  }
×
33

34
  pub async fn handle_cmd_event(&mut self, io_event: IoCmdEvent) {
×
35
    match io_event {
×
36
      IoCmdEvent::GetCliInfo => {
37
        self.get_cli_info().await;
×
38
      }
39
      IoCmdEvent::GetDescribe { kind, value, ns } => {
×
40
        self.get_describe(kind, value, ns).await;
×
41
      }
42
    };
43

44
    let mut app = self.app.lock().await;
×
45
    app.is_loading = false;
×
46
  }
×
47

48
  async fn handle_error(&self, e: anyhow::Error) {
×
49
    error!("{:?}", e);
×
50
    let mut app = self.app.lock().await;
×
51
    app.handle_error(e);
×
52
  }
×
53

54
  async fn get_cli_info(&self) {
×
55
    let mut clis: Vec<Cli> = vec![];
×
56

57
    let (version_c, version_s) = match cmd!("kubectl", "version", "-o", "json")
×
58
      .stderr_null()
×
59
      .read()
×
60
    {
61
      Ok(out) => {
×
62
        info!("kubectl version: {}", out);
×
63
        let v: serde_json::Result<JValue> = serde_json::from_str(&out);
×
64
        match v {
×
65
          Ok(val) => (
×
66
            Some(
×
67
              val["clientVersion"]["gitVersion"]
×
68
                .to_string()
×
69
                .replace('"', ""),
×
70
            ),
×
71
            Some(
×
72
              val["serverVersion"]["gitVersion"]
×
73
                .to_string()
×
74
                .replace('"', ""),
×
75
            ),
×
76
          ),
×
77
          _ => (None, None),
×
78
        }
79
      }
80
      _ => (None, None),
×
81
    };
82

83
    clis.push(build_cli("kubectl client", version_c));
×
84
    clis.push(build_cli("kubectl server", version_s));
×
85

×
86
    let version = cmd!("docker", "version", "--format", "'{{.Client.Version}}'")
×
87
      .stderr_null()
×
88
      .read()
×
89
      .map_or(None, |out| {
×
90
        if out.is_empty() {
×
91
          None
×
92
        } else {
93
          Some(format!("v{}", out.replace('\'', "")))
×
94
        }
95
      });
×
96

×
97
    clis.push(build_cli("docker", version));
×
98

×
99
    let version = cmd!("docker-compose", "version", "--short")
×
100
      .stderr_null()
×
101
      .read()
×
102
      .map_or(None, |out| {
×
103
        if out.is_empty() {
×
104
          cmd!("docker", "compose", "version", "--short")
×
105
            .stderr_null()
×
106
            .read()
×
107
            .map_or(None, |out| {
×
108
              if out.is_empty() {
×
109
                None
×
110
              } else {
111
                Some(format!("v{}", out.replace('\'', "")))
×
112
              }
113
            })
×
114
        } else {
115
          Some(format!("v{}", out.replace('\'', "")))
×
116
        }
117
      });
×
118

×
119
    clis.push(build_cli("docker-compose", version));
×
120

×
121
    let version = get_info_by_regex("kind", &["version"], r"(v[0-9.]+)");
×
122

×
123
    clis.push(build_cli("kind", version));
×
124

×
125
    let version = get_info_by_regex("helm", &["version", "-c"], r"(v[0-9.]+)");
×
126

×
127
    clis.push(build_cli("helm", version));
×
128

×
129
    let version = get_info_by_regex("istioctl", &["version"], r"([0-9.]+)");
×
130

×
131
    clis.push(build_cli("istioctl", version.map(|v| format!("v{}", v))));
×
132

133
    let mut app = self.app.lock().await;
×
134
    app.data.clis = clis;
×
135
  }
×
136

137
  // TODO temp solution, should build this from API response
138
  async fn get_describe(&self, kind: String, value: String, ns: Option<String>) {
×
139
    let mut args = vec!["describe", kind.as_str(), value.as_str()];
×
140

141
    if let Some(ns) = ns.as_ref() {
×
142
      args.push("-n");
×
143
      args.push(ns.as_str());
×
144
    }
×
145

146
    let out = duct::cmd("kubectl", &args).stderr_null().read();
×
147

×
148
    match out {
×
149
      Ok(out) => {
×
150
        let mut app = self.app.lock().await;
×
151
        app.data.describe_out = ScrollableTxt::with_string(out);
×
152
      }
153
      Err(e) => {
×
154
        self
×
155
          .handle_error(anyhow!(format!(
×
156
            "Error running {} describe. Make sure you have kubectl installed: {:?}",
×
157
            kind, e
×
158
          )))
×
159
          .await
×
160
      }
161
    }
162
  }
×
163
}
164

165
// utils
166

167
fn build_cli(name: &str, version: Option<String>) -> app::Cli {
×
168
  app::Cli {
×
169
    name: name.to_owned(),
×
170
    status: version.is_some(),
×
171
    version: version.unwrap_or_else(|| NOT_FOUND.into()),
×
172
  }
×
173
}
×
174

175
/// execute a command and get info from it using regex
176
fn get_info_by_regex(command: &str, args: &[&str], regex: &str) -> Option<String> {
2✔
177
  match cmd(command, args).stderr_null().read() {
2✔
178
    Ok(out) => match Regex::new(regex) {
2✔
179
      Ok(re) => match re.captures(out.as_str()) {
2✔
180
        Some(cap) => cap.get(1).map(|text| text.as_str().into()),
2✔
181
        _ => None,
×
182
      },
183
      _ => None,
×
184
    },
185
    _ => None,
×
186
  }
187
}
2✔
188

189
#[cfg(test)]
190
mod tests {
191
  #[test]
192
  fn test_get_info_by_regex() {
1✔
193
    use super::get_info_by_regex;
194

195
    assert_eq!(
1✔
196
      get_info_by_regex(
1✔
197
        "echo",
1✔
198
        &["Client: &version.Version{SemVer:\"v2.17.0\", GitCommit:\"a690bad98af45b015bd3da1a41f6218b1a451dbe\", GitTreeState:\"clean\"} \n Error: could not find tiller"],
1✔
199
        r"(v[0-9.]+)"
1✔
200
      ),
1✔
201
      Some("v2.17.0".into())
1✔
202
    );
1✔
203
    assert_eq!(
1✔
204
      get_info_by_regex(
1✔
205
        "echo",
1✔
206
        &["no running Istio pods in \"istio-system\"\n1.8.2"],
1✔
207
        r"([0-9.]+)"
1✔
208
      ),
1✔
209
      Some("1.8.2".into())
1✔
210
    );
1✔
211
  }
1✔
212
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc