commit c107e6ad7f7abbd3a3fa3dd26f82a66ce417fa61
parent 67653c1f63ee2c358ff79a420d2bdab07ea6027c
Author: Zack Newman <zack@philomathiclife.com>
Date: Tue, 26 Nov 2024 19:39:26 -0700
make ci work in child directories
Diffstat:
3 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -10,13 +10,10 @@ name = "ci"
readme = "README.md"
repository = "https://git.philomathiclife.com/repos/ci/"
rust-version = "1.81.0"
-version = "0.2.0"
-
-[badges]
-maintenance = { status = "actively-developed" }
+version = "0.2.1"
[dependencies]
-serde = { version = "1.0.214", default-features = false }
+serde = { version = "1.0.215", default-features = false }
toml = { version = "0.8.19", default-features = false, features = ["parse"] }
[profile.release]
diff --git a/README.md b/README.md
@@ -26,7 +26,8 @@ invoking `cargo` with each possible combination of features, this handles it aut
* `--color`: `--color always` is passed to the above commands; otherwise without this option, `--color never` is
passed.
* `--dir <path to directory Cargo.toml is in>`: `ci` changes the working directory to the passed path (after
- canonicalizing it) before executing. Without this, the current directory is used.
+ canonicalizing it) before executing. Without this, the working directory and all ancestor directories are searched
+ for `Cargo.toml` before changing the working directory to its location.
When `clippy`, `doc_tests`, and `tests` are not passed; then all three are invoked.
diff --git a/src/main.rs b/src/main.rs
@@ -87,7 +87,8 @@ use core::{
use std::{
collections::HashSet,
env, fs,
- io::{self, Write},
+ io::{self, ErrorKind, Write},
+ path::PathBuf,
};
use toml::de::Error as TomlErr;
/// Application error.
@@ -130,8 +131,35 @@ impl Error for E {}
reason = "asserts are fine when they indicate a bug"
)]
fn main() -> Result<(), E> {
+ /// Checks if `Cargo.toml` exists in `cur_dir`; if not, it recursively checks the ancestor
+ /// directories.
+ ///
+ /// We make this recursive in the rare (impossible?) case that traversal becomes circular; in which case,
+ /// we want a stack overflow to occur.
+ fn set_env(mut cur_dir: PathBuf) -> Result<bool, io::Error> {
+ if fs::exists("Cargo.toml")? {
+ Ok(true)
+ } else if cur_dir.pop() {
+ env::set_current_dir(cur_dir.as_path()).and_then(|()| set_env(cur_dir))
+ } else {
+ Ok(false)
+ }
+ }
Opts::from_args().and_then(|(mut opt, path)| {
- path.map_or(Ok(()), |p| env::set_current_dir(p).map_err(E::Io)).and_then(|()| {
+ path.map_or_else(
+ || {
+ env::current_dir().and_then(|dir| {
+ set_env(dir).and_then(|exists| {
+ if exists {
+ Ok(())
+ } else {
+ Err(io::Error::new(ErrorKind::NotFound, "Cargo.toml does not exist in the current directory nor any of the ancestor directories"))
+ }
+ })
+ })
+ },
+ env::set_current_dir
+ ).map_err(E::Io).and_then(|()| {
fs::read_to_string("Cargo.toml")
.map_err(E::Io)
.and_then(|toml| manifest::from_toml(toml.as_str()).map_err(E::Toml))