• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

baoyachi / shadow-rs / 12340312732

15 Dec 2024 04:05PM UTC coverage: 26.52% (+2.2%) from 24.368%
12340312732

push

github

web-flow
Merge pull request #195 from baoyachi/builder

Add ShadowBuilder build shadow

49 of 97 new or added lines in 2 files covered. (50.52%)

722 existing lines in 3 files now uncovered.

641 of 2417 relevant lines covered (26.52%)

0.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

17.72
/src/build.rs
1
use crate::hook::HookExt;
2
use crate::{default_deny, SdResult, Shadow};
3
use is_debug::is_debug;
4
use std::collections::BTreeSet;
5
use std::fmt::{Display, Formatter};
6

7
/// `shadow-rs` build constant identifiers.
8
pub type ShadowConst = &'static str;
9

10
/// Serialized values for build constants.
11
#[derive(Debug, Clone)]
12
pub struct ConstVal {
13
    /// User-facing documentation for the build constant.
14
    pub desc: String,
15
    /// Serialized value of the build constant.
16
    pub v: String,
17
    /// Type of the build constant.
18
    pub t: ConstType,
19
}
20

21
impl ConstVal {
22
    pub fn new<S: Into<String>>(desc: S) -> ConstVal {
1✔
23
        // Creates a new `ConstVal` with an empty string as its value and `Str` as its type.
24
        ConstVal {
25
            desc: desc.into(),
1✔
26
            v: "".to_string(),
1✔
27
            t: ConstType::Str,
28
        }
29
    }
30

31
    pub fn new_bool<S: Into<String>>(desc: S) -> ConstVal {
1✔
32
        // Creates a new `ConstVal` with "true" as its value and `Bool` as its type.
33
        ConstVal {
34
            desc: desc.into(),
1✔
35
            v: "true".to_string(),
1✔
36
            t: ConstType::Bool,
37
        }
38
    }
39

40
    pub fn new_slice<S: Into<String>>(desc: S) -> ConstVal {
1✔
41
        // Creates a new `ConstVal` with an empty string as its value and `Slice` as its type.
42
        ConstVal {
43
            desc: desc.into(),
1✔
44
            v: "".to_string(),
1✔
45
            t: ConstType::Slice,
46
        }
47
    }
48
}
49

50
/// Supported types of build constants.
51
#[derive(Debug, Clone)]
52
pub enum ConstType {
53
    /// [`&str`](`str`).
54
    Str,
55
    /// [`bool`].
56
    Bool,
57
    /// [`&[u8]`].
58
    Slice,
59
}
60

61
impl Display for ConstType {
62
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1✔
63
        match self {
1✔
64
            ConstType::Str => write!(f, "&str"),
1✔
65
            ConstType::Bool => write!(f, "bool"),
1✔
66
            ConstType::Slice => write!(f, "&[u8]"),
1✔
67
        }
68
    }
69
}
70

71
/// The BuildPattern enum defines strategies for triggering package rebuilding.
72
///
73
/// Default mode is `Lazy`.
74
///
75
/// * `Lazy`: The lazy mode. In this mode, if the current Rust environment is set to `debug`,
76
///   the rebuild package will not run every time the build script is triggered.
77
///   If the environment is set to `release`, it behaves the same as the `RealTime` mode.
78
/// * `RealTime`: The real-time mode. It will always trigger rebuilding a package upon any change,
79
///   regardless of whether the Rust environment is set to `debug` or `release`.
80
/// * `Custom`: The custom build mode, an enhanced version of `RealTime` mode, allowing for user-defined conditions
81
///   to trigger rebuilding a package.
82
///
83
#[derive(Debug, Default, Clone)]
84
pub enum BuildPattern {
85
    #[default]
86
    Lazy,
87
    RealTime,
88
    Custom {
89
        /// A list of paths that, if changed, will trigger a rebuild.
90
        /// See <https://doc.rust-lang.org/cargo/reference/build-scripts.html#rerun-if-changed>
91
        if_path_changed: Vec<String>,
92
        /// A list of environment variables that, if changed, will trigger a rebuild.
93
        /// See <https://doc.rust-lang.org/cargo/reference/build-scripts.html#rerun-if-env-changed>
94
        if_env_changed: Vec<String>,
95
    },
96
}
97

