Skip to content

Commit 010c292

Browse files
committed
refactor: remove ExecutionPlan wrapper struct
ExecutionPlan was a trivial single-field wrapper around ExecutionItemKind that added no value. Its methods either delegated trivially or were associated functions that didn't even return Self. - Promote plan_query() and plan_synthetic() to pub free functions - plan_synthetic() now returns SpawnExecution directly instead of wrapping/unwrapping through ExecutionPlan - Move Serialize impl to ExecutionGraph directly, removing the serialize_with indirection on ExecutionItemKind::Expanded - Remove unused methods: plan(), is_empty(), root_node(), into_root_node(), from_execution_graph()
1 parent 663351e commit 010c292

File tree

25 files changed

+1483
-1648
lines changed

25 files changed

+1483
-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
@@ -1,6 +1,7 @@
11
use std::ops::Deref;
22

33
use petgraph::graph::{DefaultIx, DiGraph, EdgeIndex, IndexType, NodeIndex};
4+
use serde::{Serialize, Serializer};
45

56
use crate::TaskExecution;
67

@@ -135,3 +136,9 @@ impl Deref for ExecutionGraph {
135136
&self.graph
136137
}
137138
}
139+
140+
impl Serialize for ExecutionGraph {
141+
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
142+
vite_graph_ser::serialize_by_key(&self.graph, serializer)
143+
}
144+
}

crates/vite_task_plan/src/lib.rs

Lines changed: 49 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,18 +142,11 @@ 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
pub enum ExecutionItemKind {
155148
/// Expanded from a known vp subcommand, like `vp run ...` or a synthesized task.
156-
Expanded(#[serde(serialize_with = "serialize_execution_graph_by_key")] ExecutionGraph),
149+
Expanded(ExecutionGraph),
157150
/// A normal execution that spawns a child process, like `tsc --noEmit`.
158151
Leaf(LeafExecutionKind),
159152
}
@@ -186,127 +179,53 @@ pub trait TaskGraphLoader {
186179
) -> Result<&vite_task_graph::IndexedTaskGraph, TaskGraphLoadError>;
187180
}
188181

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

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

0 commit comments

Comments
 (0)