xtask_todo_lib/devshell/vm/
workspace_host.rs1use std::path::{Path, PathBuf};
7use std::process::Command;
8
9use serde_json::Value;
10
11use super::super::sandbox;
12use super::guest_fs_ops::guest_project_dir_on_guest;
13
14const ENV_DEVSHELL_VM_WORKSPACE_PARENT: &str = "DEVSHELL_VM_WORKSPACE_PARENT";
16const ENV_DEVSHELL_VM_WORKSPACE_USE_CARGO_ROOT: &str = "DEVSHELL_VM_WORKSPACE_USE_CARGO_ROOT";
17
18fn cargo_metadata_workspace_and_target(cwd: &Path) -> Result<(PathBuf, PathBuf), ()> {
19 let out = Command::new("cargo")
20 .args(["metadata", "--format-version", "1", "--no-deps"])
21 .current_dir(cwd)
22 .output()
23 .map_err(|_| ())?;
24 if !out.status.success() {
25 return Err(());
26 }
27 let v: Value = serde_json::from_slice(&out.stdout).map_err(|_| ())?;
28 let wr = v
29 .get("workspace_root")
30 .and_then(|x| x.as_str())
31 .map(PathBuf::from)
32 .ok_or(())?;
33 let td = v
34 .get("target_directory")
35 .and_then(|x| x.as_str())
36 .map(PathBuf::from)
37 .ok_or(())?;
38 Ok((wr, td))
39}
40
41fn sanitize_instance_segment(name: &str) -> String {
42 name.chars()
43 .map(|c| {
44 if c.is_ascii_alphanumeric() || c == '-' || c == '_' {
45 c
46 } else {
47 '_'
48 }
49 })
50 .collect()
51}
52
53#[must_use]
55pub fn workspace_parent_for_instance(instance: &str) -> PathBuf {
56 if let Ok(p) = std::env::var(ENV_DEVSHELL_VM_WORKSPACE_PARENT) {
57 let p = p.trim();
58 if !p.is_empty() {
59 return PathBuf::from(p);
60 }
61 }
62 let use_cargo = std::env::var(ENV_DEVSHELL_VM_WORKSPACE_USE_CARGO_ROOT).map_or(true, |s| {
63 let s = s.trim();
64 if s.is_empty() {
65 true
66 } else {
67 !(s == "0"
68 || s.eq_ignore_ascii_case("false")
69 || s.eq_ignore_ascii_case("no")
70 || s.eq_ignore_ascii_case("off"))
71 }
72 });
73 if use_cargo {
74 if let Ok(cwd) = std::env::current_dir() {
75 if let Ok((wr, _)) = cargo_metadata_workspace_and_target(&cwd) {
76 return wr.canonicalize().unwrap_or(wr);
77 }
78 }
79 }
80 let seg = sanitize_instance_segment(instance);
81 sandbox::devshell_export_parent_dir()
82 .join("vm-workspace")
83 .join(seg)
84}
85
86#[must_use]
88pub fn guest_dir_for_vfs_cwd(guest_mount: &str, vfs_cwd: &str) -> String {
89 guest_project_dir_on_guest(guest_mount, vfs_cwd)
90}