diff --git a/mullvad-version/build.rs b/mullvad-version/build.rs index 008ec8d104e1..6b923253e3ee 100644 --- a/mullvad-version/build.rs +++ b/mullvad-version/build.rs @@ -52,15 +52,24 @@ fn get_product_version(target: Target) -> String { Target::Desktop => DESKTOP_VERSION_FILE_PATH, }; println!("cargo:rerun-if-changed={version_file_path}"); - let version = fs::read_to_string(version_file_path) + let product_version = fs::read_to_string(version_file_path) .unwrap_or_else(|_| panic!("Failed to read {version_file_path}")) .trim() .to_owned(); - if let Some(dev_suffix) = get_dev_suffix(target, &version) { - format!("{version}{dev_suffix}") + // 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(), + }; + + rerun_if_git_ref_changed(&release_tag) + .expect("Failed to set 'cargo:rerun-if-changed' on git ref changes"); + + if let Some(dev_suffix) = get_dev_suffix(&product_version) { + format!("{product_version}{dev_suffix}") } else { - version + product_version } } @@ -68,13 +77,26 @@ fn get_product_version(target: Target) -> String { /// suffix if the build is not done on a git tag named `product_version`. /// This also returns `None` if the `git` command can't run, or the code does /// not live in a git repository. -fn get_dev_suffix(target: Target, product_version: &str) -> Option { - // 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(), - }; +fn get_dev_suffix(release_tag: &str) -> Option { + // Get the git commit hashes for the latest release and current HEAD + // Return `None` if unable to find the hash for HEAD. + let head_commit_hash = git_rev_parse_commit_hash("HEAD")?; + 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 Some(&head_commit_hash) == product_version_commit_hash.as_ref() { + return None; + } + Some(format!( + "-dev-{}", + &head_commit_hash[..GIT_HASH_DEV_SUFFIX_LEN] + )) +} +/// 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`). +fn rerun_if_git_ref_changed(release_tag: &str) -> std::io::Result<()> { let git_dir = Path::new("..").join(".git"); // If we build our output on information about HEAD we need to re-run if HEAD moves @@ -83,45 +105,35 @@ fn get_dev_suffix(target: Target, product_version: &str) -> Option { println!("cargo:rerun-if-changed={}", head_path.display()); } + // If we build our output on information about the ref of the current branch, we need to re-run + // on changes to it let output = Command::new("git") .arg("branch") .arg("--show-current") - .output() - .ok()?; - let current_branch = String::from_utf8(output.stdout).unwrap(); - // If we build our output on information about a git reference, we need to re-run - // if it moves. Instead of trying to be smart, just re-run if any git reference moves. - let git_current_branch_ref = git_dir - .join("refs") - .join("heads") - .join(current_branch.trim()); - if git_current_branch_ref.exists() { - println!( - "cargo:rerun-if-changed={}", - git_current_branch_ref.display() - ); - } - let git_current_branch_ref = git_dir.join("refs").join("tags").join(&release_tag); - if git_current_branch_ref.exists() { - println!( - "cargo:rerun-if-changed={}", - git_current_branch_ref.display() - ); - } + .output()?; - // Get the git commit hashes for the latest release and current HEAD - // Return `None` if unable to find the hash for HEAD. - let head_commit_hash = git_rev_parse_commit_hash("HEAD")?; - let product_version_commit_hash = git_rev_parse_commit_hash(&release_tag); + let current_branch = String::from_utf8(output.stdout).unwrap(); + let current_branch = current_branch.trim(); - // If we are currently building the release tag, there is no dev suffix - if Some(&head_commit_hash) == product_version_commit_hash.as_ref() { - return None; + // When in 'detached HEAD' state, the output will be empty. However, in that case we already get + // the ref from `.git/HEAD`, so we can safely skip this part. + if !current_branch.is_empty() { + let git_current_branch_ref = git_dir.join("refs").join("heads").join(current_branch); + if git_current_branch_ref.exists() { + println!( + "cargo:rerun-if-changed={}", + git_current_branch_ref.display() + ); + } } - Some(format!( - "-dev-{}", - &head_commit_hash[..GIT_HASH_DEV_SUFFIX_LEN] - )) + + // To rebuild in the case where the release tag moves to the current commit, we need to track + // changes to it + let git_release_tag_ref = git_dir.join("refs").join("tags").join(release_tag); + if git_release_tag_ref.exists() { + println!("cargo:rerun-if-changed={}", git_release_tag_ref.display()); + }; + Some(()) } /// Returns the commit hash for the commit that `git_ref` is pointing to.