98
impl BuildPattern {
99
    /// Determines when Cargo should rerun the build script based on the configured pattern.
100
    ///
101
    /// # Arguments
102
    ///
103
    /// * `other_keys` - An iterator over additional keys that should trigger a rebuild if they change.
104
    /// * `out_dir` - The output directory where generated files are placed.
105
    pub(crate) fn rerun_if<'a>(
1✔
106
        &self,
107
        other_keys: impl Iterator<Item = &'a ShadowConst>,
108
        out_dir: &str,
109
    ) {
110
        match self {
1✔
NEW
111
            BuildPattern::Lazy => {
×
112
                if is_debug() {
2✔
NEW
113
                    return;
×
114
                }
115
            }
NEW
116
            BuildPattern::RealTime => {}
×
NEW
117
            BuildPattern::Custom {
×
NEW
118
                if_path_changed,
×
NEW
119
                if_env_changed,
×
NEW
120
            } => {
×
NEW
121
                if_env_changed
×
122
                    .iter()
NEW
123
                    .for_each(|key| println!("cargo:rerun-if-env-changed={key}"));
×
NEW
124
                if_path_changed
×
125
                    .iter()
NEW
126
                    .for_each(|p| println!("cargo:rerun-if-changed={p}"));
×
127
            }
128
        }
129

NEW
130
        other_keys.for_each(|key| println!("cargo:rerun-if-env-changed={key}"));
×
NEW
131
        println!("cargo:rerun-if-env-changed=SOURCE_DATE_EPOCH");
×
NEW
132
        println!("cargo:rerun-if-changed={}/shadow.rs", out_dir);
×
133
    }
134
}
135

136
/// A builder pattern structure to construct a `Shadow` instance.
137
///
138
/// This struct allows for configuring various aspects of how shadow-rs will be built into your Rust project.
139
/// It provides methods to set up hooks, specify build patterns, define paths, and deny certain build constants.
140
///
141
/// # Fields
142
///
143
/// * `hook`: An optional hook that can be used during the build process. Hooks implement the `HookExt` trait.
144
/// * `build_pattern`: Determines the strategy for triggering package rebuilds (`Lazy`, `RealTime`, or `Custom`).
145
/// * `deny_const`: A set of build constant identifiers that should not be included in the build.
146
/// * `src_path`: The source path from which files are read for building.
147
/// * `out_path`: The output path where generated files will be placed.
148
///
149
pub struct ShadowBuilder<'a> {
150
    hook: Option<Box<dyn HookExt + 'a>>,
151
    build_pattern: BuildPattern,
152
    deny_const: BTreeSet<ShadowConst>,
153
    src_path: Option<String>,
154
    out_path: Option<String>,
155
}
156

