1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//! Application version information from git
//!
//! Creates constant GIT_BUILD_VERSION from git command `git describe --tags --always`
//! 
//! Add to `bulid.rs`:
//!
//! ```no_run
//! extern crate build_version;
//! fn main() {
//!     build_version::write_version_file().expect("Failed to write version.rs file");
//! }
//! ```
//!
//! Add to `main.rs`:
//!
//! ```ignore
//! include!(concat!(env!("OUT_DIR"), "/version.rs"));
//! ```
#[macro_use]
extern crate quick_error;

use std::process::Command;

use std::env;
use std::fs::{create_dir_all, File};
use std::io::{BufWriter, Read, Write};
use std::path::Path;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Io(err: std::io::Error) {
            from()
        }
        MissingEnvVar {
        }
    }
}

fn same_content_as(path: &Path, content: &str) -> Result<bool, Error> {
    let mut f = File::open(path)?;
    let mut current = String::new();
    f.read_to_string(&mut current)?;

    Ok(current == content)
}

fn git_describe() -> Option<String> {
    Command::new("git")
        .args(&["describe", "--tags", "--always"])
        .output()
        .ok()
        .and_then(|out| {
            std::str::from_utf8(&out.stdout[..])
                .map(str::trim)
                .map(str::to_owned)
                .ok()
        })
}

/// Write version.rs file to OUT_DIR
pub fn write_version_file() -> Result<(), Error> {
    let path = env::var_os("OUT_DIR").ok_or(Error::MissingEnvVar)?;
    let path: &Path = path.as_ref();

    create_dir_all(path)?;

    let path = path.join("version.rs");

    let content = if let Some(describe) = git_describe() {
        format!("static GIT_BUILD_VERSION: Option<&'static str> = Some(\"{}\");\n", describe)
    } else {
        "static GIT_BUILD_VERSION: Option<&'static str> = None;\n".to_owned()
    };

    let is_fresh = if path.exists() {
        same_content_as(&path, &content)?
    } else {
        false
    };

    if !is_fresh {
        let mut file = BufWriter::new(File::create(&path)?);

        write!(file, "{}", content)?;
    }
    Ok(())
}