| package toolbase | 
 |  | 
 | import ( | 
 | 	"fmt" | 
 | 	"regexp" | 
 | 	"strings" | 
 | ) | 
 |  | 
 | // BazelLabel is a label, as defined by Bazel's documentation: | 
 | // | 
 | // https://docs.bazel.build/versions/main/skylark/lib/Label.html | 
 | type BazelLabel struct { | 
 | 	WorkspaceName string | 
 | 	PackagePath   []string | 
 | 	Name          string | 
 | } | 
 |  | 
 | func (b BazelLabel) Package() string { | 
 | 	return strings.Join(b.PackagePath, "/") | 
 | } | 
 |  | 
 | func (b BazelLabel) String() string { | 
 | 	return fmt.Sprintf("@%s//%s:%s", b.WorkspaceName, b.Package(), b.Name) | 
 | } | 
 |  | 
 | var ( | 
 | 	// reLabel splits a Bazel label into a workspace name (if set) and a | 
 | 	// workspace root relative package/name. | 
 | 	reLabel = regexp.MustCompile(`^(@[^:/]+)?//(.+)$`) | 
 | 	// rePathPart matches valid label path parts. | 
 | 	rePathPart = regexp.MustCompile(`^[^:/]+$`) | 
 | ) | 
 |  | 
 | // ParseBazelLabel converts parses a string representation of a Bazel Label. If | 
 | // the given representation is invalid or for some other reason unparseable, | 
 | // nil is returned. | 
 | func ParseBazelLabel(s string) *BazelLabel { | 
 | 	res := BazelLabel{ | 
 | 		WorkspaceName: "dev_source_monogon", | 
 | 	} | 
 |  | 
 | 	// Split label into workspace name (if set) and a workspace root relative | 
 | 	// package/name. | 
 | 	m := reLabel.FindStringSubmatch(s) | 
 | 	if m == nil { | 
 | 		return nil | 
 | 	} | 
 | 	packageRel := m[2] | 
 | 	if m[1] != "" { | 
 | 		res.WorkspaceName = m[1][1:] | 
 | 	} | 
 |  | 
 | 	// Split path by ':', which is the target name delimiter. If it appears | 
 | 	// exactly once, interpret everything to its right as the target name. | 
 | 	targetSplit := strings.Split(packageRel, ":") | 
 | 	switch len(targetSplit) { | 
 | 	case 1: | 
 | 	case 2: | 
 | 		packageRel = targetSplit[0] | 
 | 		res.Name = targetSplit[1] | 
 | 		if !rePathPart.MatchString(res.Name) { | 
 | 			return nil | 
 | 		} | 
 | 	default: | 
 | 		return nil | 
 | 	} | 
 |  | 
 | 	// Split the package path by /, and if the name was not explicitly given, | 
 | 	// use the last element of the package path. | 
 | 	if packageRel == "" { | 
 | 		res.PackagePath = nil | 
 | 	} else { | 
 | 		res.PackagePath = strings.Split(packageRel, "/") | 
 | 	} | 
 | 	if res.Name == "" { | 
 | 		res.Name = res.PackagePath[len(res.PackagePath)-1] | 
 | 	} | 
 |  | 
 | 	// Ensure all parts of the package path are valid. | 
 | 	for _, p := range res.PackagePath { | 
 | 		if !rePathPart.MatchString(p) { | 
 | 			return nil | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return &res | 
 | } |