func Explain()

in cmd/hub/state/explain.go [48:206]


func Explain(elaborateManifests, stateFilenames []string, opLog, global bool, componentName string, rawOutputs bool,
	format string /*text, kv, sh, json, yaml*/, color bool) {

	if (color || config.Tty) && format == "text" {
		headColor = func(str string) string {
			return aurora.Green(str).String()
		}
	}

	if format != "text" && config.Verbose && !config.Debug {
		config.Verbose = false
	}

	if opLog && format != "text" {
		log.Fatal("Lifecycle operations log can only be explained in text format")
	}

	state := MustParseStateFiles(stateFilenames)
	components := state.Lifecycle.Order

	if opLog {
		printOpLog(state)
		return
	}

	var stackManifest *manifest.Manifest
	if len(elaborateManifests) > 0 {
		var err error
		stackManifest, _, _, err = manifest.ParseManifest(elaborateManifests)
		if err != nil {
			util.Warn("Unable to parse: %v", err)
		} else if stackManifest != nil {
			order, err := manifest.GenerateLifecycleOrder(stackManifest)
			if err != nil {
				log.Fatal(err)
			}
			stackManifest.Lifecycle.Order = order
			components = stackManifest.Lifecycle.Order
		}
	}

	var prevOutputs []parameters.CapturedOutput

	if componentName != "" {
		if stackManifest != nil {
			manifest.CheckComponentsExist(stackManifest.Components, componentName)
		}

		for i, c := range components {
			if c == componentName {
				if i > 0 {
					prevComponentState, exist := state.Components[components[i-1]]
					if exist {
						prevOutputs = prevComponentState.CapturedOutputs
					}
				}
			}
		}

		components = []string{componentName}
	}

	if format == "text" {
		if global || componentName == "" {
			fmt.Printf("Kind: %s\n", state.Meta.Kind)
			fmt.Printf("Name: %s\n", state.Meta.Name)
			fmt.Printf("Timestamp: %v\n", state.Timestamp.Truncate(time.Second))
			fmt.Printf("Status: %s\n", state.Status)
			if state.Message != "" {
				fmt.Printf("Message: %s\n", state.Message)
			}
			fmt.Print(headColor("Stack parameters:\n"))
			printLockedParameters(state.StackParameters)
			printStackOutputs(state.StackOutputs)
			printProvides(state.Provides)
		}

		if !global || componentName != "" {
			for _, component := range components {
				if step, exist := state.Components[component]; exist {
					fmt.Printf("Component: %s\n", headColor(component))
					printComponenentState(component, step, prevOutputs, rawOutputs)
					prevOutputs = step.CapturedOutputs
				}
			}
		}
	} else {
		explained := ExplainedState{
			Meta:            state.Meta,
			Timestamp:       state.Timestamp,
			Status:          state.Status,
			Message:         state.Message,
			StackParameters: make(map[string]string),
			StackOutputs:    make(map[string]string),
			Components:      make(map[string]ExplainedComponent),
		}

		if global || componentName == "" {
			for _, parameter := range state.StackParameters {
				explained.StackParameters[parameter.QName()] = util.String(parameter.Value)
			}
			for _, output := range state.StackOutputs {
				explained.StackOutputs[output.Name] = util.String(output.Value)
			}
			explained.Provides = state.Provides
		}

		if !global || componentName != "" {
			for _, component := range components {
				if step, exist := state.Components[component]; exist {
					comp := ExplainedComponent{
						Timestamp:  step.Timestamp,
						Timestamps: step.Timestamps,
						Status:     step.Status,
						Message:    step.Message,
						Parameters: make(map[string]string),
						Outputs:    make(map[string]string),
						RawOutputs: make(map[string]string),
					}
					for _, parameter := range step.Parameters {
						comp.Parameters[parameter.Name] = util.String(parameter.Value)
					}
					for _, output := range DiffOutputs(step.CapturedOutputs, prevOutputs) {
						comp.Outputs[output.Name] = util.String(output.Value)
					}
					prevOutputs = step.CapturedOutputs
					if rawOutputs {
						for _, output := range step.RawOutputs {
							comp.RawOutputs[output.Name] = output.Value
						}
					}
					explained.Components[component] = comp
				}
			}
		}

		var bytes []byte
		var err error

		switch format {
		case "json":
			bytes, err = json.MarshalIndent(&explained, "", "  ")
		case "yaml":
			bytes, err = yaml.Marshal(&explained)
		// case "sh":
		default:
			log.Fatalf("`%s` output format is not implemented", format)
		}

		if err != nil {
			log.Fatalf("Unable to explain in `%s` format: %v", format, err)
		}

		written, err := os.Stdout.Write(bytes)
		if err != nil || written != len(bytes) {
			log.Fatalf("Error writting output (wrote %d of ouf %d bytes): %v", written, len(bytes), err)
		}
	}
}