| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 | 
							- package core
 
- import (
 
- 	"fmt"
 
- 	"reflect"
 
- 	"sort"
 
- 	"strings"
 
- 	"unsafe"
 
- 	"github.com/spf13/pflag"
 
- )
 
- // PipelineItemRegistry contains all the known PipelineItem-s.
 
- type PipelineItemRegistry struct {
 
- 	provided     map[string][]reflect.Type
 
- 	registered   map[string]reflect.Type
 
- 	flags        map[string]reflect.Type
 
- 	featureFlags arrayFeatureFlags
 
- }
 
- // Register adds another PipelineItem to the registry.
 
- func (registry *PipelineItemRegistry) Register(example PipelineItem) {
 
- 	t := reflect.TypeOf(example)
 
- 	registry.registered[example.Name()] = t
 
- 	if fpi, ok := example.(LeafPipelineItem); ok {
 
- 		registry.flags[fpi.Flag()] = t
 
- 	}
 
- 	for _, dep := range example.Provides() {
 
- 		ts := registry.provided[dep]
 
- 		if ts == nil {
 
- 			ts = []reflect.Type{}
 
- 		}
 
- 		ts = append(ts, t)
 
- 		registry.provided[dep] = ts
 
- 	}
 
- }
 
- // Summon searches for PipelineItem-s which provide the specified entity or named after
 
- // the specified string. It materializes all the found types and returns them.
 
- func (registry *PipelineItemRegistry) Summon(providesOrName string) []PipelineItem {
 
- 	if registry.provided == nil {
 
- 		return []PipelineItem{}
 
- 	}
 
- 	ts := registry.provided[providesOrName]
 
- 	var items []PipelineItem
 
- 	for _, t := range ts {
 
- 		items = append(items, reflect.New(t.Elem()).Interface().(PipelineItem))
 
- 	}
 
- 	if t, exists := registry.registered[providesOrName]; exists {
 
- 		items = append(items, reflect.New(t.Elem()).Interface().(PipelineItem))
 
- 	}
 
- 	return items
 
- }
 
- // GetLeaves returns all LeafPipelineItem-s registered.
 
- func (registry *PipelineItemRegistry) GetLeaves() []LeafPipelineItem {
 
- 	keys := []string{}
 
- 	for key := range registry.flags {
 
- 		keys = append(keys, key)
 
- 	}
 
- 	sort.Strings(keys)
 
- 	items := []LeafPipelineItem{}
 
- 	for _, key := range keys {
 
- 		items = append(items, reflect.New(registry.flags[key].Elem()).Interface().(LeafPipelineItem))
 
- 	}
 
- 	return items
 
- }
 
- // GetPlumbingItems returns all non-LeafPipelineItem-s registered.
 
- func (registry *PipelineItemRegistry) GetPlumbingItems() []PipelineItem {
 
- 	keys := []string{}
 
- 	for key := range registry.registered {
 
- 		keys = append(keys, key)
 
- 	}
 
- 	sort.Strings(keys)
 
- 	items := []PipelineItem{}
 
- 	for _, key := range keys {
 
- 		iface := reflect.New(registry.registered[key].Elem()).Interface()
 
- 		if _, ok := iface.(LeafPipelineItem); !ok {
 
- 			items = append(items, iface.(PipelineItem))
 
- 		}
 
- 	}
 
- 	return items
 
- }
 
- type orderedFeaturedItems []FeaturedPipelineItem
 
- func (ofi orderedFeaturedItems) Len() int {
 
- 	return len([]FeaturedPipelineItem(ofi))
 
- }
 
- func (ofi orderedFeaturedItems) Less(i, j int) bool {
 
- 	cofi := []FeaturedPipelineItem(ofi)
 
- 	return cofi[i].Name() < cofi[j].Name()
 
- }
 
- func (ofi orderedFeaturedItems) Swap(i, j int) {
 
- 	cofi := []FeaturedPipelineItem(ofi)
 
- 	cofi[i], cofi[j] = cofi[j], cofi[i]
 
- }
 
- // GetFeaturedItems returns all FeaturedPipelineItem-s registered.
 
- func (registry *PipelineItemRegistry) GetFeaturedItems() map[string][]FeaturedPipelineItem {
 
- 	features := map[string][]FeaturedPipelineItem{}
 
- 	for _, t := range registry.registered {
 
- 		if fiface, ok := reflect.New(t.Elem()).Interface().(FeaturedPipelineItem); ok {
 
- 			for _, f := range fiface.Features() {
 
- 				list := features[f]
 
- 				if list == nil {
 
- 					list = []FeaturedPipelineItem{}
 
- 				}
 
- 				list = append(list, fiface)
 
- 				features[f] = list
 
- 			}
 
- 		}
 
- 	}
 
- 	for _, vals := range features {
 
- 		sort.Sort(orderedFeaturedItems(vals))
 
- 	}
 
- 	return features
 
- }
 
- type arrayFeatureFlags struct {
 
- 	// Flags contains the features activated through the command line.
 
- 	Flags []string
 
- 	// Choices contains all registered features.
 
- 	Choices map[string]bool
 
- }
 
- func (acf *arrayFeatureFlags) String() string {
 
- 	return strings.Join([]string(acf.Flags), ", ")
 
- }
 
