internal/engine/common/commands.go (124 lines of code) (raw):

package common import ( "fmt" "github.com/Azure/InnovationEngine/internal/engine/environments" "github.com/Azure/InnovationEngine/internal/logging" "github.com/Azure/InnovationEngine/internal/parsers" "github.com/Azure/InnovationEngine/internal/shells" tea "github.com/charmbracelet/bubbletea" ) // Emitted when a command has been executed successfully. type SuccessfulCommandMessage struct { StdOut string StdErr string SimilarityScore float64 } // Emitted when a command has failed to execute. type FailedCommandMessage struct { StdOut string StdErr string Error error SimilarityScore float64 } type ExitMessage struct { EncounteredFailure bool } func Exit(encounteredFailure bool) tea.Cmd { return func() tea.Msg { return ExitMessage{EncounteredFailure: encounteredFailure} } } // Executes a bash command and returns a tea message with the output. This function // will be executed asycnhronously. func ExecuteCodeBlockAsync(codeBlock parsers.CodeBlock, env map[string]string) tea.Cmd { return func() tea.Msg { logging.GlobalLogger.Infof( "Executing command asynchronously:\n %s", codeBlock.Content) output, err := shells.ExecuteBashCommand(codeBlock.Content, shells.BashCommandConfiguration{ EnvironmentVariables: env, InheritEnvironment: true, InteractiveCommand: false, WriteToHistory: true, }) if err != nil { logging.GlobalLogger.Errorf("Error executing command:\n %s", err.Error()) return FailedCommandMessage{ StdOut: output.StdOut, StdErr: output.StdErr, Error: err, SimilarityScore: 0, } } // Check command output against the expected output. actualOutput := output.StdOut expectedOutput := codeBlock.ExpectedOutput.Content expectedSimilarity := codeBlock.ExpectedOutput.ExpectedSimilarity expectedRegex := codeBlock.ExpectedOutput.ExpectedRegex expectedOutputLanguage := codeBlock.ExpectedOutput.Language score, outputComparisonError := CompareCommandOutputs( actualOutput, expectedOutput, expectedSimilarity, expectedRegex, expectedOutputLanguage, ) if outputComparisonError != nil { logging.GlobalLogger.Errorf( "Error comparing command outputs: %s", outputComparisonError.Error(), ) return FailedCommandMessage{ StdOut: output.StdOut, StdErr: output.StdErr, Error: outputComparisonError, SimilarityScore: score, } } logging.GlobalLogger.Infof("Command output to stdout:\n %s", output.StdOut) return SuccessfulCommandMessage{ StdOut: output.StdOut, StdErr: output.StdErr, SimilarityScore: score, } } } // Executes a bash command syncrhonously. This function will block until the command // finishes executing. func ExecuteCodeBlockSync(codeBlock parsers.CodeBlock, env map[string]string) tea.Msg { logging.GlobalLogger.Info("Executing command synchronously: ", codeBlock.Content) Program.ReleaseTerminal() output, err := shells.ExecuteBashCommand( codeBlock.Content, shells.BashCommandConfiguration{ EnvironmentVariables: env, InheritEnvironment: true, InteractiveCommand: true, WriteToHistory: true, }, ) Program.RestoreTerminal() if err != nil { return FailedCommandMessage{ StdOut: output.StdOut, StdErr: output.StdErr, Error: err, } } logging.GlobalLogger.Infof("Command output to stdout:\n %s", output.StdOut) return SuccessfulCommandMessage{ StdOut: output.StdOut, StdErr: output.StdErr, } } // clearScreen returns a command that clears the terminal screen and positions the cursor at the top-left corner func ClearScreen() tea.Cmd { return func() tea.Msg { fmt.Print( "\033[H\033[2J", ) // ANSI escape codes for clearing the screen and repositioning the cursor return nil } } // Updates the azure status with the current state of the interactive mode // model. func UpdateAzureStatus(azureStatus environments.AzureDeploymentStatus, environment string) tea.Cmd { return func() tea.Msg { logging.GlobalLogger.Tracef( "Attempting to update the azure status: %+v", azureStatus, ) environments.ReportAzureStatus(azureStatus, environment) return AzureStatusUpdatedMessage{} } } // Empty struct used to indicate that the azure status has been updated so // that we can respond to it within the Update() function. type AzureStatusUpdatedMessage struct{}