1package main 2 3import ( 4 "flag" 5 "runtime" 6 7 "time" 8 9 "github.com/onsi/ginkgo/config" 10) 11 12type RunWatchAndBuildCommandFlags struct { 13 Recurse bool 14 SkipPackage string 15 GoOpts map[string]interface{} 16 17 //for run and watch commands 18 NumCPU int 19 NumCompilers int 20 ParallelStream bool 21 Notify bool 22 AfterSuiteHook string 23 AutoNodes bool 24 Timeout time.Duration 25 26 //only for run command 27 KeepGoing bool 28 UntilItFails bool 29 RandomizeSuites bool 30 31 //only for watch command 32 Depth int 33 WatchRegExp string 34 35 FlagSet *flag.FlagSet 36} 37 38const runMode = 1 39const watchMode = 2 40const buildMode = 3 41 42func NewRunCommandFlags(flagSet *flag.FlagSet) *RunWatchAndBuildCommandFlags { 43 c := &RunWatchAndBuildCommandFlags{ 44 FlagSet: flagSet, 45 } 46 c.flags(runMode) 47 return c 48} 49 50func NewWatchCommandFlags(flagSet *flag.FlagSet) *RunWatchAndBuildCommandFlags { 51 c := &RunWatchAndBuildCommandFlags{ 52 FlagSet: flagSet, 53 } 54 c.flags(watchMode) 55 return c 56} 57 58func NewBuildCommandFlags(flagSet *flag.FlagSet) *RunWatchAndBuildCommandFlags { 59 c := &RunWatchAndBuildCommandFlags{ 60 FlagSet: flagSet, 61 } 62 c.flags(buildMode) 63 return c 64} 65 66func (c *RunWatchAndBuildCommandFlags) wasSet(flagName string) bool { 67 wasSet := false 68 c.FlagSet.Visit(func(f *flag.Flag) { 69 if f.Name == flagName { 70 wasSet = true 71 } 72 }) 73 74 return wasSet 75} 76 77func (c *RunWatchAndBuildCommandFlags) computeNodes() { 78 if c.wasSet("nodes") { 79 return 80 } 81 if c.AutoNodes { 82 switch n := runtime.NumCPU(); { 83 case n <= 4: 84 c.NumCPU = n 85 default: 86 c.NumCPU = n - 1 87 } 88 } 89} 90 91func (c *RunWatchAndBuildCommandFlags) stringSlot(slot string) *string { 92 var opt string 93 c.GoOpts[slot] = &opt 94 return &opt 95} 96 97func (c *RunWatchAndBuildCommandFlags) boolSlot(slot string) *bool { 98 var opt bool 99 c.GoOpts[slot] = &opt 100 return &opt 101} 102 103func (c *RunWatchAndBuildCommandFlags) intSlot(slot string) *int { 104 var opt int 105 c.GoOpts[slot] = &opt 106 return &opt 107} 108 109func (c *RunWatchAndBuildCommandFlags) flags(mode int) { 110 c.GoOpts = make(map[string]interface{}) 111 112 onWindows := (runtime.GOOS == "windows") 113 114 c.FlagSet.BoolVar(&(c.Recurse), "r", false, "Find and run test suites under the current directory recursively.") 115 c.FlagSet.BoolVar(c.boolSlot("race"), "race", false, "Run tests with race detection enabled.") 116 c.FlagSet.BoolVar(c.boolSlot("cover"), "cover", false, "Run tests with coverage analysis, will generate coverage profiles with the package name in the current directory.") 117 c.FlagSet.StringVar(c.stringSlot("coverpkg"), "coverpkg", "", "Run tests with coverage on the given external modules.") 118 c.FlagSet.StringVar(&(c.SkipPackage), "skipPackage", "", "A comma-separated list of package names to be skipped. If any part of the package's path matches, that package is ignored.") 119 c.FlagSet.StringVar(c.stringSlot("tags"), "tags", "", "A list of build tags to consider satisfied during the build.") 120 c.FlagSet.StringVar(c.stringSlot("gcflags"), "gcflags", "", "Arguments to pass on each go tool compile invocation.") 121 c.FlagSet.StringVar(c.stringSlot("covermode"), "covermode", "", "Set the mode for coverage analysis.") 122 c.FlagSet.BoolVar(c.boolSlot("a"), "a", false, "Force rebuilding of packages that are already up-to-date.") 123 c.FlagSet.BoolVar(c.boolSlot("n"), "n", false, "Have `go test` print the commands but do not run them.") 124 c.FlagSet.BoolVar(c.boolSlot("msan"), "msan", false, "Enable interoperation with memory sanitizer.") 125 c.FlagSet.BoolVar(c.boolSlot("x"), "x", false, "Have `go test` print the commands.") 126 c.FlagSet.BoolVar(c.boolSlot("work"), "work", false, "Print the name of the temporary work directory and do not delete it when exiting.") 127 c.FlagSet.StringVar(c.stringSlot("asmflags"), "asmflags", "", "Arguments to pass on each go tool asm invocation.") 128 c.FlagSet.StringVar(c.stringSlot("buildmode"), "buildmode", "", "Build mode to use. See 'go help buildmode' for more.") 129 c.FlagSet.StringVar(c.stringSlot("compiler"), "compiler", "", "Name of compiler to use, as in runtime.Compiler (gccgo or gc).") 130 c.FlagSet.StringVar(c.stringSlot("gccgoflags"), "gccgoflags", "", "Arguments to pass on each gccgo compiler/linker invocation.") 131 c.FlagSet.StringVar(c.stringSlot("installsuffix"), "installsuffix", "", "A suffix to use in the name of the package installation directory.") 132 c.FlagSet.StringVar(c.stringSlot("ldflags"), "ldflags", "", "Arguments to pass on each go tool link invocation.") 133 c.FlagSet.BoolVar(c.boolSlot("linkshared"), "linkshared", false, "Link against shared libraries previously created with -buildmode=shared.") 134 c.FlagSet.StringVar(c.stringSlot("pkgdir"), "pkgdir", "", "install and load all packages from the given dir instead of the usual locations.") 135 c.FlagSet.StringVar(c.stringSlot("toolexec"), "toolexec", "", "a program to use to invoke toolchain programs like vet and asm.") 136 c.FlagSet.IntVar(c.intSlot("blockprofilerate"), "blockprofilerate", 1, "Control the detail provided in goroutine blocking profiles by calling runtime.SetBlockProfileRate with the given value.") 137 c.FlagSet.StringVar(c.stringSlot("coverprofile"), "coverprofile", "", "Write a coverage profile to the specified file after all tests have passed.") 138 c.FlagSet.StringVar(c.stringSlot("cpuprofile"), "cpuprofile", "", "Write a CPU profile to the specified file before exiting.") 139 c.FlagSet.StringVar(c.stringSlot("memprofile"), "memprofile", "", "Write a memory profile to the specified file after all tests have passed.") 140 c.FlagSet.IntVar(c.intSlot("memprofilerate"), "memprofilerate", 0, "Enable more precise (and expensive) memory profiles by setting runtime.MemProfileRate.") 141 c.FlagSet.StringVar(c.stringSlot("outputdir"), "outputdir", "", "Place output files from profiling in the specified directory.") 142 c.FlagSet.BoolVar(c.boolSlot("requireSuite"), "requireSuite", false, "Fail if there are ginkgo tests in a directory but no test suite (missing RunSpecs)") 143 144 if mode == runMode || mode == watchMode { 145 config.Flags(c.FlagSet, "", false) 146 c.FlagSet.IntVar(&(c.NumCPU), "nodes", 1, "The number of parallel test nodes to run") 147 c.FlagSet.IntVar(&(c.NumCompilers), "compilers", 0, "The number of concurrent compilations to run (0 will autodetect)") 148 c.FlagSet.BoolVar(&(c.AutoNodes), "p", false, "Run in parallel with auto-detected number of nodes") 149 c.FlagSet.BoolVar(&(c.ParallelStream), "stream", onWindows, "stream parallel test output in real time: less coherent, but useful for debugging") 150 if !onWindows { 151 c.FlagSet.BoolVar(&(c.Notify), "notify", false, "Send desktop notifications when a test run completes") 152 } 153 c.FlagSet.StringVar(&(c.AfterSuiteHook), "afterSuiteHook", "", "Run a command when a suite test run completes") 154 c.FlagSet.DurationVar(&(c.Timeout), "timeout", 24*time.Hour, "Suite fails if it does not complete within the specified timeout") 155 } 156 157 if mode == runMode { 158 c.FlagSet.BoolVar(&(c.KeepGoing), "keepGoing", false, "When true, failures from earlier test suites do not prevent later test suites from running") 159 c.FlagSet.BoolVar(&(c.UntilItFails), "untilItFails", false, "When true, Ginkgo will keep rerunning tests until a failure occurs") 160 c.FlagSet.BoolVar(&(c.RandomizeSuites), "randomizeSuites", false, "When true, Ginkgo will randomize the order in which test suites run") 161 } 162 163 if mode == watchMode { 164 c.FlagSet.IntVar(&(c.Depth), "depth", 1, "Ginkgo will watch dependencies down to this depth in the dependency tree") 165 c.FlagSet.StringVar(&(c.WatchRegExp), "watchRegExp", `\.go$`, "Files matching this regular expression will be watched for changes") 166 } 167} 168