|
1 |
| -use std::borrow::Cow; |
2 |
| -use std::env; |
3 |
| -use std::io::{self, Write}; |
4 |
| -use std::path::Path; |
5 |
| -use std::process::{Command, Stdio}; |
| 1 | +mod processor; |
6 | 2 |
|
7 | 3 | #[macro_use]
|
8 | 4 | extern crate lazy_static;
|
9 | 5 | extern crate regex;
|
10 |
| -use regex::bytes::Regex; |
11 |
| - |
12 |
| -fn translate_path_to_unix(arg: String) -> String { |
13 |
| - if let Some(index) = arg.find(":\\") { |
14 |
| - if index != 1 { |
15 |
| - // Not a path |
16 |
| - return arg; |
17 |
| - } |
18 |
| - let mut path_chars = arg.chars(); |
19 |
| - if let Some(drive) = path_chars.next() { |
20 |
| - let mut wsl_path = String::from("/mnt/"); |
21 |
| - wsl_path.push_str(&drive.to_lowercase().collect::<String>()); |
22 |
| - path_chars.next(); |
23 |
| - wsl_path.push_str(&path_chars |
24 |
| - .map(|c| match c { |
25 |
| - '\\' => '/', |
26 |
| - _ => c, |
27 |
| - }) |
28 |
| - .collect::<String>()); |
29 |
| - return wsl_path; |
30 |
| - } |
31 |
| - } |
32 |
| - arg |
33 |
| -} |
34 |
| - |
35 |
| -fn translate_path_to_win(line: &[u8]) -> Cow<[u8]> { |
36 |
| - lazy_static! { |
37 |
| - static ref WSLPATH_RE: Regex = Regex::new(r"(?m-u)/mnt/(?P<drive>[A-Za-z])(?P<path>/\S*)") |
38 |
| - .expect("Failed to compile WSLPATH regex"); |
39 |
| - } |
40 |
| - WSLPATH_RE.replace_all(line, &b"${drive}:${path}"[..]) |
41 |
| -} |
42 |
| - |
43 |
| -fn shell_escape(arg: String) -> String { |
44 |
| - // ToDo: This really only handles arguments with spaces and newlines. |
45 |
| - // More complete shell escaping is required for the general case. |
46 |
| - if arg.contains(" ") { |
47 |
| - return vec![String::from("\""), arg, String::from("\"")].join(""); |
48 |
| - } |
49 |
| - arg.replace("\n", "$'\n'"); |
50 |
| - arg.replace(";", "$';'") |
51 |
| -} |
52 |
| - |
53 |
| -fn use_interactive_shell() -> bool { |
54 |
| - // check for explicit environment variable setting |
55 |
| - if let Ok(interactive_flag) = env::var("WSL_USE_INTERACTIVE_SHELL") { |
56 |
| - if interactive_flag == "true" || interactive_flag == "1" { |
57 |
| - return false; |
58 |
| - } |
59 |
| - } |
60 |
| - // check for advanced usage indicated by BASH_ENV and WSLENV=BASH_ENV |
61 |
| - else if env::var("BASH_ENV").is_ok() { |
62 |
| - if let Ok(wslenv) = env::var("WSLENV") { |
63 |
| - if wslenv |
64 |
| - .split(':') |
65 |
| - .position(|r| r.eq_ignore_ascii_case("BASH_ENV")) |
66 |
| - .is_some() |
67 |
| - { |
68 |
| - return true; |
69 |
| - } |
70 |
| - } |
71 |
| - } |
72 |
| - false |
73 |
| -} |
74 | 6 |
|
75 | 7 | fn main() {
|
76 |
| - let mut cmd_args = Vec::new(); |
77 |
| - let mut wsl_args: Vec<String> = vec![]; |
78 |
| - let wsl_cmd: String; |
79 |
| - let exe: String = env::args().next().unwrap(); |
80 |
| - let path = Path::new(&exe); |
81 |
| - let file_stem = path.file_stem().unwrap().to_str().unwrap(); |
82 |
| - wsl_args.push(String::from(file_stem)); |
83 |
| - |
84 |
| - // process wsl command arguments |
85 |
| - wsl_args.extend( |
86 |
| - env::args() |
87 |
| - .skip(1) |
88 |
| - .map(translate_path_to_unix) |
89 |
| - .map(shell_escape), |
90 |
| - ); |
91 |
| - wsl_cmd = wsl_args.join(" "); |
92 |
| - |
93 |
| - if use_interactive_shell() { |
94 |
| - cmd_args.push("bash".to_string()); |
95 |
| - cmd_args.push("-ic".to_string()); |
96 |
| - cmd_args.push(wsl_cmd.clone()); |
97 |
| - } else { |
98 |
| - cmd_args.clone_from(&wsl_args); |
99 |
| - } |
100 |
| - |
101 |
| - // setup stdin/stdout |
102 |
| - let stdin_mode = if wsl_cmd.ends_with("--version") { |
103 |
| - // For some reason, the git subprocess seems to hang, waiting for |
104 |
| - // input, when VS Code 1.17.2 tries to detect if `git --version` works |
105 |
| - // on Windows 10 1709 (specifically, in `findSpecificGit` in the |
106 |
| - // VS Code source file `extensions/git/src/git.ts`). |
107 |
| - // To workaround this, we only pass stdin to the git subprocess |
108 |
| - // for all other commands, but not for the initial `--version` check. |
109 |
| - // Stdin is needed for example when commiting, where the commit |
110 |
| - // message is passed on stdin. |
111 |
| - Stdio::null() |
112 |
| - } else { |
113 |
| - Stdio::inherit() |
114 |
| - }; |
115 |
| - |
116 |
| - // setup the wsl subprocess launched inside WSL |
117 |
| - let mut wsl_proc_setup = Command::new("wsl.exe"); |
118 |
| - wsl_proc_setup.args(&cmd_args).stdin(stdin_mode); |
119 |
| - let status; |
120 |
| - |
121 |
| - // add git commands that must use translate_path_to_win |
122 |
| - const TRANSLATED_CMDS: &[&str] = &["rev-parse", "remote"]; |
123 |
| - |
124 |
| - let have_args = wsl_args.len() > 1; |
125 |
| - let translate_output = if have_args { |
126 |
| - TRANSLATED_CMDS |
127 |
| - .iter() |
128 |
| - .position(|&r| r == wsl_args[1]) |
129 |
| - .is_some() |
130 |
| - } else { |
131 |
| - false |
132 |
| - }; |
133 |
| - |
134 |
| - if translate_output { |
135 |
| - // run the subprocess and capture its output |
136 |
| - let wsl_proc = wsl_proc_setup |
137 |
| - .stdout(Stdio::piped()) |
138 |
| - .spawn() |
139 |
| - .expect(&format!("Failed to execute command '{}'", &wsl_cmd)); |
140 |
| - let output = wsl_proc |
141 |
| - .wait_with_output() |
142 |
| - .expect(&format!("Failed to wait for wsl call '{}'", &wsl_cmd)); |
143 |
| - status = output.status; |
144 |
| - let output_bytes = output.stdout; |
145 |
| - let mut stdout = io::stdout(); |
146 |
| - stdout |
147 |
| - .write_all(&translate_path_to_win(&output_bytes)) |
148 |
| - .expect("Failed to write wsl output"); |
149 |
| - stdout.flush().expect("Failed to flush output"); |
150 |
| - } else { |
151 |
| - // run the subprocess without capturing its output |
152 |
| - // the output of the subprocess is passed through unchanged |
153 |
| - status = wsl_proc_setup |
154 |
| - .status() |
155 |
| - .expect(&format!("Failed to execute command '{}'", &wsl_cmd)); |
156 |
| - } |
157 |
| - |
158 |
| - // forward any exit code |
159 |
| - if let Some(exit_code) = status.code() { |
160 |
| - std::process::exit(exit_code); |
161 |
| - } |
162 |
| -} |
163 |
| - |
164 |
| -#[test] |
165 |
| -fn win_to_unix_path_trans() { |
166 |
| - assert_eq!( |
167 |
| - translate_path_to_unix("d:\\test\\file.txt".to_string()), |
168 |
| - "/mnt/d/test/file.txt" |
169 |
| - ); |
170 |
| - assert_eq!( |
171 |
| - translate_path_to_unix("C:\\Users\\test\\a space.txt".to_string()), |
172 |
| - "/mnt/c/Users/test/a space.txt" |
173 |
| - ); |
174 |
| -} |
175 |
| - |
176 |
| -#[test] |
177 |
| -fn unix_to_win_path_trans() { |
178 |
| - assert_eq!( |
179 |
| - &*translate_path_to_win(b"/mnt/d/some path/a file.md"), |
180 |
| - b"d:/some path/a file.md" |
181 |
| - ); |
182 |
| - assert_eq!( |
183 |
| - &*translate_path_to_win(b"origin /mnt/c/path/ (fetch)"), |
184 |
| - b"origin c:/path/ (fetch)" |
185 |
| - ); |
186 |
| - let multiline = b"mirror /mnt/c/other/ (fetch)\nmirror /mnt/c/other/ (push)\n"; |
187 |
| - let multiline_result = b"mirror c:/other/ (fetch)\nmirror c:/other/ (push)\n"; |
188 |
| - assert_eq!( |
189 |
| - &*translate_path_to_win(&multiline[..]), |
190 |
| - &multiline_result[..] |
191 |
| - ); |
192 |
| -} |
193 |
| - |
194 |
| -#[test] |
195 |
| -fn no_path_translation() { |
196 |
| - assert_eq!( |
197 |
| - &*translate_path_to_win(b"/mnt/other/file.sh"), |
198 |
| - b"/mnt/other/file.sh" |
199 |
| - ); |
| 8 | + processor::execute(false) |
200 | 9 | }
|
0 commit comments