func Main()

in mito.go [60:259]


func Main() int {
	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), `Usage of %s:

  %[1]s [opts] <src.cel>

`, os.Args[0])
		flag.PrintDefaults()
	}
	use := flag.String("use", "all", "libraries to use")
	data := flag.String("data", "", "path to a JSON object holding input (exposed as the label "+root+")")
	maxExecutions := flag.Int("max_executions", -1, "maximum number of evaluations, or no maximum if -1")
	cfgPath := flag.String("cfg", "", "path to a YAML file holding run control configuration (see pkg.go.dev/github.com/elastic/mito/cmd/mito)")
	insecure := flag.Bool("insecure", false, "disable TLS verification in the HTTP client")
	logTrace := flag.Bool("log_requests", false, "log request traces to stderr (go1.21+)")
	maxTraceBody := flag.Int("max_log_body", 1000, "maximum length of body logged in request traces (go1.21+)")
	fold := flag.Bool("fold", false, "apply constant folding optimisation")
	dumpState := flag.String("dump", "", "dump eval state ('always' or 'error')")
	coverage := flag.String("coverage", "", "file to write an execution coverage report to (prefix if multiple executions are run)")
	version := flag.Bool("version", false, "print version and exit")
	flag.Parse()
	if *version {
		return printVersion()
	}
	if len(flag.Args()) != 1 {
		flag.Usage()
		return 2
	}

	libs := []cel.EnvOption{
		cel.OptionalTypes(cel.OptionalTypesVersion(lib.OptionalTypesVersion)),
	}
	if *cfgPath != "" {
		f, err := os.Open(*cfgPath)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			return 2
		}
		defer f.Close()
		dec := yaml.NewDecoder(f)
		var cfg Config
		err = dec.Decode(&cfg)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			return 2
		}
		if len(cfg.Globals) != 0 {
			libs = append(libs, lib.Globals(cfg.Globals))
		}
		if len(cfg.Regexps) != 0 {
			regexps := make(map[string]*regexp.Regexp)
			for name, expr := range cfg.Regexps {
				re, err := regexp.Compile(expr)
				if err != nil {
					fmt.Fprintln(os.Stderr, err)
					return 2
				}
				regexps[name] = re
			}
			libs = append(libs, lib.Regexp(regexps))
		}
		if len(cfg.XSDs) != 0 {
			xsds := make(map[string]string)
			for name, path := range cfg.XSDs {
				b, err := os.ReadFile(path)
				if err != nil {
					fmt.Fprintln(os.Stderr, err)
					return 2
				}
				xsds[name] = string(b)
			}
			xml, err := lib.XML(nil, xsds)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				return 2
			}
			libMap["xml"] = xml
		}
		var client *http.Client
		httpOptions := lib.HTTPOptions{
			Headers:     cfg.HTTPHeaders,
			MaxBodySize: cfg.MaxBodySize,
		}
		if cfg.Auth != nil {
			switch auth := cfg.Auth; {
			case auth.Basic != nil && auth.OAuth2 != nil:
				fmt.Fprintln(os.Stderr, "configured basic authentication and OAuth2")
				return 2
			case auth.Basic != nil:
				httpOptions.BasicAuth = auth.Basic
			case auth.OAuth2 != nil:
				client, err = oAuth2Client(*auth.OAuth2)
				if err != nil {
					fmt.Fprintln(os.Stderr, err)
					return 2
				}
			}
		}
		if client != nil || !httpOptions.IsZero() {
			ctx := context.Background()
			libMap["http"] = lib.HTTPWithContextOpts(ctx, traceReqs(setClientInsecure(client, *insecure), *logTrace, *maxTraceBody), httpOptions)
		}
		if *maxExecutions == -1 && cfg.MaxExecutions != nil {
			*maxExecutions = *cfg.MaxExecutions
		}

	}
	if libMap["http"] == nil {
		libMap["http"] = lib.HTTP(traceReqs(setClientInsecure(nil, *insecure), *logTrace, *maxTraceBody), nil, nil)
	}
	if libMap["xml"] == nil {
		var err error
		libMap["xml"], err = lib.XML(nil, nil)
		if err != nil {
			return 2
		}
	}
	if *use == "all" {
		for _, l := range libMap {
			libs = append(libs, l)
		}
	} else {
		for _, u := range strings.Split(*use, ",") {
			l, ok := libMap[u]
			if !ok {
				fmt.Fprintf(os.Stderr, "no lib %q\n", u)
				return 2
			}
			libs = append(libs, l)
		}
	}
	b, err := os.ReadFile(flag.Args()[0])
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 2
	}

	var input interface{}
	if *data != "" {
		b, err := os.ReadFile(*data)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			return 2
		}
		err = json.Unmarshal(b, &input)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			return 2
		}
		input = map[string]interface{}{root: input}
	}

	var cov lib.Coverage
	for n := int(0); *maxExecutions < 0 || n < *maxExecutions; n++ {
		res, val, dump, c, err := eval(string(b), root, input, *fold, *dumpState != "", *coverage != "", libs...)
		if err := cov.Merge(c); err != nil {
			fmt.Fprintf(os.Stderr, "internal error merging coverage: %v\n", err)
			return 1
		}
		if *dumpState == "always" {
			fmt.Fprint(os.Stderr, dump)
		}
		if err != nil {
			if *dumpState == "error" {
				fmt.Fprint(os.Stderr, dump)
			}
			fmt.Fprintln(os.Stderr, err)
			return 2
		}
		fmt.Println(res)

		// Check if we want more. This can happen when we have a map
		// and the map has a true boolean field, want_more.
		state, ok := val.(map[string]any)
		if !ok {
			break
		}
		if more, _ := state["want_more"].(bool); !more {
			break
		}
		input = map[string]any{"state": val}
	}
	if *coverage != "" {
		f, err := os.Create(*coverage)
		if err != nil {
			fmt.Fprintf(os.Stderr, "internal error opening coverage file: %v\n", err)
			return 1
		}
		defer func() {
			f.Sync()
			f.Close()
		}()
		_, err = f.WriteString(cov.String() + "\n")
		if err != nil {
			fmt.Fprintf(os.Stderr, "internal error writing coverage file: %v\n", err)
			return 1
		}
	}
	return 0
}