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::rust_crate::build::BuildParams;
9use crate::{HostTargetType, ServiceBuilder};
10
11pub mod build;
12pub mod ports;
13
14pub mod service;
15pub use service::*;
16
17#[cfg(feature = "profile-folding")]
18pub(crate) mod flamegraph;
19pub mod tracing_options;
20
21#[derive(PartialEq, Clone)]
22pub enum CrateTarget {
23    Default,
24    Bin(String),
25    Example(String),
26}
27
28/// Specifies a crate that uses `hydro_deploy_integration` to be
29/// deployed as a service.
30///
31/// A [crate](https://doc.rust-lang.org/cargo/appendix/glossary.html#crate) is a particular
32/// [target](https://doc.rust-lang.org/cargo/appendix/glossary.html#target) within a
33/// [package](https://doc.rust-lang.org/cargo/appendix/glossary.html#package).
34#[derive(Clone)]
35pub struct RustCrate {
36    src: PathBuf,
37    target: CrateTarget,
38    profile: Option<String>,
39    rustflags: Option<String>,
40    target_dir: Option<PathBuf>,
41    build_env: Vec<(String, String)>,
42    is_dylib: bool,
43    no_default_features: bool,
44    features: Option<Vec<String>>,
45    config: Vec<String>,
46    tracing: Option<TracingOptions>,
47    args: Vec<String>,
48    display_name: Option<String>,
49}
50
51impl RustCrate {
52    /// Creates a new `RustCrate`.
53    ///
54    /// The `src` argument is the path to the package's directory.
55    pub fn new(src: impl Into<PathBuf>) -> Self {
56        Self {
57            src: src.into(),
58            target: CrateTarget::Default,
59            profile: None,
60            rustflags: None,
61            target_dir: None,
62            build_env: vec![],
63            is_dylib: false,
64            no_default_features: false,
65            features: None,
66            config: vec![],
67            tracing: None,
68            args: vec![],
69            display_name: None,
70        }
71    }
72
73    /// Sets the target to be a binary with the given name,
74    /// equivalent to `cargo run --bin <name>`.
75    pub fn bin(mut self, bin: impl Into<String>) -> Self {
76        if self.target != CrateTarget::Default {
77            panic!("{} already set", name_of!(target in Self));
78        }
79
80        self.target = CrateTarget::Bin(bin.into());
81        self
82    }
83
84    /// Sets the target to be an example with the given name,
85    /// equivalent to `cargo run --example <name>`.
86    pub fn example(mut self, example: impl Into<String>) -> Self {
87        if self.target != CrateTarget::Default {
88            panic!("{} already set", name_of!(target in Self));
89        }
90
91        self.target = CrateTarget::Example(example.into());
92        self
93    }
94
95    /// Sets the profile to be used when building the crate.
96    /// Equivalent to `cargo run --profile <profile>`.
97    pub fn profile(mut self, profile: impl Into<String>) -> Self {
98        if self.profile.is_some() {
99            panic!("{} already set", name_of!(profile in Self));
100        }
101
102        self.profile = Some(profile.into());
103        self
104    }
105
106    pub fn rustflags(mut self, rustflags: impl Into<String>) -> Self {
107        if self.rustflags.is_some() {
108            panic!("{} already set", name_of!(rustflags in Self));
109        }
110
111        self.rustflags = Some(rustflags.into());
112        self
113    }
114
115    pub fn target_dir(mut self, target_dir: impl Into<PathBuf>) -> Self {
116        if self.target_dir.is_some() {
117            panic!("{} already set", name_of!(target_dir in Self));
118        }
119
120        self.target_dir = Some(target_dir.into());
121        self
122    }
123
124    pub fn build_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
125        self.build_env.push((key.into(), value.into()));
126        self
127    }
128
129    pub fn set_is_dylib(mut self, is_dylib: bool) -> Self {
130        self.is_dylib = is_dylib;
131        self
132    }
133
134    pub fn no_default_features(mut self) -> Self {
135        self.no_default_features = true;
136        self
137    }
138
139    pub fn features(mut self, features: impl IntoIterator<Item = impl Into<String>>) -> Self {
140        if self.features.is_none() {
141            self.features = Some(vec![]);
142        }
143
144        self.features
145            .as_mut()
146            .unwrap()
147            .extend(features.into_iter().map(|s| s.into()));
148
149        self
150    }
151
152    pub fn config(mut self, config: impl Into<String>) -> Self {
153        self.config.push(config.into());
154        self
155    }
156
157    pub fn tracing(mut self, perf: impl Into<TracingOptions>) -> Self {
158        if self.tracing.is_some() {
159            panic!("{} already set", name_of!(tracing in Self));
160        }
161
162        self.tracing = Some(perf.into());
163        self
164    }
165
166    /// Sets the arguments to be passed to the binary when it is launched.
167    pub fn args(mut self, args: impl IntoIterator<Item = impl Into<String>>) -> Self {
168        self.args.extend(args.into_iter().map(|s| s.into()));
169        self
170    }
171
172    /// Sets the display name for this service, which will be used in logging.
173    pub fn display_name(mut self, display_name: impl Into<String>) -> Self {
174        if self.display_name.is_some() {
175            panic!("{} already set", name_of!(display_name in Self));
176        }
177
178        self.display_name = Some(display_name.into());
179        self
180    }
181
182    pub fn get_build_params(&self, target: HostTargetType) -> BuildParams {
183        let (bin, example) = match &self.target {
184            CrateTarget::Default => (None, None),
185            CrateTarget::Bin(bin) => (Some(bin.clone()), None),
186            CrateTarget::Example(example) => (None, Some(example.clone())),
187        };
188
189        BuildParams::new(
190            self.src.clone(),
191            bin,
192            example,
193            self.profile.clone(),
194            self.rustflags.clone(),
195            self.target_dir.clone(),
196            self.build_env.clone(),
197            self.no_default_features,
198            target,
199            self.is_dylib,
200            self.features.clone(),
201            self.config.clone(),
202        )
203    }
204}
205
206impl ServiceBuilder for RustCrate {
207    type Service = RustCrateService;
208    fn build(self, id: usize, on: Arc<dyn Host>) -> Self::Service {
209        let build_params = self.get_build_params(on.target_type());
210
211        RustCrateService::new(
212            id,
213            on,
214            build_params,
215            self.tracing,
216            Some(self.args),
217            self.display_name,
218            vec![],
219        )
220    }
221}