1//! Various convenience functions for `built` at runtime.
2
3use std::fmt;
4use std::fmt::Write;
5
6#[cfg(feature = "git2")]
7pub use crate::git::{get_repo_description, get_repo_head};
8
9#[cfg(feature = "chrono")]
10pub use crate::krono::strptime;
11
12/// Parses version-strings with `semver::Version::parse()`.
13///
14/// This function is only available if `built` was compiled with the
15/// `semver` feature.
16///
17/// The function takes a reference to an array of names and version numbers as
18/// serialized by `built` and returns an iterator over the unchanged names
19/// and parsed version numbers.
20///
21/// ```
22/// pub mod build_info {
23/// pub static DEPENDENCIES: [(&'static str, &'static str); 1] = [("built", "0.1.0")];
24/// }
25///
26/// let deps = build_info::DEPENDENCIES;
27/// assert!(built::util::parse_versions(&deps)
28/// .any(|(name, ver)| name == "built" &&
29/// ver >= semver::Version::parse("0.1.0").unwrap()));
30/// ```
31///
32/// # Panics
33/// If a version can't be parsed by `semver::Version::parse()`. This should never
34/// happen with version strings provided by Cargo and `built`.
35#[cfg(feature = "semver")]
36pub fn parse_versions<'a, T>(
37 name_and_versions: T,
38) -> impl Iterator<Item = (&'a str, semver::Version)>
39where
40 T: IntoIterator<Item = &'a (&'a str, &'a str)>,
41{
42 fn parse_version<'a>(t: &'a (&'a str, &'a str)) -> (&'a str, semver::Version) {
43 (t.0, t.1.parse().unwrap())
44 }
45 name_and_versions.into_iter().map(parse_version)
46}
47
48/// Detect execution on various Continuous Integration platforms.
49///
50/// CI-platforms are detected by the presence of known environment variables.
51/// This allows to detect specific CI-platform (like `GitLab`); various
52/// generic environment variables are also checked, which may result in
53/// `CIPlatform::Generic`.
54///
55/// Since some platforms have fairly generic environment variables to begin with
56/// (e.g. `TASK_ID`), this function may have false positives.
57#[must_use]
58pub fn detect_ci() -> Option<super::CIPlatform> {
59 crate::environment::EnvironmentMap::new().detect_ci()
60}
61
62pub(crate) struct ArrayDisplay<'a, T, F>(pub &'a [T], pub F)
63where
64 F: Fn(&T, &mut fmt::Formatter<'_>) -> fmt::Result;
65
66impl<T, F> fmt::Display for ArrayDisplay<'_, T, F>
67where
68 F: Fn(&T, &mut fmt::Formatter<'_>) -> fmt::Result,
69{
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 f.write_char('[')?;
72 for (i: usize, v: &T) in self.0.iter().enumerate() {
73 if i != 0 {
74 f.write_str(data:", ")?;
75 }
76 (self.1)(v, f)?;
77 }
78 f.write_char(']')
79 }
80}
81
82#[cfg(feature = "cargo-lock")]
83pub(crate) struct TupleArrayDisplay<'a, T>(pub &'a [(T, T)]);
84
85#[cfg(feature = "cargo-lock")]
86impl<T> fmt::Display for TupleArrayDisplay<'_, T>
87where
88 T: AsRef<str>,
89{
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 write!(
92 f,
93 "{}",
94 ArrayDisplay(self.0, |(a, b), fmt| write!(
95 fmt,
96 r#"("{}", "{}")"#,
97 a.as_ref().escape_default(),
98 b.as_ref().escape_default()
99 ))
100 )
101 }
102}
103