Skip to content

Commit 9b7bae6

Browse files
committed
merge: resolve conflicts with origin/main
2 parents e88b8ba + 3a631c8 commit 9b7bae6

File tree

25 files changed

+1484
-1648
lines changed

25 files changed

+1484
-1648
lines changed

crates/vite_task/src/session/mod.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use vite_task_graph::{
2020
loader::UserConfigLoader,
2121
};
2222
use vite_task_plan::{
23-
ExecutionGraph, ExecutionPlan, TaskGraphLoader,
23+
ExecutionGraph, TaskGraphLoader,
2424
plan_request::{PlanRequest, ScriptCommand, SyntheticPlanRequest},
2525
prepend_path_env,
2626
};
@@ -457,18 +457,12 @@ impl<'a> Session<'a> {
457457
) -> anyhow::Result<ExitStatus> {
458458
// Plan the synthetic execution — returns a SpawnExecution directly
459459
// (synthetic plans are always a single spawned process)
460-
let execution_plan = ExecutionPlan::plan_synthetic(
460+
let spawn_execution = vite_task_plan::plan_synthetic(
461461
&self.workspace_path,
462462
&self.cwd,
463463
synthetic_plan_request,
464464
cache_key,
465465
)?;
466-
let vite_task_plan::ExecutionItemKind::Leaf(vite_task_plan::LeafExecutionKind::Spawn(
467-
spawn_execution,
468-
)) = execution_plan.into_root_node()
469-
else {
470-
unreachable!("plan_synthetic always produces a Leaf(Spawn(..)) node")
471-
};
472466

473467
// Initialize cache (needed for cache-aware execution)
474468
let cache = self.cache()?;
@@ -531,7 +525,7 @@ impl<'a> Session<'a> {
531525
});
532526
}
533527
};
534-
ExecutionPlan::plan_query(
528+
vite_task_plan::plan_query(
535529
query_plan_request,
536530
&self.workspace_path,
537531
&cwd,

crates/vite_task_plan/src/execution_graph.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use petgraph::{
55
visit::{DfsEvent, depth_first_search},
66
};
77
use rustc_hash::FxHashMap;
8+
use serde::{Serialize, Serializer};
89

910
use crate::TaskExecution;
1011

@@ -146,6 +147,12 @@ impl<N, Ix: IndexType> Deref for AcyclicGraph<N, Ix> {
146147
/// The execution graph type alias, specialized for task execution.
147148
pub type ExecutionGraph = AcyclicGraph<TaskExecution, ExecutionIx>;
148149

150+
impl<N: vite_graph_ser::GetKey + Serialize, Ix: IndexType> Serialize for AcyclicGraph<N, Ix> {
151+
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
152+
vite_graph_ser::serialize_by_key(&self.graph, serializer)
153+
}
154+
}
155+
149156
/// Find a cycle in the directed graph, returning the cycle path if one exists.
150157
///
151158
/// Uses a DFS with predecessor tracking. When a back edge `u → v` is detected

crates/vite_task_plan/src/lib.rs

Lines changed: 50 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub use path_env::{get_path_env, prepend_path_env};
1818
use plan::{ParentCacheConfig, plan_query_request, plan_synthetic_request};
1919
use plan_request::{PlanRequest, QueryPlanRequest, SyntheticPlanRequest};
2020
use rustc_hash::FxHashMap;
21-
use serde::{Serialize, Serializer, ser::SerializeMap as _};
21+
use serde::{Serialize, ser::SerializeMap as _};
2222
use vite_path::AbsolutePath;
2323
use vite_str::Str;
2424
use vite_task_graph::{TaskGraphLoadError, display::TaskDisplay};
@@ -142,13 +142,6 @@ pub enum LeafExecutionKind {
142142
///
143143
/// `vite_graph_ser::serialize_by_key` expects `&DiGraph<N, E, Ix>`, so we call `.inner()`
144144
/// to get the underlying `DiGraph` reference.
145-
fn serialize_execution_graph_by_key<S: Serializer>(
146-
graph: &ExecutionGraph,
147-
serializer: S,
148-
) -> Result<S::Ok, S::Error> {
149-
vite_graph_ser::serialize_by_key(graph.inner(), serializer)
150-
}
151-
152145
/// An execution item, from a split subcommand in a task's command (`item1 && item2 && ...`).
153146
#[derive(Debug, Serialize)]
154147
#[expect(
@@ -157,7 +150,7 @@ fn serialize_execution_graph_by_key<S: Serializer>(
157150
)]
158151
pub enum ExecutionItemKind {
159152
/// Expanded from a known vp subcommand, like `vp run ...` or a synthesized task.
160-
Expanded(#[serde(serialize_with = "serialize_execution_graph_by_key")] ExecutionGraph),
153+
Expanded(ExecutionGraph),
161154
/// A normal execution that spawns a child process, like `tsc --noEmit`.
162155
Leaf(LeafExecutionKind),
163156
}
@@ -190,127 +183,54 @@ pub trait TaskGraphLoader {
190183
) -> Result<&vite_task_graph::IndexedTaskGraph, TaskGraphLoadError>;
191184
}
192185

193-
#[derive(Debug, Serialize)]
194-
pub struct ExecutionPlan {
195-
root_node: ExecutionItemKind,
186+
/// Plan a query execution: load the task graph, query it, and build the execution graph.
187+
///
188+
/// # Errors
189+
/// Returns an error if task graph loading, query, or execution planning fails.
190+
#[expect(clippy::future_not_send, reason = "PlanRequestParser and TaskGraphLoader are !Send")]
191+
#[expect(clippy::implicit_hasher, reason = "FxHashMap is the only hasher used in this codebase")]
192+
pub async fn plan_query(
193+
query_plan_request: QueryPlanRequest,
194+
workspace_path: &Arc<AbsolutePath>,
195+
cwd: &Arc<AbsolutePath>,
196+
envs: &FxHashMap<Arc<OsStr>, Arc<OsStr>>,
197+
plan_request_parser: &mut (dyn PlanRequestParser + '_),
198+
task_graph_loader: &mut (dyn TaskGraphLoader + '_),
199+
) -> Result<ExecutionGraph, Error> {
200+
let indexed_task_graph = task_graph_loader.load_task_graph().await?;
201+
202+
let context = PlanContext::new(
203+
workspace_path,
204+
Arc::clone(cwd),
205+
envs.clone(),
206+
plan_request_parser,
207+
indexed_task_graph,
208+
);
209+
plan_query_request(query_plan_request, context).await
196210
}
197211

198-
impl ExecutionPlan {
199-
#[must_use]
200-
pub const fn root_node(&self) -> &ExecutionItemKind {
201-
&self.root_node
202-
}
203-
204-
#[must_use]
205-
pub fn into_root_node(self) -> ExecutionItemKind {
206-
self.root_node
207-
}
208-
209-
/// Returns `true` if the plan contains no tasks to execute.
210-
#[must_use]
211-
pub fn is_empty(&self) -> bool {
212-
match &self.root_node {
213-
ExecutionItemKind::Expanded(graph) => graph.node_count() == 0,
214-
ExecutionItemKind::Leaf(_) => false,
215-
}
216-
}
217-
218-
/// Create an execution plan from an execution graph.
219-
#[must_use]
220-
pub const fn from_execution_graph(execution_graph: ExecutionGraph) -> Self {
221-
Self { root_node: ExecutionItemKind::Expanded(execution_graph) }
222-
}
223-
224-
/// Plan a query execution: load the task graph, query it, and build the execution graph.
225-
///
226-
/// # Errors
227-
/// Returns an error if task graph loading, query, or execution planning fails.
228-
#[expect(clippy::future_not_send, reason = "PlanRequestParser and TaskGraphLoader are !Send")]
229-
pub async fn plan_query(
230-
query_plan_request: QueryPlanRequest,
231-
workspace_path: &Arc<AbsolutePath>,
232-
cwd: &Arc<AbsolutePath>,
233-
envs: &FxHashMap<Arc<OsStr>, Arc<OsStr>>,
234-
plan_request_parser: &mut (dyn PlanRequestParser + '_),
235-
task_graph_loader: &mut (dyn TaskGraphLoader + '_),
236-
) -> Result<ExecutionGraph, Error> {
237-
let indexed_task_graph = task_graph_loader.load_task_graph().await?;
238-
239-
let context = PlanContext::new(
240-
workspace_path,
241-
Arc::clone(cwd),
242-
envs.clone(),
243-
plan_request_parser,
244-
indexed_task_graph,
245-
);
246-
plan_query_request(query_plan_request, context).await
247-
}
248-
249-
/// Plan an execution from a plan request.
250-
///
251-
/// # Errors
252-
/// Returns an error if task graph loading, query, or execution planning fails.
253-
#[expect(clippy::future_not_send, reason = "PlanRequestParser and TaskGraphLoader are !Send")]
254-
pub async fn plan(
255-
plan_request: PlanRequest,
256-
workspace_path: &Arc<AbsolutePath>,
257-
cwd: &Arc<AbsolutePath>,
258-
envs: &FxHashMap<Arc<OsStr>, Arc<OsStr>>,
259-
plan_request_parser: &mut (dyn PlanRequestParser + '_),
260-
task_graph_loader: &mut (dyn TaskGraphLoader + '_),
261-
) -> Result<Self, Error> {
262-
let root_node = match plan_request {
263-
PlanRequest::Query(query_plan_request) => {
264-
let execution_graph = Self::plan_query(
265-
query_plan_request,
266-
workspace_path,
267-
cwd,
268-
envs,
269-
plan_request_parser,
270-
task_graph_loader,
271-
)
272-
.await?;
273-
ExecutionItemKind::Expanded(execution_graph)
274-
}
275-
PlanRequest::Synthetic(synthetic_plan_request) => {
276-
let execution = plan_synthetic_request(
277-
workspace_path,
278-
&BTreeMap::default(),
279-
synthetic_plan_request,
280-
None,
281-
cwd,
282-
ParentCacheConfig::None,
283-
)?;
284-
ExecutionItemKind::Leaf(LeafExecutionKind::Spawn(execution))
285-
}
286-
};
287-
Ok(Self { root_node })
288-
}
289-
290-
/// Plan a synthetic task execution, returning the resolved [`SpawnExecution`] directly.
291-
///
292-
/// Unlike `plan_query` which returns a full execution graph, synthetic executions
293-
/// are always a single spawned process. The caller can execute it directly using
294-
/// `execute_spawn`.
295-
///
296-
/// # Errors
297-
/// Returns an error if the program is not found or path fingerprinting fails.
298-
#[expect(clippy::result_large_err, reason = "Error is large for diagnostics")]
299-
pub fn plan_synthetic(
300-
workspace_path: &Arc<AbsolutePath>,
301-
cwd: &Arc<AbsolutePath>,
302-
synthetic_plan_request: SyntheticPlanRequest,
303-
cache_key: Arc<[Str]>,
304-
) -> Result<Self, Error> {
305-
let execution_cache_key = cache_metadata::ExecutionCacheKey::ExecAPI(cache_key);
306-
let execution = plan_synthetic_request(
307-
workspace_path,
308-
&BTreeMap::default(),
309-
synthetic_plan_request,
310-
Some(execution_cache_key),
311-
cwd,
312-
ParentCacheConfig::None,
313-
)?;
314-
Ok(Self { root_node: ExecutionItemKind::Leaf(LeafExecutionKind::Spawn(execution)) })
315-
}
212+
/// Plan a synthetic task execution, returning the resolved [`SpawnExecution`] directly.
213+
///
214+
/// Unlike [`plan_query`] which returns a full execution graph, synthetic executions
215+
/// are always a single spawned process. The caller can execute it directly using
216+
/// `execute_spawn`.
217+
///
218+
/// # Errors
219+
/// Returns an error if the program is not found or path fingerprinting fails.
220+
#[expect(clippy::result_large_err, reason = "Error is large for diagnostics")]
221+
pub fn plan_synthetic(
222+
workspace_path: &Arc<AbsolutePath>,
223+
cwd: &Arc<AbsolutePath>,
224+
synthetic_plan_request: SyntheticPlanRequest,
225+
cache_key: Arc<[Str]>,
226+
) -> Result<SpawnExecution, Error> {
227+
let execution_cache_key = cache_metadata::ExecutionCacheKey::ExecAPI(cache_key);
228+
plan_synthetic_request(
229+
workspace_path,
230+
&BTreeMap::default(),
231+
synthetic_plan_request,
232+
Some(execution_cache_key),
233+
cwd,
234+
ParentCacheConfig::None,
235+
)
316236
}

0 commit comments

Comments
 (0)