|  | 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 | 
|  | } |