microsoft/openvmm

Public

mirrored fromhttps://github.com/microsoft/openvmmAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
b8910f97c258ca39c8f2e535fbc241ea1e1be3ff

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

flowey/flowey_cli/src/cli/debug/interrogate.rs

253lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use crate::cli::FlowBackendCli;
5use flowey_core::node::steps::rust::RustRuntimeServices;
6use flowey_core::node::user_facing::ClaimedGhParam;
7use flowey_core::node::user_facing::GhPermission;
8use flowey_core::node::user_facing::GhPermissionValue;
9use flowey_core::node::FlowArch;
10use flowey_core::node::FlowBackend;
11use flowey_core::node::FlowPlatform;
12use flowey_core::node::NodeHandle;
13use std::collections::BTreeMap;
14
15/// (debug) get info about a specific node.
16///
17/// Information includes:
18/// - supported backends
19/// - supported requests
20/// - dependencies
21/// - inline steps (with exec-snippet indices)*
22///
23/// *inline-steps will only be listed if they are enabled via the particular
24/// combination of specified {backend x requests}. For a complete picture
25/// possible dependencies and available steps, you must inspect the Node's
26/// code and documentation directly.
27#[derive(clap::Args)]
28pub struct Interrogate {
29 /// Node to interrogate
30 node_handle: String,
31
32 /// Flow backend to interrogate with
33 flow_backend: FlowBackendCli,
34
35 /// Apply a request onto the node (as JSON)
36 #[clap(long)]
37 req: Vec<String>,
38}
39
40impl Interrogate {
41 pub fn run(self) -> anyhow::Result<()> {
42 let Self {
43 node_handle,
44 flow_backend,
45 req,
46 } = self;
47
48 let raw_json_reqs: Vec<Box<[u8]>> = req
49 .into_iter()
50 .map(|v| v.as_bytes().to_vec().into())
51 .collect();
52
53 let Some(node_handle) = NodeHandle::try_from_modpath(&node_handle) else {
54 anyhow::bail!("could not find node with that name");
55 };
56
57 let mut node = node_handle.new_erased_node();
58
59 let mut dep_registration_backend = InterrogateDepRegistrationBackend;
60 let mut dep_registration = flowey_core::node::new_import_ctx(&mut dep_registration_backend);
61
62 let mut ctx_backend = InterrogateCtx::new(flow_backend.into(), node_handle);
63
64 println!(
65 "# interrogating with {}",
66 match flow_backend {
67 FlowBackendCli::Ado => "ado",
68 FlowBackendCli::Local => "local",
69 FlowBackendCli::Github => "github",
70 }
71 );
72
73 node.imports(&mut dep_registration);
74
75 let mut ctx = flowey_core::node::new_node_ctx(&mut ctx_backend);
76 node.emit(raw_json_reqs.clone(), &mut ctx)?;
77
78 Ok(())
79 }
80}
81
82struct InterrogateDepRegistrationBackend;
83
84impl flowey_core::node::ImportCtxBackend for InterrogateDepRegistrationBackend {
85 fn on_possible_dep(&mut self, node_handle: NodeHandle) {
86 println!("[dep?] {}", node_handle.modpath())
87 }
88}
89
90struct InterrogateCtx {
91 flow_backend: FlowBackend,
92 current_node: NodeHandle,
93 idx_tracker: usize,
94 var_tracker: usize,
95}
96
97impl InterrogateCtx {
98 fn new(flow_backend: FlowBackend, current_node: NodeHandle) -> Self {
99 Self {
100 flow_backend,
101 current_node,
102 idx_tracker: 0,
103 var_tracker: 0,
104 }
105 }
106}
107
108impl flowey_core::node::NodeCtxBackend for InterrogateCtx {
109 fn on_emit_rust_step(
110 &mut self,
111 label: &str,
112 _code: Box<
113 dyn for<'a> FnOnce(&'a mut RustRuntimeServices<'_>) -> anyhow::Result<()> + 'static,
114 >,
115 ) {
116 println!("[step][rust][{}] # {}", self.idx_tracker, label);
117 self.idx_tracker += 1;
118 }
119
120 fn on_emit_ado_step(
121 &mut self,
122 label: &str,
123 yaml_snippet: Box<
124 dyn for<'a> FnOnce(
125 &'a mut flowey_core::node::user_facing::AdoStepServices<'_>,
126 ) -> String,
127 >,
128 code: Option<
129 Box<
130 dyn for<'a> FnOnce(&'a mut RustRuntimeServices<'_>) -> anyhow::Result<()> + 'static,
131 >,
132 >,
133 _condvar: Option<String>,
134 ) {
135 println!(
136 "[step][yaml] # {}{}",
137 if code.is_some() {
138 "(+inline script) "
139 } else {
140 ""
141 },
142 label
143 );
144 let mut fresh_ado_var = || "<dummy>".into();
145 let mut access = flowey_core::node::steps::ado::new_ado_step_services(&mut fresh_ado_var);
146 let raw_snippet = yaml_snippet(&mut access);
147
148 let snippet: Result<serde_yaml::Value, _> = serde_yaml::from_str(&raw_snippet);
149 match snippet {
150 Ok(snippet) => print!("{}", serde_yaml::to_string(&snippet).unwrap()),
151 Err(e) => {
152 log::error!("invalid snippet: {}", e);
153 println!(">>>");
154 println!("{}", raw_snippet);
155 println!("<<<");
156 }
157 };
158
159 self.idx_tracker += 1;
160 }
161
162 fn on_emit_gh_step(
163 &mut self,
164
165 label: &str,
166 _uses: &str,
167 _with: BTreeMap<String, ClaimedGhParam>,
168 _condvar: Option<String>,
169 _outputs: BTreeMap<String, Vec<(String, bool)>>,
170 _permissions: BTreeMap<GhPermission, GhPermissionValue>,
171 _gh_to_rust: Vec<(String, String, bool)>,
172 _rust_to_gh: Vec<(String, String, bool)>,
173 ) {
174 println!("[step][yaml] # {}", label);
175 self.idx_tracker += 1;
176 }
177
178 fn on_emit_side_effect_step(&mut self) {
179 println!("[step][anchor]");
180 }
181
182 fn backend(&mut self) -> FlowBackend {
183 self.flow_backend
184 }
185
186 fn platform(&mut self) -> FlowPlatform {
187 if cfg!(windows) {
188 FlowPlatform::Windows
189 } else if cfg!(target_os = "linux") {
190 FlowPlatform::Linux
191 } else {
192 unreachable!("flowey only runs on windows/linux at the moment")
193 }
194 }
195
196 fn arch(&mut self) -> FlowArch {
197 // xtask-fmt allow-target-arch oneoff-flowey
198 if cfg!(target_arch = "x86_64") {
199 FlowArch::X86_64
200 // xtask-fmt allow-target-arch oneoff-flowey
201 } else if cfg!(target_arch = "aarch64") {
202 FlowArch::Aarch64
203 } else {
204 unreachable!("flowey only runs on X86_64 or Aarch64 at the moment")
205 }
206 }
207
208 fn on_request(&mut self, node_handle: NodeHandle, req: anyhow::Result<Box<[u8]>>) {
209 match req {
210 Ok(data) => {
211 let data = match String::from_utf8(data.into()) {
212 Ok(data) => data,
213 Err(e) => e
214 .into_bytes()
215 .iter()
216 .map(|b| format!("(raw) {:02x}", b))
217 .collect::<Vec<_>>()
218 .join(""),
219 };
220 println!("[req] {} <-- {}", node_handle.modpath(), data)
221 }
222 Err(e) => {
223 log::error!("error serializing inter-node request: {:#}", e)
224 }
225 }
226 }
227
228 fn on_new_var(&mut self) -> String {
229 let v = self.var_tracker;
230 self.var_tracker += 1;
231 format!("<dummy>:{}", v)
232 }
233
234 fn on_claimed_runtime_var(&mut self, var: &str, is_read: bool) {
235 println!(
236 "[var][claim] {} {}",
237 var,
238 if is_read { "(read)" } else { "(write)" },
239 )
240 }
241
242 fn current_node(&self) -> NodeHandle {
243 self.current_node
244 }
245
246 fn persistent_dir_path_var(&mut self) -> Option<String> {
247 Some("<dummy>".into())
248 }
249
250 fn on_unused_read_var(&mut self, _var: &str) {
251 // not relevant
252 }
253}
254