changelog shortlog graph tags branches changeset files revisions annotate raw help

Mercurial > core / rust/lib/util/src/bs/git.rs

changeset 698: 96958d3eb5b0
parent: 0ccbbd142694
author: Richard Westhaver <ellis@rwest.io>
date: Fri, 04 Oct 2024 22:04:59 -0400
permissions: -rw-r--r--
description: fixes
1 use std::{env, fs, fs::File, io, io::Read, path::PathBuf};
2 /// Make sure the calling `build.rs` script is rerun when `.git/HEAD` or the ref
3 /// of `.git/HEAD` changed.
4 ///
5 /// The file is searched from the `CARGO_MANIFEST_DIR` upwards. If the file can
6 /// not be found, a warning is generated.
7 pub fn rerun_if_git_head_changed() {
8  let mut manifest_dir = PathBuf::from(
9  env::var("CARGO_MANIFEST_DIR")
10  .expect("`CARGO_MANIFEST_DIR` is always set by cargo."),
11  );
12  let manifest_dir_copy = manifest_dir.clone();
13 
14  while manifest_dir.parent().is_some() {
15  match get_git_paths(&manifest_dir) {
16  Err(err) => {
17  eprintln!("cargo:warning=Unable to read the Git repository: {}", err);
18 
19  return;
20  }
21  Ok(None) => {}
22  Ok(Some(paths)) => {
23  for p in paths {
24  println!("cargo:rerun-if-changed={}", p.display());
25  }
26 
27  return;
28  }
29  }
30 
31  manifest_dir.pop();
32  }
33 
34  println!(
35  "cargo:warning=Could not find `.git/HEAD` searching from `{}` upwards!",
36  manifest_dir_copy.display(),
37  );
38 }
39 
40 // Code taken from https://github.com/rustyhorde/vergen/blob/8d522db8c8e16e26c0fc9ea8e6b0247cbf5cca84/src/output/envvar.rs
41 fn get_git_paths(path: &PathBuf) -> Result<Option<Vec<PathBuf>>, io::Error> {
42  let git_dir_or_file = path.join(".git");
43 
44  if let Ok(metadata) = fs::metadata(&git_dir_or_file) {
45  if metadata.is_dir() {
46  // Echo the HEAD path
47  let git_head_path = git_dir_or_file.join("HEAD");
48 
49  // Determine where HEAD points and echo that path also.
50  let mut f = File::open(&git_head_path)?;
51  let mut git_head_contents = String::new();
52  let _ = f.read_to_string(&mut git_head_contents)?;
53  let ref_vec: Vec<&str> = git_head_contents.split(": ").collect();
54 
55  if ref_vec.len() == 2 {
56  let current_head_file = ref_vec[1];
57  let git_refs_path = git_dir_or_file.join(current_head_file);
58 
59  Ok(Some(vec![git_head_path, git_refs_path]))
60  } else {
61  Err(io::Error::new(
62  io::ErrorKind::Other,
63  "You are most likely in a detached HEAD state",
64  ))
65  }
66  } else if metadata.is_file() {
67  // We are in a worktree, so find out where the actual
68  // worktrees/<name>/HEAD file is.
69  let mut git_file = File::open(&git_dir_or_file)?;
70  let mut git_contents = String::new();
71  let _ = git_file.read_to_string(&mut git_contents)?;
72  let dir_vec: Vec<&str> = git_contents.split(": ").collect();
73  let git_path = dir_vec[1].trim();
74 
75  // Echo the HEAD psth
76  let git_head_path = PathBuf::from(git_path).join("HEAD");
77 
78  // Find out what the full path to the .git dir is.
79  let mut actual_git_dir = PathBuf::from(git_path);
80  actual_git_dir.pop();
81  actual_git_dir.pop();
82 
83  // Determine where HEAD points and echo that path also.
84  let mut f = File::open(&git_head_path)?;
85  let mut git_head_contents = String::new();
86  let _ = f.read_to_string(&mut git_head_contents)?;
87  let ref_vec: Vec<&str> = git_head_contents.split(": ").collect();
88 
89  if ref_vec.len() == 2 {
90  let current_head_file = ref_vec[1];
91  let git_refs_path = actual_git_dir.join(current_head_file);
92 
93  Ok(Some(vec![git_head_path, git_refs_path]))
94  } else {
95  Err(io::Error::new(
96  io::ErrorKind::Other,
97  "You are most likely in a detached HEAD state",
98  ))
99  }
100  } else {
101  Err(io::Error::new(
102  io::ErrorKind::Other,
103  "Invalid .git format (Not a directory or a file)",
104  ))
105  }
106  } else {
107  Ok(None)
108  }
109 }