<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/smartystreets/scantest/go-shlex"
)

func main() {
	command := flag.String("command", deriveDefaultCommand(), "The command (with arguments) to run when a .go file is saved.")
	flag.Parse()

	working, err := os.Getwd()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	args, err := shlex.Split(*command)
	if err != nil {
		log.Fatal(err)
	}
	if len(args) < 1 {
		log.Fatal("Please provide something to run.")
	}

	scanner := &Scanner{working: working}
	runner := &Runner{working: working, command: args}
	for {
		if scanner.Scan() {
			runner.Run()
		}
	}
}

// deriveDefaultCommand determines what the present as the default value of the
// command flag, in case the user does not provide one. It first looks for a
// Makefile in the current directory. If that doesn't exist it looks for the
// Makefile provided by this project, which serves as a working generic example
// that should fit a variety of use cases. If that doesn't exist for whatever
// reason (say, if the scantest binary wasn't built from source on the current
// machine) then it defaults to 'go test'.
func deriveDefaultCommand() string {
	var defaultCommand string

	if current, err := os.Getwd(); err == nil {
		if _, err := os.Stat(filepath.Join(current, "Makefile")); err == nil {
			defaultCommand = "make"
		}
	}

	if defaultCommand == "" {
		if _, file, _, ok := runtime.Caller(0); ok {
			backupMakefile := filepath.Join(filepath.Dir(file), "Makefile")
			if _, err := os.Stat(backupMakefile); err == nil {
				defaultCommand = backupMakefile
			}
		}
	}

	if defaultCommand == "" {
		defaultCommand = "go test"
	}

	return defaultCommand
}

////////////////////////////////////////////////////////////////////////////

type Scanner struct {
	state   int64
	working string
}

func (this *Scanner) Scan() bool {
	time.Sleep(time.Millisecond * 250)
	newState := this.checksum()
	defer func() { this.state = newState }()
	return newState != this.state
}

func (this *Scanner) checksum() int64 {
	var sum int64 = 0
	err := filepath.Walk(this.working, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			sum++
		} else if info.Name() == "generated_by_gunit_test.go" {
			return nil
		} else if strings.HasSuffix(info.Name(), ".go") || info.Name() == "Makefile" {
			sum += info.Size() + info.ModTime().Unix()
		}
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}
	return sum
}

////////////////////////////////////////////////////////////////////////////

type Runner struct {
	command []string
	working string
}

func (this *Runner) Run() {
	fmt.Fprintf(os.Stdout, clearScreen)
	message := fmt.Sprintln(" Executing:", strings.Join(this.command, " "))
	fmt.Fprintln(os.Stdout, "\n"+strings.Repeat("=", len(message)))
	fmt.Fprint(os.Stdout, message)
	fmt.Fprintln(os.Stdout, strings.Repeat("=", len(message)))
	output, success := this.run()
	if success {
		fmt.Fprintf(os.Stdout, greenColor)
	} else {
		fmt.Fprintf(os.Stdout, redColor)
	}
	fmt.Fprintln(os.Stdout)
	fmt.Fprintln(os.Stdout, string(output))
	fmt.Fprintln(os.Stdout, strings.Repeat("-", len(message)))
	fmt.Fprintf(os.Stdout, resetColor)
}

func (this *Runner) run() (output []byte, success bool) {
	command := exec.Command(this.command[0])
	if len(this.command) > 1 {
		command.Args = this.command[1:]
	}
	command.Dir = this.working

	until := make(chan bool, 1)
	now := time.Now()
	go spin(now, until)

	var err error
	output, err = command.CombinedOutput()
	until <- true
	fmt.Println(Round(time.Since(now), time.Millisecond))
	if err != nil {
		output = append(output, []byte(err.Error())...)
	}
	return output, command.ProcessState.Success()
}

func spin(now time.Time, finished chan bool) {
	time.Sleep(time.Millisecond * 500)
	for {
		select {
		case <-finished:
			return
		default:
			fmt.Println(Round(time.Since(now), time.Millisecond))
			time.Sleep(time.Millisecond * 500)
		}
	}
}
<commit_msg>Flushing output and using a real spinner.<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/mdwhatcott/spin"
	"github.com/smartystreets/scantest/go-shlex"
)

