From d3492e6ffe0f3c5be32939124a697b98425e36ba Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Mon, 20 May 2024 17:04:42 -0700 Subject: [PATCH] Use cache dir for temporary files (#2067) Sometimes `/tmp` is mounted with the `noexec` option, which results causes running shebang recipes to fail. Instead of `/tmp`, use the cache directory as provided by the [dirs crate](https://docs.rs/dirs/latest/src/dirs/lib.rs.html#77). --- src/error.rs | 10 ++++++++-- src/recipe.rs | 13 ++++++++++++- tests/tempdir.rs | 16 ++++++++++++---- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/error.rs b/src/error.rs index e18d7e9c5a..54caeb9dc4 100644 --- a/src/error.rs +++ b/src/error.rs @@ -20,6 +20,10 @@ pub(crate) enum Error<'src> { token: Token<'src>, output_error: OutputError, }, + CacheDirIo { + io_error: io::Error, + path: PathBuf, + }, ChooserInvoke { shell_binary: String, shell_arguments: String, @@ -279,6 +283,9 @@ impl<'src> ColorDisplay for Error<'src> { }?, OutputError::Utf8(utf8_error) => write!(f, "Backtick succeeded but stdout was not utf8: {utf8_error}")?, } + CacheDirIo { io_error, path } => { + write!(f, "I/O error in cache dir `{}`: {io_error}", path.display())?; + } ChooserInvoke { shell_binary, shell_arguments, chooser, io_error} => { let chooser = chooser.to_string_lossy(); write!(f, "Chooser `{shell_binary} {shell_arguments} {chooser}` invocation failed: {io_error}")?; @@ -382,8 +389,7 @@ impl<'src> ColorDisplay for Error<'src> { }?; } Load { io_error, path } => { - let path = path.display(); - write!(f, "Failed to read justfile at `{path}`: {io_error}")?; + write!(f, "Failed to read justfile at `{}`: {io_error}", path.display())?; } MissingImportFile { .. } => write!(f, "Could not find source file for import.")?, MissingModuleFile { module } => write!(f, "Could not find source file for module `{module}`.")?, diff --git a/src/recipe.rs b/src/recipe.rs index 48784d9438..d4ff98037c 100644 --- a/src/recipe.rs +++ b/src/recipe.rs @@ -336,7 +336,18 @@ impl<'src, D> Recipe<'src, D> { tempdir_builder.prefix("just-"); let tempdir = match &context.settings.tempdir { Some(tempdir) => tempdir_builder.tempdir_in(context.search.working_directory.join(tempdir)), - None => tempdir_builder.tempdir(), + None => { + if let Some(cache_dir) = dirs::cache_dir() { + let path = cache_dir.join("just"); + fs::create_dir_all(&path).map_err(|io_error| Error::CacheDirIo { + io_error, + path: path.clone(), + })?; + tempdir_builder.tempdir_in(path) + } else { + tempdir_builder.tempdir() + } + } } .map_err(|error| Error::TempdirIo { recipe: self.name(), diff --git a/tests/tempdir.rs b/tests/tempdir.rs index 2e48c9c533..a7d2a5fc57 100644 --- a/tests/tempdir.rs +++ b/tests/tempdir.rs @@ -1,10 +1,18 @@ use super::*; pub(crate) fn tempdir() -> TempDir { - tempfile::Builder::new() - .prefix("just-test-tempdir") - .tempdir() - .expect("failed to create temporary directory") + let mut builder = tempfile::Builder::new(); + + builder.prefix("just-test-tempdir"); + + if let Some(cache_dir) = dirs::cache_dir() { + let path = cache_dir.join("just"); + fs::create_dir_all(&path).unwrap(); + builder.tempdir_in(path) + } else { + builder.tempdir() + } + .expect("failed to create temporary directory") } #[test]