]> git.proxmox.com Git - rustc.git/blame - vendor/gix-credentials/src/helper/invoke.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / vendor / gix-credentials / src / helper / invoke.rs
CommitLineData
0a29b90c
FG
1use std::io::Read;
2
3use crate::helper::{Action, Context, Error, NextAction, Outcome, Result};
4
5impl Action {
6 /// Send ourselves to the given `write` which is expected to be credentials-helper compatible
7 pub fn send(&self, mut write: impl std::io::Write) -> std::io::Result<()> {
8 match self {
9 Action::Get(ctx) => ctx.write_to(write),
10 Action::Store(last) | Action::Erase(last) => {
49aad941
FG
11 write.write_all(last).ok();
12 write.write_all(&[b'\n']).ok();
13 Ok(())
0a29b90c
FG
14 }
15 }
16 }
17}
18
19/// Invoke the given `helper` with `action` in `context`.
20///
21/// Usually the first call is performed with [`Action::Get`] to obtain `Some` identity, which subsequently can be used if it is complete.
22/// Note that it may also only contain the username _or_ password, and should start out with everything the helper needs.
23/// On successful usage, use [`NextAction::store()`], otherwise [`NextAction::erase()`], which is when this function
24/// returns `Ok(None)` as no outcome is expected.
25pub fn invoke(helper: &mut crate::Program, action: &Action) -> Result {
26 match raw(helper, action)? {
27 None => Ok(None),
28 Some(stdout) => {
29 let ctx = Context::from_bytes(stdout.as_slice())?;
30 Ok(Some(Outcome {
31 username: ctx.username,
32 password: ctx.password,
33 quit: ctx.quit.unwrap_or(false),
34 next: NextAction {
35 previous_output: stdout.into(),
36 },
37 }))
38 }
39 }
40}
41
42pub(crate) fn raw(helper: &mut crate::Program, action: &Action) -> std::result::Result<Option<Vec<u8>>, Error> {
43 let (stdin, stdout) = helper.start(action)?;
44 if let (Action::Get(_), None) = (&action, &stdout) {
45 panic!("BUG: `Helper` impls must return an output handle to read output from if Action::Get is provided")
46 }
47 action.send(stdin)?;
48 let stdout = stdout
49 .map(|mut stdout| {
50 let mut buf = Vec::new();
51 stdout.read_to_end(&mut buf).map(|_| buf)
52 })
53 .transpose()
54 .map_err(|err| Error::CredentialsHelperFailed { source: err })?;
55 helper.finish().map_err(|err| {
56 if err.kind() == std::io::ErrorKind::Other {
57 Error::CredentialsHelperFailed { source: err }
58 } else {
59 err.into()
60 }
61 })?;
62
63 match matches!(action, Action::Get(_)).then(|| stdout).flatten() {
64 None => Ok(None),
65 Some(stdout) => Ok(Some(stdout)),
66 }
67}