git.delta.rocks / remowt / refs/commits / 2499daa8100a

difftreelog

feat enum prompt variant

wnlysuptYaroslav Bolyukin2024-08-05parent: #7c2fb57.patch.diff
in: trunk

11 files changed

modifiedCargo.lockdiffbeforeafterboth
351351
352[[package]]352[[package]]
353name = "clap"353name = "clap"
354version = "4.5.11"354version = "4.5.13"
355source = "registry+https://github.com/rust-lang/crates.io-index"355source = "registry+https://github.com/rust-lang/crates.io-index"
356checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3"356checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc"
357dependencies = [357dependencies = [
358 "clap_builder",358 "clap_builder",
359 "clap_derive",359 "clap_derive",
360]360]
361361
362[[package]]362[[package]]
363name = "clap_builder"363name = "clap_builder"
364version = "4.5.11"364version = "4.5.13"
365source = "registry+https://github.com/rust-lang/crates.io-index"365source = "registry+https://github.com/rust-lang/crates.io-index"
366checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa"366checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99"
367dependencies = [367dependencies = [
368 "anstream",368 "anstream",
369 "anstyle",369 "anstyle",
373373
374[[package]]374[[package]]
375name = "clap_derive"375name = "clap_derive"
376version = "4.5.11"376version = "4.5.13"
377source = "registry+https://github.com/rust-lang/crates.io-index"377source = "registry+https://github.com/rust-lang/crates.io-index"
378checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e"378checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
379dependencies = [379dependencies = [
380 "heck",380 "heck",
381 "proc-macro2",381 "proc-macro2",
862 "futures-io",862 "futures-io",
863]863]
864
865[[package]]
866name = "polkit-agent"
867version = "0.1.0"
868dependencies = [
869 "anyhow",
870 "pam-client",
871 "polkit-shared",
872 "rand",
873 "serde",
874 "tokio",
875 "tracing",
876 "tracing-subscriber",
877 "ui-prompt",
878 "uuid",
879 "zbus",
880 "zbus_polkit",
881]
882864
883[[package]]865[[package]]
884name = "polkit-backend"866name = "polkit-backend"
1012source = "registry+https://github.com/rust-lang/crates.io-index"994source = "registry+https://github.com/rust-lang/crates.io-index"
1013checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"995checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
996
997[[package]]
998name = "remowt-agent"
999version = "0.1.0"
1000dependencies = [
1001 "anyhow",
1002 "clap",
1003 "pam-client",
1004 "polkit-shared",
1005 "rand",
1006 "serde",
1007 "tokio",
1008 "tracing",
1009 "tracing-subscriber",
1010 "ui-prompt",
1011 "uuid",
1012 "zbus",
1013 "zbus_polkit",
1014]
1015
1016[[package]]
1017name = "remowt-ssh"
1018version = "0.1.0"
10141019
1015[[package]]1020[[package]]
1016name = "rpassword"1021name = "rpassword"
modifiedCargo.tomldiffbeforeafterboth
2members = ["cmds/*", "crates/*"]2members = ["cmds/*", "crates/*"]
3resolver = "2"3resolver = "2"
4
5[workspace.packages]
6bifrostlink = { path = "../bifrostlink/crates/bifrostlink" }
7bifrostlink-ports = { path = "../bifrostlink/crates/bifrostlink-ports" }
48
deletedcmds/polkit-agent/Cargo.tomldiffbeforeafterboth

no changes

deletedcmds/polkit-agent/src/main.rsdiffbeforeafterboth

no changes

addedcmds/remowt-agent/Cargo.tomldiffbeforeafterboth

no changes

addedcmds/remowt-agent/src/main.rsdiffbeforeafterboth

no changes

addedcmds/remowt-ssh/Cargo.tomldiffbeforeafterboth

no changes

addedcmds/remowt-ssh/src/main.rsdiffbeforeafterboth

no changes

modifiedcrates/ui-prompt/src/dbus.rsdiffbeforeafterboth
4040
41#[proxy(interface = "lach.PolkitInputHandler")]41#[proxy(interface = "lach.PolkitInputHandler")]
42trait DbusPrompter {42trait DbusPrompter {
43 async fn prompt_radio(43 async fn prompt_enum(
44 &self,44 &self,
45 prompt: &str,45 prompt: &str,
46 description: &str,46 description: &str,
47 variants: &[&str],
47 source: &[Source],48 source: &[Source],
48 ) -> fdo::Result<bool>;49 ) -> fdo::Result<u32>;
49 async fn prompt_text(50 async fn prompt_text(
50 &self,51 &self,
51 echo: bool,52 echo: bool,
62}63}
6364
64impl Prompter for DbusPrompterProxy<'_> {65impl Prompter for DbusPrompterProxy<'_> {
65 async fn prompt_radio(66 async fn prompt_enum(
66 &self,67 &self,
67 prompt: &str,68 prompt: &str,
68 description: &str,69 description: &str,
70 variants: &[&str],
69 source: &[Source],71 source: &[Source],
70 ) -> Result<bool> {72 ) -> Result<u32> {
71 Ok(self.prompt_radio(prompt, description, source).await?)73 Ok(self
74 .prompt_enum(prompt, description, variants, source)
75 .await?)
72 }76 }
7377
86 }90 }
87}91}
88impl BlockingPrompter for DbusPrompterProxyBlocking<'_> {92impl BlockingPrompter for DbusPrompterProxyBlocking<'_> {
89 fn prompt_radio(&self, prompt: &str, description: &str, source: &[Source]) -> Result<bool> {93 fn prompt_enum(
94 &self,
95 prompt: &str,
96 description: &str,
97 variants: &[&str],
98 source: &[Source],
99 ) -> Result<u32> {
90 Ok(self.prompt_radio(prompt, description, source)?)100 Ok(self.prompt_enum(prompt, description, variants, source)?)
91 }101 }
92102
93 fn prompt_text(103 fn prompt_text(
modifiedcrates/ui-prompt/src/lib.rsdiffbeforeafterboth
31 prompt: &str,31 prompt: &str,
32 description: &str,32 description: &str,
33 source: &[Source],33 source: &[Source],
34 ) -> impl Future<Output = Result<bool>> + Send;34 ) -> impl Future<Output = Result<bool>> + Send {
35 let fut = self.prompt_enum(prompt, description, &["No", "Yes"], source);
36 async { fut.await.map(|v| v == 1) }
37 }
38 fn prompt_enum(
39 &self,
40 prompt: &str,
41 description: &str,
42 variants: &[&str],
43 source: &[Source],
44 ) -> impl Future<Output = Result<u32>> + Send;
35 fn prompt_text(45 fn prompt_text(
36 &self,46 &self,
37 echo: bool,47 echo: bool,
47 ) -> impl Future<Output = Result<()>> + Send;57 ) -> impl Future<Output = Result<()>> + Send;
48}58}
49pub trait BlockingPrompter {59pub trait BlockingPrompter {
50 fn prompt_radio(&self, prompt: &str, description: &str, source: &[Source]) -> Result<bool>;60 fn prompt_radio(&self, prompt: &str, description: &str, source: &[Source]) -> Result<bool> {
61 self.prompt_enum(prompt, description, &["No", "Yes"], source)
62 .map(|v| v == 1)
63 }
64 fn prompt_enum(
65 &self,
66 prompt: &str,
67 description: &str,
68 variants: &[&str],
69 source: &[Source],
70 ) -> Result<u32>;
51 fn prompt_text(71 fn prompt_text(
52 &self,72 &self,
53 echo: bool,73 echo: bool,
73where93where
74 P: Prompter + Sync,94 P: Prompter + Sync,
75{95{
76 async fn prompt_radio(96 async fn prompt_enum(
77 &self,97 &self,
78 prompt: &str,98 prompt: &str,
79 description: &str,99 description: &str,
100 variants: &[&str],
80 source: &[Source],101 source: &[Source],
81 ) -> Result<bool> {102 ) -> Result<u32> {
82 self.prompter103 self.prompter
83 .prompt_radio(prompt, description, &self.source(source))104 .prompt_enum(prompt, description, variants, &self.source(source))
84 .await105 .await
85 }106 }
86107
modifiedcrates/ui-prompt/src/rofi.rsdiffbeforeafterboth
88
9pub struct RofiPrompter;9pub struct RofiPrompter;
10
11fn fixup_prompt(prompt: &str) -> &str {
12 // Rofi always appends such suffix
13 prompt.strip_suffix(": ").unwrap_or(prompt)
14}
1015
11impl Prompter for RofiPrompter {16impl Prompter for RofiPrompter {
12 async fn prompt_radio(17 async fn prompt_enum(
13 &self,18 &self,
14 prompt: &str,19 prompt: &str,
15 description: &str,20 description: &str,
21 variants: &[&str],
16 source: &[Source],22 source: &[Source],
17 ) -> Result<bool> {23 ) -> Result<u32> {
18 trace!("rofi radio");24 trace!("rofi radio");
19 let mut cmd = Command::new("rofi");25 let mut cmd = Command::new("rofi");
20 let mesg = if source.is_empty() {26 let mesg = if source.is_empty() {
34 "-sync",40 "-sync",
35 "-only-match",41 "-only-match",
36 "-p",42 "-p",
37 prompt,43 fixup_prompt(prompt),
44 "-format",
45 "i",
38 ]);46 ]);
39 cmd.stdin(Stdio::piped());47 cmd.stdin(Stdio::piped());
40 cmd.stdout(Stdio::piped());48 cmd.stdout(Stdio::piped());
43 .spawn()51 .spawn()
44 .map_err(|e| Error::InputError(format!("failed to spawn rofi: {e}")))?;52 .map_err(|e| Error::InputError(format!("failed to spawn rofi: {e}")))?;
4553
46 child54 let mut stdin = child.stdin.take().expect("stdin is piped");
47 .stdin55 for var in variants {
48 .take()56 stdin
49 .expect("stdin is piped")57 .write_all(var.replace('\n', " ").as_bytes())
58 .await
59 .map_err(|e| Error::InputError(format!("failed to write rofi variants: {e}")))?;
60 stdin
50 .write_all(b"Yes\nNo\n")61 .write_all(b"\n")
51 .await62 .await
52 .map_err(|e| Error::InputError(format!("failed to write rofi variants: {e}")))?;63 .map_err(|e| Error::InputError(format!("failed to write rofi variants: {e}")))?;
64 }
65 // write_all already flushes, just to be sure.
66 let _ = stdin.flush().await;
67 drop(stdin);
5368
54 let out = child69 let out = child
55 .wait_with_output()70 .wait_with_output()
61 .unwrap_or(&out.stdout)76 .unwrap_or(&out.stdout)
62 .to_owned();77 .to_owned();
6378
79 let id: u32 = String::from_utf8(stdout)
80 .map_err(|e| Error::InputError(format!("rofi produced invalid output: {e}")))?
81 .parse()
82 .map_err(|e| Error::InputError(format!("rofi produced invalid output: {e}")))?;
64 if &stdout == b"Yes" {83 if id as usize >= variants.len() {
65 Ok(true)
66 } else if &stdout == b"No" {
67 Ok(false)
68 } else {
69 Err(Error::InputError("bad rofi response".to_owned()))84 return Err(Error::InputError("invalid rofi response".to_owned()));
70 }85 }
86
87 Ok(id)
71 }88 }
7289
73 async fn prompt_text(90 async fn prompt_text(
89 out.push_str("</b>");106 out.push_str("</b>");
90 out107 out
91 };108 };
92 cmd.args(["-dmenu", "-mesg", &mesg, "-p", prompt]);109 cmd.args(["-dmenu", "-mesg", &mesg, "-p", fixup_prompt(prompt)]);
93 if !echo {110 if !echo {
94 cmd.arg("-password");111 cmd.arg("-password");
95 }112 }