Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix most data race issues & enable in CI tests #447

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

josh-pritchard
Copy link

To resolve #439

There was a very large list of data race conditions when running against the race detector. I have no doubt some of these were causing some inconsistent behavior. I did not change any of the component APIs. I only made a minor change to it in the pterm file (see comments for details). This PR will allow most components to now be used in projects that run tests with race detection on. For now the interactive components that leverage atomicgo.dev/keyboard still have race conditions because of that library & I have disabled the race detector for them. It will either need to be switched out or contributed to in order to resolve this. Looking at the lib its not something that I think impacts functionality but it is restrictive when trying to use the project in others that leverage the race detector.

Let me know what you think!

@codecov
Copy link

codecov bot commented Jan 25, 2023

Codecov Report

Merging #447 (fde0869) into master (c0cd74f) will decrease coverage by 13.39%.
The diff coverage is 100.00%.

❗ Current head fde0869 differs from pull request most recent head 12ebc30. Consider uploading reports for the commit 12ebc30 to get more accurate results

@@             Coverage Diff             @@
##           master     #447       +/-   ##
===========================================
- Coverage   86.07%   72.68%   -13.39%     
===========================================
  Files          29       29               
  Lines        2119     2175       +56     
===========================================
- Hits         1824     1581      -243     
- Misses        264      591      +327     
+ Partials       31        3       -28     
Impacted Files Coverage Δ
barchart.go 100.00% <100.00%> (ø)
bigtext_printer.go 100.00% <100.00%> (ø)
center_printer.go 100.00% <100.00%> (ø)
color.go 100.00% <100.00%> (ø)
header_printer.go 100.00% <100.00%> (ø)
panel_printer.go 100.00% <100.00%> (ø)
paragraph_printer.go 100.00% <100.00%> (ø)
prefix_printer.go 100.00% <100.00%> (ø)
print.go 100.00% <100.00%> (ø)
progressbar_printer.go 98.26% <100.00%> (+0.03%) ⬆️
... and 8 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@josh-pritchard
Copy link
Author

Looks like there are a few data races that still need to be addressed, will update this.

Comment on lines 15 to +24
// Output completely disables output from pterm if set to false. Can be used in CLI application quiet mode.
Output = true
Output = atomic.NewBool(true)

// PrintDebugMessages sets if messages printed by the DebugPrinter should be printed.
PrintDebugMessages = false
PrintDebugMessages = atomic.NewBool(false)

// RawOutput is set to true if pterm.DisableStyling() was called.
// The variable indicates that PTerm will not add additional styling to text.
// Use pterm.DisableStyling() or pterm.EnableStyling() to change this variable.
// Changing this variable directly, will disable or enable the output of colored text.
RawOutput = false
RawOutput = atomic.NewBool(false)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went back and forth on this part but this is the only place where the API actually changed. If I implemented with internal atomic variables like I did elsewhere it could lead to other issues. IMO these should not be exposed publicly anyways as it can lead to inconsistent usage. Looks like it may have only been done for the tests

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should just expose a getter and a setter function for the atomic variables. Ubers atomic package provides much more functionality than needed. Also, if we ever decide to switch it, we would have another breaking change. A simple wrapper would fix that :)

// EnableStyling enables the default PTerm styling.
// This also calls EnableColor.
func EnableStyling() {
	RawOutput.Store(false)
	EnableColor()
}

// DisableStyling sets PTerm to RawOutput mode and disables all of PTerms styling.
// You can use this to print to text files etc.
// This also calls DisableColor.
func DisableStyling() {
	RawOutput.Store(true)
	DisableColor()
}

Those functions can be used, but I would also introduce SetStylingEnabled(bool) and GetStylingEnabled(). We could get rid of the exposed RawOutput then.

The same for the other variables.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, will change this around. No need for a braking change here I think either.

messageLines := strings.Split(message, "\n")
for i, line := range messageLines {
messageLines[i] = color.RenderCode(c.String(), strings.ReplaceAll(line, color.ResetSet, Sprintf("\x1b[0m\u001B[%sm", c.String())))
messageLines[i] = color.RenderCode(c.String(), strings.ReplaceAll(line, color.ResetSet, color.Sprintf("\x1b[0m\u001B[%sm", c.String())))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason for changing this to use color directly?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all revolves around how the color lib is NOT thread safe at all. A lot of the Data Races revolved around it and I needed to add the print lock to this function as it leverages the color lib directly so I needed to change that out since Sprintf also has a lock on it so we would get recursive locking and deadlock

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO I may have been a little lazy here and I was trying not to be too intrusive. The use of the color lib should be all wrapped up in one sub package so we can use it everywhere safely without this type of thing because its not super clear why this is necessary, could be a good follow up.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so I needed to change that out since Sprintf also has a lock on it so we would get recursive locking and deadlock

Ok, that makes sense!

The use of the color lib should be all wrapped up in one sub package

Honestly, I often thought about completely switching the color library, or writing an own implementation. There are so many workarounds that we did in the past 2 years, because of it. Sadly, back in the days when PTerm was young and only created to be used in one of my projects, I used the color library to create the Style, RGB, FgXxx and BgXxx colors. So it's not easy to switch it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah makes sense. Probably part of a bigger effort, just another reason to write a custom implementation.


"github.com/gookit/color"
)

// Need to use this because "github.com/gookit/color" is NOT a thread-safe library for Print & Sprintf functions.
// Used to protect against some unsafe actions in Fprint as well
var pLock sync.RWMutex
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please rename this to something like printLock?

Comment on lines -111 to +127
ret += Sprinto(a...)
ret += "\r" + color.Sprint(a...)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there are particular reason for not using Sprinto?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah same as previous comments, would cause a deadlock

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add that as a comment? I think that might be confusing for others at first glance. :)

@josh-pritchard
Copy link
Author

Also just want to explain the race detector is finicky. It does not always catch everything every run. I ran this a ton of times to find everything I did and it seems to be passing now consistently. You could see more crop up in the future occasionally. If that happens they should just be documented as issues and addressed. For other PRs they shouldn't be blocking since a retry of the action will likely get it to pass.

pterm.go Show resolved Hide resolved
@MarvinJWendt
Copy link
Member

Hi @josh-pritchard, do you have any update on this?

@josh-pritchard
Copy link
Author

Apologies for the long delay, I will make sure get this cleaned up for you.

@MarvinJWendt
Copy link
Member

MarvinJWendt commented May 19, 2023

Awesome! And don't worry, open-source contributions are voluntary, and I was often enough in the situation myself where other things were more important, so some tickets took really long.

@klyalldr
Copy link

klyalldr commented Oct 2, 2023

Hi, I have just started using PTerm and loving it but ran into the Data Race errors when running my tests.

Is this PR dead or do you have an ETA on when it might get merged?

@f-belliard
Copy link

Hello, any news for a potential fix on this ?
Pterm is a great lib. It's a shame to have to exclude some tests due to these race conditions 😞

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Better concurrency pattern for LivePrinters
4 participants