Added simple fatal error message verbosity levels controllable by environment variable at runtime (`RUST_VERBOSE =~ /1|v|verbose/i`), and compile-time (`NO_RT_ERROR_CTL`, `DEFAULT_ERROR =~ /1|v|verbose/i`.) Default is simple error messages at compile and runtime.

Fortune for collect's current commit: Curse − 凶
exec
Avril 2 years ago
parent f918d5f6e1
commit 715fa4d5a8
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -41,7 +41,7 @@ mode-buffered = ["jemalloc", "bytes"]
# * Statically sized (the program can infer the size of standard input.)
# * The standard input file/buffer pipe size is large enough to pre-allocate enough splicing space to use up the rest of your physical RAM.
# (This will very likely not happen unless you're specifically trying to make it happen, however.)
memfile = ["bitflags", "lazy_static"]
memfile = ["bitflags"]
# `memfile`: When unable to determine the size of the input, preallocate the buffer to a multiple of the system page-size before writing to it. This can save extra `ftruncate()` calls, but will also result in the buffer needing to be truncated to the correct size at the end if the sizes as not matched.
#
@ -95,5 +95,5 @@ recolored = { version = "1.9.3", optional = true }
memchr = "2.4.1"
lazy_format = "1.10.0"
bitflags = {version = "1.3.2", optional = true }
lazy_static = { version = "1.4.0", optional = true }
lazy_static = "1.4.0" #TODO: XXX: Required for dispersed error messages
#smallvec = { version = "1.9.0", features = ["write", "const_generics", "const_new", "may_dangle", "union"] }

@ -0,0 +1,203 @@
//! Errors and helpers for errors.
use super::*;
use std::{
fmt,
error,
};
pub const DEFAULT_USE_ENV: bool = std::option_env!("NO_RT_ERROR_CTL").is_none();
pub type DispersedResult<T, const USE_ENV: bool = DEFAULT_USE_ENV> = Result<T, Dispersed<USE_ENV>>;
pub const ENV_NAME: &'static str = "RUST_VERBOSE";
const DEFAULT_ENV_VERBOSE: DispersedVerbosity = match std::option_env!("DEFAULT_ERROR") {
Some("1") |
Some("V") |
Some("verbose") |
Some("VERBOSE") |
Some("v") => DispersedVerbosity::Verbose,
Some("0") |
_ => DispersedVerbosity::static_default(),
};
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
#[repr(u8)]
pub enum DispersedVerbosity
{
Simple = 0,
Verbose = 1,
}
impl From<DispersedVerbosity> for bool
{
#[inline]
fn from(from: DispersedVerbosity) -> Self
{
from.is_verbose()
}
}
impl Default for DispersedVerbosity
{
#[inline]
fn default() -> Self
{
DEFAULT_ENV_VERBOSE
}
}
impl DispersedVerbosity
{
#[inline(always)]
const fn static_default() -> Self
{
Self::Simple
}
#[inline(always)]
pub const fn is_verbose(self) -> bool
{
(self as u8) != 0
}
}
fn get_env_value() -> DispersedVerbosity
{
match std::env::var_os(ENV_NAME) {
Some(mut value) => {
value.make_ascii_lowercase();
match value {
"1" |
"v" |
"verbose" => DispersedVerbosity::Verbose,
"0" |
"s" |
"simple" => DispersedVerbosity::Simple,
_ => DispersedVerbosity::default(),
}
},
None => Default::default(),
}
}
#[inline]
pub fn dispersed_env_verbosity() -> DispersedVerbosity
{
lazy_static! {
static ref VALUE: DispersedVerbosity = get_env_value();
}
*VALUE
}
/// A simpler error message when returning an `eyre::Report` from main.
pub struct Dispersed<const USE_ENV: bool = DEFAULT_USE_ENV>(eyre::Report);
impl<const E: bool> From<eyre::Report> for Dispersed<E>
{
#[inline]
fn from(from: eyre::Report) -> Self
{
Self(from)
}
}
impl<const E: bool> Dispersed<E>
{
#[inline]
pub fn into_inner(self) -> eyre::Report
{
self.0
}
}
impl Dispersed<false>
{
#[inline(always)]
pub const fn obey_env(self) -> Dispersed<true>
{
Dispersed(self.0)
}
}
impl Dispersed<true>
{
#[inline(always)]
pub const fn ignore_env(self) -> Dispersed<false>
{
Dispersed(self.1)
}
}
impl<const E: bool> Dispersed<E>
{
#[inline(always)]
pub const fn set_env<const To: bool>(self) -> Dispersed<To>
{
Dispersed(self.0)
}
}
impl error::Error for Dispersed<true>
{
#[inline]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
self.0
}
}
impl error::Error for Dispersed<false>
{
#[inline]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
self.0
}
}
impl fmt::Debug for Dispersed<false>
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
fmt::Display::fmt(&self.0, f)
}
}
impl fmt::Display for Dispersed<false>
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
fmt::Debug::fmt(&self.0, f)
}
}
impl fmt::Debug for Dispersed<true>
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
if dispersed_env_verbosity().is_verbose() {
fmt::Debug::fmt(&self.0, f)
} else {
fmt::Display::fmt(&self.0, f)
}
}
}
impl fmt::Display for Dispersed<true>
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
if dispersed_env_verbosity().is_verbose() {
fmt::Display::fmt(&self.0, f)
} else {
fmt::Debug::fmt(&self.0, f)
}
}
}

