analyzer

package
v0.0.0-...-bb95b05 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 19, 2019 License: MIT Imports: 14 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Analyzers = map[string]Analyzer{
	"is-there-a-race": newAnalyzerImpl(
		"is-there-a-race",
		"Analyzes if there is a specific race in the replay.",
		1,
		map[string]struct{}{},
		true,
		true,
		false,
		false,
		&argumentValidatorRace{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				for _, p := range replay.Header.OrigPlayers {
					if p.Race.Name == args[0] {
						return "true", true, nil, nil
					}
				}
				return "false", true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"my-apm": newAnalyzerImpl(
		"my-apm",
		"Analyzes the APM of the -me player.",
		1,
		map[string]struct{}{},
		false,
		false,
		true,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "-1",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				if replay.Computed == nil {
					return "-1", true, nil, nil
				}
				playerID := findPlayerID(replay, ctx.Me)
				if playerID == 127 {
					return "-1", true, nil, fmt.Errorf("-me player not present in this replay")
				}
				for _, pDesc := range replay.Computed.PlayerDescs {
					if pDesc.PlayerID == playerID {
						return fmt.Sprintf("%v", pDesc.APM), true, nil, nil
					}
				}
				return "-1", true, nil, fmt.Errorf("unexpected error")
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"my-race": newAnalyzerImpl(
		"my-race",
		"Analyzes the race of the -me player.",
		1,
		map[string]struct{}{},
		false,
		false,
		false,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				playerID := findPlayerID(replay, ctx.Me)
				if playerID == 127 {
					return "", true, nil, fmt.Errorf("-me player not present in this replay")
				}
				return replay.Header.PIDPlayers[playerID].Race.Name, true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"my-race-is": newAnalyzerImpl(
		"my-race-is",
		"Analyzes if the race of the -me player is the one specified.",
		1,
		map[string]struct{}{},
		true,
		true,
		false,
		false,
		&argumentValidatorRace{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				playerID := findPlayerID(replay, ctx.Me)
				if playerID == 127 {
					return "", true, nil, fmt.Errorf("-me player not present in this replay")
				}
				result := "false"
				if replay.Header.PIDPlayers[playerID].Race.Name == args[0] {
					result = "true"
				}
				return result, true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"date": newAnalyzerImpl(
		"date",
		"Analyzes the date of the replay. Uses yyyy-mm-dd pattern because it's lexicographically sorted.",
		1,
		map[string]struct{}{},
		false,
		false,
		false,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				return replay.Header.StartTime.Format("2006-01-02"), true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"my-name": newAnalyzerImpl(
		"my-name",
		"Analyzes the name of the -me player.",
		1,
		map[string]struct{}{},
		false,
		false,
		false,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				playerID := findPlayerID(replay, ctx.Me)
				if playerID == 127 {
					return "", true, nil, fmt.Errorf("-me player not present in this replay")
				}
				return replay.Header.PIDPlayers[playerID].Name, true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"replay-name": newAnalyzerImpl(
		"replay-name",
		"Analyzes the replay's name.",
		1,
		map[string]struct{}{},
		false,
		false,
		false,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				result := path.Base(replayPath)
				return result[:len(result)-4], true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"replay-path": newAnalyzerImpl(
		"replay-path",
		"Analyzes the replay's path.",
		1,
		map[string]struct{}{},
		false,
		false,
		false,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				return replayPath, true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"my-win": newAnalyzerImpl(
		"my-win",
		"Analyzes if the -me player won the game.",
		1,
		map[string]struct{}{},
		false,
		false,
		false,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				if replay.Computed == nil || replay.Computed.WinnerTeam == 0 {
					return "unknown", true, nil, nil
				}
				playerID := findPlayerID(replay, ctx.Me)
				if playerID == 127 {
					return "", true, nil, fmt.Errorf("-me player not present in this replay")
				}
				if replay.Header.PIDPlayers[playerID].Team == replay.Computed.WinnerTeam {
					return "true", true, nil, nil
				}
				return "false", true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"my-game": newAnalyzerImpl(
		"my-game",
		"Analyzes if the -me player played the game.",
		1,
		map[string]struct{}{},
		false,
		true,
		false,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				if playerID := findPlayerID(replay, ctx.Me); playerID == 127 {
					return "false", true, nil, nil
				}
				return "true", true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"map-name": newAnalyzerImpl(
		"map-name",
		"Analyzes the map's name. Note that it doesn't do anything clever, so many versions of a map can have slightly different names, or two maps with the same name might be actually different.",
		1,
		map[string]struct{}{},
		false,
		false,
		false,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				return replay.Header.Map, true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"is-1v1": newAnalyzerImpl(
		"is-1v1",
		"Analyzes if the replay is of an 1v1 match.",
		1,
		map[string]struct{}{},
		false,
		false,
		false,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {

				if len(replay.Header.Players) == 2 && (replay.Header.Players[0].Team != replay.Header.Players[1].Team ||
					replay.Header.Type.Name == "Melee" ||
					replay.Header.Type.Name == "One on One" ||
					replay.Header.Type.Name == "Free For All") {
					return "true", true, nil, nil
				}
				return "false", true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"is-2v2": newAnalyzerImpl(
		"is-2v2",
		"Analyzes if the replay is of a 2v2 match.",
		1,
		map[string]struct{}{},
		false,
		false,
		false,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				if len(replay.Header.Players) == 4 && replay.Header.Players[0].Team == replay.Header.Players[1].Team &&
					replay.Header.Players[1].Team != replay.Header.Players[2].Team &&
					replay.Header.Players[2].Team == replay.Header.Players[3].Team {
					return "true", true, nil, nil
				}
				return "false", true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"duration-minutes": newAnalyzerImpl(
		"duration-minutes",
		"Analyzes the duration of the replay in minutes.",
		1,
		map[string]struct{}{},
		false,
		false,
		false,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				return fmt.Sprintf("%v", int(replay.Header.Duration().Minutes())), true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"duration-minutes-is-greater-than": newAnalyzerImpl(
		"duration-minutes-is-greater-than",
		"Analyzes if the duration of the replay in minutes is greater than specified.",
		1,
		map[string]struct{}{},
		true,
		true,
		false,
		false,
		&argumentValidatorMinutes{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				actualMinutes := int(replay.Header.Duration().Minutes())
				expectedMinutes, _ := strconv.Atoi(args[0])
				return fmt.Sprintf("%v", actualMinutes > expectedMinutes), true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"duration-minutes-is-lower-than": newAnalyzerImpl(
		"duration-minutes-is-lower-than",
		"Analyzes if the duration of the replay in minutes is lower than specified.",
		1,
		map[string]struct{}{},
		true,
		true,
		false,
		false,
		&argumentValidatorMinutes{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				actualMinutes := int(replay.Header.Duration().Minutes())
				expectedMinutes, _ := strconv.Atoi(args[0])
				return fmt.Sprintf("%v", actualMinutes < expectedMinutes), true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"matchup": newAnalyzerImpl(
		"matchup",
		"Analyzes the replay's matchup. On an 1v1, it will sort the races lexicographically, so it will return TvZ rather than ZvT. Other than 1v1, it will simply return whatever screp returns.",
		1,
		map[string]struct{}{},
		false,
		false,
		false,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				if len(replay.Header.Players) == 2 {
					r0 := strings.ToUpper(string(replay.Header.Players[0].Race.Letter))
					r1 := strings.ToUpper(string(replay.Header.Players[1].Race.Letter))
					if r0 > r1 {
						return r1 + "v" + r0, true, nil, nil
					}
					return r0 + "v" + r1, true, nil, nil
				}
				return replay.Header.Matchup(), true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"my-matchup": newAnalyzerImpl(
		"my-matchup",
		"Analyzes the replay's matchup from the point of view of the -me player. For example, if the -me player is Z and the opponent is T it will return ZvT rather than TvZ. At the moment, the behaviour other than 1v1 is unexpected: it returns the matchup as returned by screp.",
		1,
		map[string]struct{}{},
		false,
		false,
		false,
		false,
		&argumentValidatorNoArguments{},
		&analyzerProcessorImpl{
			result: "",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				playerID := findPlayerID(replay, ctx.Me)
				if playerID == 127 {
					return "", true, nil, nil
				}
				if len(replay.Header.Players) == 2 {

					r0 := strings.ToUpper(string(replay.Header.Players[0].Race.Letter))
					r1 := strings.ToUpper(string(replay.Header.Players[1].Race.Letter))
					if playerID == replay.Header.Players[1].ID {
						return r1 + "v" + r0, true, nil, nil
					}
					return r0 + "v" + r1, true, nil, nil
				}
				return replay.Header.Matchup(), true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"matchup-is": newAnalyzerImpl(
		"matchup-is",
		"Analyzes if the replay's MatchupIs is equal to the specified one (only works for 1v1 for now). The specified matchup can be in either order (i.e. ZvT == TvZ).",
		1,
		map[string]struct{}{},
		true,
		true,
		false,
		false,
		&argumentValidator1v1Matchup{},
		&analyzerProcessorImpl{
			result: "false",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				if len(replay.Header.Players) != 2 {
					return "", true, nil, nil
				}
				actualRaces := []string{
					strings.ToUpper(string(replay.Header.Players[0].Race.Letter)),
					strings.ToUpper(string(replay.Header.Players[1].Race.Letter)),
				}
				sort.Strings(actualRaces)
				return fmt.Sprintf("%v", reflect.DeepEqual(args, actualRaces)), true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"my-matchup-is": newAnalyzerImpl(
		"my-matchup-is",
		"Analyzes if the replay's matchup is equal to the specified one, from the -me player perspective (only works for 1v1 for now). The specified matchup must contain the -me player's race first.",
		1,
		map[string]struct{}{},
		true,
		true,
		false,
		false,
		&argumentValidator1v1Matchup{},
		&analyzerProcessorImpl{
			result: "false",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				playerID := findPlayerID(replay, ctx.Me)
				if playerID == 127 || len(replay.Header.Players) != 2 {
					return "", true, nil, nil
				}
				actualRaces := []string{
					strings.ToUpper(string(replay.Header.Players[0].Race.Letter)),
					strings.ToUpper(string(replay.Header.Players[1].Race.Letter)),
				}
				sort.Strings(actualRaces)
				return fmt.Sprintf("%v", reflect.DeepEqual(args, actualRaces)), true, nil, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				return result, true, nil
			},
		},
	),
	"my-first-specific-unit-seconds": newAnalyzerImpl(
		"my-first-specific-unit-seconds",
		"Analyzes the time the first specified unit/building/evolution was built, in seconds. Refer to the unit name list in utils.go#nameToUnitID. -1 if the unit never appears.",
		1,
		map[string]struct{}{},
		true,
		false,
		true,
		false,
		&argumentValidatorUnit{},
		&analyzerProcessorImpl{
			result: "-1",
			done:   false,
			startReadingReplay: func(replay *rep.Replay, ctx Context, replayPath string, args []string) (string, bool, interface{}, error) {
				unitID, _ := strconv.Atoi(args[0])
				playerID := findPlayerID(replay, ctx.Me)
				state := []int{unitID, int(playerID)}
				return "-1", playerID == 127, state, nil
			},
			processCommand: func(command repcmd.Cmd, args []string, result string, state interface{}) (string, bool, error) {
				_state := state.([]int)
				unitID, playerID := _state[0], _state[1]
				result, done := maybePlayersUnitSeconds(command, byte(playerID), uint16(unitID))
				return result, done, nil
			},
		},
	),
}

Analyzers are all implemented replay analyzers. Should be cloned before being used.

Functions

This section is empty.

Types

type Analyzer

type Analyzer interface {
	// Name is used for DependsOn() and as argument to CLI, so must be
	// hyphenated and without spaces or special characters.
	Name() string

	// Description is a human readable description for what the analyzer is useful for. Used
	// in command line usage help.
	Description() string

	// SetArguments for running: should be called before StartReadingReplay().
	// It may error, signaling that this Analyzer should not be used, and an error
	// should be shown to the client, but execution of the rest may continue.
	SetArguments(args []string) error

	// DependsOn are the Analyzer Name's whose Results this Analyzer depends on: for building DAG.
	DependsOn() map[string]struct{}

	// StartReadingReplay is called at the beginning of a Replay analyzing cycle.
	// Should not read anything from Commands; use ProcessCommand for that.
	// Returns true if the analyzer is finished calculating the result (i.e. no need
	// to process commands)
	// It may error, signaling that this Analyzer should no longer be used, and an error
	// should be shown to the client, but execution of the rest may continue.
	StartReadingReplay(replay *rep.Replay, ctx Context, replayPath string) (bool, error)

	// ProcessCommand should be called for every command during a Replay analizing cycle.
	// StartReadingReplay should be called before processing any command, to refresh
	// any state and to decide if processing commands are necessary to determine result.
	// Returns true if the analyzer is finished calculating the result (i.e. no need
	// to process further commands).
	// It may error, signaling that this Analyzer should no longer be used, and an error
	// should be shown to the client, but execution of the rest may continue.
	ProcessCommand(command repcmd.Cmd) (bool, error)

	// IsDone Returns true if the analyzer is finished calculating the result, and
	// returns it. Shouldn't be called before calling StartReadingReplay.
	IsDone() (string, bool)

	// Version is useful for managing updates to an Analyzer: whenever an update is made to an
	// analyzer, the Version should be numerically higher. Then, if there's a cached
	// Result of an Analyzer on a Replay, the result should be recomputed.
	Version() int

	// IsStringFlag determines the type of the CLI flag. It can either be Bool (default) or String.
	IsStringFlag() bool

	// IsBooleanResult Determines if the result type is "true"/"false". Used for providing -filter-- and -filter-not--
	// flags.
	IsBooleanResult() bool

	// Clone is a convenience method just so there can be a map[string]analyzer.Analyzer in createSortedAnalyzerWrappers
	Clone() Analyzer

	// RequiresParsingCommandss is true if this Analyzer requires parsing commands from the replay
	RequiresParsingCommands() bool

	// RequiresParsingMapData is true if this Analyzer requires parsing map data from the replay
	RequiresParsingMapData() bool
}

An Analyzer is structured code that, given a replay, it determines something about it. It is optimized for modularity, extensibility and performance. An example would be an Analyzer that answers if the game is a 1v1, or if a player did a 5rax BO.

type CSVOutput

type CSVOutput struct {
	// contains filtered or unexported fields
}

CSVOutput outputs results in CSV format with header.

func NewCSVOutput

func NewCSVOutput(w io.Writer) *CSVOutput

NewCSVOutput is the CSVOutput constructor.

func (*CSVOutput) Post

func (o *CSVOutput) Post() error

Post runs at the end of the replay analyzing cycle.

func (*CSVOutput) Pre

func (o *CSVOutput) Pre(analyzerWrappers []analyzerWrapper) error

Pre runs at the beginning of the replay analyzing cycle.

func (*CSVOutput) ReplayResults

func (o *CSVOutput) ReplayResults(_results []string) error

ReplayResults runs at each replay result cycle.

type Context

type Context struct {
	Me map[string]struct{}
}

Context is all context necessary for analyzers to properly analyze a replay

func NewContext

func NewContext(me map[string]struct{}) Context

NewContext creates an Analyzer Context. Context should be everything unrelated to a replay that an Analyzer should know in order to analyze a replay e.g. who is the -me player

type Executor

type Executor struct {
	// contains filtered or unexported fields
}

Executor is the main struct the client should interact with: it receives a list of replays and analyzer requests, and executes the analyzers on the replays.

func NewExecutor

func NewExecutor(replayPaths []string, analyzerRequests [][]string, ctx Context, output Output, copyPath string) (*Executor, []error)

NewExecutor should be the entrypoint of this library to the client. It creates an Executor. It may return several errors: replay paths may not exist, analyzer requests may be for unknown analyzers, copy path may not exist, etc.

func (*Executor) Execute

func (e *Executor) Execute() []error

Execute executes the given Analyzers on the given replays. Use this method if you want JSON/CSV output onto a file or Stdout. If you're using the library and want to work with the results programatically, use ExecuteWithResults instead. Execute may fail for a number of reasons, but the failures may be isolated to a replay or even a single analyzer, so it doesn't necessarily mean that the complete result is unusable.

func (*Executor) ExecuteWithResults

func (e *Executor) ExecuteWithResults() ([][]string, []error)

ExecuteWithResults executes the given Analyzers on the given replays and returns all results. Use this method if you want to work with the results programatically; otherwise use Execute instead. ExecuteWithResults may fail for a number of reasons, but the failures may be isolated to a replay or even a single analyzer, so it doesn't necessarily mean that the complete result is unusable. Usually, when using this method, the Executor's output should be NoOutput, since the results are available in the return value of this method.

type JSONOutput

type JSONOutput struct {
	// contains filtered or unexported fields
}

JSONOutput outputs results in JSON format as an array of objects.

func NewJSONOutput

func NewJSONOutput(w io.Writer) *JSONOutput

NewJSONOutput is the JSONOutput constructor.

func (*JSONOutput) Post

func (o *JSONOutput) Post() error

Post runs at the end of the replay analyzing cycle.

func (*JSONOutput) Pre

func (o *JSONOutput) Pre(analyzerWrappers []analyzerWrapper) error

Pre runs at the beginning of the replay analyzing cycle.

func (*JSONOutput) ReplayResults

func (o *JSONOutput) ReplayResults(_results []string) error

ReplayResults runs at each replay result cycle.

type NoOutput

type NoOutput struct{}

NoOutput swallows output. Usually used together with AnalyzerExecutor.ExecuteWithResults().

func NewNoOutput

func NewNoOutput() *NoOutput

NewNoOutput is the NoOutput constructor.

func (*NoOutput) Post

func (o *NoOutput) Post() error

Post runs at the end of the replay analyzing cycle.

func (*NoOutput) Pre

func (o *NoOutput) Pre(analyzerWrappers []analyzerWrapper) error

Pre runs at the beginning of the replay analyzing cycle.

func (*NoOutput) ReplayResults

func (o *NoOutput) ReplayResults(results []string) error

ReplayResults runs at each replay result cycle.

type Output

type Output interface {
	Pre(analyzerWrappers []analyzerWrapper) error
	ReplayResults(results []string) error
	Post() error
}

Output is an interface for outputting the results of Analyzers. Some implementations are: CSVOutput: outputs results in CSV format with header. JSONOutput: outputs results in JSON format as an array of objects. NoOutput: swallows output. Usually used together with AnalyzerExecutor.ExecuteWithResults().

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL