|  | // depstool is a command-line tool for manipulating QUICHE WORKSPACE.bazel file. | 
|  | package main | 
|  |  | 
|  | import ( | 
|  | "flag" | 
|  | "fmt" | 
|  | "io/ioutil" | 
|  | "log" | 
|  | "os" | 
|  | "time" | 
|  |  | 
|  | "github.com/bazelbuild/buildtools/build" | 
|  | "quiche.googlesource.com/quiche/depstool/deps" | 
|  | ) | 
|  |  | 
|  | func list(path string, contents []byte) { | 
|  | flags, err := deps.ParseHTTPArchiveRules(contents) | 
|  | if err != nil { | 
|  | log.Fatalf("Failed to parse %s: %v", path, err) | 
|  | } | 
|  |  | 
|  | fmt.Println("+------------------------------+--------------------------+") | 
|  | fmt.Println("|                   Dependency | Last updated             |") | 
|  | fmt.Println("+------------------------------+--------------------------+") | 
|  | for _, flag := range flags { | 
|  | lastUpdated, err := time.Parse("2006-01-02", flag.LastUpdated) | 
|  | if err != nil { | 
|  | log.Fatalf("Failed to parse date %s: %v", flag.LastUpdated, err) | 
|  | } | 
|  | delta := time.Since(lastUpdated) | 
|  | days := int(delta.Hours() / 24) | 
|  | fmt.Printf("| %28s | %s, %3d days ago |\n", flag.Name, flag.LastUpdated, days) | 
|  | } | 
|  | fmt.Println("+------------------------------+--------------------------+") | 
|  | } | 
|  |  | 
|  | func validate(path string, contents []byte) { | 
|  | file, err := build.ParseWorkspace(path, contents) | 
|  | if err != nil { | 
|  | log.Fatalf("Failed to parse the WORKSPACE.bazel file: %v", err) | 
|  | } | 
|  |  | 
|  | success := true | 
|  | for _, stmt := range file.Stmt { | 
|  | rule, ok := deps.HTTPArchiveRule(stmt) | 
|  | if !ok { | 
|  | // Skip unrelated rules | 
|  | continue | 
|  | } | 
|  | if _, err := deps.ParseHTTPArchiveRule(rule); err != nil { | 
|  | log.Printf("Failed to parse http_archive in %s on the line %d, issue: %v", path, rule.Pos.Line, err) | 
|  | success = false | 
|  | } | 
|  | } | 
|  | if !success { | 
|  | os.Exit(1) | 
|  | } | 
|  | log.Printf("All http_archive rules have been validated successfully") | 
|  | os.Exit(0) | 
|  | } | 
|  |  | 
|  | func fetch(path string, contents []byte, outdir string) { | 
|  | rules, err := deps.ParseHTTPArchiveRules(contents) | 
|  | if err != nil { | 
|  | log.Fatalf("Failed to parse %s: %v", path, err) | 
|  | } | 
|  |  | 
|  | for _, rule := range rules { | 
|  | log.Printf("Fetching %s into %s...", rule.Name, outdir) | 
|  | outfile, err := deps.FetchEntry(rule, outdir) | 
|  | if err != nil { | 
|  | log.Fatalf("Failed to fetch %s: %s", rule.Name, err) | 
|  | } | 
|  | log.Printf("Successfully fetched %s into %s", rule.Name, outfile) | 
|  | } | 
|  | } | 
|  |  | 
|  | func usage() { | 
|  | fmt.Fprintf(flag.CommandLine.Output(), ` | 
|  | usage: depstool [WORKSPACE file] [subcommand] | 
|  |  | 
|  | Available subcommands: | 
|  | list       Lists all of the rules in the file | 
|  | validate   Validates that the WORKSPACE file is parsable | 
|  | fetch      Fetches all dependencies into the specified directory | 
|  |  | 
|  | If no subcommand is specified, "list" is assumed. | 
|  | `) | 
|  | flag.PrintDefaults() | 
|  | } | 
|  |  | 
|  | func main() { | 
|  | flag.Usage = usage | 
|  | flag.Parse() | 
|  | path := flag.Arg(0) | 
|  | if path == "" { | 
|  | usage() | 
|  | os.Exit(1) | 
|  | } | 
|  | contents, err := ioutil.ReadFile(path) | 
|  | if err != nil { | 
|  | log.Fatalf("Failed to read WORKSPACE.bazel file: %v", err) | 
|  | } | 
|  |  | 
|  | subcommand := flag.Arg(1) | 
|  | switch subcommand { | 
|  | case "": | 
|  | fallthrough // list is the default action | 
|  | case "list": | 
|  | list(path, contents) | 
|  | case "validate": | 
|  | validate(path, contents) | 
|  | case "fetch": | 
|  | fetch(path, contents, flag.Arg(2)) | 
|  | default: | 
|  | log.Fatalf("Unknown command: %s", subcommand) | 
|  | } | 
|  | } |