build_version/
lib.rs

1//! Application version information from git
2//!
3//! Creates constant GIT_BUILD_VERSION from git command `git describe --tags --always`
4//! 
5//! Add to `bulid.rs`:
6//!
7//! ```no_run
8//! extern crate build_version;
9//! fn main() {
10//!     build_version::write_version_file().expect("Failed to write version.rs file");
11//! }
12//! ```
13//!
14//! Add to `main.rs`:
15//!
16//! ```ignore
17//! include!(concat!(env!("OUT_DIR"), "/version.rs"));
18//! ```
19#[macro_use]
20extern crate quick_error;
21
22use std::process::Command;
23
24use std::env;
25use std::fs::{create_dir_all, File};
26use std::io::{BufWriter, Read, Write};
27use std::path::Path;
28
29quick_error! {
30    #[derive(Debug)]
31    pub enum Error {
32        Io(err: std::io::Error) {
33            from()
34        }
35        MissingEnvVar {
36        }
37    }
38}
39
40fn same_content_as(path: &Path, content: &str) -> Result<bool, Error> {
41    let mut f = File::open(path)?;
42    let mut current = String::new();
43    f.read_to_string(&mut current)?;
44
45    Ok(current == content)
46}
47
48fn git_describe() -> Option<String> {
49    Command::new("git")
50        .args(&["describe", "--tags", "--always"])
51        .output()
52        .ok()
53        .and_then(|out| {
54            std::str::from_utf8(&out.stdout[..])
55                .map(str::trim)
56                .map(str::to_owned)
57                .ok()
58        })
59}
60
61/// Write version.rs file to OUT_DIR
62pub fn write_version_file() -> Result<(), Error> {
63    let path = env::var_os("OUT_DIR").ok_or(Error::MissingEnvVar)?;
64    let path: &Path = path.as_ref();
65
66    create_dir_all(path)?;
67
68    let path = path.join("version.rs");
69
70    let content = if let Some(describe) = git_describe() {
71        format!("static GIT_BUILD_VERSION: Option<&'static str> = Some(\"{}\");\n", describe)
72    } else {
73        "static GIT_BUILD_VERSION: Option<&'static str> = None;\n".to_owned()
74    };
75
76    let is_fresh = if path.exists() {
77        same_content_as(&path, &content)?
78    } else {
79        false
80    };
81
82    if !is_fresh {
83        let mut file = BufWriter::new(File::create(&path)?);
84
85        write!(file, "{}", content)?;
86    }
87    Ok(())
88}