shepherd-registry 6.7.0

The shepherd registry: the SQLite schema, migration runner, and query surface that every harness reads directly.
//! One canonical display spelling for registry-owned filesystem identity.

use std::path::{Component, Path, Prefix};

/// Render a path with `/` separators and without a Windows verbatim prefix.
///
/// The registry uses this spelling both for durable layout manifests and when
/// comparing a caller's already-canonical path with `fs::canonicalize`. On
/// Windows, `canonicalize` normally adds `\\?\` even when the caller supplied
/// the same directory as `C:\...`; treating that representation change as an
/// alias made every repair path fail. Building from components also preserves
/// a literal backslash in a Unix filename.
pub(crate) fn canonical_path_string(path: &Path) -> String {
    let mut rendered = String::new();
    for component in path.components() {
        match component {
            Component::Prefix(prefix) => {
                let text = match prefix.kind() {
                    Prefix::VerbatimDisk(letter) => format!("{}:", char::from(letter)),
                    Prefix::VerbatimUNC(server, share) => {
                        format!("//{}/{}", server.to_string_lossy(), share.to_string_lossy())
                    }
                    Prefix::Verbatim(name) => name.to_string_lossy().into_owned(),
                    _ => prefix.as_os_str().to_string_lossy().replace('\\', "/"),
                };
                rendered.push_str(&text);
            }
            Component::RootDir => {
                if !rendered.ends_with('/') {
                    rendered.push('/');
                }
            }
            other => {
                if !rendered.is_empty() && !rendered.ends_with('/') {
                    rendered.push('/');
                }
                rendered.push_str(&other.as_os_str().to_string_lossy());
            }
        }
    }
    rendered
}

#[cfg(test)]
mod tests {
    use super::canonical_path_string;
    use std::path::Path;

    #[cfg(unix)]
    #[test]
    fn unix_backslash_remains_a_filename_character() {
        assert_eq!(canonical_path_string(Path::new(r"/a/b\c")), r"/a/b\c");
    }

    #[cfg(windows)]
    #[test]
    fn plain_and_verbatim_disk_paths_share_one_identity_spelling() {
        assert_eq!(
            canonical_path_string(Path::new(r"C:\Users\runner\project")),
            canonical_path_string(Path::new(r"\\?\C:\Users\runner\project")),
        );
        assert_eq!(
            canonical_path_string(Path::new(r"\\?\C:\Users\runner\project")),
            "C:/Users/runner/project"
        );
    }
}