Skip to content

Commit

Permalink
Change justfile type from PathBuf to an Option<PathBuf>
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcin Drzymala committed Sep 17, 2024
1 parent f6bb501 commit aa4785d
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 52 deletions.
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ pub(crate) enum Error<'src> {
},
NoChoosableRecipes,
NoDefaultRecipe,
JustfileIsNotAFile,
NoRecipes,
NotConfirmed {
recipe: &'src str,
Expand Down Expand Up @@ -403,6 +404,7 @@ impl<'src> ColorDisplay for Error<'src> {
_ => write!(f, "Recipe `{recipe}` could not be run because of an IO error while launching the shell: {io_error}"),
}?;
}
JustfileIsNotAFile => write!(f, "Justfile is not a file.")?,
Load { io_error, path } => {
write!(f, "Failed to read justfile at `{}`: {io_error}", path.display())?;
}
Expand Down
20 changes: 16 additions & 4 deletions src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,12 +397,14 @@ fn justfile(context: Context) -> FunctionResult {
.context
.search
.justfile
.as_ref()
.ok_or(String::from("Justfile is not a file"))?
.to_str()
.map(str::to_owned)
.ok_or_else(|| {
format!(
"Justfile path is not valid unicode: {}",
context.evaluator.context.search.justfile.display()
"Justfile path is not valid unicode: {:?}",
context.evaluator.context.search.justfile
)
})
}
Expand All @@ -413,11 +415,13 @@ fn justfile_directory(context: Context) -> FunctionResult {
.context
.search
.justfile
.as_ref()
.ok_or(String::from("Justfile is not a file"))?
.parent()
.ok_or_else(|| {
format!(
"Could not resolve justfile directory. Justfile `{}` had no parent.",
context.evaluator.context.search.justfile.display()
"Could not resolve justfile directory. Justfile `{:?}` had no parent.",
context.evaluator.context.search.justfile
)
})?;

Expand Down Expand Up @@ -450,6 +454,8 @@ fn module_directory(context: Context) -> FunctionResult {
.context
.search
.justfile
.as_ref()
.ok_or(String::from("Module is not a file"))?
.parent()
.unwrap()
.join(&context.evaluator.context.module.source)
Expand Down Expand Up @@ -478,6 +484,8 @@ fn module_file(context: Context) -> FunctionResult {
.context
.search
.justfile
.as_ref()
.ok_or(String::from("Module is not a file"))?
.parent()
.unwrap()
.join(&context.evaluator.context.module.source)
Expand Down Expand Up @@ -589,6 +597,8 @@ fn source_directory(context: Context) -> FunctionResult {
.context
.search
.justfile
.as_ref()
.ok_or(String::from("Source is not a file"))?
.parent()
.unwrap()
.join(context.name.token.path)
Expand All @@ -610,6 +620,8 @@ fn source_file(context: Context) -> FunctionResult {
.context
.search
.justfile
.as_ref()
.ok_or(String::from("Source is not a file"))?
.parent()
.unwrap()
.join(context.name.token.path)
Expand Down
55 changes: 23 additions & 32 deletions src/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const PROJECT_ROOT_CHILDREN: &[&str] = &[".bzr", ".git", ".hg", ".svn", "_darcs"

#[derive(Debug)]
pub(crate) struct Search {
pub(crate) justfile: PathBuf,
pub(crate) justfile: Option<PathBuf>,
pub(crate) working_directory: PathBuf,
}

Expand Down Expand Up @@ -51,15 +51,15 @@ impl Search {
})
}
SearchConfig::GlobalJustfile => Ok(Self {
justfile: Self::global_justfile_paths()
justfile: Some(Self::global_justfile_paths()
.iter()
.find(|path| path.exists())
.cloned()
.ok_or(SearchError::GlobalJustfileNotFound)?,
.ok_or(SearchError::GlobalJustfileNotFound)?),
working_directory: Self::project_root(invocation_directory)?,
}),
SearchConfig::WithJustfile { justfile } => {
let justfile = Self::clean(invocation_directory, justfile);
let justfile = Some(Self::clean(invocation_directory, justfile));
let working_directory = Self::working_directory_from_justfile(&justfile)?;
Ok(Self {
justfile,
Expand All @@ -70,20 +70,20 @@ impl Search {
justfile,
working_directory,
} => Ok(Self {
justfile: Self::clean(invocation_directory, justfile),
justfile: Some(Self::clean(invocation_directory, justfile)),
working_directory: Self::clean(invocation_directory, working_directory),
}),
}
}

/// Find justfile starting from parent directory of current justfile
pub(crate) fn search_parent_directory(&self) -> SearchResult<Self> {
let parent = self
.justfile
let justfile = self.justfile.as_ref().ok_or(SearchError::JustfileIsNotAFile)?;
let parent = justfile
.parent()
.and_then(|path| path.parent())
.ok_or_else(|| SearchError::JustfileHadNoParent {
path: self.justfile.clone(),
path: justfile.clone(),
})?;
Self::find_in_directory(parent)
}
Expand All @@ -102,47 +102,37 @@ impl Search {
pub(crate) fn init(
search_config: &SearchConfig,
invocation_directory: &Path,
) -> SearchResult<Self> {
) -> SearchResult<PathBuf> {
match search_config {
SearchConfig::FromInvocationDirectory => {
let working_directory = Self::project_root(invocation_directory)?;
let justfile = working_directory.join(DEFAULT_JUSTFILE_NAME);
Ok(Self {
justfile,
working_directory,
})
Ok(justfile)
}
SearchConfig::FromSearchDirectory { search_directory } => {
let search_directory = Self::clean(invocation_directory, search_directory);
let working_directory = Self::project_root(&search_directory)?;
let justfile = working_directory.join(DEFAULT_JUSTFILE_NAME);
Ok(Self {
justfile,
working_directory,
})
Ok(justfile)
}
SearchConfig::GlobalJustfile => Err(SearchError::GlobalJustfileInit),
SearchConfig::WithJustfile { justfile } => {
let justfile = Self::clean(invocation_directory, justfile);
let working_directory = Self::working_directory_from_justfile(&justfile)?;
Ok(Self {
justfile,
working_directory,
})
Ok(justfile)
}
SearchConfig::WithJustfileAndWorkingDirectory {
justfile,
working_directory,
} => Ok(Self {
justfile: Self::clean(invocation_directory, justfile),
working_directory: Self::clean(invocation_directory, working_directory),
}),
working_directory: _,
} => {
let justfile = Self::clean(invocation_directory, justfile);
Ok(justfile)
}
}
}

/// Search upwards from `directory` for a file whose name matches one of
/// `JUSTFILE_NAMES`
fn justfile(directory: &Path) -> SearchResult<PathBuf> {
fn justfile(directory: &Path) -> SearchResult<Option<PathBuf>> {
for directory in directory.ancestors() {
let mut candidates = BTreeSet::new();

Expand All @@ -166,7 +156,7 @@ impl Search {

match candidates.len() {
0 => {}
1 => return Ok(candidates.into_iter().next().unwrap()),
1 => return Ok(candidates.pop_first()),
_ => return Err(SearchError::MultipleCandidates { candidates }),
}
}
Expand Down Expand Up @@ -218,7 +208,8 @@ impl Search {
Ok(directory.to_owned())
}

fn working_directory_from_justfile(justfile: &Path) -> SearchResult<PathBuf> {
fn working_directory_from_justfile(justfile: &Option<impl AsRef<Path>>) -> SearchResult<PathBuf> {
let justfile = justfile.as_ref().ok_or(SearchError::JustfileIsNotAFile)?.as_ref();
Ok(
justfile
.parent()
Expand Down Expand Up @@ -333,7 +324,7 @@ mod tests {
Ok(found_path) => {
path.pop();
path.push(DEFAULT_JUSTFILE_NAME);
assert_eq!(found_path, path);
assert_eq!(found_path, Some(path));
}
Err(err) => panic!("No errors were expected: {err}"),
}
Expand All @@ -360,7 +351,7 @@ mod tests {

let search = Search::find(&search_config, &sub).unwrap();

assert_eq!(search.justfile, justfile);
assert_eq!(search.justfile.unwrap(), justfile);
assert_eq!(search.working_directory, sub);
}

Expand Down
2 changes: 2 additions & 0 deletions src/search_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ pub(crate) enum SearchError {
directory: PathBuf,
io_error: io::Error,
},
#[snafu(display("Justfile is not a file"))]
JustfileIsNotAFile,
#[snafu(display("Justfile path had no parent: {}", path.display()))]
JustfileHadNoParent { path: PathBuf },
#[snafu(display(
Expand Down
38 changes: 23 additions & 15 deletions src/subcommand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ impl Subcommand {
arguments: &[String],
overrides: &BTreeMap<String, String>,
) -> RunResult<'src> {
let starting_parent = search.justfile.parent().as_ref().unwrap().lexiclean();
let justfile = search.justfile.as_ref().ok_or(Error::JustfileIsNotAFile)?;
let starting_parent = justfile.parent().as_ref().unwrap().lexiclean();

loop {
let justfile = &compilation.justfile;
Expand All @@ -119,17 +120,18 @@ impl Subcommand {
if fallback {
if let Err(err @ (Error::UnknownRecipe { .. } | Error::UnknownSubmodule { .. })) = result {
search = search.search_parent_directory().map_err(|_| err)?;
let justfile = search.justfile.as_ref().ok_or(Error::JustfileIsNotAFile)?;

if config.verbosity.loquacious() {
eprintln!(
"Trying {}",
starting_parent
.strip_prefix(search.justfile.parent().unwrap())
.strip_prefix(justfile.parent().unwrap())
.unwrap()
.components()
.map(|_| path::Component::ParentDir)
.collect::<PathBuf>()
.join(search.justfile.file_name().unwrap())
.join(justfile.file_name().unwrap())
.display()
);
}
Expand All @@ -149,7 +151,9 @@ impl Subcommand {
loader: &'src Loader,
search: &Search,
) -> RunResult<'src, Compilation<'src>> {
let compilation = Compiler::compile(loader, &search.justfile)?;
let justfile = search.justfile.as_ref().ok_or(Error::JustfileIsNotAFile)?;

let compilation = Compiler::compile(loader, justfile)?;

compilation.justfile.check_unstable(config)?;

Expand Down Expand Up @@ -192,9 +196,10 @@ impl Subcommand {
let chooser = if let Some(chooser) = chooser {
OsString::from(chooser)
} else {
let justfile = search.justfile.as_ref().ok_or(Error::JustfileIsNotAFile)?;
let mut chooser = OsString::new();
chooser.push("fzf --multi --preview 'just --unstable --color always --justfile \"");
chooser.push(&search.justfile);
chooser.push(justfile);
chooser.push("\" --show {}'");
chooser
};
Expand Down Expand Up @@ -279,9 +284,10 @@ impl Subcommand {
.or_else(|| env::var_os("EDITOR"))
.unwrap_or_else(|| "vim".into());

let justfile = search.justfile.as_ref().ok_or(Error::JustfileIsNotAFile)?;
let error = Command::new(&editor)
.current_dir(&search.working_directory)
.arg(&search.justfile)
.arg(&justfile)
.status();

let status = match error {
Expand Down Expand Up @@ -333,36 +339,38 @@ impl Subcommand {
};
}

fs::write(&search.justfile, formatted).map_err(|io_error| Error::WriteJustfile {
justfile: search.justfile.clone(),
let justfile = search.justfile.as_ref().ok_or(Error::JustfileIsNotAFile)?;

fs::write(justfile, formatted).map_err(|io_error| Error::WriteJustfile {
justfile: justfile.clone(),
io_error,
})?;

if config.verbosity.loud() {
eprintln!("Wrote justfile to `{}`", search.justfile.display());
eprintln!("Wrote justfile to `{}`", justfile.display());
}

Ok(())
}

fn init(config: &Config) -> RunResult<'static> {
let search = Search::init(&config.search_config, &config.invocation_directory)?;
let justfile = Search::init(&config.search_config, &config.invocation_directory)?;

if search.justfile.is_file() {
if justfile.is_file() {
return Err(Error::InitExists {
justfile: search.justfile,
justfile: justfile.clone(),
});
}

if let Err(io_error) = fs::write(&search.justfile, INIT_JUSTFILE) {
if let Err(io_error) = fs::write(&justfile, INIT_JUSTFILE) {
return Err(Error::WriteJustfile {
justfile: search.justfile,
justfile: justfile.clone(),
io_error,
});
}

if config.verbosity.loud() {
eprintln!("Wrote justfile to `{}`", search.justfile.display());
eprintln!("Wrote justfile to `{}`", justfile.display());
}

Ok(())
Expand Down
2 changes: 1 addition & 1 deletion src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub(crate) fn search(config: &Config) -> Search {
let justfile = working_directory.join("justfile");

Search {
justfile,
justfile: Some(justfile),
working_directory,
}
}
Expand Down

0 comments on commit aa4785d

Please sign in to comment.