1// depstool is a command-line tool for manipulating QUICHE WORKSPACE.bazel file. 2package main 3 4import ( 5 "flag" 6 "fmt" 7 "io/ioutil" 8 "log" 9 "os" 10 "time" 11 12 "github.com/bazelbuild/buildtools/build" 13 "quiche.googlesource.com/quiche/depstool/deps" 14) 15 16func list(path string, contents []byte) { 17 flags, err := deps.ParseHTTPArchiveRules(contents) 18 if err != nil { 19 log.Fatalf("Failed to parse %s: %v", path, err) 20 } 21 22 fmt.Println("+------------------------------+--------------------------+") 23 fmt.Println("| Dependency | Last updated |") 24 fmt.Println("+------------------------------+--------------------------+") 25 for _, flag := range flags { 26 lastUpdated, err := time.Parse("2006-01-02", flag.LastUpdated) 27 if err != nil { 28 log.Fatalf("Failed to parse date %s: %v", flag.LastUpdated, err) 29 } 30 delta := time.Since(lastUpdated) 31 days := int(delta.Hours() / 24) 32 fmt.Printf("| %28s | %s, %3d days ago |\n", flag.Name, flag.LastUpdated, days) 33 } 34 fmt.Println("+------------------------------+--------------------------+") 35} 36 37func validate(path string, contents []byte) { 38 file, err := build.ParseWorkspace(path, contents) 39 if err != nil { 40 log.Fatalf("Failed to parse the WORKSPACE.bazel file: %v", err) 41 } 42 43 success := true 44 for _, stmt := range file.Stmt { 45 rule, ok := deps.HTTPArchiveRule(stmt) 46 if !ok { 47 // Skip unrelated rules 48 continue 49 } 50 if _, err := deps.ParseHTTPArchiveRule(rule); err != nil { 51 log.Printf("Failed to parse http_archive in %s on the line %d, issue: %v", path, rule.Pos.Line, err) 52 success = false 53 } 54 } 55 if !success { 56 os.Exit(1) 57 } 58 log.Printf("All http_archive rules have been validated successfully") 59 os.Exit(0) 60} 61 62func fetch(path string, contents []byte, outdir string) { 63 rules, err := deps.ParseHTTPArchiveRules(contents) 64 if err != nil { 65 log.Fatalf("Failed to parse %s: %v", path, err) 66 } 67 68 for _, rule := range rules { 69 log.Printf("Fetching %s into %s...", rule.Name, outdir) 70 outfile, err := deps.FetchEntry(rule, outdir) 71 if err != nil { 72 log.Fatalf("Failed to fetch %s: %s", rule.Name, err) 73 } 74 log.Printf("Successfully fetched %s into %s", rule.Name, outfile) 75 } 76} 77 78func usage() { 79 fmt.Fprintf(flag.CommandLine.Output(), ` 80usage: depstool [WORKSPACE file] [subcommand] 81 82Available subcommands: 83 list Lists all of the rules in the file 84 validate Validates that the WORKSPACE file is parsable 85 fetch Fetches all dependencies into the specified directory 86 87If no subcommand is specified, "list" is assumed. 88`) 89 flag.PrintDefaults() 90} 91 92func main() { 93 flag.Usage = usage 94 flag.Parse() 95 path := flag.Arg(0) 96 if path == "" { 97 usage() 98 os.Exit(1) 99 } 100 contents, err := ioutil.ReadFile(path) 101 if err != nil { 102 log.Fatalf("Failed to read WORKSPACE.bazel file: %v", err) 103 } 104 105 subcommand := flag.Arg(1) 106 switch subcommand { 107 case "": 108 fallthrough // list is the default action 109 case "list": 110 list(path, contents) 111 case "validate": 112 validate(path, contents) 113 case "fetch": 114 fetch(path, contents, flag.Arg(2)) 115 default: 116 log.Fatalf("Unknown command: %s", subcommand) 117 } 118} 119