gix_prompt/types.rs
1use std::{borrow::Cow, path::Path};
2
3/// The error returned by [ask()][crate::ask()].
4#[derive(Debug, thiserror::Error)]
5#[allow(missing_docs)]
6pub enum Error {
7 #[error("Terminal prompts are disabled")]
8 Disabled,
9 #[error("The current platform has no implementation for prompting in the terminal")]
10 UnsupportedPlatform,
11 #[error(
12 "Failed to open terminal at {:?} for writing prompt, or to write it",
13 crate::unix::TTY_PATH
14 )]
15 TtyIo(#[from] std::io::Error),
16 #[cfg(unix)]
17 #[error("Failed to obtain or set terminal configuration")]
18 TerminalConfiguration(#[from] rustix::io::Errno),
19}
20
21/// The way the user is prompted.
22#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
23pub enum Mode {
24 /// Visibly show user input.
25 Visible,
26 /// Do not show user input, suitable for sensitive data.
27 #[default]
28 Hidden,
29 /// Do not prompt the user at all but rather abort with an error. This is useful in conjunction with [Options::askpass].
30 Disable,
31}
32
33/// The options used in `[ask()]`.
34#[derive(Default, Clone)]
35pub struct Options<'a> {
36 /// The path or name (for lookup in `PATH`) to the askpass program to call before prompting the user.
37 ///
38 /// It's called like this `askpass <prompt>`, but note that it won't know if the input should be hidden or not.
39 pub askpass: Option<Cow<'a, Path>>,
40 /// The way the user is prompted.
41 pub mode: Mode,
42}
43
44impl Options<'_> {
45 /// Change this instance to incorporate information from the environment.
46 ///
47 /// - if `use_git_askpass` is true, use `GIT_ASKPASS` to override any existing [`askpass`][Options::askpass] program
48 /// - otherwise fall back to the [`askpass`][Options::askpass] program already set
49 /// - or try to use the `SSH_ASKPASS` if `use_ssh_askpass` is true
50 ///
51 /// At the and of this process, the `askpass` program may be set depending on the rules above.
52 ///
53 /// Lastly, if `use_git_terminal_prompt` is set, use the `GIT_TERMINAL_PROMPT` environment variable and evaluate it as boolean,
54 /// and if false, set [`mode`][Options::mode] to `disable`.
55 pub fn apply_environment(
56 mut self,
57 use_git_askpass: bool,
58 use_ssh_askpass: bool,
59 use_git_terminal_prompt: bool,
60 ) -> Self {
61 if let Some(askpass) = use_git_askpass.then(|| std::env::var_os("GIT_ASKPASS")).flatten() {
62 self.askpass = Some(Cow::Owned(askpass.into()));
63 }
64 if self.askpass.is_none() {
65 if let Some(askpass) = use_ssh_askpass.then(|| std::env::var_os("SSH_ASKPASS")).flatten() {
66 self.askpass = Some(Cow::Owned(askpass.into()));
67 }
68 }
69 self.mode = use_git_terminal_prompt
70 .then(|| {
71 std::env::var_os("GIT_TERMINAL_PROMPT")
72 .and_then(|val| gix_config_value::Boolean::try_from(val).ok())
73 .and_then(|allow| (!allow.0).then_some(Mode::Disable))
74 })
75 .flatten()
76 .unwrap_or(self.mode);
77 self
78 }
79}