1 | use crate::OpenError; |
2 | use std::ffi::OsStr; |
3 | use std::io; |
4 | use std::io::Write; |
5 | use std::process::{Child, Command, Stdio}; |
6 | |
7 | const XDG_OPEN_SCRIPT: &[u8] = include_bytes!("xdg-open" ); |
8 | |
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 | |
17 | #[cfg (all(feature = "reveal" , target_os = "linux" ))] |
18 | pub(crate) fn reveal(path: &std::path::Path) -> Result<(), OpenError> { |
19 | if crate::is_wsl() { |
20 | reveal_in_windows_explorer(path) |
21 | } else { |
22 | crate::freedesktop::reveal_with_dbus(path).or_else(|_| reveal_fallback(path)) |
23 | } |
24 | } |
25 | |
26 | #[cfg (all(feature = "reveal" , not(target_os = "linux" )))] |
27 | pub(crate) fn reveal(path: &std::path::Path) -> Result<(), OpenError> { |
28 | reveal_fallback(path) |
29 | } |
30 | |
31 | #[cfg (feature = "reveal" )] |
32 | fn reveal_fallback(path: &std::path::Path) -> Result<(), OpenError> { |
33 | let path = path.canonicalize().map_err(OpenError::Io)?; |
34 | let parent = path.parent().unwrap_or(std::path::Path::new("/" )); |
35 | open(parent.as_os_str()) |
36 | } |
37 | |
38 | fn wsl_open(path: &OsStr) -> Result<(), OpenError> { |
39 | let result: Result = open_with_wslview(path); |
40 | if let Ok(mut child: Child) = result { |
41 | return crate::wait_child(&mut child, cmd_name:"wslview" ); |
42 | } |
43 | |
44 | open_with_system_xdg_open(path).map_err(|err: Error| OpenError::Spawn { |
45 | cmds: "wslview, xdg-open" .into(), |
46 | source: err, |
47 | })?; |
48 | |
49 | Ok(()) |
50 | } |
51 | |
52 | fn non_wsl_open(path: &OsStr) -> Result<(), OpenError> { |
53 | if open_with_system_xdg_open(path).is_err() { |
54 | open_with_internal_xdg_open(path)?; |
55 | } |
56 | |
57 | Ok(()) |
58 | } |
59 | |
60 | fn open_with_wslview(path: &OsStr) -> io::Result<Child> { |
61 | Command&mut Command::new("wslview" ) |
62 | .arg(path) |
63 | .stdin(Stdio::null()) |
64 | .stdout(Stdio::null()) |
65 | .stderr(cfg:Stdio::piped()) |
66 | .spawn() |
67 | } |
68 | |
69 | fn open_with_system_xdg_open(path: &OsStr) -> io::Result<Child> { |
70 | Command&mut Command::new("xdg-open" ) |
71 | .arg(path) |
72 | .stdin(Stdio::null()) |
73 | .stdout(Stdio::null()) |
74 | .stderr(cfg:Stdio::null()) |
75 | .spawn() |
76 | } |
77 | |
78 | fn open_with_internal_xdg_open(path: &OsStr) -> Result<Child, OpenError> { |
79 | let mut sh: Child = Command::new("sh" ) |
80 | .arg("-s" ) |
81 | .arg(path) |
82 | .stdin(Stdio::piped()) |
83 | .stdout(Stdio::null()) |
84 | .stderr(Stdio::null()) |
85 | .spawn() |
86 | .map_err(|err: Error| OpenError::Spawn { |
87 | cmds: "sh" .into(), |
88 | source: err, |
89 | })?; |
90 | |
91 | sh.stdin |
92 | .as_mut() |
93 | .unwrap() |
94 | .write_all(XDG_OPEN_SCRIPT) |
95 | .map_err(op:OpenError::Io)?; |
96 | |
97 | Ok(sh) |
98 | } |
99 | |
100 | #[cfg (all(feature = "reveal" , target_os = "linux" ))] |
101 | fn reveal_in_windows_explorer(path: &std::path::Path) -> Result<(), OpenError> { |
102 | let converted_path = crate::wsl_to_windows_path(path.as_os_str()); |
103 | let converted_path = converted_path.as_deref(); |
104 | let path = match converted_path { |
105 | None => path, |
106 | Some(x) => std::path::Path::new(x), |
107 | }; |
108 | Command::new("explorer.exe" ) |
109 | .arg("/select," ) |
110 | .arg(path) |
111 | .stdout(Stdio::null()) |
112 | .stderr(Stdio::null()) |
113 | .spawn() |
114 | .map_err(|err| OpenError::Spawn { |
115 | cmds: "explorer.exe" .into(), |
116 | source: err, |
117 | })?; |
118 | Ok(()) |
119 | } |
120 | |
121 | #[cfg (target_os = "linux" )] |
122 | pub(crate) fn is_wsl() -> bool { |
123 | if is_docker() { |
124 | return false; |
125 | } |
126 | |
127 | if let Ok(true) = std::fs::read_to_string("/proc/sys/kernel/osrelease" ) |
128 | .map(|osrelease: String| osrelease.to_ascii_lowercase().contains("microsoft" )) |
129 | { |
130 | return true; |
131 | } |
132 | |
133 | if let Ok(true) = std::fs::read_to_string("/proc/version" ) |
134 | .map(|version: String| version.to_ascii_lowercase().contains("microsoft" )) |
135 | { |
136 | return true; |
137 | } |
138 | |
139 | false |
140 | } |
141 | |
142 | #[cfg (target_os = "linux" )] |
143 | fn is_docker() -> bool { |
144 | let has_docker_env: bool = std::fs::metadata(path:"/.dockerenv" ).is_ok(); |
145 | |
146 | let has_docker_cgroup: bool = std::fs::read_to_string("/proc/self/cgroup" ) |
147 | .map(|cgroup| cgroup.to_ascii_lowercase().contains("docker" )) |
148 | .unwrap_or(default:false); |
149 | |
150 | has_docker_env || has_docker_cgroup |
151 | } |
152 | |