- func (acf *arrayFeatureFlags) Set(value string) error {
 
- 	if _, exists := acf.Choices[value]; !exists {
 
- 		return fmt.Errorf("feature \"%s\" is not registered", value)
 
- 	}
 
- 	acf.Flags = append(acf.Flags, value)
 
- 	return nil
 
- }
 
- func (acf *arrayFeatureFlags) Type() string {
 
- 	return "string"
 
- }
 
- // AddFlags inserts the cmdline options from PipelineItem.ListConfigurationOptions(),
 
- // FeaturedPipelineItem().Features() and LeafPipelineItem.Flag() into the global "flag" parser
 
- // built into the Go runtime.
 
- // Returns the "facts" which can be fed into PipelineItem.Configure() and the dictionary of
 
- // runnable analysis (LeafPipelineItem) choices. E.g. if "BurndownAnalysis" was activated
 
- // through "-burndown" cmdline argument, this mapping would contain ["BurndownAnalysis"] = *true.
 
- func (registry *PipelineItemRegistry) AddFlags(flagSet *pflag.FlagSet) (
 
- 	map[string]interface{}, map[string]*bool) {
 
- 	flags := map[string]interface{}{}
 
- 	deployed := map[string]*bool{}
 
- 	for name, it := range registry.registered {
 
- 		formatHelp := func(desc string) string {
 
- 			return fmt.Sprintf("%s [%s]", desc, name)
 
- 		}
 
- 		itemIface := reflect.New(it.Elem()).Interface()
 
- 		for _, opt := range itemIface.(PipelineItem).ListConfigurationOptions() {
 
- 			var iface interface{}
 
- 			getPtr := func() unsafe.Pointer {
 
- 				return unsafe.Pointer(uintptr(unsafe.Pointer(&iface)) + unsafe.Sizeof(&iface))
 
- 			}
 
- 			switch opt.Type {
 
- 			case BoolConfigurationOption:
 
- 				iface = interface{}(true)
 
- 				ptr := (**bool)(getPtr())
 
- 				*ptr = flagSet.Bool(opt.Flag, opt.Default.(bool), formatHelp(opt.Description))
 
- 			case IntConfigurationOption:
 
- 				iface = interface{}(0)
 
- 				ptr := (**int)(getPtr())
 
- 				*ptr = flagSet.Int(opt.Flag, opt.Default.(int), formatHelp(opt.Description))
 
- 			case StringConfigurationOption:
 
- 				iface = interface{}("")
 
- 				ptr := (**string)(getPtr())
 
- 				*ptr = flagSet.String(opt.Flag, opt.Default.(string), formatHelp(opt.Description))
 
- 			case FloatConfigurationOption:
 
- 				iface = interface{}(float32(0))
 
- 				ptr := (**float32)(getPtr())
 
- 				*ptr = flagSet.Float32(opt.Flag, opt.Default.(float32), formatHelp(opt.Description))
 
- 			case StringsConfigurationOption:
 
- 				iface = interface{}([]string{})
 
- 				ptr := (**[]string)(getPtr())
 
- 				*ptr = flagSet.StringSlice(opt.Flag, opt.Default.([]string), formatHelp(opt.Description))
 
- 			}
 
- 			flags[opt.Name] = iface
 
- 		}
 
- 		if fpi, ok := itemIface.(FeaturedPipelineItem); ok {
 
- 			for _, f := range fpi.Features() {
 
- 				registry.featureFlags.Choices[f] = true
 
- 			}
 
- 		}
 
- 		if fpi, ok := itemIface.(LeafPipelineItem); ok {
 
- 			deployed[fpi.Name()] = flagSet.Bool(
 
- 				fpi.Flag(), false, fmt.Sprintf("Runs %s analysis.", fpi.Name()))
 
- 		}
 
- 	}
 
- 	{
 
- 		// Pipeline flags
 
- 		iface := interface{}("")
 
- 		ptr1 := (**string)(unsafe.Pointer(uintptr(unsafe.Pointer(&iface)) + unsafe.Sizeof(&iface)))
 
- 		*ptr1 = flagSet.String("dump-dag", "", "Write the pipeline DAG to a Graphviz file.")
 
- 		flags[ConfigPipelineDumpPath] = iface
 
- 		iface = interface{}(true)
 
- 		ptr2 := (**bool)(unsafe.Pointer(uintptr(unsafe.Pointer(&iface)) + unsafe.Sizeof(&iface)))
 
- 		*ptr2 = flagSet.Bool("dry-run", false, "Do not run any analyses - only resolve the DAG. "+
 
- 			"Useful for --dump-dag.")
 
- 		flags[ConfigPipelineDryRun] = iface
 
- 	}
 
- 	var features []string
 
- 	for f := range registry.featureFlags.Choices {
 
- 		features = append(features, f)
 
- 	}
 
- 	flagSet.Var(®istry.featureFlags, "feature",
 
- 		fmt.Sprintf("Enables the items which depend on the specified features. Can be specified "+
 
- 			"multiple times. Available features: [%s] (see --feature below).",
 
- 			strings.Join(features, ", ")))
 
- 	return flags, deployed
 
- }
 
- // Registry contains all known pipeline item types.
 
- var Registry = &PipelineItemRegistry{
 
- 	provided:     map[string][]reflect.Type{},
 
- 	registered:   map[string]reflect.Type{},
 
- 	flags:        map[string]reflect.Type{},
 
- 	featureFlags: arrayFeatureFlags{Flags: []string{}, Choices: map[string]bool{}},
 
- }
 
 
  |