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  }