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
Warnings API redux #3722
base: main
Are you sure you want to change the base?
Warnings API redux #3722
Conversation
This provides the base for how we will report warnings to the caller. The warnins are global and we pass in a pointer to a library-allocated struct which the caller can copy if they wish.
I like this - very simple and elegant. One concern that I have is that - as a consumer - I may have to carry a lot of state to figure out what I should do in the default cases. With this implementation, I register a single warning handler that will get called for all types of warnings. I think there are two types of warnings that we will end up adding:
An example of #2 is a malformed commit, which we could fill with crazy default values ("Unknown", perhaps) but we would not want to in the default case. A user - if they want just CRLF warnings (for example) would be likely to build out a default handler like:
Which would - inadvertently - continue on in the should-be-error cases (which would be errors if there were no warning configured.) This is a sort of "you're holding it wrong" situation, but I think we're really encouraging people to hold it wrong. In this sort of situation, people would really need to know what the default should be for each type of warning. There are a couple of ways to mitigate this:
I lean a bit towards 1, but I'm pretty flexible. I'm more interested in making sure that we don't trap the user here. |
This is what I'm targeting with this. You may want to print a message, or present a neat table of how badly formatted your files are.
Recoverable errors feel like they're a different kind of beast, and I think separating the callbacks would help to hold it wrong less often.
Would this be a different registration per warning type? I can see this not being too bad as we know the size of the array at compile time.
We can have
The previous PR includes this, and I feel the same way :) We do however already provide something similar with the host certificate check, where we say whether we think it's valid, and then let the user decide (or not). |
Since an application may have more than one repository open at a given time and the callback is global, it might be sensible to pass the repository that caused the problem as an argument. Or the callback could be a per-repository setting. I guess the repository can probably be deduced from the filename - but that seems a little finicky. |
There is no guarantee that we know what the repository is where we'd want to generate a warning, or that there even is a repository so it ends up being the same issue with figuring out where the issue comes from. If you do use multiple repositories, you already have to handle concurrent callbacks for certain operations, so you can extend whatever mechanism you already have. |
One thing that makes this tricky is that generally you provide the Generally the warnings will get fired on the same thread that you started from, but that's not always true. It's hard for me to imagine how you would reconcile which warnings were fired from which operation if each of them fired off multiple threads. Unless we either arbitrate the warnings through the calling thread (which sounds crazy) or we stamp some sort of ID into the warning. Perhaps the thread ID of the originating thread. I dunno. This is a little icky, but I think that we need to give a little bit more context to the callers. |
The only way to provide a per-call payload would be to carry it around anywhere, so I think we're realistically stuck with making the user provide a global payload.
Do you have something particular operation in mind where we would raise warnings in a thread we created as opposed to the caller?
We have something similar for pack-objects progress (and I would expect a multi-threaded indexer or checkout would behave the same way) . The threads update the stats and it's the calling thread (which is otherwise sleeping) the one which calls the callback, since we do have the guarantee that we won't jump around threads (at least implicitly). As the places where we do perform multi-threaded operations on behalf of the user should be rather limited, and we would be performing status/progress updates by proxying through the calling thread anyhow. It doesn't seem like a big deal to also make sure warnings in these cases are raised by the calling thread.
Originating as the worker thread that generated the warning when proxying? I suppose we could add this (though iirc thread IDs are tricky to get the right size). But the way I did expect the (presumably tiny amount of) callers which actually do multiple operations concurrently is to set either thread-local data to know which thread is dealing with which repository or attach some global hash table associating a task id (for thread-hopping workpool systems) with the repository. I would like to provide some more context, if we can have it, but if we only have it sometimes, I'm not sure it'd help too much since a caller would have to handle the case without the information already. |
/** | ||
* Sentinel value. Should never be used. | ||
*/ | ||
GIT_GENERIC_NONE = 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this rather be GIT_WARNING_NONE
?
* Warning related to line ending conversion. | ||
*/ | ||
GIT_WARNING_CRLF, | ||
} git_warning_t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
git_warning_type
would be a bit more obvious
git_warning_crlf warning; | ||
git_buf buf = GIT_BUF_INIT; | ||
|
||
if (git_buf_printf(&buf, lfwarning, git_filter_source_path(src)) < 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I bet this kind of stuff would come up quite a lot. So a function to build a warning with a type and a format string would be nice, as well as one cleaning up the warning
{ | ||
cl_assert_equal_p(&g_warning, warning); | ||
cl_assert_equal_p(&g_dummy_payload, payload); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't you set a static value here to assert in the caller that the callback was in fact invoked?
This is another attempt at #2101 which incorporates the subclassing described in the comments. An application may choose to print to stdout/stderr or it may look into the subclass to show the warnings in a GUI or to provide its own format.
The commit signature parsing code has changed quite a bit since the original PR, so I've used CRLF as an example of how we'd use it.