commit c1b52e436d4256bffd29a1059323c9ac079eede3
parent df7e4b016c9aad07aa08e7abe9573b6d9fc26631
Author: Zack Newman <zack@philomathiclife.com>
Date: Thu, 8 Aug 2024 15:17:50 -0600
improve run_cmd
Diffstat:
3 files changed, 25 insertions(+), 42 deletions(-)
diff --git a/README.md b/README.md
@@ -7,8 +7,8 @@
feature `bar` and `bar` automatically enables feature `fizz`, then no combination of features that contains
`foo` and `bar`, `foo` and `fizz`, or `bar` and `fizz` will be tested.
-`ci` writes to `stdout` iff an error arises. The error is written as well as the command and features
-that caused the error.
+`ci` writes to `stderr` iff an error arises. The error is written as well as the command and features
+that caused the error. `stdout` is never written to.
## Why is this useful?
diff --git a/src/args.rs b/src/args.rs
@@ -38,20 +38,14 @@ pub enum Opts {
Tests,
}
impl Opts {
- /// Returns the string representation of `self`.
- const fn as_str(self) -> &'static str {
- match self {
- Self::None => "",
- Self::Clippy => "clippy",
- Self::DocTests => "doc_tests",
- Self::Tests => "tests",
- }
- }
/// Runs `cargo` with argument based on `self` and features of `features`.
- #[allow(clippy::unreachable)]
pub fn run_cmd(self, features: &str) -> Result<(), E> {
match self {
- Self::None => unreachable!("Opts::run_cmd must not be called on Opts::None"),
+ Self::None => Self::Clippy.run_cmd(features).and_then(|()| {
+ Self::DocTests
+ .run_cmd(features)
+ .and_then(|()| Self::Tests.run_cmd(features))
+ }),
Self::Clippy => {
let mut args = vec!["clippy", "-q", "--no-default-features"];
if !features.is_empty() {
@@ -141,23 +135,19 @@ impl Opts {
/// Returns `Opts` based on arguments passed to the application.
pub fn from_args() -> Result<Self, ArgsErr> {
let mut args = env::args();
- if args.next().is_some() {
- let mut opts = Self::None;
- for arg in args {
- if matches!(opts, Self::None) {
- match arg.as_str() {
- "clippy" => opts = Self::Clippy,
- "doc_tests" => opts = Self::DocTests,
- "tests" => opts = Self::Tests,
- _ => return Err(ArgsErr::InvalidOption(arg)),
- }
- } else {
- return Err(ArgsErr::InvalidOption(format!("{} {arg}", opts.as_str())));
+ args.next().ok_or(ArgsErr::NoArgs).and_then(|_| {
+ args.next().map_or(Ok(Self::None), |arg| {
+ match arg.as_str() {
+ "clippy" => Ok(Self::Clippy),
+ "doc_tests" => Ok(Self::DocTests),
+ "tests" => Ok(Self::Tests),
+ _ => Err(ArgsErr::InvalidOption(arg)),
}
- }
- Ok(opts)
- } else {
- Err(ArgsErr::NoArgs)
- }
+ .and_then(|opts| {
+ args.next()
+ .map_or(Ok(opts), |opt| Err(ArgsErr::InvalidOption(opt)))
+ })
+ })
+ })
}
}
diff --git a/src/main.rs b/src/main.rs
@@ -7,8 +7,8 @@
//! feature `bar` and `bar` automatically enables feature `fizz`, then no combination of features that contains
//! `foo` and `bar`, `foo` and `fizz`, or `bar` and `fizz` will be tested.
//!
-//! `ci` writes to `stdout` iff an error arises. The error is written as well as the command and features
-//! that caused the error.
+//! `ci` writes to `stderr` iff an error arises. The error is written as well as the command and features
+//! that caused the error. `stdout` is never written to.
//!
//! ## Why is this useful?
//!
@@ -110,17 +110,10 @@ fn main() -> Result<(), E> {
fs::read_to_string("Cargo.toml")
.map_err(E::Io)
.and_then(|toml| manifest::from_toml(toml.as_str()).map_err(E::Toml))
- .and_then(|features| match opt {
- Opts::None => features.into_iter().try_fold((), |(), feature| {
- Opts::Clippy.run_cmd(feature.as_str()).and_then(|()| {
- Opts::DocTests
- .run_cmd(feature.as_str())
- .and_then(|()| Opts::Tests.run_cmd(feature.as_str()))
- })
- }),
- Opts::Clippy | Opts::DocTests | Opts::Tests => features
+ .and_then(|features| {
+ features
.into_iter()
- .try_fold((), |(), feature| opt.run_cmd(feature.as_str())),
+ .try_fold((), |(), feature| opt.run_cmd(feature.as_str()))
})
})
}