-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Hook support #3824
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
Hook support #3824
Conversation
Some hook support already exists. The trick with hooks is that they're basically shell scripts and require the platform to support executing then. |
Yep, I'm aware that direct hook execution does not belong in the library. The current plan is to have clients use Also, what did you meant by "already exists" ? I haven't been able to find anything other than some references in tests, but maybe I'm blind 😉 . |
I'm sorry, the hook support is in the C# wrapper library, not in LibGit2 core. My mistake. |
It feels to me like you're trying to design the support in libgit2 that you think you want before you've tried to implement any hooks in your application itself. I feel like trying to build "hooks support" into libgit2 before trying to get your application to do anything is actually the wrong direction to attack this problem. Instead, I think that you should get your application to exec some hooks so that you know what you can get libgit2 to help you with. I realize it seems counterintuitive to do it in the application first, since generally you're coding a functionality or a UI on top of libgit2 and in that case the libgit2 part must already exist. But without having actually succeeded in running a hook from your application, I think that we will merely be making wild guesses as to what we want the hooks support (if any) to look like and will very likely design this wrong. As a concrete example, it's unclear to me how Similarly, most hooks don't make sense in the context of libgit2. Things like the We think that we have callbacks in the appropriate places that you can map those to hook execution if that's something that you're interested in (though they are not called "hooks" callbacks, they are generally more generic than that.) I think the best first place to start is to identify hooks that you want to support that are lacking callbacks (that can be supported, that is, unlike the aforementioned hooks around commit messages). That's a clear improvement. libgit2 certainly can provide some support for hooks, like providing the path. This seems of limited use to me, since it's mostly just string concatenation, ( Anyway. There are probably some things that libgit2 can help you with here, but I would like to be conservative with these APIs. |
Thanks for the thorough reply @ethomson. Just so we're clear, the API I wrote is inspired from what's in PROJECTS.md, and Looking at that as an app developer, what I want is a way to be told when I need to exec a hook, because I want to be compatible with git/not break expectations. For example, I would expect (and I might be wrong 😉) libgit2 to detect that there's a
But then, maybe that whole responsibility could indeed be moved down to the application (provided the same effect can be achieved through the generic callbacks). I might be worrying too much about duplicated code 😉. |
Thanks for the clarification - I didn't realize that was there. :P
Right - so the thing is that we don't have an API that maps to the This is important because if we were to (say) fire the This is why we've asked the callers to handle hooks-like things: you know when you're going through a commit workflow like the Of course, the problem here is that various other libraries (say, LibGit2Sharp) may provide a commit like workflow as API. So this makes the problem a little bit more difficult. Anyway. I'm sorry that I don't have clearer answers here yet. This is something that's been discussed a few times, and I think that all the vendors who are building UI on top of libgit2 should absolutely be supporting. As a result, I would love to give as much help as we can to you (and the rest) so that it's less of a slog. |
Thanks, that makes it clear why hook support is a hard problem. IIUC, if libgit2 had a I'll go ponder what the bindings are currently up to, to see if there's any common infrastructure we could bring in, but arguably this API is bound to be a simple wrapper around |
#964 (I knew there had been some discussion already). |
In preparation for executing hooks
And fix a bug. Gotta *love* C arrays.
Here's a first pass at hook execution. It allows the client to register a callback for hook execution and a wrapper that we (or, for some hooks, the client) can call to cause that callback to be executed with the expected arguments after the checks are done. This still needs to tackle the case of the few hooks that do I/O, but I think I'll just pass a I'm saddened by the fact that this is so STRINGS EVERYWHERE, with additional NULL SENTINELS 😅 . There might be a way to make it cleaner, but as "conservative" is a keyword, let's keep it simple for now. It's related to the point above, but there will be times where the client has OIDs and Right now the code has a list of hardcoded hook names, but there might be a way to make that more generic (just found out about |
include/git2/hook.h
Outdated
git_repository *repo, | ||
git_hook_foreach_cb callback, | ||
void *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.
Our coding style has the closing brace on the same line as the last argument. Also applies for the following functions.
Hummm... I think we shouldn't actually worry about git.git deprecating certain hooks. For one, I think it rather unlikely that they'd deprecate hooks as there will always be use-cases which are broken by removing a hook. And furthermore, git.git always pays strong attention not to remove existing features. And even in the case that git.git does deprecate a hook I think there's a big benefit in having an enum here. If the client will just compare strings, he cannot easily know when a hook has been deprecated and may fail silently. But in the case of an enum which subsequently got removed due to deprecation, the client will fail to compile. While I agree it is not a nice thing to break API I deem it better still than causing a client to silently fail. |
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.
Just skipped the changes. There's a compilation error on MSVC currently
tests/clar_libgit2.h
Outdated
clar__assert_equal(file, line, "Vector length mismatch: %" PRIuZ " != %" PRIuZ, 1, PRIuZ, git_vector_length(a), git_vector_length(b)); | ||
|
||
size_t i; | ||
char *string; |
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.
This is illegal in C90. Declarations have to come before all statements.
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.
And by the way, there's some compilation error on Windows with MSVC here. Seems to be related to size_t
, but I didn't really take a look into it.
tests/hook/execute.c
Outdated
const char * test_str = "a test string"; | ||
char **malloc_str = git__malloc(sizeof(*malloc_str)); | ||
*malloc_str = git__calloc(strlen(test_str), sizeof(*malloc_str)); | ||
strcpy(*malloc_str, test_str); |
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.
You could just have a normal char *malloc_str
and pass that to the callback. No need to allocate a pointer to a string here. The callback would then directly get the string and cast it to char *
.
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.
Yeah, I seem to remember having a hard time not freeing a stack-allocated string, hence the mess. I'll try to clean that up.
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.
Actually, looking at it, I'm not even sure what's the point of building something to pass to the destructor. The test is only concerned with making sure its called, freeing things is not its responsibility.
tests/hook/enumerate.c
Outdated
cl_git_pass(git_config_set_string(cfg, "core.hooksPath", ALT_HOOK_DIR)); | ||
|
||
cl_git_pass(git_hook_dir(&alt_hook_str, g_repo)); | ||
cl_git_pass(git_buf_sets(&alt_hook, alt_hook_str)); |
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.
You're leaking alt_hook_str
. You probably want git_buf_attach(&alt_hook, alt_hook_str, strlen(alt_hook_str) + 1)
here, which will also free the string later on.
I've added I hooked up (pun intended) As for the enum vs strings discussion, providing those higher-level functions make the enum useless from the executor standpoint. As I see it, it's only concerned with executing the given hook, with the given arguments and optional input. If you (still) like where this is going, I'll add more of the high-level functions. For th E5FC e record, here is my current FIXME comment 😉 :
|
Closing in favor of #4620. |
This is a first pass at supporting hooks. It aims to provide the basic blocks (as per PROJECTS.md), so enumeration, loading and saving is supported, and there's a quick skeleton of how I'm planning to handle hook execution.
A few points/questions :
git_hook_iterator_new()
) ?git_hook__execute(hook_name, ...)
and sprinkle those everywhere, but it might or might not be doable — I haven't been that far yet.