]> git.lizzy.rs Git - rust.git/blob - src/tools/build_helper/src/git.rs
Rollup merge of #106689 - GuillaumeGomez:rustdoc-gui-files-array, r=notriddle
[rust.git] / src / tools / build_helper / src / git.rs
1 use std::{path::Path, process::Command};
2
3 /// Finds the remote for rust-lang/rust.
4 /// For example for these remotes it will return `upstream`.
5 /// ```text
6 /// origin  https://github.com/Nilstrieb/rust.git (fetch)
7 /// origin  https://github.com/Nilstrieb/rust.git (push)
8 /// upstream        https://github.com/rust-lang/rust (fetch)
9 /// upstream        https://github.com/rust-lang/rust (push)
10 /// ```
11 pub fn get_rust_lang_rust_remote(git_dir: Option<&Path>) -> Result<String, String> {
12     let mut git = Command::new("git");
13     if let Some(git_dir) = git_dir {
14         git.current_dir(git_dir);
15     }
16     git.args(["config", "--local", "--get-regex", "remote\\..*\\.url"]);
17
18     let output = git.output().map_err(|err| format!("{err:?}"))?;
19     if !output.status.success() {
20         return Err("failed to execute git config command".to_owned());
21     }
22
23     let stdout = String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?;
24
25     let rust_lang_remote = stdout
26         .lines()
27         .find(|remote| remote.contains("rust-lang"))
28         .ok_or_else(|| "rust-lang/rust remote not found".to_owned())?;
29
30     let remote_name =
31         rust_lang_remote.split('.').nth(1).ok_or_else(|| "remote name not found".to_owned())?;
32     Ok(remote_name.into())
33 }
34
35 pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result<bool, String> {
36     let mut git = Command::new("git");
37     if let Some(git_dir) = git_dir {
38         git.current_dir(git_dir);
39     }
40     git.args(["rev-parse", rev]);
41     let output = git.output().map_err(|err| format!("{err:?}"))?;
42
43     match output.status.code() {
44         Some(0) => Ok(true),
45         Some(128) => Ok(false),
46         None => {
47             return Err(format!(
48                 "git didn't exit properly: {}",
49                 String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
50             ));
51         }
52         Some(code) => {
53             return Err(format!(
54                 "git command exited with status code: {code}: {}",
55                 String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
56             ));
57         }
58     }
59 }
60
61 /// Returns the master branch from which we can take diffs to see changes.
62 /// This will usually be rust-lang/rust master, but sometimes this might not exist.
63 /// This could be because the user is updating their forked master branch using the GitHub UI
64 /// and therefore doesn't need an upstream master branch checked out.
65 /// We will then fall back to origin/master in the hope that at least this exists.
66 pub fn updated_master_branch(git_dir: Option<&Path>) -> Result<String, String> {
67     let upstream_remote = get_rust_lang_rust_remote(git_dir)?;
68     let upstream_master = format!("{upstream_remote}/master");
69     if rev_exists(&upstream_master, git_dir)? {
70         return Ok(upstream_master);
71     }
72
73     // We could implement smarter logic here in the future.
74     Ok("origin/master".into())
75 }