1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//! Duplicate-`dst` detector for a single pack's `symlink` actions.
//!
//! Per pack-spec patch 3, two or more `symlink` actions within the same
//! pack whose `dst` literals collide are a **plan-phase error**. The
//! check is pre-expansion: we compare the authored string verbatim, not
//! the post-variable-expansion filesystem path. Any environment-variable
//! mismatch (e.g. `$HOME/a` vs `/home/user/a`) is a separate slice.
//!
//! # Emission policy (all-pairs)
//!
//! For `n` symlinks sharing the same `dst`, the validator emits
//! `n * (n - 1) / 2` errors — one per unordered pair. This surfaces the
//! full conflict graph to the CLI so an author renaming one entry can see
//! exactly which others it was colliding against, rather than replaying
//! after each fix. Indices are the flattened action-walk positions
//! produced by [`PackManifest::iter_all_symlinks`].
//!
//! # Platform-aware collision key
//!
//! The bucket key is platform-folded before comparison:
//!
//! * **Windows** and **macOS** — ASCII-lowercased so `FOO` and `foo`
//! collide (NTFS is case-insensitive by default; APFS and HFS+ on
//! macOS default to case-insensitive too).
//! * **Other Unix** — byte-exact, matching typical case-sensitive
//! filesystems.
//!
//! Full Unicode case-folding is not applied; the overhead is not
//! justified for the rare pack `dst` that relies on non-ASCII casing.
//! APFS can be reformatted case-sensitive; this validator stays
//! pessimistic in that rare configuration (it may flag a non-collision
//! the filesystem would actually accept). Probing filesystem
//! case-sensitivity is a future enhancement. The error message carries
//! the **original** authored `dst`, not the folded form.
use BTreeMap;
use ;
use cratePackManifest;
/// Flags duplicate literal `dst` strings across all symlink actions in a
/// pack (including those nested inside `when` blocks).
///
/// See the module docs for the all-pairs emission rationale.
;
/// Canonicalise a `dst` literal for collision bucketing.
///
/// Case-folds on Windows and macOS (whose default filesystems are
/// case-insensitive), and passes bytes through unchanged elsewhere. See
/// the module docs for the full rationale and caveats.