From 5b0c7ef5fc1788533a60afe944fd5150094d8cf1 Mon Sep 17 00:00:00 2001 From: Marcin Drzymala Date: Tue, 11 Jun 2024 01:55:21 +0200 Subject: [PATCH] WIP: Add JustfileKind to Search: Path or Stdin --- src/search.rs | 170 +++++++++++++++++++++++++++++++++++++++++++------ src/testing.rs | 5 +- 2 files changed, 152 insertions(+), 23 deletions(-) diff --git a/src/search.rs b/src/search.rs index c14eb55354..b6a3a8e51b 100644 --- a/src/search.rs +++ b/src/search.rs @@ -1,15 +1,60 @@ -use {super::*, std::path::Component}; +use { + super::*, + std::{ + io::{stdin, Read}, + path::{Component, Display}, + }, +}; const DEFAULT_JUSTFILE_NAME: &str = JUSTFILE_NAMES[0]; pub(crate) const JUSTFILE_NAMES: &[&str] = &["justfile", ".justfile"]; const PROJECT_ROOT_CHILDREN: &[&str] = &[".bzr", ".git", ".hg", ".svn", "_darcs"]; pub(crate) struct Search { - pub(crate) justfile: PathBuf, + pub(crate) justfile: JustfileKind, pub(crate) working_directory: PathBuf, } +#[derive(Debug, Clone)] +pub enum JustfileKind { + Path { path: PathBuf }, + Stdin { data: String }, +} + +impl JustfileKind { + pub fn to_str(&self) -> Option<&str> { + match self { + JustfileKind::Path { path } => path.to_str(), + JustfileKind::Stdin { .. } => None, + } + } + + pub fn display(&self) -> Display<'_> { + match self { + JustfileKind::Path { path } => path.display(), + JustfileKind::Stdin { .. } => Path::new("").display(), + } + } + + pub fn parent(&self) -> Option<&Path> { + match self { + JustfileKind::Path { path } => path.parent(), + JustfileKind::Stdin { .. } => None, + } + } +} + +impl PartialEq for JustfileKind { + fn eq(&self, other: &PathBuf) -> bool { + match self { + JustfileKind::Path { path } => path == other, + JustfileKind::Stdin { .. } => false, + } + } +} + impl Search { + /// Search for a Justfile pub(crate) fn find( search_config: &SearchConfig, invocation_directory: &Path, @@ -19,9 +64,10 @@ impl Search { SearchConfig::FromSearchDirectory { search_directory } => { let search_directory = Self::clean(invocation_directory, search_directory); - let justfile = Self::justfile(&search_directory)?; + let path = Self::justfile(&search_directory)?; + let justfile = JustfileKind::Path { path: path.clone() }; - let working_directory = Self::working_directory_from_justfile(&justfile)?; + let working_directory = Self::working_directory_from_justfile(&path)?; Ok(Self { justfile, @@ -29,9 +75,10 @@ impl Search { }) } SearchConfig::WithJustfile { justfile } => { - let justfile = Self::clean(invocation_directory, justfile); + let path = Self::clean(invocation_directory, justfile); + let justfile = JustfileKind::Path { path: path.clone() }; - let working_directory = Self::working_directory_from_justfile(&justfile)?; + let working_directory = Self::working_directory_from_justfile(&path)?; Ok(Self { justfile, @@ -41,17 +88,57 @@ impl Search { SearchConfig::WithJustfileAndWorkingDirectory { justfile, working_directory, - } => Ok(Self { - justfile: Self::clean(invocation_directory, justfile), - working_directory: Self::clean(invocation_directory, working_directory), - }), + } => { + let path = Self::clean(invocation_directory, justfile); + let justfile = JustfileKind::Path { path }; + + Ok(Self { + justfile, + working_directory: Self::clean(invocation_directory, working_directory), + }) + } + SearchConfig::WithStdin => { + let working_directory = PathBuf::from(invocation_directory); + + let mut data = String::new(); + if let Err(err) = stdin().read_to_string(&mut data) { + return Err(SearchError::Io { + directory: working_directory, + io_error: err, + }); + } + let justfile = JustfileKind::Stdin { data }; + + Ok(Self { + justfile, + working_directory, + }) + } + SearchConfig::WithStdinAndWorkingDirectory { working_directory } => { + let working_directory = working_directory.to_owned(); + + let mut data = String::new(); + if let Err(err) = stdin().read_to_string(&mut data) { + return Err(SearchError::Io { + directory: working_directory, + io_error: err, + }); + } + let justfile = JustfileKind::Stdin { data }; + + Ok(Self { + justfile, + working_directory, + }) + } } } pub(crate) fn find_next(starting_dir: &Path) -> SearchResult { - let justfile = Self::justfile(starting_dir)?; + let path = Self::justfile(starting_dir)?; + let justfile = JustfileKind::Path { path: path.clone() }; - let working_directory = Self::working_directory_from_justfile(&justfile)?; + let working_directory = Self::working_directory_from_justfile(&path)?; Ok(Self { justfile, @@ -59,6 +146,7 @@ impl Search { }) } + /// Search for a Justfile when running "init" subcommand pub(crate) fn init( search_config: &SearchConfig, invocation_directory: &Path, @@ -67,7 +155,8 @@ impl Search { SearchConfig::FromInvocationDirectory => { let working_directory = Self::project_root(invocation_directory)?; - let justfile = working_directory.join(DEFAULT_JUSTFILE_NAME); + let path = working_directory.join(DEFAULT_JUSTFILE_NAME); + let justfile = JustfileKind::Path { path }; Ok(Self { justfile, @@ -80,7 +169,8 @@ impl Search { let working_directory = Self::project_root(&search_directory)?; - let justfile = working_directory.join(DEFAULT_JUSTFILE_NAME); + let path = working_directory.join(DEFAULT_JUSTFILE_NAME); + let justfile = JustfileKind::Path { path }; Ok(Self { justfile, @@ -89,9 +179,10 @@ impl Search { } SearchConfig::WithJustfile { justfile } => { - let justfile = Self::clean(invocation_directory, justfile); + let path = Self::clean(invocation_directory, justfile); - let working_directory = Self::working_directory_from_justfile(&justfile)?; + let working_directory = Self::working_directory_from_justfile(&path)?; + let justfile = JustfileKind::Path { path }; Ok(Self { justfile, @@ -102,14 +193,51 @@ impl Search { SearchConfig::WithJustfileAndWorkingDirectory { justfile, working_directory, - } => Ok(Self { - justfile: Self::clean(invocation_directory, justfile), - working_directory: Self::clean(invocation_directory, working_directory), - }), + } => { + let path = Self::clean(invocation_directory, justfile); + let justfile = JustfileKind::Path { path }; + let working_directory = Self::clean(invocation_directory, working_directory); + Ok(Self { + justfile, + working_directory, + }) + } + + SearchConfig::WithStdin => { + let working_directory = Self::project_root(invocation_directory)?; + let mut data = String::new(); + if let Err(err) = io::stdin().read_to_string(&mut data) { + return Err(SearchError::Io { + directory: working_directory, + io_error: err, + }); + } + let justfile = JustfileKind::Stdin { data }; + Ok(Self { + justfile, + working_directory, + }) + } + + SearchConfig::WithStdinAndWorkingDirectory { working_directory } => { + let working_directory = working_directory.to_owned(); + let mut data = String::new(); + if let Err(err) = io::stdin().read_to_string(&mut data) { + return Err(SearchError::Io { + directory: working_directory, + io_error: err, + }); + } + let justfile = JustfileKind::Stdin { data }; + Ok(Self { + justfile, + working_directory, + }) + } } } - pub(crate) fn justfile(directory: &Path) -> SearchResult { + fn justfile(directory: &Path) -> SearchResult { for directory in directory.ancestors() { let mut candidates = BTreeSet::new(); diff --git a/src/testing.rs b/src/testing.rs index bf3cbbf5e5..b793295f04 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -1,4 +1,4 @@ -use {super::*, pretty_assertions::assert_eq}; +use {self::search::JustfileKind, super::*, pretty_assertions::assert_eq}; pub(crate) fn compile(src: &str) -> Justfile { Compiler::test_compile(src).expect("expected successful compilation") @@ -17,7 +17,8 @@ pub(crate) fn config(args: &[&str]) -> Config { pub(crate) fn search(config: &Config) -> Search { let working_directory = config.invocation_directory.clone(); - let justfile = working_directory.join("justfile"); + let path = working_directory.join("justfile"); + let justfile = JustfileKind::Path { path }; Search { justfile,