Show More
@@ -11,6 +11,7 b' use hg::utils::files::{get_bytes_from_os' | |||||
11 | use hg::utils::SliceExt; |
|
11 | use hg::utils::SliceExt; | |
12 | use std::ffi::OsString; |
|
12 | use std::ffi::OsString; | |
13 | use std::path::PathBuf; |
|
13 | use std::path::PathBuf; | |
|
14 | use std::process::Command; | |||
14 |
|
15 | |||
15 | mod blackbox; |
|
16 | mod blackbox; | |
16 | mod error; |
|
17 | mod error; | |
@@ -138,9 +139,43 b' fn exit_code(result: &Result<(), Command' | |||||
138 |
|
139 | |||
139 | fn exit( |
|
140 | fn exit( | |
140 | ui: &Ui, |
|
141 | ui: &Ui, | |
141 | on_unsupported: OnUnsupported, |
|
142 | mut on_unsupported: OnUnsupported, | |
142 | result: Result<(), CommandError>, |
|
143 | result: Result<(), CommandError>, | |
143 | ) -> ! { |
|
144 | ) -> ! { | |
|
145 | if let ( | |||
|
146 | OnUnsupported::Fallback { executable }, | |||
|
147 | Err(CommandError::UnsupportedFeature { .. }), | |||
|
148 | ) = (&on_unsupported, &result) | |||
|
149 | { | |||
|
150 | let mut args = std::env::args_os(); | |||
|
151 | let executable_path = get_path_from_bytes(&executable); | |||
|
152 | let this_executable = args.next().expect("exepcted argv[0] to exist"); | |||
|
153 | if executable_path == &PathBuf::from(this_executable) { | |||
|
154 | // Avoid spawning infinitely many processes until resource | |||
|
155 | // exhaustion. | |||
|
156 | let _ = ui.write_stderr(&format_bytes!( | |||
|
157 | b"Blocking recursive fallback. The 'rhg.fallback-executable = {}' config \ | |||
|
158 | points to `rhg` itself.\n", | |||
|
159 | executable | |||
|
160 | )); | |||
|
161 | on_unsupported = OnUnsupported::Abort | |||
|
162 | } else { | |||
|
163 | // `args` is now `argv[1..]` since we’ve already consumed `argv[0]` | |||
|
164 | let result = Command::new(executable_path).args(args).status(); | |||
|
165 | match result { | |||
|
166 | Ok(status) => std::process::exit( | |||
|
167 | status.code().unwrap_or(exitcode::ABORT), | |||
|
168 | ), | |||
|
169 | Err(error) => { | |||
|
170 | let _ = ui.write_stderr(&format_bytes!( | |||
|
171 | b"tried to fall back to a '{}' sub-process but got error {}\n", | |||
|
172 | executable, format_bytes::Utf8(error) | |||
|
173 | )); | |||
|
174 | on_unsupported = OnUnsupported::Abort | |||
|
175 | } | |||
|
176 | } | |||
|
177 | } | |||
|
178 | } | |||
144 | match &result { |
|
179 | match &result { | |
145 | Ok(_) => {} |
|
180 | Ok(_) => {} | |
146 | Err(CommandError::Abort { message }) => { |
|
181 | Err(CommandError::Abort { message }) => { | |
@@ -160,6 +195,7 b' fn exit(' | |||||
160 | )); |
|
195 | )); | |
161 | } |
|
196 | } | |
162 | OnUnsupported::AbortSilent => {} |
|
197 | OnUnsupported::AbortSilent => {} | |
|
198 | OnUnsupported::Fallback { .. } => unreachable!(), | |||
163 | } |
|
199 | } | |
164 | } |
|
200 | } | |
165 | } |
|
201 | } | |
@@ -268,18 +304,32 b' enum OnUnsupported {' | |||||
268 | Abort, |
|
304 | Abort, | |
269 | /// Silently exit with code 252. |
|
305 | /// Silently exit with code 252. | |
270 | AbortSilent, |
|
306 | AbortSilent, | |
|
307 | /// Try running a Python implementation | |||
|
308 | Fallback { executable: Vec<u8> }, | |||
271 | } |
|
309 | } | |
272 |
|
310 | |||
273 | impl OnUnsupported { |
|
311 | impl OnUnsupported { | |
|
312 | const DEFAULT: Self = OnUnsupported::Abort; | |||
|
313 | const DEFAULT_FALLBACK_EXECUTABLE: &'static [u8] = b"hg"; | |||
|
314 | ||||
274 | fn from_config(config: &Config) -> Self { |
|
315 | fn from_config(config: &Config) -> Self { | |
275 | let default = OnUnsupported::Abort; |
|
316 | match config | |
276 |
|
|
317 | .get(b"rhg", b"on-unsupported") | |
|
318 | .map(|value| value.to_ascii_lowercase()) | |||
|
319 | .as_deref() | |||
|
320 | { | |||
277 | Some(b"abort") => OnUnsupported::Abort, |
|
321 | Some(b"abort") => OnUnsupported::Abort, | |
278 | Some(b"abort-silent") => OnUnsupported::AbortSilent, |
|
322 | Some(b"abort-silent") => OnUnsupported::AbortSilent, | |
279 | None => default, |
|
323 | Some(b"fallback") => OnUnsupported::Fallback { | |
|
324 | executable: config | |||
|
325 | .get(b"rhg", b"fallback-executable") | |||
|
326 | .unwrap_or(Self::DEFAULT_FALLBACK_EXECUTABLE) | |||
|
327 | .to_owned(), | |||
|
328 | }, | |||
|
329 | None => Self::DEFAULT, | |||
280 | Some(_) => { |
|
330 | Some(_) => { | |
281 | // TODO: warn about unknown config value |
|
331 | // TODO: warn about unknown config value | |
282 |
|
|
332 | Self::DEFAULT | |
283 | } |
|
333 | } | |
284 | } |
|
334 | } | |
285 | } |
|
335 | } |
@@ -1,9 +1,10 b'' | |||||
1 | #require rust |
|
1 | #require rust | |
2 |
|
2 | |||
3 | Define an rhg function that will only run if rhg exists |
|
3 | Define an rhg function that will only run if rhg exists | |
|
4 | $ RHG="$RUNTESTDIR/../rust/target/release/rhg" | |||
4 | $ rhg() { |
|
5 | $ rhg() { | |
5 | > if [ -f "$RUNTESTDIR/../rust/target/release/rhg" ]; then |
|
6 | > if [ -f "$RHG" ]; then | |
6 | > "$RUNTESTDIR/../rust/target/release/rhg" "$@" |
|
7 | > "$RHG" "$@" | |
7 | > else |
|
8 | > else | |
8 | > echo "skipped: Cannot find rhg. Try to run cargo build in rust/rhg." |
|
9 | > echo "skipped: Cannot find rhg. Try to run cargo build in rust/rhg." | |
9 | > exit 80 |
|
10 | > exit 80 | |
@@ -151,6 +152,27 b' Cat copied file should not display copy ' | |||||
151 | $ rhg cat -r 1 copy_of_original |
|
152 | $ rhg cat -r 1 copy_of_original | |
152 | original content |
|
153 | original content | |
153 |
|
154 | |||
|
155 | Fallback to Python | |||
|
156 | $ rhg cat original | |||
|
157 | unsupported feature: `rhg cat` without `--rev` / `-r` | |||
|
158 | [252] | |||
|
159 | $ FALLBACK="--config rhg.on-unsupported=fallback" | |||
|
160 | $ rhg cat original $FALLBACK | |||
|
161 | original content | |||
|
162 | ||||
|
163 | $ rhg cat original $FALLBACK --config rhg.fallback-executable=false | |||
|
164 | [1] | |||
|
165 | ||||
|
166 | $ rhg cat original $FALLBACK --config rhg.fallback-executable=hg-non-existent | |||
|
167 | tried to fall back to a 'hg-non-existent' sub-process but got error $ENOENT$ | |||
|
168 | unsupported feature: `rhg cat` without `--rev` / `-r` | |||
|
169 | [252] | |||
|
170 | ||||
|
171 | $ rhg cat original $FALLBACK --config rhg.fallback-executable="$RHG" | |||
|
172 | Blocking recursive fallback. The 'rhg.fallback-executable = */rust/target/release/rhg' config points to `rhg` itself. (glob) | |||
|
173 | unsupported feature: `rhg cat` without `--rev` / `-r` | |||
|
174 | [252] | |||
|
175 | ||||
154 | Requirements |
|
176 | Requirements | |
155 | $ rhg debugrequirements |
|
177 | $ rhg debugrequirements | |
156 | dotencode |
|
178 | dotencode |
General Comments 0
You need to be logged in to leave comments.
Login now