Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions crates/but-testsupport/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ pub fn visualize_tree(tree_id: gix::Id<'_>) -> termtree::Tree<String> {
visualize_tree(tree_id.object().unwrap().peel_to_tree().unwrap().id(), None).unwrap()
}

const FILETYPE_MASK: u32 = 0o170000;

/// Visualize a tree on disk with mode information.
/// For convenience, skip `.git` and don't display the root.
///
Expand All @@ -304,20 +306,22 @@ pub fn visualize_tree(tree_id: gix::Id<'_>) -> termtree::Tree<String> {
pub fn visualize_disk_tree_skip_dot_git(root: &Path) -> anyhow::Result<termtree::Tree<String>> {
use std::os::unix::fs::MetadataExt;
fn normalize_mode(mode: u32) -> u32 {
match mode {
0o40777 => 0o40755,
0o40775 => 0o40755,
0o10664 => 0o10644,
0o10666 => 0o10644,
0o100664 => 0o100644,
0o100666 => 0o100644,
0o100775 => 0o100755,
0o100777 => 0o100755,
0o120775 => 0o120755,
0o120777 => 0o120755,
other => other,
let normalize_permission_bits = |mode: u32| if mode & 0o100 == 0 { 0o644 } else { 0o755 };

match mode & FILETYPE_MASK {
// File types Git cares about
directory @ 0o40000 => directory | normalize_permission_bits(mode),
symlink @ 0o120000 => symlink | normalize_permission_bits(mode),
Comment on lines +313 to +314
Copy link
Contributor Author

@slarse slarse Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a Git perspective it's a bit weird to propagate permission bits on directories and symlinks, as Git does not store those. But the current snapshots do so.

Do we want to "properly" normalize this to a more Git-aligned view (i.e. zero out the permission bits for these types in existing snapshots), or is this fine?

Copy link
Contributor Author

@slarse slarse Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize that if we don't care about "proper" Git normalization for the snapshots, this entire thing could be reduced to just:

    fn normalize_mode(mode: u32) -> u32 {
        let normalize_permission_bits = |mode: u32| if mode & 0o100 == 0 { 0o644 } else { 0o755 };
        (mode & 0o170000) | normalize_permission_bits(mode)
    }

Because every match arm is just doing the same thing right now, except for the panic, which I don't feel strongly about keeping.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, why not go with the minimal version that also can't panic. Let's merge this as well and you can follow it up.

Copy link
Contributor Author

@slarse slarse Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Byron Your word is my law, here's the followup: #11389

I had too much fun playing with bits not to do it...

regular_file @ 0o100000 => regular_file | normalize_permission_bits(mode),

// File types Git does not care about. These may still appear in the worktree.
// Note: Add more file types here if needed (e.g. socket, block device, etc)
fifo @ 0o10000 => fifo | normalize_permission_bits(mode),

_ => panic!("Unhandled file mode {mode}"),
}
}

fn label(p: &Path, md: &std::fs::Metadata) -> String {
format!(
"{name}:{mode:o}",
Expand Down
Loading