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