github.com/kcmvp/gob@v1.0.17/cmd/gbc/artifact/multiple_writer.go (about)

     1  package artifact
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"regexp"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/fatih/color"
    14  	"github.com/samber/lo"
    15  
    16  	"github.com/creack/pty"
    17  )
    18  
    19  type consoleFormatter func(msg string) string
    20  
    21  func StreamCmdOutput(cmd *exec.Cmd, task string, formatter consoleFormatter) error {
    22  	// Start the command with a pty
    23  	var scanner *bufio.Scanner
    24  	if ptmx, err := pty.Start(cmd); err == nil {
    25  		scanner = bufio.NewScanner(ptmx)
    26  		defer ptmx.Close()
    27  	} else if rd, err := cmd.StdoutPipe(); err == nil {
    28  		scanner = bufio.NewScanner(rd)
    29  	} else {
    30  		return err
    31  	}
    32  	color.Green("start %s ......\n", task)
    33  	// Create a file to save the output
    34  	log, err := os.Create(filepath.Join(CurProject().Target(), fmt.Sprintf("%s.log", strings.ReplaceAll(task, " ", "_"))))
    35  	if err != nil {
    36  		return fmt.Errorf(color.RedString("Error creating file:", err))
    37  	}
    38  	defer log.Close()
    39  
    40  	// Create a regular expression to match color escape sequences
    41  	colorRegex := regexp.MustCompile(`\x1b\[[0-9;]*m`)
    42  	// Goroutine to remove color escape sequences, print the colored output, and write the modified output to the file
    43  	ch := make(chan string)
    44  	eof := false
    45  	go func() {
    46  		for scanner.Scan() {
    47  			line := strings.TrimSpace(scanner.Text())
    48  			if formatter != nil {
    49  				line = strings.TrimSpace(formatter(line))
    50  			}
    51  			if len(line) > 1 {
    52  				ch <- line
    53  			}
    54  		}
    55  		eof = true
    56  		if err = scanner.Err(); err != nil {
    57  			fmt.Println("Error reading output:", err)
    58  		}
    59  	}()
    60  	ticker := time.NewTicker(150 * time.Millisecond)
    61  	overwrite := true
    62  	progress := NewProgress()
    63  	for !eof {
    64  		select {
    65  		case line := <-ch:
    66  			progress.Reset()
    67  			lineWithoutColor := colorRegex.ReplaceAllString(line, "")
    68  			_, err = log.WriteString(lineWithoutColor + "\n")
    69  			line = lo.IfF(overwrite, func() string {
    70  				overwrite = false
    71  				return fmt.Sprintf("\r%-15s", line)
    72  			}).Else(line)
    73  			fmt.Println(line)
    74  			if err != nil {
    75  				fmt.Println("Error writing to file:", err)
    76  				break
    77  			}
    78  		case <-ticker.C:
    79  			if !overwrite {
    80  				overwrite = true
    81  			}
    82  			_ = progress.Add(1)
    83  		}
    84  	}
    85  	_ = progress.Finish()
    86  	color.Green("\rfinished %s ......\n", task)
    87  	ticker.Stop()
    88  	return cmd.Wait()
    89  }