NEW
157
impl<'a> ShadowBuilder<'a> {
×
158
    /// Creates a new `ShadowBuilder` with default settings.
159
    ///
160
    /// Initializes the builder with the following defaults:
161
    /// - `hook`: None
162
    /// - `build_pattern`: `BuildPattern::Lazy`
163
    /// - `deny_const`: Uses the result from `default_deny()`
164
    /// - `src_path`: Attempts to get the manifest directory using `CARGO_MANIFEST_DIR` environment variable.
165
    /// - `out_path`: Attempts to get the output directory using `OUT_DIR` environment variable.
166
    ///
167
    /// # Returns
168
    ///
169
    /// A new instance of `ShadowBuilder`.
170
    pub fn builder() -> Self {
1✔
171
        let default_src_path = std::env::var("CARGO_MANIFEST_DIR").ok();
1✔
172
        let default_out_path = std::env::var("OUT_DIR").ok();
2✔
173
        Self {
174
            hook: None,
175
            build_pattern: BuildPattern::default(),
1✔
176
            deny_const: default_deny(),
1✔
177
            src_path: default_src_path,
178
            out_path: default_out_path,
179
        }
180
    }
181

182
    /// Sets the build hook for this builder.
183
    ///
184
    /// # Arguments
185
    ///
186
    /// * `hook` - An object implementing the `HookExt` trait that defines custom behavior for the build process.
187
    ///
188
    /// # Returns
189
    ///
190
    /// A new `ShadowBuilder` instance with the specified hook applied.
NEW
191
    pub fn hook(mut self, hook: impl HookExt + 'a) -> Self {
×
NEW
192
        self.hook = Some(Box::new(hook));
×
NEW
193
        self
×
194
    }
195

196
    /// Sets the source path for this builder.
197
    ///
198
    /// # Arguments
199
    ///
200
    /// * `src_path` - A string reference that specifies the source directory for the build.
201
    ///
202
    /// # Returns
203
    ///
204
    /// A new `ShadowBuilder` instance with the specified source path.
205
    pub fn src_path<P: AsRef<str>>(mut self, src_path: P) -> Self {
1✔
206
        self.src_path = Some(src_path.as_ref().to_owned());
2✔
207
        self
1✔
208
    }
209

210
    /// Sets the output path for this builder.
211
    ///
212
    /// # Arguments
213
    ///
214
    /// * `out_path` - A string reference that specifies the output directory for the build.
215
    ///
216
    /// # Returns
217
    ///
218
    /// A new `ShadowBuilder` instance with the specified output path.
219
    pub fn out_path<P: AsRef<str>>(mut self, out_path: P) -> Self {
1✔
220
        self.out_path = Some(out_path.as_ref().to_owned());
2✔
221
        self
1✔
222
    }
223

224
    /// Sets the build pattern for this builder.
225
    ///
226
    /// # Arguments
227
    ///
228
    /// * `pattern` - A `BuildPattern` that determines when the package should be rebuilt.
229
    ///
230
    /// # Returns
231
    ///
232
    /// A new `ShadowBuilder` instance with the specified build pattern.
NEW
233
    pub fn build_pattern(mut self, pattern: BuildPattern) -> Self {
×
NEW
234
        self.build_pattern = pattern;
×
NEW
235
        self
×
236
    }
237

238
    /// Sets the denied constants for this builder.
239
    ///
240
    /// # Arguments
241
    ///
242
    /// * `deny_const` - A set of `ShadowConst` that should be excluded from the build.
243
    ///
244
    /// # Returns
245
    ///
246
    /// A new `ShadowBuilder` instance with the specified denied constants.
247
    pub fn deny_const(mut self, deny_const: BTreeSet<ShadowConst>) -> Self {
1✔
248
        self.deny_const = deny_const;
2✔
249
        self
1✔
250
    }
251

252
    /// Builds a `Shadow` instance based on the current configuration.
253
    ///
254
    /// # Returns
255
    ///
256
    /// A `SdResult<Shadow>` that represents the outcome of the build operation.
257
    pub fn build(self) -> SdResult<Shadow> {
1✔
258
        Shadow::build_inner(self)
1✔
259
    }
260

261
    /// Gets the source path if it has been set.
262
    ///
263
    /// # Returns
264
    ///
265
    /// A `SdResult<&String>` containing the source path or an error if the path is missing.
266
    pub fn get_src_path(&self) -> SdResult<&String> {
1✔
267
        let src_path = self.src_path.as_ref().ok_or("missing `src_path`")?;
1✔
268
        Ok(src_path)
1✔
269
    }
270

271
    /// Gets the output path if it has been set.
272
    ///
273
    /// # Returns
274
    ///
275
    /// A `SdResult<&String>` containing the output path or an error if the path is missing.
276
    pub fn get_out_path(&self) -> SdResult<&String> {
1✔
277
        let out_path = self.out_path.as_ref().ok_or("missing `out_path`")?;
1✔
278
        Ok(out_path)
1✔
279
    }
280

281
    /// Gets the build pattern.
282
    ///
283
    /// # Returns
284
    ///
285
    /// A reference to the `BuildPattern` currently configured for this builder.
286
    pub fn get_build_pattern(&self) -> &BuildPattern {
1✔
287
        &self.build_pattern
1✔
288
    }
289

290
    /// Gets the denied constants.
291
    ///
292
    /// # Returns
293
    ///
294
    /// A reference to the set of `ShadowConst` that are denied for this build.
295
    pub fn get_deny_const(&self) -> &BTreeSet<ShadowConst> {
1✔
296
        &self.deny_const
1✔
297
    }
298

299
    /// Gets the build hook if it has been set.
300
    ///
301
    /// # Returns
302
    ///
303
    /// An option containing a reference to the hook if one is present.
304
    pub fn get_hook(&'a self) -> Option<&'a (dyn HookExt + 'a)> {
1✔
305
        self.hook.as_deref()
1✔
306
    }
307
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc