Skip to content

Commit 9ed775d

Browse files
cacheDir for env, config, and flag (#8947)
1 parent 0145168 commit 9ed775d

File tree

11 files changed

+106
-23
lines changed

11 files changed

+106
-23
lines changed

crates/turborepo-cache/src/async_cache.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ mod tests {
218218
use std::{assert_matches::assert_matches, time::Duration};
219219

220220
use anyhow::Result;
221+
use camino::Utf8PathBuf;
221222
use futures::future::try_join_all;
222223
use tempfile::tempdir;
223224
use turbopath::AbsoluteSystemPathBuf;
@@ -253,7 +254,7 @@ mod tests {
253254
let hash = format!("{}-no-fs", test_case.hash);
254255

255256
let opts = CacheOpts {
256-
override_dir: None,
257+
cache_dir: Utf8PathBuf::from(".turbo/cache"),
257258
remote_cache_read_only: false,
258259
skip_remote: false,
259260
skip_filesystem: true,
@@ -335,7 +336,7 @@ mod tests {
335336
let hash = format!("{}-no-remote", test_case.hash);
336337

337338
let opts = CacheOpts {
338-
override_dir: None,
339+
cache_dir: Utf8PathBuf::from(".turbo/cache"),
339340
remote_cache_read_only: false,
340341
skip_remote: true,
341342
skip_filesystem: false,
@@ -427,7 +428,7 @@ mod tests {
427428
let hash = format!("{}-both", test_case.hash);
428429

429430
let opts = CacheOpts {
430-
override_dir: None,
431+
cache_dir: Utf8PathBuf::from(".turbo/cache"),
431432
remote_cache_read_only: false,
432433
skip_remote: false,
433434
skip_filesystem: false,

crates/turborepo-cache/src/fs.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,18 @@ impl CacheMetadata {
3232
impl FSCache {
3333
fn resolve_cache_dir(
3434
repo_root: &AbsoluteSystemPath,
35-
override_dir: Option<&Utf8Path>,
35+
cache_dir: &Utf8Path,
3636
) -> AbsoluteSystemPathBuf {
37-
if let Some(override_dir) = override_dir {
38-
AbsoluteSystemPathBuf::from_unknown(repo_root, override_dir)
39-
} else {
40-
repo_root.join_components(&[".turbo", "cache"])
41-
}
37+
AbsoluteSystemPathBuf::from_unknown(repo_root, cache_dir)
4238
}
4339

4440
#[tracing::instrument(skip_all)]
4541
pub fn new(
46-
override_dir: Option<&Utf8Path>,
42+
cache_dir: &Utf8Path,
4743
repo_root: &AbsoluteSystemPath,
4844
analytics_recorder: Option<AnalyticsSender>,
4945
) -> Result<Self, CacheError> {
50-
let cache_directory = Self::resolve_cache_dir(repo_root, override_dir);
46+
let cache_directory = Self::resolve_cache_dir(repo_root, cache_dir);
5147
cache_directory.create_dir_all()?;
5248

5349
Ok(FSCache {
@@ -233,7 +229,11 @@ mod test {
233229
let (analytics_sender, analytics_handle) =
234230
start_analytics(api_auth.clone(), api_client.clone());
235231

236-
let cache = FSCache::new(None, repo_root_path, Some(analytics_sender.clone()))?;
232+
let cache = FSCache::new(
233+
Utf8Path::new(""),
234+
repo_root_path,
235+
Some(analytics_sender.clone()),
236+
)?;
237237

238238
let expected_miss = cache.fetch(repo_root_path, test_case.hash)?;
239239
assert!(expected_miss.is_none());

crates/turborepo-cache/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ pub struct CacheHitMetadata {
105105

106106
#[derive(Debug, Default)]
107107
pub struct CacheOpts {
108-
pub override_dir: Option<Utf8PathBuf>,
108+
pub cache_dir: Utf8PathBuf,
109109
pub remote_cache_read_only: bool,
110110
pub skip_remote: bool,
111111
pub skip_filesystem: bool,

crates/turborepo-cache/src/multiplexer.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,7 @@ impl CacheMultiplexer {
4848
}
4949

5050
let fs_cache = use_fs_cache
51-
.then(|| {
52-
FSCache::new(
53-
opts.override_dir.as_deref(),
54-
repo_root,
55-
analytics_recorder.clone(),
56-
)
57-
})
51+
.then(|| FSCache::new(&opts.cache_dir, repo_root, analytics_recorder.clone()))
5852
.transpose()?;
5953

6054
let http_cache = use_http_cache

crates/turborepo-lib/src/commands/config.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use camino::Utf8Path;
12
use serde::Serialize;
23
use turborepo_repository::{
34
package_graph::PackageGraph, package_json::PackageJson, package_manager::PackageManager,
@@ -24,6 +25,7 @@ struct ConfigOutput<'a> {
2425
env_mode: EnvMode,
2526
scm_base: &'a str,
2627
scm_head: &'a str,
28+
cache_dir: &'a Utf8Path,
2729
}
2830

2931
pub async fn run(base: CommandBase) -> Result<(), cli::Error> {
@@ -55,6 +57,7 @@ pub async fn run(base: CommandBase) -> Result<(), cli::Error> {
5557
env_mode: config.env_mode(),
5658
scm_base: config.scm_base(),
5759
scm_head: config.scm_head(),
60+
cache_dir: config.cache_dir(),
5861
})?
5962
);
6063
Ok(())

crates/turborepo-lib/src/commands/mod.rs

+15
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,21 @@ impl CommandBase {
103103
.and_then(|args| args.env_mode)
104104
}),
105105
)
106+
.with_cache_dir(
107+
self.args
108+
.command
109+
.as_ref()
110+
.and_then(|c| match c {
111+
Command::Run { execution_args, .. } => execution_args.cache_dir.clone(),
112+
_ => None,
113+
})
114+
.or_else(|| {
115+
self.args
116+
.execution_args
117+
.as_ref()
118+
.and_then(|args| args.cache_dir.clone())
119+
}),
120+
)
106121
.build()
107122
}
108123

crates/turborepo-lib/src/config.rs

+51-1
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ use std::{
44
io,
55
};
66

7+
use camino::{Utf8Path, Utf8PathBuf};
78
use convert_case::{Case, Casing};
89
use miette::{Diagnostic, NamedSource, SourceSpan};
910
use serde::Deserialize;
1011
use struct_iterable::Iterable;
1112
use thiserror::Error;
12-
use turbopath::{AbsoluteSystemPathBuf, AnchoredSystemPath};
13+
use turbopath::{AbsoluteSystemPathBuf, AnchoredSystemPath, RelativeUnixPath};
1314
use turborepo_auth::{TURBO_TOKEN_DIR, TURBO_TOKEN_FILE, VERCEL_TOKEN_DIR, VERCEL_TOKEN_FILE};
1415
use turborepo_dirs::{config_dir, vercel_config_dir};
1516
use turborepo_errors::TURBO_SITE;
@@ -161,6 +162,14 @@ pub enum Error {
161162
#[error(transparent)]
162163
#[diagnostic(transparent)]
163164
TurboJsonParseError(#[from] turbo_json::parser::Error),
165+
#[error("found absolute path in `cacheDir`")]
166+
#[diagnostic(help("if absolute paths are required, use `--cache-dir` or `TURBO_CACHE_DIR`"))]
167+
AbsoluteCacheDir {
168+
#[label("make `cacheDir` value a relative unix path")]
169+
span: Option<SourceSpan>,
170+
#[source_code]
171+
text: NamedSource,
172+
},
164173
}
165174

166175
macro_rules! create_builder {
@@ -215,6 +224,8 @@ pub struct ConfigurationOptions {
215224
pub(crate) env_mode: Option<EnvMode>,
216225
pub(crate) scm_base: Option<String>,
217226
pub(crate) scm_head: Option<String>,
227+
#[serde(rename = "cacheDir")]
228+
pub(crate) cache_dir: Option<Utf8PathBuf>,
218229
}
219230

220231
#[derive(Default)]
@@ -306,6 +317,16 @@ impl ConfigurationOptions {
306317
pub fn env_mode(&self) -> EnvMode {
307318
self.env_mode.unwrap_or_default()
308319
}
320+
321+
pub fn cache_dir(&self) -> &Utf8Path {
322+
self.cache_dir.as_deref().unwrap_or_else(|| {
323+
Utf8Path::new(if cfg!(windows) {
324+
".turbo\\cache"
325+
} else {
326+
".turbo/cache"
327+
})
328+
})
329+
}
309330
}
310331

311332
// Maps Some("") to None to emulate how Go handles empty strings
@@ -332,6 +353,21 @@ impl ResolvedConfigurationOptions for RawTurboJson {
332353
} else {
333354
ConfigurationOptions::default()
334355
};
356+
357+
let cache_dir = if let Some(cache_dir) = self.cache_dir {
358+
let cache_dir_str: &str = &cache_dir;
359+
let cache_dir_unix = RelativeUnixPath::new(cache_dir_str).map_err(|_| {
360+
let (span, text) = cache_dir.span_and_text("turbo.json");
361+
Error::AbsoluteCacheDir { span, text }
362+
})?;
363+
// Convert the relative unix path to an anchored system path
364+
// For unix/macos this is a no-op
365+
let cache_dir_system = cache_dir_unix.to_anchored_system_path_buf();
366+
Some(Utf8PathBuf::from(cache_dir_system.to_string()))
367+
} else {
368+
None
369+
};
370+
335371
// Don't allow token to be set for shared config.
336372
opts.token = None;
337373
opts.spaces_id = self
@@ -342,6 +378,7 @@ impl ResolvedConfigurationOptions for RawTurboJson {
342378
opts.allow_no_package_manager = self.allow_no_package_manager;
343379
opts.daemon = self.daemon.map(|daemon| *daemon.as_inner());
344380
opts.env_mode = self.env_mode;
381+
opts.cache_dir = cache_dir;
345382
Ok(opts)
346383
}
347384
}
@@ -380,6 +417,7 @@ fn get_env_var_config(
380417
);
381418
turbo_mapping.insert(OsString::from("turbo_daemon"), "daemon");
382419
turbo_mapping.insert(OsString::from("turbo_env_mode"), "env_mode");
420+
turbo_mapping.insert(OsString::from("turbo_cache_dir"), "cache_dir");
383421
turbo_mapping.insert(OsString::from("turbo_preflight"), "preflight");
384422
turbo_mapping.insert(OsString::from("turbo_scm_base"), "scm_base");
385423
turbo_mapping.insert(OsString::from("turbo_scm_head"), "scm_head");
@@ -490,6 +528,8 @@ fn get_env_var_config(
490528
_ => None,
491529
});
492530

531+
let cache_dir = output_map.get("cache_dir").map(|s| s.clone().into());
532+
493533
// We currently don't pick up a Spaces ID via env var, we likely won't
494534
// continue using the Spaces name, we can add an env var when we have the
495535
// name we want to stick with.
@@ -517,6 +557,7 @@ fn get_env_var_config(
517557
upload_timeout,
518558
spaces_id,
519559
env_mode,
560+
cache_dir,
520561
};
521562

522563
Ok(output)
@@ -580,6 +621,7 @@ fn get_override_env_var_config(
580621
spaces_id: None,
581622
allow_no_package_manager: None,
582623
env_mode: None,
624+
cache_dir: None,
583625
};
584626

585627
Ok(output)
@@ -722,6 +764,7 @@ impl TurborepoConfigBuilder {
722764
);
723765
create_builder!(with_daemon, daemon, Option<bool>);
724766
create_builder!(with_env_mode, env_mode, Option<EnvMode>);
767+
create_builder!(with_cache_dir, cache_dir, Option<Utf8PathBuf>);
725768

726769
pub fn build(&self) -> Result<ConfigurationOptions, Error> {
727770
// Priority, from least significant to most significant:
@@ -816,6 +859,9 @@ impl TurborepoConfigBuilder {
816859
if let Some(scm_head) = current_source_config.scm_head {
817860
acc.scm_head = Some(scm_head);
818861
}
862+
if let Some(cache_dir) = current_source_config.cache_dir {
863+
acc.cache_dir = Some(cache_dir);
864+
}
819865

820866
acc
821867
})
@@ -828,6 +874,7 @@ impl TurborepoConfigBuilder {
828874
mod test {
829875
use std::{collections::HashMap, ffi::OsString};
830876

877+
use camino::Utf8PathBuf;
831878
use tempfile::TempDir;
832879
use turbopath::AbsoluteSystemPathBuf;
833880

@@ -865,6 +912,7 @@ mod test {
865912
let turbo_team = "vercel";
866913
let turbo_teamid = "team_nLlpyC6REAqxydlFKbrMDlud";
867914
let turbo_token = "abcdef1234567890abcdef";
915+
let cache_dir = Utf8PathBuf::from("nebulo9");
868916
let turbo_remote_cache_timeout = 200;
869917

870918
env.insert("turbo_api".into(), turbo_api.into());
@@ -884,6 +932,7 @@ mod test {
884932
env.insert("turbo_daemon".into(), "true".into());
885933
env.insert("turbo_preflight".into(), "true".into());
886934
env.insert("turbo_env_mode".into(), "strict".into());
935+
env.insert("turbo_cache_dir".into(), cache_dir.clone().into());
887936

888937
let config = get_env_var_config(&env).unwrap();
889938
assert!(config.preflight());
@@ -897,6 +946,7 @@ mod test {
897946
assert_eq!(Some(true), config.allow_no_package_manager);
898947
assert_eq!(Some(true), config.daemon);
899948
assert_eq!(Some(EnvMode::Strict), config.env_mode);
949+
assert_eq!(cache_dir, config.cache_dir.unwrap());
900950
}
901951

902952
#[test]

crates/turborepo-lib/src/opts.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{backtrace, backtrace::Backtrace};
22

3+
use camino::Utf8PathBuf;
34
use thiserror::Error;
45
use turbopath::AnchoredSystemPathBuf;
56
use turborepo_api_client::APIAuth;
@@ -149,6 +150,7 @@ pub struct RunOpts {
149150
pub(crate) concurrency: u32,
150151
pub(crate) parallel: bool,
151152
pub(crate) env_mode: EnvMode,
153+
pub(crate) cache_dir: Utf8PathBuf,
152154
// Whether or not to infer the framework for each workspace.
153155
pub(crate) framework_inference: bool,
154156
pub profile: Option<String>,
@@ -263,6 +265,7 @@ impl<'a> TryFrom<OptsInputs<'a>> for RunOpts {
263265
graph,
264266
dry_run: inputs.run_args.dry_run,
265267
env_mode: inputs.config.env_mode(),
268+
cache_dir: inputs.config.cache_dir().into(),
266269
is_github_actions,
267270
})
268271
}
@@ -358,7 +361,7 @@ impl<'a> From<OptsInputs<'a>> for CacheOpts {
358361
));
359362

360363
CacheOpts {
361-
override_dir: inputs.execution_args.cache_dir.clone(),
364+
cache_dir: inputs.config.cache_dir().into(),
362365
skip_filesystem: inputs.execution_args.remote_only,
363366
remote_cache_read_only: inputs.run_args.remote_cache_read_only,
364367
workers: inputs.run_args.cache_workers,
@@ -488,6 +491,7 @@ mod test {
488491
concurrency: 10,
489492
parallel: opts_input.parallel,
490493
env_mode: crate::cli::EnvMode::Loose,
494+
cache_dir: camino::Utf8PathBuf::new(),
491495
framework_inference: true,
492496
profile: None,
493497
continue_on_error: opts_input.continue_on_error,

crates/turborepo-lib/src/turbo_json/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ pub struct RawTurboJson {
135135
pub daemon: Option<Spanned<bool>>,
136136
#[serde(skip_serializing_if = "Option::is_none")]
137137
pub env_mode: Option<EnvMode>,
138+
#[serde(skip_serializing_if = "Option::is_none")]
139+
pub cache_dir: Option<Spanned<UnescapedString>>,
138140

139141
#[deserializable(rename = "//")]
140142
#[serde(skip)]

crates/turborepo-lib/src/turbo_json/parser.rs

+2
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ impl WithMetadata for RawTurboJson {
105105
self.global_env.add_text(text.clone());
106106
self.global_pass_through_env.add_text(text.clone());
107107
self.tasks.add_text(text.clone());
108+
self.cache_dir.add_text(text.clone());
108109
self.pipeline.add_text(text);
109110
}
110111

@@ -115,6 +116,7 @@ impl WithMetadata for RawTurboJson {
115116
self.global_env.add_path(path.clone());
116117
self.global_pass_through_env.add_path(path.clone());
117118
self.tasks.add_path(path.clone());
119+
self.cache_dir.add_path(path.clone());
118120
self.pipeline.add_path(path);
119121
}
120122
}

0 commit comments

Comments
 (0)