FindNameCollisions detects skills whose Name fields collide (meaning they would be installed to the same directory) and returns a sorted slice of collisions. Skills are installed flat by Name, so two skills with the same Name but different Namespace values still conflict. Callers decide how to prese
(skills []Skill)
| 19 | // Name but different Namespace values still conflict. Callers decide how to |
| 20 | // present the conflict to the user. |
| 21 | func FindNameCollisions(skills []Skill) []NameCollision { |
| 22 | byName := make(map[string][]Skill) |
| 23 | for _, s := range skills { |
| 24 | byName[s.Name] = append(byName[s.Name], s) |
| 25 | } |
| 26 | |
| 27 | var collisions []NameCollision |
| 28 | for name, group := range byName { |
| 29 | if len(group) <= 1 { |
| 30 | continue |
| 31 | } |
| 32 | names := make([]string, len(group)) |
| 33 | for i, s := range group { |
| 34 | names[i] = s.DisplayName() |
| 35 | } |
| 36 | collisions = append(collisions, NameCollision{Name: name, DisplayNames: names}) |
| 37 | } |
| 38 | |
| 39 | sort.Slice(collisions, func(i, j int) bool { |
| 40 | return collisions[i].Name < collisions[j].Name |
| 41 | }) |
| 42 | return collisions |
| 43 | } |
| 44 | |
| 45 | // FormatCollisions builds a human-readable string listing each collision, |
| 46 | // suitable for embedding in an error message. Each collision is formatted as |