diff --git a/mullvad-version/build.rs b/mullvad-version/build.rs index 3485f175ecc6..45366ef9add0 100644 --- a/mullvad-version/build.rs +++ b/mullvad-version/build.rs @@ -32,8 +32,8 @@ impl Target { } fn main() { - let product_version = compute_product_version(Target::current_target()); - let android_product_version = compute_product_version(Target::Android); + let product_version = get_product_version(Target::current_target()); + let android_product_version = get_product_version(Target::Android); let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); fs::write(out_dir.join("product-version.txt"), product_version).unwrap(); @@ -47,64 +47,61 @@ fn main() { /// Computes the Mullvad product version using the latest release on the given platform and the git /// hash pointed to by `HEAD`. Also triggers a rebuild of this crate when the information becomes /// outdated. -fn compute_product_version(target: Target) -> String { +fn get_product_version(target: Target) -> String { let version_file_path = match target { Target::Android => ANDROID_VERSION_FILE_PATH, Target::Desktop => DESKTOP_VERSION_FILE_PATH, }; println!("cargo:rerun-if-changed={version_file_path}"); - let product_version = fs::read_to_string(version_file_path) + + let release_version = fs::read_to_string(version_file_path) .unwrap_or_else(|_| panic!("Failed to read {version_file_path}")) .trim() .to_owned(); // Compute the expected tag name for the release named `product_version` let release_tag = match target { - Target::Android => format!("android/{product_version}"), - Target::Desktop => product_version.to_owned(), + Target::Android => format!("android/{release_version}"), + Target::Desktop => release_version.to_owned(), }; + format!("{release_version}{}", get_suffix(&release_tag)) +} + +/// Returns the suffix for the current build. If the build is done on a git tag named +/// `product_version`, the suffix is empty. Otherwise, `-dev-$hash` is appended to the +/// release version, or `-dev-unknown` when a git hash cannot be found. +fn get_suffix(release_tag: &str) -> String { + if !valid_git_repo() { + return "-dev-unknown".to_owned(); + }; // Rerun this build script on changes to the git ref that affects the build version. // NOTE: This must be kept up to date with the behavior of `git_rev_parse_commit_hash`. - // If an error is returned, we are not in a repository and a proper release version cannot be - // built. - if let Err(()) = rerun_if_git_ref_changed(&release_tag) { - return format!("{release_tag}-dev-local"); - }; - - // Get the git commit hashes for the latest release and current HEAD - let head_commit_hash = git_rev_parse_commit_hash("HEAD"); - let product_version_commit_hash = git_rev_parse_commit_hash(&release_tag); + rerun_if_git_ref_changed(release_tag); + let head_commit_hash = + git_rev_parse_commit_hash("HEAD").expect("Failed to run `git rev-parse HEAD^{{commit}}`"); + let product_version_commit_hash = git_rev_parse_commit_hash(release_tag); // If we are currently building the release tag, there is no dev suffix - if head_commit_hash == product_version_commit_hash { - product_version + if Some(&head_commit_hash) == product_version_commit_hash.as_ref() { + String::new() } else { - format!( - "{release_tag}-dev-{}", - &head_commit_hash[..GIT_HASH_DEV_SUFFIX_LEN] - ) + format!("-dev-{}", &head_commit_hash[..GIT_HASH_DEV_SUFFIX_LEN]) } } +fn valid_git_repo() -> bool { + matches!(Command::new("git").arg("status").status(), Ok(status) if status.success()) +} + /// Trigger rebuild of `mullvad-version` on changing branch (`.git/HEAD`), on changes to the ref of /// the current branch (`.git/refs/heads/$current_branch`) and on changes to the ref of the current /// release tag (`.git/refs/tags/$current_release_tag`). /// /// Returns an error if not in a git repository, or the git binary is not in `PATH`. -fn rerun_if_git_ref_changed(release_tag: &str) -> Result<(), ()> { +fn rerun_if_git_ref_changed(release_tag: &str) { let git_dir = Path::new("..").join(".git"); - if !git_dir.exists() { - return Err(()); - } - - // Check that `git` can be executed - match Command::new("git").arg("--version").status() { - Ok(status) if status.success() => {} - _ => return Err(()), - }; - // The `.git/HEAD` file contains the position of the current head. If in 'detached HEAD' state, // this will be the ref of the current commit. If on a branch it will just point to it, e.g. // `ref: refs/heads/main`. Tracking changes to this file will tell us if we change branch, or @@ -150,21 +147,17 @@ fn rerun_if_git_ref_changed(release_tag: &str) -> Result<(), ()> { // track this file, however, as any changes to the current branch, 'detached HEAD' state // or tags will update the corresponding `.git/refs` file we are tracking, even if it had // previously been pruned. - - Ok(()) } /// Returns the commit hash for the commit that `git_ref` is pointing to. -fn git_rev_parse_commit_hash(git_ref: &str) -> String { +fn git_rev_parse_commit_hash(git_ref: &str) -> Option { let output = Command::new("git") .arg("rev-parse") .arg(format!("{git_ref}^{{commit}}")) .output() .expect("Failed to run `git rev-parse`"); - let stdout = String::from_utf8(output.stdout).unwrap(); if !output.status.success() { - let stderr = String::from_utf8(output.stderr).unwrap(); - panic!("Command `git rev-parse` failed:\nstdout: {stdout}\nstderr: {stderr}"); + return None; } - stdout.trim().to_owned() + Some(String::from_utf8(output.stdout).unwrap().trim().to_owned()) }