func main()

in cmd/main.go [100:293]


func main() {

	log.SetOutput(os.Stderr)
	log.SetPrefix("NOTE: ")
	log.SetFlags(log.Flags() &^ (log.Ldate | log.Ltime))

	shortUsage := "A tool to filter EC2 Instance Types based on various resource criteria"
	longUsage := binName + ` is a CLI tool to filter EC2 instance types based on resource criteria. 
Filtering allows you to select all the instance types that match your application requirements.
Full docs can be found at github.com/aws/amazon-` + binName
	examples := fmt.Sprintf(`%s --vcpus 4 --region us-east-2 --availability-zones us-east-2b
%s --memory-min 4 --memory-max 8 --vcpus-min 4 --vcpus-max 8 --region us-east-2`, binName, binName)

	runFunc := func(cmd *cobra.Command, args []string) {}
	cli := commandline.New(binName, shortUsage, longUsage, examples, runFunc)

	cliOutputTypes := []string{
		tableOutput,
		tableWideOutput,
		oneLine,
	}
	resultsOutputFn := outputs.SimpleInstanceTypeOutput

	// Registers flags with specific input types from the cli pkg
	// Filter Flags - These will be grouped at the top of the help flags

	cli.IntMinMaxRangeFlags(vcpus, cli.StringMe("c"), nil, "Number of vcpus available to the instance type.")
	cli.ByteQuantityMinMaxRangeFlags(memory, cli.StringMe("m"), nil, "Amount of Memory available (Example: 4 GiB)")
	cli.RatioFlag(vcpusToMemoryRatio, nil, nil, "The ratio of vcpus to GiBs of memory. (Example: 1:2)")
	cli.StringOptionsFlag(cpuArchitecture, cli.StringMe("a"), nil, "CPU architecture [x86_64/amd64, i386, or arm64]", []string{"x86_64", "amd64", "i386", "arm64"})
	cli.IntMinMaxRangeFlags(gpus, cli.StringMe("g"), nil, "Total Number of GPUs (Example: 4)")
	cli.ByteQuantityMinMaxRangeFlags(gpuMemoryTotal, nil, nil, "Number of GPUs' total memory (Example: 4 GiB)")
	cli.StringOptionsFlag(placementGroupStrategy, nil, nil, "Placement group strategy: [cluster, partition, spread]", []string{"cluster", "partition", "spread"})
	cli.StringOptionsFlag(usageClass, cli.StringMe("u"), nil, "Usage class: [spot or on-demand]", []string{"spot", "on-demand"})
	cli.StringOptionsFlag(rootDeviceType, nil, nil, "Supported root device types: [ebs or instance-store]", []string{"ebs", "instance-store"})
	cli.BoolFlag(enaSupport, cli.StringMe("e"), nil, "Instance types where ENA is supported or required")
	cli.BoolFlag(efaSupport, nil, nil, "Instance types that support Elastic Fabric Adapters (EFA)")
	cli.BoolFlag(hibernationSupport, nil, nil, "Hibernation supported")
	cli.BoolFlag(baremetal, nil, nil, "Bare Metal instance types (.metal instances)")
	cli.BoolFlag(fpgaSupport, cli.StringMe("f"), nil, "FPGA instance types")
	cli.BoolFlag(burstSupport, cli.StringMe("b"), nil, "Burstable instance types")
	cli.StringOptionsFlag(hypervisor, nil, nil, "Hypervisor: [xen or nitro]", []string{"xen", "nitro"})
	cli.StringSliceFlag(availabilityZones, cli.StringMe("z"), nil, "Availability zones or zone ids to check EC2 capacity offered in specific AZs")
	cli.BoolFlag(currentGeneration, nil, nil, "Current generation instance types (explicitly set this to false to not return current generation instance types)")
	cli.IntMinMaxRangeFlags(networkInterfaces, nil, nil, "Number of network interfaces (ENIs) that can be attached to the instance")
	cli.IntMinMaxRangeFlags(networkPerformance, nil, nil, "Bandwidth in Gib/s of network performance (Example: 100)")
	cli.RegexFlag(allowList, nil, nil, "List of allowed instance types to select from w/ regex syntax (Example: m[3-5]\\.*)")
	cli.RegexFlag(denyList, nil, nil, "List of instance types which should be excluded w/ regex syntax (Example: m[1-2]\\.*)")
	cli.StringOptionsFlag(virtualizationType, nil, nil, "Virtualization Type supported: [hvm or pv]", []string{"hvm", "paravirtual", "pv"})
	cli.Float64MinMaxRangeFlags(pricePerHour, nil, nil, "Price/hour in USD (Example: 0.09)")

	// Suite Flags - higher level aggregate filters that return opinionated result

	cli.SuiteStringFlag(instanceTypeBase, nil, nil, "Instance Type used to retrieve similarly spec'd instance types", nil)
	cli.SuiteBoolFlag(flexible, nil, nil, "Retrieves a group of instance types spanning multiple generations based on opinionated defaults and user overridden resource filters")
	cli.SuiteStringFlag(service, nil, nil, "Filter instance types based on service support (Example: eks, eks-20201211, or emr-5.20.0)", nil)

	// Configuration Flags - These will be grouped at the bottom of the help flags

	cli.ConfigIntFlag(maxResults, nil, cli.IntMe(20), "The maximum number of instance types that match your criteria to return")
	cli.ConfigStringFlag(profile, nil, nil, "AWS CLI profile to use for credentials and config", nil)
	cli.ConfigStringFlag(region, cli.StringMe("r"), nil, "AWS Region to use for API requests (NOTE: if not passed in, uses AWS SDK default precedence)", nil)
	cli.ConfigStringFlag(output, cli.StringMe("o"), nil, fmt.Sprintf("Specify the output format (%s)", strings.Join(cliOutputTypes, ", ")), nil)
	cli.ConfigBoolFlag(verbose, cli.StringMe("v"), nil, "Verbose - will print out full instance specs")
	cli.ConfigBoolFlag(help, cli.StringMe("h"), nil, "Help")
	cli.ConfigBoolFlag(version, nil, nil, "Prints CLI version")

	// Parses the user input with the registered flags and runs type specific validation on the user input
	flags, err := cli.ParseAndValidateFlags()
	if err != nil {
		log.Printf("There was an error while parsing the commandline flags: %v", err)
		os.Exit(1)
	}

	if flags[help] != nil {
		os.Exit(0)
	}

	if flags[version] != nil {
		fmt.Printf("%s", versionID)
		os.Exit(0)
	}

	sess, err := getRegionAndProfileAWSSession(cli.StringMe(flags[region]), cli.StringMe(flags[profile]))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	flags[region] = sess.Config.Region

	instanceSelector := selector.New(sess)
	outputFlag := cli.StringMe(flags[output])
	if outputFlag != nil && *outputFlag == tableWideOutput {
		// If output type is `table-wide`, simply print both prices for better comparison,
		//   even if the actual filter is applied on any one of those based on usage class

		// Save time by hydrating in parallel
		wg := &sync.WaitGroup{}
		wg.Add(2)
		go func(waitGroup *sync.WaitGroup) {
			defer waitGroup.Done()
			_ = instanceSelector.EC2Pricing.HydrateOndemandCache()
		}(wg)
		go func(waitGroup *sync.WaitGroup) {
			defer waitGroup.Done()
			_ = instanceSelector.EC2Pricing.HydrateSpotCache(30)
		}(wg)
		wg.Wait()
	} else if flags[pricePerHour] != nil {
		// Else, if price filters are applied, only hydrate the respective cache as we don't have to print the prices
		if flags[usageClass] == nil || *cli.StringMe(flags[usageClass]) == "on-demand" {
			_ = instanceSelector.EC2Pricing.HydrateOndemandCache()
		} else {
			_ = instanceSelector.EC2Pricing.HydrateSpotCache(30)
		}
	}

	filters := selector.Filters{
		VCpusRange:             cli.IntRangeMe(flags[vcpus]),
		MemoryRange:            cli.ByteQuantityRangeMe(flags[memory]),
		VCpusToMemoryRatio:     cli.Float64Me(flags[vcpusToMemoryRatio]),
		CPUArchitecture:        cli.StringMe(flags[cpuArchitecture]),
		GpusRange:              cli.IntRangeMe(flags[gpus]),
		GpuMemoryRange:         cli.ByteQuantityRangeMe(flags[gpuMemoryTotal]),
		PlacementGroupStrategy: cli.StringMe(flags[placementGroupStrategy]),
		UsageClass:             cli.StringMe(flags[usageClass]),
		RootDeviceType:         cli.StringMe(flags[rootDeviceType]),
		EnaSupport:             cli.BoolMe(flags[enaSupport]),
		EfaSupport:             cli.BoolMe(flags[efaSupport]),
		HibernationSupported:   cli.BoolMe(flags[hibernationSupport]),
		Hypervisor:             cli.StringMe(flags[hypervisor]),
		BareMetal:              cli.BoolMe(flags[baremetal]),
		Fpga:                   cli.BoolMe(flags[fpgaSupport]),
		Burstable:              cli.BoolMe(flags[burstSupport]),
		Region:                 cli.StringMe(flags[region]),
		AvailabilityZones:      cli.StringSliceMe(flags[availabilityZones]),
		CurrentGeneration:      cli.BoolMe(flags[currentGeneration]),
		MaxResults:             cli.IntMe(flags[maxResults]),
		NetworkInterfaces:      cli.IntRangeMe(flags[networkInterfaces]),
		NetworkPerformance:     cli.IntRangeMe(flags[networkPerformance]),
		AllowList:              cli.RegexMe(flags[allowList]),
		DenyList:               cli.RegexMe(flags[denyList]),
		InstanceTypeBase:       cli.StringMe(flags[instanceTypeBase]),
		Flexible:               cli.BoolMe(flags[flexible]),
		Service:                cli.StringMe(flags[service]),
		VirtualizationType:     cli.StringMe(flags[virtualizationType]),
		PricePerHour:           cli.Float64RangeMe(flags[pricePerHour]),
	}

	if flags[verbose] != nil {
		resultsOutputFn = outputs.VerboseInstanceTypeOutput
		transformedFilters, err := instanceSelector.AggregateFilterTransform(filters)
		if err != nil {
			fmt.Printf("An error occurred while transforming the aggregate filters")
			os.Exit(1)
		}
		filtersJSON, err := filters.MarshalIndent("", "    ")
		if err != nil {
			fmt.Printf("An error occurred when printing filters due to --verbose being specified: %v", err)
			os.Exit(1)
		}
		transformedFiltersJSON, err := transformedFilters.MarshalIndent("", "    ")
		if err != nil {
			fmt.Printf("An error occurred when printing aggregate filters due to --verbose being specified: %v", err)
			os.Exit(1)
		}
		log.Println("\n\n\"Filters\":", string(filtersJSON))
		if string(transformedFiltersJSON) != string(filtersJSON) {
			log.Println("\n\n\"Transformed Filters\":", string(transformedFiltersJSON))
		} else {
			log.Println("There were no transformations on the filters to display")
		}
	}

	outputFn := getOutputFn(outputFlag, selector.InstanceTypesOutputFn(resultsOutputFn))

	instanceTypes, itemsTruncated, err := instanceSelector.FilterWithOutput(filters, outputFn)
	if err != nil {
		fmt.Printf("An error occurred when filtering instance types: %v", err)
		os.Exit(1)
	}
	if len(instanceTypes) == 0 {
		log.Println("The criteria was too narrow and returned no valid instance types. Consider broadening your criteria so that more instance types are returned.")
		os.Exit(1)
	}

	for _, instanceType := range instanceTypes {
		fmt.Println(instanceType)
	}

	if itemsTruncated > 0 {
		log.Printf("%d entries were truncated, increase --%s to see more", itemsTruncated, maxResults)
	}
}