_origen/utility/
results.rs1use origen_metal::{Outcome, OutcomeSubtypes, Result, TypedValue};
2use pyapi_metal::prelude::typed_value;
3use pyapi_metal::runtime_error;
4use pyo3::prelude::*;
5use pyo3::types::{PyDict, PyType};
6
7#[macro_export]
8macro_rules! incomplete_result_error {
9 ($result_type:expr) => {{
10 crate::runtime_error!(format!(
11 "Incomplete or Uninitialized {} encountered",
12 $result_type
13 ))?
14 }};
15}
16
17pub fn define(py: Python, m: &PyModule) -> PyResult<()> {
18 let subm = PyModule::new(py, "results")?;
19 subm.add_class::<BuildResult>()?;
20 subm.add_class::<UploadResult>()?;
21 subm.add_class::<ExecResult>()?;
22 m.add_submodule(subm)?;
23 Ok(())
24}
25
26#[pyclass(subclass)]
28pub struct BuildResult {
29 pub build_result: Option<Outcome>,
31}
32
33#[pymethods]
34impl BuildResult {
35 #[classmethod]
36 #[pyo3(signature=(instance, succeeded, build_contents=None, message=None, metadata=None))]
37 fn __init__(
38 _cls: &PyType,
39 instance: &PyAny,
40 succeeded: bool,
41 build_contents: Option<Vec<String>>,
42 message: Option<String>,
43 metadata: Option<&PyDict>,
44 ) -> PyResult<()> {
45 let mut i = instance.extract::<PyRefMut<Self>>()?;
46 let mut o = Outcome::new_success_or_fail(succeeded);
47 o.subtype = Some(OutcomeSubtypes::BuildResult);
48 o.message = message;
49 o.metadata = typed_value::from_optional_pydict(metadata)?;
50 o.insert_keyword_result("build_contents", build_contents);
51 i.build_result = Some(o);
52 Ok(())
53 }
54
55 #[new]
56 fn new() -> Self {
57 Self { build_result: None }
58 }
59
60 #[getter]
61 fn succeeded(&self) -> PyResult<bool> {
62 Ok(self.build_result()?.succeeded())
63 }
64
65 #[getter]
66 fn failed(&self) -> PyResult<bool> {
67 Ok(!self.succeeded()?)
68 }
69
70 #[getter]
71 fn build_contents(&self) -> PyResult<Option<Vec<String>>> {
72 match self
73 .build_result()?
74 .require_keyword_result("build_contents")?
75 {
76 TypedValue::None => Ok(None),
77 TypedValue::Vec(v) => Ok(Some(
78 v.iter()
79 .map(|i| i.as_string())
80 .collect::<Result<Vec<String>>>()?,
81 )),
82 _ => runtime_error!(
83 "Cannot extract build contents as either 'None' or as a 'list of strs'"
84 ),
85 }
86 }
87
88 #[getter]
89 fn message(&self) -> PyResult<Option<String>> {
90 Ok(self.build_result()?.message.clone())
91 }
92
93 #[getter]
94 fn metadata<'py>(&self, py: Python<'py>) -> PyResult<Option<&'py PyDict>> {
95 typed_value::into_optional_pydict(py, self.build_result()?.metadata.as_ref())
96 }
97}
98
99impl BuildResult {
100 pub fn build_result(&self) -> PyResult<&Outcome> {
101 match self.build_result.as_ref() {
102 Some(r) => Ok(r),
103 None => return crate::incomplete_result_error!("Build Result"),
104 }
105 }
106
107 pub fn to_py(py: Python, build_result: &Outcome) -> PyResult<Py<Self>> {
108 Py::new(
109 py,
110 Self {
111 build_result: Some(build_result.clone()),
112 },
113 )
114 }
115}
116
117#[pyclass(subclass)]
119pub struct UploadResult {
120 pub upload_result: Option<Outcome>,
122}
123
124#[pymethods]
125impl UploadResult {
126 #[classmethod]
127 #[pyo3(signature=(instance, succeeded, message=None, metadata=None))]
128 fn __init__(
129 _cls: &PyType,
130 instance: &PyAny,
131 succeeded: bool,
132 message: Option<String>,
133 metadata: Option<&PyDict>,
134 ) -> PyResult<()> {
135 let mut i = instance.extract::<PyRefMut<Self>>()?;
136 let mut o = Outcome::new_success_or_fail(succeeded);
137 o.subtype = Some(OutcomeSubtypes::UploadResult);
138 o.message = message;
139 o.metadata = typed_value::from_optional_pydict(metadata)?;
140 i.upload_result = Some(o);
141 Ok(())
142 }
143
144 #[new]
145 fn new() -> Self {
146 Self {
147 upload_result: None,
148 }
149 }
150}
151
152impl UploadResult {
153 pub fn upload_result(&self) -> PyResult<&Outcome> {
154 match self.upload_result.as_ref() {
155 Some(r) => Ok(r),
156 None => crate::incomplete_result_error!("Upload Result"),
157 }
158 }
159}
160
161#[pyclass]
162pub struct ExecResult {
163 pub exec_result: Option<Outcome>,
164}
165
166#[pymethods]
167impl ExecResult {
168 #[classmethod]
169 #[pyo3(signature=(instance, exit_code, stdout=None, stderr=None))]
170 fn __init__(
171 _cls: &PyType,
172 instance: &PyAny,
173 exit_code: i32,
174 stdout: Option<Vec<String>>,
175 stderr: Option<Vec<String>>,
176 ) -> PyResult<()> {
177 let mut i = instance.extract::<PyRefMut<Self>>()?;
178 let mut o = Outcome::new_success_or_fail(exit_code == 0);
179 o.subtype = Some(OutcomeSubtypes::ExecResult);
180 o.insert_keyword_result("exit_code", exit_code);
181 o.insert_keyword_result("stdout", stdout);
182 o.insert_keyword_result("stderr", stderr);
183 i.exec_result = Some(o);
184 Ok(())
185 }
186
187 #[new]
188 fn new() -> Self {
189 Self { exec_result: None }
190 }
191
192 #[getter]
193 pub fn exit_code(&self) -> PyResult<i32> {
194 Ok(self
195 .exec_result()?
196 .require_keyword_result("exit_code")?
197 .try_into()?)
198 }
199
200 #[getter]
201 pub fn stdout(&self) -> PyResult<Option<Vec<String>>> {
202 Ok(
203 match self
204 .exec_result()?
205 .require_keyword_result("stdout")?
206 .as_option()
207 {
208 Some(out_lines) => Some(out_lines.try_into()?),
209 None => None,
210 },
211 )
212 }
213
214 #[getter]
215 pub fn stderr(&self) -> PyResult<Option<Vec<String>>> {
216 Ok(
217 match self
218 .exec_result()?
219 .require_keyword_result("stderr")?
220 .as_option()
221 {
222 Some(err_lines) => Some(err_lines.try_into()?),
223 None => None,
224 },
225 )
226 }
227
228 pub fn succeeded(&self) -> PyResult<bool> {
229 Ok(self.exec_result()?.succeeded())
230 }
231
232 pub fn failed(&self) -> PyResult<bool> {
233 Ok(self.exec_result()?.failed())
234 }
235}
236
237impl ExecResult {
238 fn exec_result(&self) -> PyResult<&Outcome> {
239 match self.exec_result.as_ref() {
240 Some(r) => Ok(r),
241 None => crate::incomplete_result_error!("Exec Result"),
242 }
243 }
244}