git_prompt/
types.rs

1use std::{borrow::Cow, convert::TryFrom, 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] nix::errno::Errno),
19}
20
21/// The way the user is prompted.
22#[derive(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    Hidden,
28    /// Do not prompt the user at all but rather abort with an error. This is useful in conjunction with [Options::askpass].
29    Disable,
30}
31
32impl Default for Mode {
33    fn default() -> Self {
34        Mode::Hidden
35    }
36}
37
38/// The options used in `[ask()]`.
39#[derive(Default, Clone)]
40pub struct Options<'a> {
41    /// The path or name (for lookup in `PATH`) to the askpass program to call before prompting the user.
42    ///
43    /// It's called like this `askpass <prompt>`, but note that it won't know if the input should be hidden or not.
44    pub askpass: Option<Cow<'a, Path>>,
45    /// The way the user is prompted.
46    pub mode: Mode,
47}
48
49impl Options<'_> {
50    /// Change this instance to incorporate information from the environment.
51    ///
52    /// - if `use_git_askpass` is true, use `GIT_ASKPASS` to override any existing [`askpass`][Options::askpass] program
53    /// - otherwise fall back to the [`askpass`][Options::askpass] program already set
54    /// - or try to use the `SSH_ASKPASS` if `use_ssh_askpass` is true
55    ///
56    /// At the and of this process, the `askpass` program may be set depending on the rules above.
57    ///
58    /// Lastly, if `use_git_terminal_prompt` is set, use the `GIT_TERMINAL_PROMPT` environment variable and evaluate it as boolean,
59    /// and if false, set [`mode`][Options::mode] to `disable`.
60    pub fn apply_environment(
61        mut self,
62        use_git_askpass: bool,
63        use_ssh_askpass: bool,
64        use_git_terminal_prompt: bool,
65    ) -> Self {
66        if let Some(askpass) = use_git_askpass.then(|| std::env::var_os("GIT_ASKPASS")).flatten() {
67            self.askpass = Some(Cow::Owned(askpass.into()))
68        }
69        if self.askpass.is_none() {
70            if let Some(askpass) = use_ssh_askpass.then(|| std::env::var_os("SSH_ASKPASS")).flatten() {
71                self.askpass = Some(Cow::Owned(askpass.into()))
72            }
73        }
74        self.mode = use_git_terminal_prompt
75            .then(|| {
76                std::env::var_os("GIT_TERMINAL_PROMPT")
77                    .and_then(|val| git_config_value::Boolean::try_from(val).ok())
78                    .and_then(|allow| (!allow.0).then_some(Mode::Disable))
79            })
80            .flatten()
81            .unwrap_or(self.mode);
82        self
83    }
84}