@ -0,0 +1,95 @@
//! Used for implementation of `-exec[{}]`
use super::*;
use args::Options;
use std::{
fs,
process,
path::{
Path,
PathBuf,
},
ffi::{
OsStr,
OsString,
}
};
/// Get a path to the file-descriptor refered to by `file`.
fn proc_file<F: ?Sized + AsRawFd>(file: &F) -> PathBuf
{
let fd = file.as_raw_fd();
let pid = process::id();
format!("/proc/{pid}/fd/{fd}").into()
}
/// Attempt to `dup()` a file descriptor into a `RawFile`.
#[inline]
fn dup_file<F: ?Sized + AsRawFd>(file: &F) -> io::Result<memfile::RawFile>
{
let fd = file.as_raw_fd();
debug_assert!(fd >= 0, "Bad input file descriptor from {} (value was {fd})", std::any::type_name::<F>());
let fd = unsafe {
let res = libc::dup(fd);
if res < 0 {
return Err(io::Error::last_os_error());
} else {
res
}
};
Ok(memfile::RawFile::take_ownership_of_unchecked(fd))
}
fn run_stdin<I>(file: impl Into<fs::File>, filename: impl AsRef<OsStr>, args: I) -> io::Result<process::Child>
where I: IntoIterator<Item = OsString>,
{
let file = {
let mut file: fs::File = file.into();
//TODO: Do we need to fcntl() this to make it (the fd) RW?
file
};
let child = process::Command::new(filename)
.args(args)
.stdin(process::Stdio::from(file))
.stdout(process::Stdio::inherit())
.spawn()?;
if_trace!(info!("Spawned child process: {}", child.id()));
/*Ok(child.wait()?
.code()
.unwrap_or(-1)) //XXX: What should we do if the process terminates without a code (i.e. by a signal?)
*/
Ok(child)
}
/// Run a single `-exec` / `-exec{}` and return the (possibly still running) child process if succeeded in spawning.
///
/// The caller must wait for all child processes to exit before the parent does.
#[inline]
pub fn run_single<F: ?Sized + AsRawFd>(file: &F, opt: args::ExecMode) -> io::Result<process::Child>
{
let input = dup_file(file)?;
match opt {
args::ExecMode::Positional { command, args } => {
todo!("implement this with `proc_file(&file)`")
},
args::ExecMode::Stdin { command, args } => {
run_stdin(input, command, args)
}
}
}
/// Spawn all `-exec/{}` commands and return all running children.
///
/// # Returns
/// An iterator of each (possibly running) spawned child, or the error that occoured when trying to spawn that child from the `exec` option in `opt`.
pub fn spawn_from<F: ?Sized + AsRawFd>(file: &F, opt: Options) -> io::Result<impl IntoIterator<Item = io::Result<process::Child> + 'static>>
{
todo!("Loop through `opt.into_exec()`, map the call to `|x| run_single(file, x)`, and return that iterator")
}
#[inline]
pub fn spawn_from<F: ?Sized + AsRawFd>(file: &F, opt: Options) -> io::Result<impl IntoIterator<Item = io::Result<i32> + 'static>>
{
todo!("Map `spawn_from(...)` and wait for each child to terminate concurrently. Then return an iterator or the return codes or spawning errors for that now terminated child.")
}

@ -3,7 +3,7 @@
#[cfg(feature="logging")]
#[macro_use] extern crate tracing;
#[cfg(feature="memfile")]
//#[cfg(feature="memfile")]
#[macro_use] extern crate lazy_static;
/// Run this statement only if `tracing` is enabled
@ -79,12 +79,15 @@ macro_rules! function {
}
mod ext; use ext::*;
mod errors;
mod sys;
use sys::{
try_get_size,
tell_file,
};
mod exec;
mod buffers;
use buffers::prelude::*;
@ -117,7 +120,6 @@ trait ModeReturn: Send {
}
fn init() -> eyre::Result<()>
{
cfg_if!{ if #[cfg(feature="logging")] {
@ -486,7 +488,6 @@ mod work {
}
}
#[cfg_attr(feature="logging", instrument(err))]
#[inline(always)]
unsafe fn close_raw_fileno(fd: RawFd) -> io::Result<()>
@ -529,7 +530,7 @@ fn parse_args() -> eyre::Result<args::Options>
}
#[cfg_attr(feature="logging", instrument(err))]
fn main() -> eyre::Result<()> {
fn main() -> errors::DispersedResult<()> {
init()?;
feature_check()?;
if_trace!(debug!("initialised"));

@ -110,7 +110,7 @@ impl RawFile
}
#[inline(always)]
const fn take_ownership_of_unchecked(fd: RawFd) -> Self
pub(crate) const fn take_ownership_of_unchecked(fd: RawFd) -> Self
{
//! **Internal**: Non-`unsafe` and `const` version of `take_ownership_of_raw_unchecked()`
//! : assumes `fd` is `>= 0`

Loading…
Cancel
Save