diff --git a/pkg/console/console.go b/pkg/console/console.go index 013b61a5..257b73cc 100644 --- a/pkg/console/console.go +++ b/pkg/console/console.go @@ -53,7 +53,10 @@ var Theme = map[string]*color.Color{ } var ( - mutex = &sync.RWMutex{} + // Used by the caller to print multiple lines atomically. Exposed by Lock/Unlock methods. + publicMutex = &sync.Mutex{} + // Used internally by console. + privateMutex = &sync.Mutex{} stderrColoredOutput = ansicolor.NewAnsiColorWriter(os.Stderr) @@ -198,164 +201,162 @@ var ( } ) -var ( - // wrap around standard fmt functions - // consolePrint prints a message prefixed with message type and program name - consolePrint = func(tag string, c *color.Color, a ...interface{}) { - mutex.Lock() - defer mutex.Unlock() +// wrap around standard fmt functions +// consolePrint prints a message prefixed with message type and program name +func consolePrint(tag string, c *color.Color, a ...interface{}) { + privateMutex.Lock() + defer privateMutex.Unlock() - switch tag { - case "Debug": - output := color.Output - color.Output = stderrColoredOutput - if isatty.IsTerminal(os.Stderr.Fd()) { - c.Print(ProgramName() + ": ") - c.Print(a...) - } else { - fmt.Fprint(color.Output, ProgramName()+": ") - fmt.Fprint(color.Output, a...) - } - color.Output = output - case "Fatal": - fallthrough - case "Error": - output := color.Output - color.Output = stderrColoredOutput - if isatty.IsTerminal(os.Stderr.Fd()) { - c.Print(ProgramName() + ": ") - c.Print(a...) - } else { - fmt.Fprint(color.Output, ProgramName()+": ") - fmt.Fprint(color.Output, a...) - } - color.Output = output - case "Info": - if isatty.IsTerminal(os.Stdout.Fd()) { - c.Print(ProgramName() + ": ") - c.Print(a...) - } else { - fmt.Fprint(color.Output, ProgramName()+": ") - fmt.Fprint(color.Output, a...) - } - default: - if isatty.IsTerminal(os.Stdout.Fd()) { - c.Print(a...) - } else { - fmt.Fprint(color.Output, a...) - } + switch tag { + case "Debug": + output := color.Output + color.Output = stderrColoredOutput + if isatty.IsTerminal(os.Stderr.Fd()) { + c.Print(ProgramName() + ": ") + c.Print(a...) + } else { + fmt.Fprint(color.Output, ProgramName()+": ") + fmt.Fprint(color.Output, a...) + } + color.Output = output + case "Fatal": + fallthrough + case "Error": + output := color.Output + color.Output = stderrColoredOutput + if isatty.IsTerminal(os.Stderr.Fd()) { + c.Print(ProgramName() + ": ") + c.Print(a...) + } else { + fmt.Fprint(color.Output, ProgramName()+": ") + fmt.Fprint(color.Output, a...) + } + color.Output = output + case "Info": + if isatty.IsTerminal(os.Stdout.Fd()) { + c.Print(ProgramName() + ": ") + c.Print(a...) + } else { + fmt.Fprint(color.Output, ProgramName()+": ") + fmt.Fprint(color.Output, a...) + } + default: + if isatty.IsTerminal(os.Stdout.Fd()) { + c.Print(a...) + } else { + fmt.Fprint(color.Output, a...) } } +} - // consolePrintf - same as print with a new line - consolePrintf = func(tag string, c *color.Color, format string, a ...interface{}) { - mutex.Lock() - defer mutex.Unlock() +// consolePrintf - same as print with a new line +func consolePrintf(tag string, c *color.Color, format string, a ...interface{}) { + privateMutex.Lock() + defer privateMutex.Unlock() - switch tag { - case "Debug": - output := color.Output - color.Output = stderrColoredOutput - if isatty.IsTerminal(os.Stderr.Fd()) { - c.Print(ProgramName() + ": ") - c.Printf(format, a...) - } else { - fmt.Fprint(color.Output, ProgramName()+": ") - fmt.Fprintf(color.Output, format, a...) - } - color.Output = output - case "Fatal": - fallthrough - case "Error": - output := color.Output - color.Output = stderrColoredOutput - if isatty.IsTerminal(os.Stderr.Fd()) { - c.Print(ProgramName() + ": ") - c.Printf(format, a...) - } else { - fmt.Fprint(color.Output, ProgramName()+": ") - fmt.Fprintf(color.Output, format, a...) - } - color.Output = output - case "Info": - if isatty.IsTerminal(os.Stdout.Fd()) { - c.Print(ProgramName() + ": ") - c.Printf(format, a...) - } else { - fmt.Fprint(color.Output, ProgramName()+": ") - fmt.Fprintf(color.Output, format, a...) - } - default: - if isatty.IsTerminal(os.Stdout.Fd()) { - c.Printf(format, a...) - } else { - fmt.Fprintf(color.Output, format, a...) - } + switch tag { + case "Debug": + output := color.Output + color.Output = stderrColoredOutput + if isatty.IsTerminal(os.Stderr.Fd()) { + c.Print(ProgramName() + ": ") + c.Printf(format, a...) + } else { + fmt.Fprint(color.Output, ProgramName()+": ") + fmt.Fprintf(color.Output, format, a...) + } + color.Output = output + case "Fatal": + fallthrough + case "Error": + output := color.Output + color.Output = stderrColoredOutput + if isatty.IsTerminal(os.Stderr.Fd()) { + c.Print(ProgramName() + ": ") + c.Printf(format, a...) + } else { + fmt.Fprint(color.Output, ProgramName()+": ") + fmt.Fprintf(color.Output, format, a...) + } + color.Output = output + case "Info": + if isatty.IsTerminal(os.Stdout.Fd()) { + c.Print(ProgramName() + ": ") + c.Printf(format, a...) + } else { + fmt.Fprint(color.Output, ProgramName()+": ") + fmt.Fprintf(color.Output, format, a...) + } + default: + if isatty.IsTerminal(os.Stdout.Fd()) { + c.Printf(format, a...) + } else { + fmt.Fprintf(color.Output, format, a...) } } +} - // consolePrintln - same as print with a new line - consolePrintln = func(tag string, c *color.Color, a ...interface{}) { - mutex.Lock() - defer mutex.Unlock() +// consolePrintln - same as print with a new line +func consolePrintln(tag string, c *color.Color, a ...interface{}) { + privateMutex.Lock() + defer privateMutex.Unlock() - switch tag { - case "Debug": - output := color.Output - color.Output = stderrColoredOutput - if isatty.IsTerminal(os.Stderr.Fd()) { - c.Print(ProgramName() + ": ") - c.Println(a...) - } else { - fmt.Fprint(color.Output, ProgramName()+": ") - fmt.Fprintln(color.Output, a...) - } - color.Output = output - case "Fatal": - fallthrough - case "Error": - output := color.Output - color.Output = stderrColoredOutput - if isatty.IsTerminal(os.Stderr.Fd()) { - c.Print(ProgramName() + ": ") - c.Println(a...) - } else { - fmt.Fprint(color.Output, ProgramName()+": ") - fmt.Fprintln(color.Output, a...) - } - color.Output = output - case "Info": - if isatty.IsTerminal(os.Stdout.Fd()) { - c.Print(ProgramName() + ": ") - c.Println(a...) - } else { - fmt.Fprint(color.Output, ProgramName()+": ") - fmt.Fprintln(color.Output, a...) - } - default: - if isatty.IsTerminal(os.Stdout.Fd()) { - c.Println(a...) - } else { - fmt.Fprintln(color.Output, a...) - } + switch tag { + case "Debug": + output := color.Output + color.Output = stderrColoredOutput + if isatty.IsTerminal(os.Stderr.Fd()) { + c.Print(ProgramName() + ": ") + c.Println(a...) + } else { + fmt.Fprint(color.Output, ProgramName()+": ") + fmt.Fprintln(color.Output, a...) + } + color.Output = output + case "Fatal": + fallthrough + case "Error": + output := color.Output + color.Output = stderrColoredOutput + if isatty.IsTerminal(os.Stderr.Fd()) { + c.Print(ProgramName() + ": ") + c.Println(a...) + } else { + fmt.Fprint(color.Output, ProgramName()+": ") + fmt.Fprintln(color.Output, a...) + } + color.Output = output + case "Info": + if isatty.IsTerminal(os.Stdout.Fd()) { + c.Print(ProgramName() + ": ") + c.Println(a...) + } else { + fmt.Fprint(color.Output, ProgramName()+": ") + fmt.Fprintln(color.Output, a...) + } + default: + if isatty.IsTerminal(os.Stdout.Fd()) { + c.Println(a...) + } else { + fmt.Fprintln(color.Output, a...) } } -) +} // Lock console func Lock() { - mutex.Lock() + publicMutex.Lock() } // Unlock locked console func Unlock() { - mutex.Unlock() + publicMutex.Unlock() } // SetCustomTheme sets a color theme func SetCustomTheme(theme map[string]*color.Color) *probe.Error { - mutex.Lock() - defer mutex.Unlock() + privateMutex.Lock() + defer privateMutex.Unlock() // add new theme for k, v := range theme { Theme[k] = v @@ -371,7 +372,7 @@ func ProgramName() string { // SetNoColor disable coloring func SetNoColor() { - mutex.Lock() - defer mutex.Unlock() + privateMutex.Lock() + defer privateMutex.Unlock() color.NoColor = true } diff --git a/pkg/console/console_test.go b/pkg/console/console_test.go index bcccbbc2..67e27d25 100644 --- a/pkg/console/console_test.go +++ b/pkg/console/console_test.go @@ -35,3 +35,18 @@ func (s *MySuite) TestSetTheme(c *C) { _, ok := Theme["unknown"] c.Assert(ok, Equals, true) } + +func (s *MySuite) TestLock(c *C) { + Lock() + Print("") // Test for deadlocks. + Unlock() +} + +func (s *MySuite) TestTesting(c *C) { + // Enable testing + IsTesting = true + Fatalln("THIS IS A TEST MESSAGE. PLEASE INGORE.") + c.Assert(IsExited, Equals, true) + // reset back + IsExited = false +}