mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-21 06:11:31 +08:00
fix(core): resolve git metadata in worktrees
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
This commit is contained in:
@@ -4,16 +4,20 @@
|
||||
use std::env;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[path = "build_support/git.rs"]
|
||||
mod git;
|
||||
|
||||
const PROTO_REL: &str = "../../proto";
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
|
||||
|
||||
// --- Git-derived version ---
|
||||
// Compute a version from `git describe` for local builds. In Docker/CI
|
||||
// builds where .git is absent, this silently does nothing and the binary
|
||||
// falls back to CARGO_PKG_VERSION (which is already sed-patched by the
|
||||
// build pipeline).
|
||||
println!("cargo:rerun-if-changed=../../.git/HEAD");
|
||||
println!("cargo:rerun-if-changed=../../.git/refs/tags");
|
||||
git::emit_rerun_if_changed(&manifest_dir);
|
||||
|
||||
if let Some(version) = git_version() {
|
||||
println!("cargo:rustc-env=OPENSHELL_GIT_VERSION={version}");
|
||||
@@ -33,7 +37,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
env::set_var("PROTOC", protobuf_src::protoc());
|
||||
}
|
||||
|
||||
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
|
||||
let proto_root = manifest_dir.join(PROTO_REL);
|
||||
|
||||
let mut proto_files = Vec::new();
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
const WATCH_PATHS: [&str; 2] = ["HEAD", "refs/tags"];
|
||||
|
||||
#[cfg(not(test))]
|
||||
pub fn emit_rerun_if_changed(manifest_dir: &Path) {
|
||||
for path in watch_paths(manifest_dir) {
|
||||
println!("cargo:rerun-if-changed={}", path.display());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn watch_paths(manifest_dir: &Path) -> Vec<PathBuf> {
|
||||
WATCH_PATHS
|
||||
.into_iter()
|
||||
.filter_map(|path| resolve_existing_git_path(manifest_dir, path))
|
||||
.collect::<BTreeSet<_>>()
|
||||
.into_iter()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn resolve_existing_git_path(manifest_dir: &Path, path: &str) -> Option<PathBuf> {
|
||||
let output = Command::new("git")
|
||||
.args(["rev-parse", "--git-path", path])
|
||||
.current_dir(manifest_dir)
|
||||
.output()
|
||||
.ok()?;
|
||||
|
||||
if !output.status.success() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let path = PathBuf::from(String::from_utf8(output.stdout).ok()?.trim());
|
||||
let path = if path.is_absolute() {
|
||||
path
|
||||
} else {
|
||||
manifest_dir.join(path)
|
||||
};
|
||||
|
||||
path.exists().then_some(path)
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[path = "../build_support/git.rs"]
|
||||
mod git;
|
||||
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
fn run_git(repo: &Path, args: &[&str]) -> String {
|
||||
let output = Command::new("git")
|
||||
.arg("-C")
|
||||
.arg(repo)
|
||||
.args(args)
|
||||
.output()
|
||||
.expect("run git");
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"git {args:?} failed: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
String::from_utf8(output.stdout)
|
||||
.expect("git output is UTF-8")
|
||||
.trim()
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn init_repository() -> (tempfile::TempDir, PathBuf) {
|
||||
let temp = tempfile::tempdir().expect("create temp directory");
|
||||
let repo = temp.path().join("repo");
|
||||
fs::create_dir(&repo).expect("create repository directory");
|
||||
|
||||
run_git(&repo, &["init", "--quiet"]);
|
||||
run_git(&repo, &["config", "user.name", "OpenShell Test"]);
|
||||
run_git(
|
||||
&repo,
|
||||
&["config", "user.email", "openshell@example.invalid"],
|
||||
);
|
||||
fs::write(repo.join("README.md"), "test\n").expect("write tracked file");
|
||||
run_git(&repo, &["add", "README.md"]);
|
||||
run_git(&repo, &["commit", "--quiet", "-m", "initial"]);
|
||||
run_git(&repo, &["tag", "v0.0.1"]);
|
||||
|
||||
(temp, repo)
|
||||
}
|
||||
|
||||
fn git_path(repo: &Path, path: &str) -> PathBuf {
|
||||
let path = PathBuf::from(run_git(repo, &["rev-parse", "--git-path", path]));
|
||||
if path.is_absolute() {
|
||||
path
|
||||
} else {
|
||||
repo.join(path)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolves_metadata_paths_in_normal_checkout() {
|
||||
let (_temp, repo) = init_repository();
|
||||
|
||||
let paths = git::watch_paths(&repo);
|
||||
|
||||
assert!(paths.contains(&git_path(&repo, "HEAD")));
|
||||
assert!(paths.contains(&git_path(&repo, "refs/tags")));
|
||||
assert!(paths.iter().all(|path| path.exists()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolves_metadata_paths_in_linked_worktree() {
|
||||
let (temp, repo) = init_repository();
|
||||
let worktree = temp.path().join("linked");
|
||||
let worktree_arg = worktree.to_str().expect("worktree path is UTF-8");
|
||||
run_git(
|
||||
&repo,
|
||||
&["worktree", "add", "--quiet", "-b", "linked", worktree_arg],
|
||||
);
|
||||
|
||||
let paths = git::watch_paths(&worktree);
|
||||
let head = git_path(&worktree, "HEAD");
|
||||
|
||||
assert!(paths.contains(&head));
|
||||
assert_ne!(head, worktree.join(".git/HEAD"));
|
||||
assert!(paths.contains(&git_path(&worktree, "refs/tags")));
|
||||
assert!(paths.iter().all(|path| path.exists()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignores_source_tree_without_git_metadata() {
|
||||
let temp = tempfile::tempdir().expect("create temp directory");
|
||||
|
||||
assert!(git::watch_paths(temp.path()).is_empty());
|
||||
}
|
||||
Reference in New Issue
Block a user