Skip to content

Commit a795311

Browse files
chore(turbo_json): lift $TURBO_DEFAULT$ handling to turbo.json resolution (#10709)
### Description This PR moves the handling of `$TURBO_DEFAULT$` to be the responsibility of `turbo.json` resolution. Previously it was handled by our SCM module which should only be focused on SCM operations, not magical strings from Turborepo. The changes to the daemon only affect the daemon input hashing logic which is currently disabled. Reviewing each commit independently is suggested. ### Testing Instructions Added unit tests and existing tests.
1 parent 61b6855 commit a795311

File tree

10 files changed

+194
-111
lines changed

10 files changed

+194
-111
lines changed

crates/turborepo-filewatch/src/hash_watcher.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use tokio::{
1717
use tracing::{debug, trace};
1818
use turbopath::{AbsoluteSystemPathBuf, AnchoredSystemPath, AnchoredSystemPathBuf};
1919
use turborepo_repository::discovery::DiscoveryResponse;
20-
use turborepo_scm::{package_deps::INPUT_INCLUDE_DEFAULT_FILES, Error as SCMError, GitHashes, SCM};
20+
use turborepo_scm::{Error as SCMError, GitHashes, SCM};
2121

2222
use crate::{
2323
debouncer::Debouncer,
@@ -41,15 +41,15 @@ pub enum InputGlobs {
4141
}
4242

4343
impl InputGlobs {
44-
pub fn from_raw(mut raw: Vec<String>) -> Result<Self, GlobError> {
44+
pub fn from_raw(raw: Vec<String>, include_default: bool) -> Result<Self, GlobError> {
4545
if raw.is_empty() {
46-
Ok(Self::Default)
47-
} else if let Some(default_pos) = raw.iter().position(|g| g == INPUT_INCLUDE_DEFAULT_FILES)
48-
{
49-
raw.remove(default_pos);
50-
Ok(Self::DefaultWithExtras(GlobSet::from_raw_unfiltered(raw)?))
46+
return Ok(Self::Default);
47+
}
48+
let glob_set = GlobSet::from_raw_unfiltered(raw)?;
49+
if include_default {
50+
Ok(Self::DefaultWithExtras(glob_set))
5151
} else {
52-
Ok(Self::Specific(GlobSet::from_raw_unfiltered(raw)?))
52+
Ok(Self::Specific(glob_set))
5353
}
5454
}
5555

@@ -64,12 +64,16 @@ impl InputGlobs {
6464
fn as_inputs(&self) -> Vec<String> {
6565
match self {
6666
InputGlobs::Default => Vec::new(),
67-
InputGlobs::DefaultWithExtras(glob_set) => {
68-
let mut inputs = glob_set.as_inputs();
69-
inputs.push(INPUT_INCLUDE_DEFAULT_FILES.to_string());
70-
inputs
67+
InputGlobs::DefaultWithExtras(glob_set) | InputGlobs::Specific(glob_set) => {
68+
glob_set.as_inputs()
7169
}
72-
InputGlobs::Specific(glob_set) => glob_set.as_inputs(),
70+
}
71+
}
72+
73+
pub fn include_default_files(&self) -> bool {
74+
match self {
75+
InputGlobs::Default | InputGlobs::DefaultWithExtras(..) => true,
76+
InputGlobs::Specific(..) => false,
7377
}
7478
}
7579
}
@@ -542,6 +546,7 @@ impl Subscriber {
542546
&repo_root,
543547
&spec.package_path,
544548
&inputs,
549+
spec.inputs.include_default_files(),
545550
telemetry,
546551
);
547552
trace!("hashing complete for {:?}", spec);

crates/turborepo-lib/src/daemon/client.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ use super::{
1313
proto::{DiscoverPackagesResponse, GetFileHashesResponse},
1414
Paths,
1515
};
16-
use crate::daemon::{proto, proto::PackageChangeEvent};
16+
use crate::{
17+
daemon::proto::{self, PackageChangeEvent},
18+
task_graph::TaskInputs,
19+
};
1720

1821
#[derive(Debug, Clone)]
1922
pub struct DaemonClient<T> {
@@ -160,13 +163,14 @@ impl<T> DaemonClient<T> {
160163
pub async fn get_file_hashes(
161164
&mut self,
162165
package_path: &AnchoredSystemPath,
163-
inputs: &[String],
166+
inputs: &TaskInputs,
164167
) -> Result<GetFileHashesResponse, DaemonError> {
165168
let response = self
166169
.client
167170
.get_file_hashes(proto::GetFileHashesRequest {
168171
package_path: package_path.to_string(),
169-
input_globs: inputs.to_vec(),
172+
input_globs: inputs.globs.to_vec(),
173+
include_default: Some(inputs.default),
170174
})
171175
.await?
172176
.into_inner();

crates/turborepo-lib/src/daemon/proto/turbod.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ message GetFileHashesRequest {
141141
// AnchoredSystemPathBuf
142142
string package_path = 1;
143143
repeated string input_globs = 2;
144+
optional bool include_default = 3;
144145
}
145146

146147
message GetFileHashesResponse {

crates/turborepo-lib/src/daemon/server.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,9 @@ impl TurboGrpcServiceInner {
386386
&self,
387387
package_path: String,
388388
inputs: Vec<String>,
389+
include_default: bool,
389390
) -> Result<HashMap<String, String>, RpcError> {
390-
let inputs = InputGlobs::from_raw(inputs)?;
391+
let inputs = InputGlobs::from_raw(inputs, include_default)?;
391392
let package_path = AnchoredSystemPathBuf::try_from(package_path.as_str())
392393
.map_err(|e| RpcError::InvalidAnchoredPath(package_path, e))?;
393394
let hash_spec = HashSpec {
@@ -549,7 +550,13 @@ impl proto::turbod_server::Turbod for TurboGrpcServiceInner {
549550
) -> Result<tonic::Response<proto::GetFileHashesResponse>, tonic::Status> {
550551
let inner = request.into_inner();
551552
let file_hashes = self
552-
.get_file_hashes(inner.package_path, inner.input_globs)
553+
.get_file_hashes(
554+
inner.package_path,
555+
inner.input_globs,
556+
// If an old client attempts to talk to a new server, assume that we should watch
557+
// default files
558+
inner.include_default.unwrap_or(true),
559+
)
553560
.await?;
554561
Ok(tonic::Response::new(proto::GetFileHashesResponse {
555562
file_hashes,

crates/turborepo-lib/src/run/cache.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -506,11 +506,11 @@ impl ConfigCache {
506506

507507
// empty inputs to get all files
508508
let inputs: Vec<String> = vec![];
509-
let hash_object = match scm.get_package_file_hashes(repo_root, anchored_root, &inputs, None)
510-
{
511-
Ok(hash_object) => hash_object,
512-
Err(_) => return Err(CacheError::ConfigCacheError),
513-
};
509+
let hash_object =
510+
match scm.get_package_file_hashes(repo_root, anchored_root, &inputs, false, None) {
511+
Ok(hash_object) => hash_object,
512+
Err(_) => return Err(CacheError::ConfigCacheError),
513+
};
514514

515515
// return the hash
516516
Ok(FileHashes(hash_object).hash())

crates/turborepo-lib/src/run/summary/task.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,13 +311,13 @@ impl From<TaskDefinition> for TaskSummaryTaskDefinition {
311311
depends_on.sort();
312312
outputs.sort();
313313
env.sort();
314-
inputs.sort();
314+
inputs.globs.sort();
315315

316316
Self {
317317
outputs,
318318
cache,
319319
depends_on,
320-
inputs,
320+
inputs: inputs.globs,
321321
output_logs,
322322
persistent,
323323
interruptible,

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

Lines changed: 55 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,40 +11,8 @@ pub use visitor::{Error as VisitorError, Visitor};
1111
use crate::{
1212
cli::{EnvMode, OutputLogsMode},
1313
run::task_id::{TaskId, TaskName},
14-
turbo_json::RawTaskDefinition,
1514
};
1615

17-
// TaskOutputs represents the patterns for including and excluding files from
18-
// outputs
19-
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
20-
pub struct TaskOutputs {
21-
pub inclusions: Vec<String>,
22-
pub exclusions: Vec<String>,
23-
}
24-
25-
impl TaskOutputs {
26-
// We consider an empty outputs to be a log output and nothing else
27-
pub fn is_empty(&self) -> bool {
28-
self.inclusions.len() == 1
29-
&& self.inclusions[0].ends_with(".log")
30-
&& self.exclusions.is_empty()
31-
}
32-
33-
pub fn validated_inclusions(&self) -> Result<Vec<ValidatedGlob>, GlobError> {
34-
self.inclusions
35-
.iter()
36-
.map(|i| ValidatedGlob::from_str(i))
37-
.collect()
38-
}
39-
40-
pub fn validated_exclusions(&self) -> Result<Vec<ValidatedGlob>, GlobError> {
41-
self.exclusions
42-
.iter()
43-
.map(|e| ValidatedGlob::from_str(e))
44-
.collect()
45-
}
46-
}
47-
4816
// Constructed from a RawTaskDefinition
4917
#[derive(Debug, PartialEq, Clone, Eq)]
5018
pub struct TaskDefinition {
@@ -70,10 +38,10 @@ pub struct TaskDefinition {
7038

7139
// Inputs indicate the list of files this Task depends on. If any of those files change
7240
// we can conclude that any cached outputs or logs for this Task should be invalidated.
73-
pub(crate) inputs: Vec<String>,
41+
pub inputs: TaskInputs,
7442

7543
// OutputMode determines how we should log the output.
76-
pub(crate) output_logs: OutputLogsMode,
44+
pub output_logs: OutputLogsMode,
7745

7846
// Persistent indicates whether the Task is expected to exit or not
7947
// Tasks marked Persistent do not exit (e.g. watch mode or dev servers)
@@ -98,6 +66,22 @@ pub struct TaskDefinition {
9866
pub with: Option<Vec<Spanned<TaskName<'static>>>>,
9967
}
10068

69+
// TaskOutputs represents the patterns for including and excluding files from
70+
// outputs
71+
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
72+
pub struct TaskOutputs {
73+
pub inclusions: Vec<String>,
74+
pub exclusions: Vec<String>,
75+
}
76+
77+
// Structure for holding the inputs for a task
78+
#[derive(Debug, PartialEq, Clone, Eq, Default)]
79+
pub struct TaskInputs {
80+
pub globs: Vec<String>,
81+
// Set when $TURBO_DEFAULT$ is in inputs
82+
pub default: bool,
83+
}
84+
10185
impl Default for TaskDefinition {
10286
fn default() -> Self {
10387
Self {
@@ -118,16 +102,6 @@ impl Default for TaskDefinition {
118102
}
119103
}
120104

121-
impl FromIterator<RawTaskDefinition> for RawTaskDefinition {
122-
fn from_iter<T: IntoIterator<Item = RawTaskDefinition>>(iter: T) -> Self {
123-
iter.into_iter()
124-
.fold(RawTaskDefinition::default(), |mut def, other| {
125-
def.merge(other);
126-
def
127-
})
128-
}
129-
}
130-
131105
const LOG_DIR: &str = ".turbo";
132106

133107
impl TaskDefinition {
@@ -190,6 +164,43 @@ impl TaskDefinition {
190164
}
191165
}
192166

167+
impl TaskInputs {
168+
pub fn new(globs: Vec<String>) -> Self {
169+
Self {
170+
globs,
171+
default: false,
172+
}
173+
}
174+
175+
pub fn with_default(mut self, default: bool) -> Self {
176+
self.default = default;
177+
self
178+
}
179+
}
180+
181+
impl TaskOutputs {
182+
// We consider an empty outputs to be a log output and nothing else
183+
pub fn is_empty(&self) -> bool {
184+
self.inclusions.len() == 1
185+
&& self.inclusions[0].ends_with(".log")
186+
&& self.exclusions.is_empty()
187+
}
188+
189+
pub fn validated_inclusions(&self) -> Result<Vec<ValidatedGlob>, GlobError> {
190+
self.inclusions
191+
.iter()
192+
.map(|i| ValidatedGlob::from_str(i))
193+
.collect()
194+
}
195+
196+
pub fn validated_exclusions(&self) -> Result<Vec<ValidatedGlob>, GlobError> {
197+
self.exclusions
198+
.iter()
199+
.map(|e| ValidatedGlob::from_str(e))
200+
.collect()
201+
}
202+
}
203+
193204
fn task_log_filename(task_name: &str) -> String {
194205
format!("turbo-{}.log", task_name.replace(':', "$colon$"))
195206
}

crates/turborepo-lib/src/task_hash.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,8 @@ impl PackageInputsHashes {
190190
let local_hash_result = scm.get_package_file_hashes(
191191
repo_root,
192192
package_path,
193-
&task_definition.inputs,
193+
&task_definition.inputs.globs,
194+
task_definition.inputs.default,
194195
Some(scm_telemetry),
195196
);
196197
match local_hash_result {
@@ -541,7 +542,7 @@ pub fn get_internal_deps_hash(
541542

542543
let file_hashes = package_dirs
543544
.into_par_iter()
544-
.map(|package_dir| scm.get_package_file_hashes::<&str>(root, package_dir, &[], None))
545+
.map(|package_dir| scm.get_package_file_hashes::<&str>(root, package_dir, &[], false, None))
545546
.reduce(
546547
|| Ok(HashMap::new()),
547548
|acc, hashes| {

0 commit comments

Comments
 (0)