|  | // Package deps package provides methods to extract and manipulate external code dependencies from the QUICHE WORKSPACE.bazel file. | 
|  | package deps | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "regexp" | 
|  |  | 
|  | "github.com/bazelbuild/buildtools/build" | 
|  | ) | 
|  |  | 
|  | var lastUpdatedRE = regexp.MustCompile(`Last updated (\d{4}-\d{2}-\d{2})`) | 
|  |  | 
|  | // Entry is a parsed representation of a dependency entry in the WORKSPACE.bazel file. | 
|  | type Entry struct { | 
|  | Name        string | 
|  | SHA256      string | 
|  | Prefix      string | 
|  | URL         string | 
|  | LastUpdated string | 
|  | } | 
|  |  | 
|  | // HTTPArchiveRule returns a CallExpr describing the provided http_archive | 
|  | // rule, or nil if the expr in question is not an http_archive rule. | 
|  | func HTTPArchiveRule(expr build.Expr) (*build.CallExpr, bool) { | 
|  | callexpr, ok := expr.(*build.CallExpr) | 
|  | if !ok { | 
|  | return nil, false | 
|  | } | 
|  | name, ok := callexpr.X.(*build.Ident) | 
|  | if !ok || name.Name != "http_archive" { | 
|  | return nil, false | 
|  | } | 
|  | return callexpr, true | 
|  | } | 
|  |  | 
|  | func parseString(expr build.Expr) (string, error) { | 
|  | str, ok := expr.(*build.StringExpr) | 
|  | if !ok { | 
|  | return "", fmt.Errorf("expected string as the function argument") | 
|  | } | 
|  | return str.Value, nil | 
|  | } | 
|  |  | 
|  | func parseSingleElementList(expr build.Expr) (string, error) { | 
|  | list, ok := expr.(*build.ListExpr) | 
|  | if !ok { | 
|  | return "", fmt.Errorf("expected a list as the function argument") | 
|  | } | 
|  | if len(list.List) != 1 { | 
|  | return "", fmt.Errorf("expected a single-element list as the function argument, got %d elements", len(list.List)) | 
|  | } | 
|  | return parseString(list.List[0]) | 
|  | } | 
|  |  | 
|  | // ParseHTTPArchiveRule parses the provided http_archive rule and returns all of the dependency metadata embedded. | 
|  | func ParseHTTPArchiveRule(callexpr *build.CallExpr) (*Entry, error) { | 
|  | result := Entry{} | 
|  | for _, arg := range callexpr.List { | 
|  | assign, ok := arg.(*build.AssignExpr) | 
|  | if !ok { | 
|  | return nil, fmt.Errorf("a non-named argument passed as a function parameter") | 
|  | } | 
|  | argname, _ := build.GetParamName(assign.LHS) | 
|  | var err error = nil | 
|  | switch argname { | 
|  | case "name": | 
|  | result.Name, err = parseString(assign.RHS) | 
|  | case "sha256": | 
|  | result.SHA256, err = parseString(assign.RHS) | 
|  |  | 
|  | if len(assign.Comments.Suffix) != 1 { | 
|  | return nil, fmt.Errorf("missing the \"Last updated\" comment on the sha256 field") | 
|  | } | 
|  | comment := assign.Comments.Suffix[0].Token | 
|  | match := lastUpdatedRE.FindStringSubmatch(comment) | 
|  | if match == nil { | 
|  | return nil, fmt.Errorf("unable to parse the \"Last updated\" comment, comment value: %s", comment) | 
|  | } | 
|  | result.LastUpdated = match[1] | 
|  | case "strip_prefix": | 
|  | result.Prefix, err = parseString(assign.RHS) | 
|  | case "urls": | 
|  | result.URL, err = parseSingleElementList(assign.RHS) | 
|  | default: | 
|  | continue | 
|  | } | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | } | 
|  | if result.Name == "" { | 
|  | return nil, fmt.Errorf("missing the name field") | 
|  | } | 
|  | if result.SHA256 == "" { | 
|  | return nil, fmt.Errorf("missing the sha256 field") | 
|  | } | 
|  | if result.URL == "" { | 
|  | return nil, fmt.Errorf("missing the urls field") | 
|  | } | 
|  | return &result, nil | 
|  | } | 
|  |  | 
|  | // ParseHTTPArchiveRules parses the entire WORKSPACE.bazel file and returns all of the http_archive rules in it. | 
|  | func ParseHTTPArchiveRules(source []byte) ([]*Entry, error) { | 
|  | file, err := build.ParseWorkspace("WORKSPACE.bazel", source) | 
|  | if err != nil { | 
|  | return []*Entry{}, err | 
|  | } | 
|  |  | 
|  | result := make([]*Entry, 0) | 
|  | for _, expr := range file.Stmt { | 
|  | callexpr, ok := HTTPArchiveRule(expr) | 
|  | if !ok { | 
|  | continue | 
|  | } | 
|  | parsed, err := ParseHTTPArchiveRule(callexpr) | 
|  | if err != nil { | 
|  | return []*Entry{}, err | 
|  | } | 
|  | result = append(result, parsed) | 
|  | } | 
|  | return result, nil | 
|  | } |