From 243a8c53ae03713b3d6b4f5bf82859f9c93be6ed Mon Sep 17 00:00:00 2001 From: Rory Dudley Date: Sat, 28 Sep 2024 14:57:03 -0600 Subject: Add support for inline environment variables This patch adds the 'Notes' rune (`=`), which allows for passing environment variables, inline, to a binary, like so: EDITOR=vim sudo visudo Signed-off-by: Rory Dudley --- src/poem/elements/rune.rs | 5 +++++ src/poem/elements/verse.rs | 20 ++++++++++++++++++++ src/poem/read.rs | 16 +++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/poem/elements/rune.rs b/src/poem/elements/rune.rs index 79d53d0..8573583 100644 --- a/src/poem/elements/rune.rs +++ b/src/poem/elements/rune.rs @@ -35,6 +35,10 @@ pub enum Rune { /// A subcommand to run first (`\``) Poem, + /// Denotes an environment variable (`=`), + /// only if the verse is empty so far + Notes, + /// Read files into STDIN (`<`) Read, @@ -89,6 +93,7 @@ impl fmt::Display for Rune { Rune::Remark => "#", Rune::String => "\"", Rune::Poem => "`", + Rune::Notes => "=", Rune::Read => "<", Rune::Write => ">", Rune::Write2 => "2>", diff --git a/src/poem/elements/verse.rs b/src/poem/elements/verse.rs index 9ebd31d..4d5f31c 100644 --- a/src/poem/elements/verse.rs +++ b/src/poem/elements/verse.rs @@ -23,6 +23,9 @@ use std::sync::{Arc, Mutex}; /// input on `STDIN` from the previous [Verse]. #[derive(Debug, Clone)] pub struct Verse { + /// Environment variables to fork with + pub notes: Stanza, + /// A command and its arguments (also see [Stanza]) pub stanza: Stanza, @@ -119,6 +122,7 @@ impl Verse { /// [Rune::None], and `couplet` set to 0. pub fn new() -> Self { Verse { + notes: Stanza::new(), stanza: Stanza::new(), couplet: 0, io: Vec::new(), @@ -148,6 +152,20 @@ impl Verse { } } + /// Set the [Verse]'s command's environment + /// + /// Use self.notate to set inline environment variables + pub fn notate(&self, command: &mut Command) { + for var in self.notes.clone() { + let split: Vec<&str> = var.split("=").collect(); + if split.len() == 1 { + command.env(split[0], ""); + } else { + command.env(split[0], split[1]); + } + } + } + /// Alias to [Verse].stanza.push() pub fn push(&mut self, word: String) { self.stanza.push(word); @@ -202,6 +220,7 @@ impl Verse { // Push the word match channel { + Some(Rune::Notes) => self.notes.push(word.iter().collect()), Some(Rune::Read) => self.ip.push(word.iter().collect()), Some(Rune::Write) | Some(Rune::Addendum) => self.op.push(word.iter().collect()), Some(Rune::Write2) | Some(Rune::Addendum2) => self.ep.push(word.iter().collect()), @@ -334,6 +353,7 @@ impl Verse { } _ => { let mut command = Command::new(self.verb()); + self.notate(&mut command); incant!(self.verb(), command, out, pids, env, self) } } diff --git a/src/poem/read.rs b/src/poem/read.rs index 99e9aa6..baf6a1d 100644 --- a/src/poem/read.rs +++ b/src/poem/read.rs @@ -246,6 +246,7 @@ impl Readable for Poem { '#' => Rune::Remark, '\'' | '"' => Rune::String, '`' => Rune::Poem, + '=' => Rune::Notes, '<' => Rune::Read, '>' => next(&mut chars, &mut i, Rune::Write, vec![(">", Rune::Addendum)]), '1' => next( @@ -352,7 +353,11 @@ impl Readable for Poem { match rune { // Indicates the end of a word (space dilineated) Rune::Pause => { + if word.contains(&'=') && verse.is_empty() { + channel = Some(Rune::Notes); + } verse.add(&mut word, channel); + channel = Some(rune); } Rune::Special => { @@ -378,6 +383,15 @@ impl Readable for Poem { poem!(chars, j, i, c, verse, word, env); } + // Indicates an environment variable to fork with, + // if the verse's stanza is empty so far + // Rune::Environment => { + // word.push(c); + // if verse.is_empty() { + // channel = Some(rune); + // } + // } + // Indicates a file operation (<, >, or >>) Rune::Read | Rune::Write @@ -388,7 +402,7 @@ impl Readable for Poem { | Rune::AddendumAll => { channel = Some(rune); verse.add(&mut word, channel); - channel = Some(rune); + // channel = Some(rune); verse.io.push(rune); } -- cgit v1.2.3