diff options
Diffstat (limited to 'refstore/shorten.go')
| -rw-r--r-- | refstore/shorten.go | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/refstore/shorten.go b/refstore/shorten.go new file mode 100644 index 00000000..26fa82c0 --- /dev/null +++ b/refstore/shorten.go @@ -0,0 +1,74 @@ +package refstore + +import "strings" + +type shortenRule struct { + prefix string + suffix string +} + +var shortenRules = [...]shortenRule{ + {prefix: "", suffix: ""}, + {prefix: "refs/", suffix: ""}, + {prefix: "refs/tags/", suffix: ""}, + {prefix: "refs/heads/", suffix: ""}, + {prefix: "refs/remotes/", suffix: ""}, + {prefix: "refs/remotes/", suffix: "/HEAD"}, +} + +func (rule shortenRule) match(name string) (string, bool) { + if !strings.HasPrefix(name, rule.prefix) { + return "", false + } + if !strings.HasSuffix(name, rule.suffix) { + return "", false + } + short := strings.TrimPrefix(name, rule.prefix) + short = strings.TrimSuffix(short, rule.suffix) + if short == "" { + return "", false + } + if rule.prefix+short+rule.suffix != name { + return "", false + } + return short, true +} + +func (rule shortenRule) render(short string) string { + return rule.prefix + short + rule.suffix +} + +// ShortenName returns the shortest unambiguous shorthand for name among all. +// +// all must contain full reference names visible to the shortening scope. +func ShortenName(name string, all []string) string { + names := make(map[string]struct{}, len(all)) + for _, full := range all { + if full == "" { + continue + } + names[full] = struct{}{} + } + + for i := len(shortenRules) - 1; i > 0; i-- { + short, ok := shortenRules[i].match(name) + if !ok { + continue + } + ambiguous := false + for j := range shortenRules { + if j == i { + continue + } + full := shortenRules[j].render(short) + if _, found := names[full]; found { + ambiguous = true + break + } + } + if !ambiguous { + return short + } + } + return name +} |
