1 //! Build configuration for Rust's release channels. 2 //! 3 //! Implements the stable/beta/nightly channel distinctions by setting various 4 //! flags like the `unstable_features`, calculating variables like `release` and 5 //! `package_vers`, and otherwise indicating to the compiler what it should 6 //! print out as part of its version information. 7 8 use std::path::Path; 9 use std::process::Command; 10 11 use build_helper::output; 12 13 use crate::Build; 14 15 pub enum GitInfo { 16 /// This is not a git repository. 17 Absent, 18 /// This is a git repository. 19 /// If the info should be used (`ignore_git` is false), this will be 20 /// `Some`, otherwise it will be `None`. 21 Present(Option<Info>), 22 } 23 24 pub struct Info { 25 commit_date: String, 26 sha: String, 27 short_sha: String, 28 } 29 30 impl GitInfo { new(ignore_git: bool, dir: &Path) -> GitInfo31 pub fn new(ignore_git: bool, dir: &Path) -> GitInfo { 32 // See if this even begins to look like a git dir 33 if !dir.join(".git").exists() { 34 return GitInfo::Absent; 35 } 36 37 // Make sure git commands work 38 match Command::new("git").arg("rev-parse").current_dir(dir).output() { 39 Ok(ref out) if out.status.success() => {} 40 _ => return GitInfo::Absent, 41 } 42 43 // If we're ignoring the git info, we don't actually need to collect it, just make sure this 44 // was a git repo in the first place. 45 if ignore_git { 46 return GitInfo::Present(None); 47 } 48 49 // Ok, let's scrape some info 50 let ver_date = output( 51 Command::new("git") 52 .current_dir(dir) 53 .arg("log") 54 .arg("-1") 55 .arg("--date=short") 56 .arg("--pretty=format:%cd"), 57 ); 58 let ver_hash = output(Command::new("git").current_dir(dir).arg("rev-parse").arg("HEAD")); 59 let short_ver_hash = output( 60 Command::new("git").current_dir(dir).arg("rev-parse").arg("--short=9").arg("HEAD"), 61 ); 62 GitInfo::Present(Some(Info { 63 commit_date: ver_date.trim().to_string(), 64 sha: ver_hash.trim().to_string(), 65 short_sha: short_ver_hash.trim().to_string(), 66 })) 67 } 68 info(&self) -> Option<&Info>69 fn info(&self) -> Option<&Info> { 70 match self { 71 GitInfo::Present(info) => info.as_ref(), 72 GitInfo::Absent => None, 73 } 74 } 75 sha(&self) -> Option<&str>76 pub fn sha(&self) -> Option<&str> { 77 self.info().map(|s| &s.sha[..]) 78 } 79 sha_short(&self) -> Option<&str>80 pub fn sha_short(&self) -> Option<&str> { 81 self.info().map(|s| &s.short_sha[..]) 82 } 83 commit_date(&self) -> Option<&str>84 pub fn commit_date(&self) -> Option<&str> { 85 self.info().map(|s| &s.commit_date[..]) 86 } 87 version(&self, build: &Build, num: &str) -> String88 pub fn version(&self, build: &Build, num: &str) -> String { 89 let mut version = build.release(num); 90 if let Some(ref inner) = self.info() { 91 version.push_str(" ("); 92 version.push_str(&inner.short_sha); 93 version.push(' '); 94 version.push_str(&inner.commit_date); 95 version.push(')'); 96 } 97 version 98 } 99 is_git(&self) -> bool100 pub fn is_git(&self) -> bool { 101 match self { 102 GitInfo::Absent => false, 103 GitInfo::Present(_) => true, 104 } 105 } 106 } 107