Skip to content

Commit c0959d5

Browse files
committed
Split process building into smaller mods
1 parent 9cd8464 commit c0959d5

File tree

11 files changed

+185
-194
lines changed

11 files changed

+185
-194
lines changed

src/args.rs

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
use clap::crate_name;
1+
use crate::env::ENV_BUF_MODE;
2+
use crate::env::ENV_BUF_SIZE;
3+
use crate::env::ENV_NULL;
24
use clap::Args;
35
use clap::ValueEnum;
46
use derive_more::Display;
57
use derive_more::IsVariant;
6-
use std::env;
78
use std::io::stdout;
89
use std::io::IsTerminal;
910

@@ -12,42 +13,6 @@ use std::io::IsTerminal;
1213
// Also used internally by the `linereader` library https://github.com/Freaky/rust-linereader.
1314
const DEFAULT_BUF_SIZE: usize = 32 * 1024;
1415

15-
// Publicly known env variables:
16-
pub const ENV_NULL: &str = "REW_NULL";
17-
pub const ENV_BUF_MODE: &str = "REW_BUF_MODE";
18-
pub const ENV_BUF_SIZE: &str = "REW_BUF_SIZE";
19-
20-
// Internal env variables:
21-
//
22-
// When `rew` is spawned as a child of some parent `rew` process,
23-
// it recieves the parent's name through this environment variable.
24-
pub const ENV_SPAWNED_BY: &str = "_REW_SPAWNED_BY";
25-
26-
pub fn get_spawned_by(cmd_name: &str) -> String {
27-
format!("{} {cmd_name}", get_bin_name())
28-
}
29-
30-
pub fn get_bin_name() -> String {
31-
if let Some(spawned_by) = env::var_os(ENV_SPAWNED_BY) {
32-
let mut spawned_by = spawned_by.to_string_lossy().to_string();
33-
34-
if let Some(bin_name_len) = spawned_by.rfind(' ') {
35-
spawned_by.truncate(bin_name_len); // Trim rew subcommand name
36-
}
37-
38-
// Parent `rew` process `argv[0]`
39-
return spawned_by;
40-
}
41-
42-
if let Some(bin_name) = env::args_os().next() {
43-
// Current `rew` process `argv[0]`
44-
return bin_name.to_string_lossy().to_string();
45-
}
46-
47-
// exec syscall did not receive `argv0`?
48-
crate_name!().to_owned()
49-
}
50-
5116
#[derive(Clone, Copy, ValueEnum, Display, Debug, IsVariant, PartialEq, Eq)]
5217
pub enum BufMode {
5318
/// Writes to stdout after a line was processed or when the output buffer is full.

src/command.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::args::BufMode;
22
use crate::args::GlobalArgs;
3+
use crate::env::Env;
34
use crate::examples::Example;
45
use crate::io::ByteChunkReader;
56
use crate::io::CharChunkReader;
@@ -55,11 +56,11 @@ macro_rules! command_meta {
5556
use clap::FromArgMatches;
5657

5758
if $crate::examples::is_arg_set(&matches) {
58-
return $crate::examples::print(&meta.name, meta.examples);
59+
return $crate::examples::print(meta.name, meta.examples);
5960
}
6061

6162
let global_args = $crate::args::GlobalArgs::from_arg_matches(matches)?;
62-
let context = $crate::command::Context::from(global_args);
63+
let context = $crate::command::Context::new(meta.name, global_args);
6364
let args = $args::from_arg_matches(matches)?;
6465

6566
$run(&context, &args)
@@ -129,15 +130,16 @@ impl Group {
129130
}
130131

131132
#[derive(Clone)]
132-
pub struct Context(GlobalArgs);
133-
134-
impl From<GlobalArgs> for Context {
135-
fn from(args: GlobalArgs) -> Self {
136-
Self(args)
137-
}
133+
pub struct Context {
134+
command: &'static str,
135+
args: GlobalArgs,
138136
}
139137

140138
impl Context {
139+
pub fn new(command: &'static str, args: GlobalArgs) -> Self {
140+
Self { command, args }
141+
}
142+
141143
#[allow(clippy::unused_self)]
142144
pub fn raw_reader(&self) -> StdinLock<'_> {
143145
stdin().lock()
@@ -182,18 +184,22 @@ impl Context {
182184
}
183185

184186
pub fn buf_mode(&self) -> BufMode {
185-
self.0.buf_mode
187+
self.args.buf_mode
186188
}
187189

188190
pub fn buf_size(&self) -> usize {
189-
self.0.buf_size
191+
self.args.buf_size
190192
}
191193

192194
pub fn separator(&self) -> Separator {
193-
if self.0.null {
195+
if self.args.null {
194196
Separator::Null
195197
} else {
196198
Separator::Newline
197199
}
198200
}
201+
202+
pub fn env(&self) -> Env {
203+
Env::new(self.command, self.args.clone())
204+
}
199205
}

src/commands/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ mod trim;
1515
mod upper;
1616
mod x;
1717

18-
pub const METAS: &[&Meta] = &[
18+
pub const COMMANDS: &[&Meta] = &[
1919
&ascii::META,
2020
&cat::META,
2121
&first::META,
@@ -33,5 +33,5 @@ pub const METAS: &[&Meta] = &[
3333
];
3434

3535
pub fn get_meta(name: &str) -> Option<&'static Meta> {
36-
METAS.iter().find(|meta| meta.name == name).copied()
36+
COMMANDS.iter().find(|meta| meta.name == name).copied()
3737
}

src/commands/x.rs

Lines changed: 40 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
use super::get_meta;
2-
use crate::args::get_spawned_by;
3-
use crate::args::ENV_BUF_MODE;
4-
use crate::args::ENV_BUF_SIZE;
5-
use crate::args::ENV_NULL;
6-
use crate::args::ENV_SPAWNED_BY;
71
use crate::colors::RESET;
82
use crate::colors::YELLOW;
93
use crate::command::Context;
@@ -12,32 +6,26 @@ use crate::command::Meta;
126
use crate::command_examples;
137
use crate::command_meta;
148
use crate::commands::cat;
9+
use crate::env::Env;
1510
use crate::examples::Example;
1611
use crate::io::LineReader;
17-
use crate::pattern;
1812
use crate::pattern::Expression;
1913
use crate::pattern::ExpressionValue;
2014
use crate::pattern::Item;
2115
use crate::pattern::Pattern;
2216
use crate::pattern::SimpleItem;
2317
use crate::pattern::SimplePattern;
18+
use crate::process::Command;
2419
use crate::process::Pipeline;
25-
use crate::process::StdinMode;
2620
use crate::shell::Shell;
2721
use crate::spawn::Spawned;
28-
use crate::stdbuf::StdBuf;
29-
use anyhow::Context as _;
3022
use anyhow::Result;
3123
use bstr::ByteVec;
32-
use clap::crate_name;
3324
use clap::ArgAction;
34-
use std::env;
35-
use std::env::current_exe;
3625
use std::panic::resume_unwind;
3726
use std::process::Child;
3827
use std::process::ChildStdin;
3928
use std::process::ChildStdout;
40-
use std::process::Command;
4129
use std::thread;
4230
use std::time::Duration;
4331

@@ -211,7 +199,7 @@ fn eval_simple_pattern(context: &Context, pattern: &SimplePattern) -> Result<()>
211199
}
212200

213201
fn eval_pattern(context: &Context, pattern: &Pattern, shell: &Shell) -> Result<()> {
214-
let mut stdbuf = StdBuf::default();
202+
let mut env = context.env();
215203
let mut children = Vec::new();
216204
let mut consumers = Vec::new();
217205
let mut producers = Vec::new();
@@ -220,7 +208,7 @@ fn eval_pattern(context: &Context, pattern: &Pattern, shell: &Shell) -> Result<(
220208
match &item {
221209
Item::Constant(value) => producers.push(Producer::Constant(value.clone())),
222210
Item::Expression(ref expr) => {
223-
let pipeline = build_pipeline(context, &mut stdbuf, shell, expr)?;
211+
let pipeline = build_pipeline(&mut env, shell, expr)?;
224212

225213
for child in pipeline.children {
226214
children.push(child);
@@ -260,9 +248,37 @@ fn eval_pattern(context: &Context, pattern: &Pattern, shell: &Shell) -> Result<(
260248
}
261249
}
262250

263-
enum Producer {
264-
Constant(String),
265-
Child(Spawned<LineReader<ChildStdout>>),
251+
fn build_pipeline(env: &mut Env, shell: &Shell, expr: &Expression) -> Result<Pipeline> {
252+
let raw_expr = format!("{YELLOW}{}{RESET}", expr.raw_value);
253+
254+
match build_pipeline_internal(env, shell, expr) {
255+
Ok(pipeline) => Ok(pipeline.context(format!("expression: {raw_expr}"))),
256+
Err(err) => Err(err.context(format!("failed to initialize expression {raw_expr}"))),
257+
}
258+
}
259+
260+
fn build_pipeline_internal(env: &mut Env, shell: &Shell, expr: &Expression) -> Result<Pipeline> {
261+
let mut pipeline = Pipeline::new(expr.stdin_mode);
262+
263+
match &expr.value {
264+
ExpressionValue::RawShell(command) => {
265+
let mut command = shell.build_command(command);
266+
command.envs(env.external());
267+
pipeline = pipeline.add_command(command, expr.stdin_mode)?;
268+
}
269+
ExpressionValue::Pipeline(commands) => {
270+
for command in commands {
271+
let command = Command::detect(&command.name, &command.args, command.external);
272+
pipeline = pipeline.add_command(command.build(env)?, command.stdin_mode())?;
273+
}
274+
if pipeline.is_empty() {
275+
let command = Command::internal(&cat::META);
276+
pipeline = pipeline.add_command(command.build(env)?, command.stdin_mode())?;
277+
}
278+
}
279+
};
280+
281+
Ok(pipeline)
266282
}
267283

268284
fn forward_input(context: &Context, mut stdins: Vec<Option<Spawned<ChildStdin>>>) -> Result<()> {
@@ -291,6 +307,11 @@ fn forward_input(context: &Context, mut stdins: Vec<Option<Spawned<ChildStdin>>>
291307
Ok(())
292308
}
293309

310+
enum Producer {
311+
Constant(String),
312+
Child(Spawned<LineReader<ChildStdout>>),
313+
}
314+
294315
fn collect_output(context: &Context, mut producers: Vec<Producer>) -> Result<()> {
295316
let mut writer = context.writer();
296317
let mut buffer = context.uninit_buf();
@@ -342,111 +363,3 @@ fn wait_children(mut children: Vec<Spawned<Child>>) -> Result<()> {
342363

343364
Ok(())
344365
}
345-
346-
fn build_pipeline(
347-
context: &Context,
348-
stdbuf: &mut StdBuf,
349-
shell: &Shell,
350-
expr: &Expression,
351-
) -> Result<Pipeline> {
352-
let raw_expr = format!("{YELLOW}{}{RESET}", expr.raw_value);
353-
354-
match build_pipeline_internal(context, stdbuf, shell, expr) {
355-
Ok(pipeline) => Ok(pipeline.context(format!("expression: {raw_expr}"))),
356-
Err(err) => Err(err.context(format!("failed to initialize expression {raw_expr}"))),
357-
}
358-
}
359-
360-
fn build_pipeline_internal(
361-
context: &Context,
362-
stdbuf: &mut StdBuf,
363-
shell: &Shell,
364-
expr: &Expression,
365-
) -> Result<Pipeline> {
366-
let mut pipeline = Pipeline::new(expr.stdin_mode);
367-
368-
match &expr.value {
369-
ExpressionValue::RawShell(command) => {
370-
let command = shell.build_command(command);
371-
pipeline = pipeline.command(command, expr.stdin_mode)?;
372-
}
373-
ExpressionValue::Pipeline(commands) => {
374-
for command in commands {
375-
let (command, stdin_mode) = build_command(context, stdbuf, command)?;
376-
pipeline = pipeline.command(command, stdin_mode)?;
377-
}
378-
if pipeline.is_empty() {
379-
let command = build_default_command(context)?;
380-
pipeline = pipeline.command(command, StdinMode::Connected)?;
381-
}
382-
}
383-
};
384-
385-
Ok(pipeline)
386-
}
387-
388-
fn build_command(
389-
context: &Context,
390-
stdbuf: &mut StdBuf,
391-
params: &pattern::Command,
392-
) -> Result<(Command, StdinMode)> {
393-
let pattern::Command {
394-
name,
395-
args,
396-
external,
397-
} = params;
398-
399-
if !external {
400-
if let Some(meta) = get_meta(name) {
401-
let command = build_internal_command(context, Some(name), args)?;
402-
return Ok((command, meta.group.stdin_mode()));
403-
}
404-
405-
if name == crate_name!() {
406-
if let Some((name, args)) = args.split_first() {
407-
if let Some(meta) = get_meta(name) {
408-
let command = build_internal_command(context, Some(name), args)?;
409-
return Ok((command, meta.group.stdin_mode()));
410-
}
411-
}
412-
413-
let command = build_internal_command(context, None, args)?;
414-
return Ok((command, StdinMode::Connected));
415-
}
416-
}
417-
418-
let mut command = Command::new(name);
419-
command.args(args);
420-
421-
if context.buf_mode().is_line() {
422-
command.envs(stdbuf.line_buf_envs()); // libc based programs
423-
command.env("PYTHONUNBUFFERED", "1"); // Python programs
424-
}
425-
426-
Ok((command, StdinMode::Connected))
427-
}
428-
429-
fn build_internal_command(
430-
context: &Context,
431-
name: Option<&str>,
432-
args: &[String],
433-
) -> Result<Command> {
434-
let program = current_exe().context("could not detect current executable")?;
435-
let mut command = Command::new(program);
436-
437-
command.env(ENV_NULL, context.separator().is_null().to_string());
438-
command.env(ENV_BUF_MODE, context.buf_mode().to_string());
439-
command.env(ENV_BUF_SIZE, context.buf_size().to_string());
440-
command.env(ENV_SPAWNED_BY, get_spawned_by(META.name));
441-
442-
if let Some(name) = name {
443-
command.arg(name);
444-
}
445-
446-
command.args(args);
447-
Ok(command)
448-
}
449-
450-
fn build_default_command(context: &Context) -> Result<Command> {
451-
build_internal_command(context, Some(cat::META.name), &[])
452-
}

src/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use crate::args::get_bin_name;
2-
use crate::args::ENV_SPAWNED_BY;
31
use crate::colors::Colorizer;
42
use crate::colors::BOLD;
53
use crate::colors::BOLD_RED;
64
use crate::colors::RESET;
5+
use crate::env::get_bin_name;
6+
use crate::env::ENV_SPAWNED_BY;
77
use anstream::eprint;
88
use anstream::eprintln;
99
use anstream::stdout;

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ pub mod command;
99
#[doc(hidden)]
1010
pub mod commands;
1111
#[doc(hidden)]
12+
pub mod env;
13+
#[doc(hidden)]
1214
pub mod error;
1315
#[doc(hidden)]
1416
pub mod examples;

0 commit comments

Comments
 (0)