hydro_deploy/rust_crate/
mod.rs1use std::path::PathBuf;
2use std::sync::Arc;
3
4use nameof::name_of;
5use tracing_options::TracingOptions;
6
7use super::Host;
8use crate::rust_crate::build::BuildParams;
9use crate::{HostTargetType, ServiceBuilder};
10
11pub mod build;
12pub mod ports;
13
14pub mod service;
15pub use service::*;
16
17pub(crate) mod flamegraph;
18pub mod tracing_options;
19
20#[derive(PartialEq, Clone)]
21pub enum CrateTarget {
22 Default,
23 Bin(String),
24 Example(String),
25}
26
27#[derive(Clone)]
34pub struct RustCrate {
35 src: PathBuf,
36 target: CrateTarget,
37 profile: Option<String>,
38 rustflags: Option<String>,
39 target_dir: Option<PathBuf>,
40 build_env: Vec<(String, String)>,
41 no_default_features: bool,
42 features: Option<Vec<String>>,
43 config: Vec<String>,
44 tracing: Option<TracingOptions>,
45 args: Vec<String>,
46 display_name: Option<String>,
47}
48
49impl RustCrate {
50 pub fn new(src: impl Into<PathBuf>) -> Self {
54 Self {
55 src: src.into(),
56 target: CrateTarget::Default,
57 profile: None,
58 rustflags: None,
59 target_dir: None,
60 build_env: vec![],
61 no_default_features: false,
62 features: None,
63 config: vec![],
64 tracing: None,
65 args: vec![],
66 display_name: None,
67 }
68 }
69
70 pub fn bin(mut self, bin: impl Into<String>) -> Self {
73 if self.target != CrateTarget::Default {
74 panic!("{} already set", name_of!(target in Self));
75 }
76
77 self.target = CrateTarget::Bin(bin.into());
78 self
79 }
80
81 pub fn example(mut self, example: impl Into<String>) -> Self {
84 if self.target != CrateTarget::Default {
85 panic!("{} already set", name_of!(target in Self));
86 }
87
88 self.target = CrateTarget::Example(example.into());
89 self
90 }
91
92 pub fn profile(mut self, profile: impl Into<String>) -> Self {
95 if self.profile.is_some() {
96 panic!("{} already set", name_of!(profile in Self));
97 }
98
99 self.profile = Some(profile.into());
100 self
101 }
102
103 pub fn rustflags(mut self, rustflags: impl Into<String>) -> Self {
104 if self.rustflags.is_some() {
105 panic!("{} already set", name_of!(rustflags in Self));
106 }
107
108 self.rustflags = Some(rustflags.into());
109 self
110 }
111
112 pub fn target_dir(mut self, target_dir: impl Into<PathBuf>) -> Self {
113 if self.target_dir.is_some() {
114 panic!("{} already set", name_of!(target_dir in Self));
115 }
116
117 self.target_dir = Some(target_dir.into());
118 self
119 }
120
121 pub fn build_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
122 self.build_env.push((key.into(), value.into()));
123 self
124 }
125
126 pub fn no_default_features(mut self) -> Self {
127 self.no_default_features = true;
128 self
129 }
130
131 pub fn features(mut self, features: impl IntoIterator<Item = impl Into<String>>) -> Self {
132 if self.features.is_none() {
133 self.features = Some(vec![]);
134 }
135
136 self.features
137 .as_mut()
138 .unwrap()
139 .extend(features.into_iter().map(|s| s.into()));
140
141 self
142 }
143
144 pub fn config(mut self, config: impl Into<String>) -> Self {
145 self.config.push(config.into());
146 self
147 }
148
149 pub fn tracing(mut self, perf: impl Into<TracingOptions>) -> Self {
150 if self.tracing.is_some() {
151 panic!("{} already set", name_of!(tracing in Self));
152 }
153
154 self.tracing = Some(perf.into());
155 self
156 }
157
158 pub fn args(mut self, args: impl IntoIterator<Item = impl Into<String>>) -> Self {
160 self.args.extend(args.into_iter().map(|s| s.into()));
161 self
162 }
163
164 pub fn display_name(mut self, display_name: impl Into<String>) -> Self {
166 if self.display_name.is_some() {
167 panic!("{} already set", name_of!(display_name in Self));
168 }
169
170 self.display_name = Some(display_name.into());
171 self
172 }
173
174 pub fn get_build_params(&self, target: HostTargetType) -> BuildParams {
175 let (bin, example) = match &self.target {
176 CrateTarget::Default => (None, None),
177 CrateTarget::Bin(bin) => (Some(bin.clone()), None),
178 CrateTarget::Example(example) => (None, Some(example.clone())),
179 };
180
181 BuildParams::new(
182 self.src.clone(),
183 bin,
184 example,
185 self.profile.clone(),
186 self.rustflags.clone(),
187 self.target_dir.clone(),
188 self.build_env.clone(),
189 self.no_default_features,
190 target,
191 self.features.clone(),
192 self.config.clone(),
193 )
194 }
195}
196
197impl ServiceBuilder for RustCrate {
198 type Service = RustCrateService;
199 fn build(self, id: usize, on: Arc<dyn Host>) -> Self::Service {
200 let build_params = self.get_build_params(on.target_type());
201
202 RustCrateService::new(
203 id,
204 on,
205 build_params,
206 self.tracing,
207 Some(self.args),
208 self.display_name,
209 vec![],
210 )
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217 use crate::deployment;
218
219 #[tokio::test]
220 async fn test_crate_panic() {
221 let mut deployment = deployment::Deployment::new();
222
223 let service = deployment.add_service(
224 RustCrate::new("../hydro_deploy_examples")
225 .example("panic_program")
226 .profile("dev"),
227 deployment.Localhost(),
228 );
229
230 deployment.deploy().await.unwrap();
231
232 let mut stdout = service.stdout();
233
234 deployment.start().await.unwrap();
235
236 assert_eq!(stdout.recv().await.unwrap(), "hello!");
237
238 assert!(stdout.recv().await.is_none());
239 }
240}