func main() {
	command := flag.String("command", deriveDefaultCommand(), "The command (with arguments) to run when a .go file is saved.")
	flag.Parse()

	working, err := os.Getwd()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	args, err := shlex.Split(*command)
	if err != nil {
		log.Fatal(err)
	}
	if len(args) < 1 {
		log.Fatal("Please provide something to run.")
	}

	scanner := &Scanner{working: working}
	runner := &Runner{working: working, command: args}
	for {
		if scanner.Scan() {
			runner.Run()
		}
	}
}

// deriveDefaultCommand determines what the present as the default value of the
// command flag, in case the user does not provide one. It first looks for a
// Makefile in the current directory. If that doesn't exist it looks for the
// Makefile provided by this project, which serves as a working generic example
// that should fit a variety of use cases. If that doesn't exist for whatever
// reason (say, if the scantest binary wasn't built from source on the current
// machine) then it defaults to 'go test'.
func deriveDefaultCommand() string {
	var defaultCommand string

	if current, err := os.Getwd(); err == nil {
		if _, err := os.Stat(filepath.Join(current, "Makefile")); err == nil {
			defaultCommand = "make"
		}
	}

	if defaultCommand == "" {
		if _, file, _, ok := runtime.Caller(0); ok {
			backupMakefile := filepath.Join(filepath.Dir(file), "Makefile")
			if _, err := os.Stat(backupMakefile); err == nil {
				defaultCommand = backupMakefile
			}
		}
	}

	if defaultCommand == "" {
		defaultCommand = "go test"
	}

	return defaultCommand
}

////////////////////////////////////////////////////////////////////////////

type Scanner struct {
	state   int64
	working string
}

func (this *Scanner) Scan() bool {
	time.Sleep(time.Millisecond * 250)
	newState := this.checksum()
	defer func() { this.state = newState }()
	return newState != this.state
}

func (this *Scanner) checksum() int64 {
	var sum int64 = 0
	err := filepath.Walk(this.working, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			sum++
		} else if info.Name() == "generated_by_gunit_test.go" {
			return nil
		} else if strings.HasSuffix(info.Name(), ".go") || info.Name() == "Makefile" {
			sum += info.Size() + info.ModTime().Unix()
		}
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}
	return sum
}

////////////////////////////////////////////////////////////////////////////

type Runner struct {
	command []string
	working string
}

func (this *Runner) Run() {
	message := fmt.Sprintln(" Executing:", strings.Join(this.command, " "))

	write(clearScreen)
	writeln()
	write(strings.Repeat("=", len(message)))
	writeln()
	write(message)
	write(strings.Repeat("=", len(message)))
	writeln()
	output, success := this.run()
	if success {
		write(greenColor)
	} else {
		write(redColor)
	}
	write(string(output))
	writeln()
	write(strings.Repeat("-", len(message)))
	writeln()
	write(resetColor)
}

func writeln() {
	write("\n")
}
func write(a ...interface{}) {
	fmt.Fprint(os.Stdout, a...)
	os.Stdout.Sync()
	// time.Sleep(time.Millisecond * 30)
}

func (this *Runner) run() (output []byte, success bool) {
	command := exec.Command(this.command[0])
	if len(this.command) > 1 {
		command.Args = this.command[1:]
	}
	command.Dir = this.working

	now := time.Now()
	spin.GoStart()

	var err error
	output, err = command.CombinedOutput()
	spin.Stop()
	fmt.Print("\r")
	fmt.Println(Round(time.Since(now), time.Millisecond))
	if err != nil {
		output = append(output, []byte(err.Error())...)
	}
	return output, command.ProcessState.Success()
}

{'fraction_non_alphanumeric': 0.1856089499110094, 'fraction_numerical': 0.005212306127637936, 'mean_word_length': 3.166843220338983, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1898437', 'n_tokens_mistral': 2811, 'n_tokens_neox': 2648, 'n_words': 727}