gix_credentials/helper/
invoke.rs1use std::io::Read;
2
3use crate::helper::{Action, Context, Error, NextAction, Outcome, Result};
4
5impl Action {
6 pub fn send(&self, write: &mut dyn std::io::Write) -> std::io::Result<()> {
8 match self {
9 Action::Get(ctx) => ctx.write_to(write),
10 Action::Store(last) | Action::Erase(last) => {
11 write.write_all(last).ok();
12 write.write_all(b"\n").ok();
13 Ok(())
14 }
15 }
16 }
17}
18
19pub 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 oauth_refresh_token: ctx.oauth_refresh_token,
34 quit: ctx.quit.unwrap_or(false),
35 next: NextAction {
36 previous_output: stdout.into(),
37 },
38 }))
39 }
40 }
41}
42
43pub(crate) fn raw(helper: &mut crate::Program, action: &Action) -> std::result::Result<Option<Vec<u8>>, Error> {
44 let (mut stdin, stdout) = helper.start(action)?;
45 if let (Action::Get(_), None) = (&action, &stdout) {
46 panic!("BUG: `Helper` impls must return an output handle to read output from if Action::Get is provided")
47 }
48 action.send(&mut stdin)?;
49 drop(stdin);
50 let stdout = stdout
51 .map(|mut stdout| {
52 let mut buf = Vec::new();
53 stdout.read_to_end(&mut buf).map(|_| buf)
54 })
55 .transpose()
56 .map_err(|err| Error::CredentialsHelperFailed { source: err })?;
57 helper.finish().map_err(|err| {
58 if err.kind() == std::io::ErrorKind::Other {
59 Error::CredentialsHelperFailed { source: err }
60 } else {
61 err.into()
62 }
63 })?;
64
65 match matches!(action, Action::Get(_)).then(|| stdout).flatten() {
66 None => Ok(None),
67 Some(stdout) => Ok(Some(stdout)),
68 }
69}