Skip to content

read_directory/walk_directory should return entries in name order, making enumeration determinism structural #179

Description

@typeless

Summary

readdir order is the one place filesystem nondeterminism enters putup. Today every consumer is responsible for canonicalizing it, which is a conventional invariant — and two of the five consumers got it wrong (#171, #175).

Consumers of pup::platform::read_directory / walk_directory:

site status
src/parser/glob.cpp:230,243 was readdir-ordered → fixed in #174
src/core/layout.cpp:208 was readdir-ordered → fixed in #176
src/cli/context.cpp:237 benign: handle sort is a set structure, iteration order re-derived by content in sort_dirs_by_depth
src/cli/target.cpp:162 unsorted, currently unobservable: variants are content-sorted at multi_variant.cpp:76 before use

Proposal

Sort entries by name inside read_directory, and per-directory inside walk_directory before visiting and recursing. Then enumeration order is a function of directory content at the one site that produces it (count=1), instead of at each consumer that happens to remember.

This is what the equivalent boundary in tup already provides: listings come out of node_dir_index (dir, name).

What it does not replace

Boundary sorting gives determinism, not canonical path order, for recursive walks: DFS pre-order over per-directory sorted entries is not lexicographic — sub.txt sorts before sub/a.txt as a string, but the walk emits sub/a.txt first because it descends sub when it reaches it. So glob_expand's own sort stays necessary and is not made redundant by this change.

Cost

One sort per directory read. walk_directory is on the project-discovery path; the existing guarantee that it interns no per-entry strings (test_platform_file_io.cpp) is unaffected, since sorting compares the name views already in the listing.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TLob4Ef3qyMd3Dnp9q3XmA

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions