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