Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/gunnar

xtask/src/worktree.rs

//! Where this checkout sits relative to the repository's main working tree.
//!
//! One implementation, used by two callers that otherwise could not agree
//! (one implementation, not two): `ci`'s znippy-engine decision, which refuses rather than shrinking its
//! own scope when znippy is beside the MAIN checkout and not this one, and
//! `fmt`, which has the same problem for the same reason — several manifests
//! in this repository reach sibling repositories by relative path, and cargo
//! resolves those relative to the manifest, not to the main checkout.

use std::path::{Path, PathBuf};
use std::process::Command;

/// The main working tree of the repository at `root`, if `root` is a **linked**
/// worktree of one.
///
/// `git rev-parse --git-common-dir` is the only thing that knows: it names the
/// shared `.git` directory, whose parent is the main checkout. `None` when
/// `root` is itself the main checkout (the common dir is its own `.git`), when
/// git cannot be reached, or when the layout is not the ordinary one — every
/// one of which lands on `ZnippyCheckout::AbsentEverywhere`, i.e. exactly the
/// behaviour before this function existed.
pub fn main_worktree(root: &Path) -> Option<PathBuf> {
    let out = Command::new("git")
        .current_dir(root)
        .args(["rev-parse", "--path-format=absolute", "--git-common-dir"])
        .output()
        .ok()?;
    if !out.status.success() {
        return None;
    }
    let common = PathBuf::from(String::from_utf8_lossy(&out.stdout).trim().to_string());
    let main = common.parent()?.to_path_buf();
    // The main checkout answers with its own `.git`, so its parent is `root`
    // again. Comparing canonical paths, because `root` and the git answer can
    // spell the same directory differently through a symlink.
    let same = std::fs::canonicalize(&main).ok()? == std::fs::canonicalize(root).ok()?;
    if same {
        None
    } else {
        Some(main)
    }
}