github.com/quay/claircore@v1.5.28/test/bisect/main.go (about) 1 // Bisect is a git bisect helper. 2 package main 3 4 import ( 5 "bytes" 6 "context" 7 "errors" 8 "flag" 9 "fmt" 10 "os" 11 "os/exec" 12 "os/signal" 13 "path/filepath" 14 ) 15 16 /* 17 This tool is significantly weird in that it makes heavy use of test harnesses for automatic setup, 18 so the "normal" binary here is mostly setup around correctly building and invoking the test binary. 19 */ 20 21 func main() { 22 var exit int 23 defer func() { 24 if exit != 0 { 25 os.Exit(exit) 26 } 27 }() 28 args := Args{} 29 flag.BoolVar(&args.Verbose, "v", false, "verbose output") 30 flag.BoolVar(&args.Warmup, "warmup", false, "do a warmup run before making any requests.") 31 flag.String("dump-manifest", "{{.}}.manifest.json", "dump manifest to templated location, if provided") 32 flag.String("dump-index", "{{.}}.index.json", "dump index to templated location, if provided") 33 flag.String("dump-report", "{{.}}.report.json", "dump report to templated location, if provided") 34 flag.Parse() 35 flag.Visit(func(f *flag.Flag) { 36 switch f.Name { 37 case "dump-manifest": 38 if f.Value.String() == "" { 39 f.Value.Set(f.DefValue) 40 } 41 v := f.Value.String() 42 args.DumpManifest = &v 43 case "dump-index": 44 if f.Value.String() == "" { 45 f.Value.Set(f.DefValue) 46 } 47 v := f.Value.String() 48 args.DumpIndex = &v 49 case "dump-report": 50 if f.Value.String() == "" { 51 f.Value.Set(f.DefValue) 52 } 53 v := f.Value.String() 54 args.DumpReport = &v 55 } 56 }) 57 58 ctx, done := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill) 59 defer done() 60 if err := Main(ctx, args, flag.Args()); err != nil { 61 fmt.Fprintln(os.Stderr, err) 62 exit = 1 63 } 64 } 65 66 type Args struct { 67 DumpManifest *string 68 DumpIndex *string 69 DumpReport *string 70 Verbose bool 71 Warmup bool 72 } 73 74 func Main(ctx context.Context, args Args, imgs []string) error { 75 if err := checkDeps(ctx); err != nil { 76 return err 77 } 78 root, err := findRoot(ctx) 79 if err != nil { 80 return err 81 } 82 workDir := filepath.Join(root, `test/bisect`) 83 cmd := exec.CommandContext(ctx, "go", "test", "-tags", "integration", "-c") 84 cmd.Dir = workDir 85 cmd.Stdout = os.Stdout 86 cmd.Stderr = os.Stderr 87 if err := cmd.Run(); err != nil { 88 return err 89 } 90 91 if flag.NArg() == 0 { 92 flag.PrintDefaults() 93 return errors.New("no arguments given") 94 } 95 96 if args.Warmup { 97 cmd = exec.CommandContext(ctx, filepath.Join(workDir, `bisect.test`), "-enable") 98 if args.Verbose { 99 cmd.Args = append(cmd.Args, "-stderr") 100 } 101 cmd.Dir = workDir 102 cmd.Stdout = os.Stdout 103 cmd.Stderr = os.Stderr 104 if err := cmd.Run(); err != nil { 105 return err 106 } 107 } 108 109 cmd = exec.CommandContext(ctx, filepath.Join(workDir, `bisect.test`), "-enable") 110 if args.Verbose { 111 cmd.Args = append(cmd.Args, "-stderr") 112 } 113 if f := args.DumpManifest; f != nil { 114 p, err := filepath.Abs(*f) 115 if err != nil { 116 return err 117 } 118 cmd.Args = append(cmd.Args, "-dump-manifest", p) 119 } 120 if f := args.DumpIndex; f != nil { 121 p, err := filepath.Abs(*f) 122 if err != nil { 123 return err 124 } 125 cmd.Args = append(cmd.Args, "-dump-index", p) 126 } 127 if f := args.DumpReport; f != nil { 128 p, err := filepath.Abs(*f) 129 if err != nil { 130 return err 131 } 132 cmd.Args = append(cmd.Args, "-dump-report", p) 133 } 134 cmd.Args = append(cmd.Args, imgs...) 135 cmd.Dir = workDir 136 cmd.Stdout = os.Stdout 137 cmd.Stderr = os.Stderr 138 return cmd.Run() 139 } 140 141 func findRoot(ctx context.Context) (string, error) { 142 cmd := exec.CommandContext(ctx, "git", "rev-parse", "--show-toplevel") 143 cmd.Stderr = nil 144 b, err := cmd.Output() 145 if err != nil { 146 return "", err 147 } 148 return string(bytes.TrimSpace(b)), nil 149 } 150 151 func checkDeps(_ context.Context) error { 152 for _, exe := range []string{ 153 "git", 154 "skopeo", 155 } { 156 if _, err := exec.LookPath(exe); err != nil { 157 return err 158 } 159 } 160 return nil 161 }