-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathcontext.rs
More file actions
178 lines (150 loc) · 5.37 KB
/
context.rs
File metadata and controls
178 lines (150 loc) · 5.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
use std::{
collections::HashMap, env::JoinPathsError, ffi::OsStr, fmt::Display, ops::Range, sync::Arc,
};
use vite_path::AbsolutePath;
use vite_str::Str;
use vite_task_graph::{IndexedTaskGraph, TaskNodeIndex, display::TaskDisplay};
use crate::{PlanRequestParser, path_env::prepend_path_env};
#[derive(Debug, thiserror::Error)]
#[error(
"Detected a recursion in task call stack: the last frame calls the {0}th frame", recursion_point + 1
)]
pub struct TaskRecursionError {
/// The index in `task_call_stack` where the last frame recurses to.
recursion_point: usize,
}
/// The context for planning an execution from a task.
#[derive(Debug)]
pub struct PlanContext<'a> {
/// The root path of the workspace.
workspace_path: &'a Arc<AbsolutePath>,
/// The current working directory.
cwd: Arc<AbsolutePath>,
/// The environment variables for the current execution context.
envs: HashMap<Arc<OsStr>, Arc<OsStr>>,
/// The callbacks for loading task graphs and parsing commands.
callbacks: &'a mut (dyn PlanRequestParser + 'a),
/// The current call stack of task index nodes being planned.
task_call_stack: Vec<(TaskNodeIndex, Range<usize>)>,
/// The extra args (`vite run task [extra_arg...]`).
/// It may come from real cli args, or commands in task scripts.
extra_args: Arc<[Str]>,
indexed_task_graph: &'a IndexedTaskGraph,
}
/// A human-readable frame in the task call stack.
#[derive(Debug, Clone)]
pub struct TaskCallStackFrameDisplay {
pub task_display: TaskDisplay,
#[expect(dead_code)] // To be used in terminal error display
pub command_span: Range<usize>,
}
impl Display for TaskCallStackFrameDisplay {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// TODO: display command_span
write!(f, "{}", self.task_display)
}
}
/// A human-readable display of the task call stack.
#[derive(Default, Debug, Clone)]
pub struct TaskCallStackDisplay {
frames: Arc<[TaskCallStackFrameDisplay]>,
}
impl Display for TaskCallStackDisplay {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (i, frame) in self.frames.iter().enumerate() {
if i > 0 {
write!(f, " -> ")?;
}
write!(f, "{}", frame)?;
}
Ok(())
}
}
impl<'a> PlanContext<'a> {
pub fn new(
workspace_path: &'a Arc<AbsolutePath>,
cwd: Arc<AbsolutePath>,
envs: HashMap<Arc<OsStr>, Arc<OsStr>>,
callbacks: &'a mut (dyn PlanRequestParser + 'a),
indexed_task_graph: &'a IndexedTaskGraph,
) -> Self {
Self {
workspace_path,
cwd,
envs,
callbacks,
task_call_stack: Vec::new(),
indexed_task_graph,
extra_args: Default::default(),
}
}
pub fn envs(&self) -> &HashMap<Arc<OsStr>, Arc<OsStr>> {
&self.envs
}
/// Get a human-readable display of the current task call stack.
pub fn display_call_stack(&self) -> TaskCallStackDisplay {
TaskCallStackDisplay {
frames: self
.task_call_stack
.iter()
.map(|(idx, span)| TaskCallStackFrameDisplay {
task_display: self.indexed_task_graph.display_task(*idx),
command_span: span.clone(),
})
.collect(),
}
}
/// Check if adding the given task node index would create a recursion in the call stack.
pub fn check_recursion(
&self,
task_node_index: TaskNodeIndex,
) -> Result<(), TaskRecursionError> {
if let Some(recursion_start) =
self.task_call_stack.iter().position(|(idx, _)| *idx == task_node_index)
{
return Err(TaskRecursionError { recursion_point: recursion_start });
}
Ok(())
}
pub fn indexed_task_graph(&self) -> &'a IndexedTaskGraph {
self.indexed_task_graph
}
pub fn workspace_path(&self) -> &Arc<AbsolutePath> {
self.workspace_path
}
/// Push a new frame onto the task call stack.
pub fn push_stack_frame(&mut self, task_node_index: TaskNodeIndex, command_span: Range<usize>) {
self.task_call_stack.push((task_node_index, command_span));
}
pub fn callbacks(&mut self) -> &mut (dyn PlanRequestParser + '_) {
self.callbacks
}
pub fn prepend_path(&mut self, path_to_prepend: &AbsolutePath) -> Result<(), JoinPathsError> {
prepend_path_env(&mut self.envs, path_to_prepend)
}
pub fn add_envs(
&mut self,
new_envs: impl Iterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>,
) {
for (key, value) in new_envs {
self.envs.insert(Arc::from(key.as_ref()), Arc::from(value.as_ref()));
}
}
pub fn extra_args(&self) -> &Arc<[Str]> {
&self.extra_args
}
pub fn set_extra_args(&mut self, extra_args: Arc<[Str]>) {
self.extra_args = extra_args;
}
pub fn duplicate(&mut self) -> PlanContext<'_> {
PlanContext {
workspace_path: self.workspace_path,
cwd: Arc::clone(&self.cwd),
envs: self.envs.clone(),
callbacks: self.callbacks,
task_call_stack: self.task_call_stack.clone(),
indexed_task_graph: self.indexed_task_graph,
extra_args: Arc::clone(&self.extra_args),
}
}
}