summaryrefslogtreecommitdiffstats
path: root/src/tools/build_helper
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/build_helper')
-rw-r--r--src/tools/build_helper/Cargo.toml8
-rw-r--r--src/tools/build_helper/src/ci.rs40
-rw-r--r--src/tools/build_helper/src/git.rs75
-rw-r--r--src/tools/build_helper/src/lib.rs2
4 files changed, 125 insertions, 0 deletions
diff --git a/src/tools/build_helper/Cargo.toml b/src/tools/build_helper/Cargo.toml
new file mode 100644
index 000000000..99f6fea2e
--- /dev/null
+++ b/src/tools/build_helper/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "build_helper"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs
new file mode 100644
index 000000000..9f113c72b
--- /dev/null
+++ b/src/tools/build_helper/src/ci.rs
@@ -0,0 +1,40 @@
+use std::process::Command;
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum CiEnv {
+ /// Not a CI environment.
+ None,
+ /// The Azure Pipelines environment, for Linux (including Docker), Windows, and macOS builds.
+ AzurePipelines,
+ /// The GitHub Actions environment, for Linux (including Docker), Windows and macOS builds.
+ GitHubActions,
+}
+
+impl CiEnv {
+ /// Obtains the current CI environment.
+ pub fn current() -> CiEnv {
+ if std::env::var("TF_BUILD").map_or(false, |e| e == "True") {
+ CiEnv::AzurePipelines
+ } else if std::env::var("GITHUB_ACTIONS").map_or(false, |e| e == "true") {
+ CiEnv::GitHubActions
+ } else {
+ CiEnv::None
+ }
+ }
+
+ pub fn is_ci() -> bool {
+ Self::current() != CiEnv::None
+ }
+
+ /// If in a CI environment, forces the command to run with colors.
+ pub fn force_coloring_in_ci(self, cmd: &mut Command) {
+ if self != CiEnv::None {
+ // Due to use of stamp/docker, the output stream of rustbuild is not
+ // a TTY in CI, so coloring is by-default turned off.
+ // The explicit `TERM=xterm` environment is needed for
+ // `--color always` to actually work. This env var was lost when
+ // compiling through the Makefile. Very strange.
+ cmd.env("TERM", "xterm").args(&["--color", "always"]);
+ }
+ }
+}
diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs
new file mode 100644
index 000000000..dc62051cb
--- /dev/null
+++ b/src/tools/build_helper/src/git.rs
@@ -0,0 +1,75 @@
+use std::{path::Path, process::Command};
+
+/// Finds the remote for rust-lang/rust.
+/// For example for these remotes it will return `upstream`.
+/// ```text
+/// origin https://github.com/Nilstrieb/rust.git (fetch)
+/// origin https://github.com/Nilstrieb/rust.git (push)
+/// upstream https://github.com/rust-lang/rust (fetch)
+/// upstream https://github.com/rust-lang/rust (push)
+/// ```
+pub fn get_rust_lang_rust_remote(git_dir: Option<&Path>) -> Result<String, String> {
+ let mut git = Command::new("git");
+ if let Some(git_dir) = git_dir {
+ git.current_dir(git_dir);
+ }
+ git.args(["config", "--local", "--get-regex", "remote\\..*\\.url"]);
+
+ let output = git.output().map_err(|err| format!("{err:?}"))?;
+ if !output.status.success() {
+ return Err("failed to execute git config command".to_owned());
+ }
+
+ let stdout = String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?;
+
+ let rust_lang_remote = stdout
+ .lines()
+ .find(|remote| remote.contains("rust-lang"))
+ .ok_or_else(|| "rust-lang/rust remote not found".to_owned())?;
+
+ let remote_name =
+ rust_lang_remote.split('.').nth(1).ok_or_else(|| "remote name not found".to_owned())?;
+ Ok(remote_name.into())
+}
+
+pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result<bool, String> {
+ let mut git = Command::new("git");
+ if let Some(git_dir) = git_dir {
+ git.current_dir(git_dir);
+ }
+ git.args(["rev-parse", rev]);
+ let output = git.output().map_err(|err| format!("{err:?}"))?;
+
+ match output.status.code() {
+ Some(0) => Ok(true),
+ Some(128) => Ok(false),
+ None => {
+ return Err(format!(
+ "git didn't exit properly: {}",
+ String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
+ ));
+ }
+ Some(code) => {
+ return Err(format!(
+ "git command exited with status code: {code}: {}",
+ String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
+ ));
+ }
+ }
+}
+
+/// Returns the master branch from which we can take diffs to see changes.
+/// This will usually be rust-lang/rust master, but sometimes this might not exist.
+/// This could be because the user is updating their forked master branch using the GitHub UI
+/// and therefore doesn't need an upstream master branch checked out.
+/// We will then fall back to origin/master in the hope that at least this exists.
+pub fn updated_master_branch(git_dir: Option<&Path>) -> Result<String, String> {
+ let upstream_remote = get_rust_lang_rust_remote(git_dir)?;
+ let upstream_master = format!("{upstream_remote}/master");
+ if rev_exists(&upstream_master, git_dir)? {
+ return Ok(upstream_master);
+ }
+
+ // We could implement smarter logic here in the future.
+ Ok("origin/master".into())
+}
diff --git a/src/tools/build_helper/src/lib.rs b/src/tools/build_helper/src/lib.rs
new file mode 100644
index 000000000..d3d2323db
--- /dev/null
+++ b/src/tools/build_helper/src/lib.rs
@@ -0,0 +1,2 @@
+pub mod ci;
+pub mod git;