1 use crate::OpenError;
2 use std::ffi::OsStr;
3 use std::io::Write;
4 use std::process::{Child, Command, Stdio};
5 use std::{fs, io};
6
7 const XDG_OPEN_SCRIPT: &[u8] = include_bytes!("xdg-open");
8
open(path: &OsStr) -> Result<(), OpenError>9 pub(crate) fn open(path: &OsStr) -> Result<(), OpenError> {
10 if crate::is_wsl() {
11 wsl_open(path)
12 } else {
13 non_wsl_open(path)
14 }
15 }
16
wsl_open(path: &OsStr) -> Result<(), OpenError>17 fn wsl_open(path: &OsStr) -> Result<(), OpenError> {
18 let result = open_with_wslview(path);
19 if let Ok(mut child) = result {
20 return crate::wait_child(&mut child, "wslview");
21 }
22
23 open_with_system_xdg_open(path).map_err(OpenError::Io)?;
24
25 Ok(())
26 }
27
non_wsl_open(path: &OsStr) -> Result<(), OpenError>28 fn non_wsl_open(path: &OsStr) -> Result<(), OpenError> {
29 if open_with_system_xdg_open(path).is_err() {
30 open_with_internal_xdg_open(path)?;
31 }
32
33 Ok(())
34 }
35
open_with_wslview(path: &OsStr) -> io::Result<Child>36 fn open_with_wslview(path: &OsStr) -> io::Result<Child> {
37 let converted_path = crate::wsl_to_windows_path(path);
38 let converted_path = converted_path.as_deref();
39 let path = match converted_path {
40 None => path,
41 Some(x) => x,
42 };
43
44 Command::new("wslview")
45 .arg(path)
46 .stdin(Stdio::null())
47 .stdout(Stdio::null())
48 .stderr(Stdio::piped())
49 .spawn()
50 }
51
open_with_system_xdg_open(path: &OsStr) -> io::Result<Child>52 fn open_with_system_xdg_open(path: &OsStr) -> io::Result<Child> {
53 Command::new("xdg-open")
54 .arg(path)
55 .stdin(Stdio::null())
56 .stdout(Stdio::null())
57 .stderr(Stdio::null())
58 .spawn()
59 }
60
open_with_internal_xdg_open(path: &OsStr) -> Result<Child, OpenError>61 fn open_with_internal_xdg_open(path: &OsStr) -> Result<Child, OpenError> {
62 let mut sh = Command::new("sh")
63 .arg("-s")
64 .arg(path)
65 .stdin(Stdio::piped())
66 .stdout(Stdio::null())
67 .stderr(Stdio::null())
68 .spawn()
69 .map_err(OpenError::Io)?;
70
71 sh.stdin
72 .as_mut()
73 .unwrap()
74 .write_all(XDG_OPEN_SCRIPT)
75 .map_err(OpenError::Io)?;
76
77 Ok(sh)
78 }
79
is_wsl() -> bool80 pub(crate) fn is_wsl() -> bool {
81 if is_docker() {
82 return false;
83 }
84
85 if let Ok(true) = fs::read_to_string("/proc/sys/kernel/osrelease")
86 .map(|osrelease| osrelease.to_ascii_lowercase().contains("microsoft"))
87 {
88 return true;
89 }
90
91 if let Ok(true) = fs::read_to_string("/proc/version")
92 .map(|version| version.to_ascii_lowercase().contains("microsoft"))
93 {
94 return true;
95 }
96
97 false
98 }
99
is_docker() -> bool100 fn is_docker() -> bool {
101 let has_docker_env = fs::metadata("/.dockerenv").is_ok();
102
103 let has_docker_cgroup = fs::read_to_string("/proc/self/cgroup")
104 .map(|cgroup| cgroup.to_ascii_lowercase().contains("docker"))
105 .unwrap_or(false);
106
107 has_docker_env || has_docker_cgroup
108 }
109