cargo_tangle/command/dev/
status.rs1use std::fs;
4use std::path::{Path, PathBuf};
5
6use color_eyre::eyre::Result;
7
8use crate::workspace::{TangleWorkspace, WORKSPACE_FILE};
9
10const DEV_DIR: &str = ".tangle/dev";
11
12pub fn execute() -> Result<()> {
13 let dev_dir = PathBuf::from(DEV_DIR);
14 let ws_path = Path::new(WORKSPACE_FILE);
15
16 if !dev_dir.exists() && !ws_path.exists() {
17 println!("No devnet in this directory. Run `cargo-tangle dev up` to start one.");
18 return Ok(());
19 }
20
21 if ws_path.exists() {
22 match TangleWorkspace::load(ws_path) {
23 Ok(ws) => {
24 println!("Workspace: {}", ws.source.display());
25 println!("Active net: {}", ws.active);
26 if let Ok(net) = ws.active_network() {
27 println!("HTTP RPC: {}", net.http_rpc_url);
28 println!("WS RPC: {}", net.ws_rpc_url);
29 println!("Tangle: {}", net.tangle_contract);
30 }
31 if let Some(p) = &ws.defaults.keystore_path {
32 println!("Keystore: {}", p.display());
33 }
34 }
35 Err(e) => eprintln!("⚠ {WORKSPACE_FILE} exists but failed to parse: {e}"),
36 }
37 }
38
39 for (label, file) in [("anvil", "anvil.pid"), ("manager", "manager.pid")] {
40 let path = dev_dir.join(file);
41 match read_pid(&path) {
42 Some(pid) if pid_alive(pid) => println!("{label:10} running (PID {pid})"),
43 Some(pid) => println!("{label:10} stale PID {pid} (not running)"),
44 None => println!("{label:10} not started"),
45 }
46 }
47
48 Ok(())
49}
50
51fn read_pid(path: &Path) -> Option<u32> {
52 fs::read_to_string(path)
53 .ok()
54 .and_then(|s| s.trim().parse().ok())
55}
56
57fn pid_alive(pid: u32) -> bool {
58 use nix::sys::signal::kill;
59 use nix::unistd::Pid;
60 kill(Pid::from_raw(pid as i32), None).is_ok()
61}