shithub: furgit

ref: 085c9f5ab171f4ebeb6ff1d02e1067c0d48a629d
dir: /refstore/shorten.go/

View raw version
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
}