1+ use std:: path:: PathBuf ;
2+ use std:: process:: Command ;
13use std:: str;
24
35/// This macro creates the version string during compilation from the
@@ -32,6 +34,7 @@ macro_rules! get_version_info {
3234#[ macro_export]
3335macro_rules! setup_version_info {
3436 ( ) => { {
37+ let _ = $crate:: rerun_if_git_changes( ) ;
3538 println!(
3639 "cargo:rustc-env=GIT_HASH={}" ,
3740 $crate:: get_commit_hash( ) . unwrap_or_default( )
@@ -100,24 +103,52 @@ impl std::fmt::Debug for VersionInfo {
100103}
101104
102105#[ must_use]
103- pub fn get_commit_hash ( ) -> Option < String > {
104- let output = std:: process:: Command :: new ( "git" )
105- . args ( [ "rev-parse" , "HEAD" ] )
106- . output ( )
107- . ok ( ) ?;
106+ fn get_output ( cmd : & str , args : & [ & str ] ) -> Option < String > {
107+ let output = Command :: new ( cmd) . args ( args) . output ( ) . ok ( ) ?;
108108 let mut stdout = output. status . success ( ) . then_some ( output. stdout ) ?;
109- stdout. truncate ( 10 ) ;
109+ // Remove trailing newlines.
110+ while stdout. last ( ) . copied ( ) == Some ( b'\n' ) {
111+ stdout. pop ( ) ;
112+ }
110113 String :: from_utf8 ( stdout) . ok ( )
111114}
112115
116+ #[ must_use]
117+ pub fn rerun_if_git_changes ( ) -> Option < ( ) > {
118+ // Make sure we get rerun when the git commit changes.
119+ // We want to watch two files: HEAD, which tracks which branch we are on,
120+ // and the file for that branch that tracks which commit is is on.
121+
122+ // First, find the `HEAD` file. This should work even with worktrees.
123+ let git_head_file = PathBuf :: from ( get_output ( "git" , & [ "rev-parse" , "--git-path" , "HEAD" ] ) ?) ;
124+ if git_head_file. exists ( ) {
125+ println ! ( "cargo::rerun-if-changed={}" , git_head_file. display( ) ) ;
126+ }
127+
128+ // Determine the name of the current ref.
129+ // This will quit if HEAD is detached.
130+ let git_head_ref = get_output ( "git" , & [ "symbolic-ref" , "-q" , "HEAD" ] ) ?;
131+ // Ask git where this ref is stored.
132+ let git_head_ref_file = PathBuf :: from ( get_output ( "git" , & [ "rev-parse" , "--git-path" , & git_head_ref] ) ?) ;
133+ // If this ref is packed, the file does not exist. However, the checked-out branch is never (?)
134+ // packed, so we should always be able to find this file.
135+ if git_head_ref_file. exists ( ) {
136+ println ! ( "cargo::rerun-if-changed={}" , git_head_ref_file. display( ) ) ;
137+ }
138+
139+ Some ( ( ) )
140+ }
141+
142+ #[ must_use]
143+ pub fn get_commit_hash ( ) -> Option < String > {
144+ let mut stdout = get_output ( "git" , & [ "rev-parse" , "HEAD" ] ) ?;
145+ stdout. truncate ( 10 ) ;
146+ Some ( stdout)
147+ }
148+
113149#[ must_use]
114150pub fn get_commit_date ( ) -> Option < String > {
115- let output = std:: process:: Command :: new ( "git" )
116- . args ( [ "log" , "-1" , "--date=short" , "--pretty=format:%cd" ] )
117- . output ( )
118- . ok ( ) ?;
119- let stdout = output. status . success ( ) . then_some ( output. stdout ) ?;
120- String :: from_utf8 ( stdout) . ok ( )
151+ get_output ( "git" , & [ "log" , "-1" , "--date=short" , "--pretty=format:%cd" ] )
121152}
122153
123154#[ must_use]
@@ -127,15 +158,11 @@ pub fn get_channel() -> String {
127158 }
128159
129160 // if that failed, try to ask rustc -V, do some parsing and find out
130- if let Ok ( output) = std:: process:: Command :: new ( "rustc" ) . arg ( "-V" ) . output ( ) {
131- if output. status . success ( ) {
132- if let Ok ( rustc_output) = str:: from_utf8 ( & output. stdout ) {
133- if rustc_output. contains ( "beta" ) {
134- return String :: from ( "beta" ) ;
135- } else if rustc_output. contains ( "stable" ) {
136- return String :: from ( "stable" ) ;
137- }
138- }
161+ if let Some ( rustc_output) = get_output ( "rustc" , & [ "-V" ] ) {
162+ if rustc_output. contains ( "beta" ) {
163+ return String :: from ( "beta" ) ;
164+ } else if rustc_output. contains ( "stable" ) {
165+ return String :: from ( "stable" ) ;
139166 }
140167 }
141168
@@ -151,7 +178,7 @@ mod test {
151178 fn test_struct_local ( ) {
152179 let vi = get_version_info ! ( ) ;
153180 assert_eq ! ( vi. major, 0 ) ;
154- assert_eq ! ( vi. minor, 3 ) ;
181+ assert_eq ! ( vi. minor, 4 ) ;
155182 assert_eq ! ( vi. patch, 0 ) ;
156183 assert_eq ! ( vi. crate_name, "rustc_tools_util" ) ;
157184 // hard to make positive tests for these since they will always change
@@ -162,7 +189,7 @@ mod test {
162189 #[ test]
163190 fn test_display_local ( ) {
164191 let vi = get_version_info ! ( ) ;
165- assert_eq ! ( vi. to_string( ) , "rustc_tools_util 0.3 .0" ) ;
192+ assert_eq ! ( vi. to_string( ) , "rustc_tools_util 0.4 .0" ) ;
166193 }
167194
168195 #[ test]
@@ -171,7 +198,7 @@ mod test {
171198 let s = format ! ( "{vi:?}" ) ;
172199 assert_eq ! (
173200 s,
174- "VersionInfo { crate_name: \" rustc_tools_util\" , major: 0, minor: 3 , patch: 0 }"
201+ "VersionInfo { crate_name: \" rustc_tools_util\" , major: 0, minor: 4 , patch: 0 }"
175202 ) ;
176203 }
177204}
0 commit comments