func gatherOptions() options {
	return gatherFlagOptions(flag.CommandLine, os.Args[1:]...)
}
gatherOptions reads options from flags
package main
import (
	"context"
	"errors"
	"flag"
	"fmt"
	"os"
	"runtime"
	"strings"
	"time"
	gpubsub "cloud.google.com/go/pubsub"
	"github.com/GoogleCloudPlatform/testgrid/pkg/pubsub"
	"github.com/GoogleCloudPlatform/testgrid/pkg/updater"
	"github.com/GoogleCloudPlatform/testgrid/util/gcs"
	"github.com/GoogleCloudPlatform/testgrid/util/metrics"
	"github.com/sirupsen/logrus"
	"google.golang.org/api/option"
)
type Strings struct {
	vals []string
}
func (s *Strings) Strings() []string {
	return s.vals
}
func (s *Strings) String() string {
	return strings.Join(s.vals, ",")
}
func (s *Strings) Set(value string) error {
	s.vals = append(s.vals, value)
	return nil
}
type options struct {
	config           gcs.Path  
	creds            string
	confirm          bool
	groups           Strings
	groupConcurrency int
	buildConcurrency int
	wait             time.Duration
	groupTimeout     time.Duration
	buildTimeout     time.Duration
	gridPrefix       string
	subscriptions    Strings
	debug    bool
	trace    bool
	jsonLogs bool
}
func (o *options) validate() error {
	if o.config.String() == "" {
		return errors.New("empty --config")
	}
	if o.config.Bucket() == "k8s-testgrid" && o.gridPrefix == "" && o.confirm {
		return fmt.Errorf("--config=%s: cannot write grid state to gs://k8s-testgrid", o.config)
	}
	if o.groupConcurrency == 0 {
		o.groupConcurrency = runtime.NumCPU()
	}
	if o.buildConcurrency == 0 {
		o.buildConcurrency = runtime.NumCPU()
		if o.buildConcurrency > 4 {
			o.buildConcurrency = 4
		}
	}
	return subscribeGCS(o.subscriptions.Strings()...)
}
func subscribeGCS(subs ...string) error {
	for _, sub := range subs {
		parts := strings.SplitN(sub, "=", 2)
		if len(parts) != 2 {
			return fmt.Errorf("--subscribe format is prefix=proj/sub, got %q", sub)
		}
		prefix := parts[0]
		parts = strings.SplitN(parts[1], "/", 2)
		if len(parts) != 2 {
			return fmt.Errorf("--subscribe format is prefix=proj/sub, got %q", sub)
		}
		proj, sub := parts[0], parts[1]
		updater.AddManualSubscription(proj, sub, prefix)
	}
	return nil
}
func gatherFlagOptions(fs *flag.FlagSet, args ...string) options {
	var o options
	fs.Var(&o.config, "config", "gs://path/to/config.pb")
	fs.StringVar(&o.creds, "gcp-service-account", "", "/path/to/gcp/creds (use local creds if empty)")
	fs.BoolVar(&o.confirm, "confirm", false, "Upload data if set")
	fs.Var(&o.groups, "test-group", "Only update named groups if set (repeatable)")
	fs.IntVar(&o.groupConcurrency, "group-concurrency", 0, "Manually define the number of groups to concurrently update if non-zero")
	fs.IntVar(&o.buildConcurrency, "build-concurrency", 0, "Manually define the number of builds to concurrently read if non-zero")
	fs.DurationVar(&o.wait, "wait", 0, "Ensure at least this much time has passed since the last loop (exit if zero).")
	fs.Var(&o.subscriptions, "subscribe", "gcs-prefix=project-id/sub-id (repeatable)")
	fs.DurationVar(&o.groupTimeout, "group-timeout", 10*time.Minute, "Maximum time to wait for each group to update")
	fs.DurationVar(&o.buildTimeout, "build-timeout", 3*time.Minute, "Maximum time to wait to read each build")
	fs.StringVar(&o.gridPrefix, "grid-prefix", "grid", "Join this with the grid name to create the GCS suffix")
	fs.BoolVar(&o.debug, "debug", false, "Log debug lines if set")
	fs.BoolVar(&o.trace, "trace", false, "Log trace and debug lines if set")
	fs.BoolVar(&o.jsonLogs, "json-logs", false, "Uses a json logrus formatter when set")
	fs.Parse(args)
	return o
}