Skip to main content

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