git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH/WIP v3 04/31] am: implement patch queue mechanism

From
Paul Tan <pyokagan@gmail.com>
Date
Jun 25, 2015, 15:16 UTC
Message-ID
<CACRoPnSZn=8keW3meUvLY-B_4vQigMTQW_VVvY2rU8ctjcxcaQ@mail.gmail.com>
In-Reply-To
<6560adbc8b1842dd369628980f1264c3@www.dscho.org>

On Wed, Jun 24, 2015 at 10:59 PM, Johannes Schindelin <johannes.schindelin@gmx.de> wrote:

Show 35 quoted lines
>> diff --git a/builtin/am.c b/builtin/am.c
>> index dbc8836..af68c51 100644
>> --- a/builtin/am.c
>> +++ b/builtin/am.c
>> @@ -6,6 +6,158 @@
>>  #include "cache.h"
>>  #include "builtin.h"
>>  #include "exec_cmd.h"
>> +#include "parse-options.h"
>> +#include "dir.h"
>> +
>> +struct am_state {
>> +     /* state directory path */
>> +     struct strbuf dir;
>> +
>> +     /* current and last patch numbers, 1-indexed */
>> +     int cur;
>> +     int last;
>> +};
>> +
>> +/**
>> + * Initializes am_state with the default values.
>> + */
>> +static void am_state_init(struct am_state *state)
>> +{
>> +     memset(state, 0, sizeof(*state));
>> +
>> +     strbuf_init(&state->dir, 0);
>> +}
>
> With strbufs, we use the initializer STRBUF_INIT. How about using
>
> #define AM_STATE_INIT { STRBUF_INIT, 0, 0 }
>
> here?

Later in the patch series am_state_init() will also take into account config settings when filling up the default values. e.g. see patches 25/31[1] or 31/31[2]. I think that is reasonable: the purpose of am_state_init() is to initialize the am_state struct with the default values, and the default values can be set by the user through the config settings.

This means, though, that we can't use initializers without introducing global variables.

[1] http://thread.gmane.org/gmane.comp.version-control.git/271967/focus=271972 [2] http://thread.gmane.org/gmane.comp.version-control.git/271967/focus=271972

Show 26 quoted lines
>> +/**
>> + * Reads the contents of `file`. The third argument can be used to give a hint
>> + * about the file size, to avoid reallocs. Returns number of bytes read on
>> + * success, -1 if the file does not exist. If trim is set, trailing whitespace
>> + * will be removed from the file contents.
>> + */
>> +static int read_state_file(struct strbuf *sb, const char *file,
>> size_t hint, int trim)
>> +{
>> +     strbuf_reset(sb);
>> +     if (strbuf_read_file(sb, file, hint) >= 0) {
>> +             if (trim)
>> +                     strbuf_trim(sb);
>> +
>> +             return sb->len;
>> +     }
>> +
>> +     if (errno == ENOENT)
>> +             return -1;
>> +
>> +     die_errno(_("could not read '%s'"), file);
>> +}
>
> A couple of thoughts:
>
> - why not reuse the strbuf by making it a part of the am_state()? That way, you can allocate, say, 1024 bytes (should be plenty enough for most of our operations) and just reuse them in all of the functions. We will not make any of this multi-threaded anyway, I don't think.

But too much usage of this temporary strbuf may lead to a situation where one function calls another, and both functions write to the strbuf and clobber its contents.

Besides, if we are talking about read_state_file(), it takes an external strbuf, so it gives the caller the freedom to choose which strbuf it uses (e.g. if it is stack allocated or in the am_state struct). I think it's more flexible this way.

> - Given that we only read short files all the time, why not skip the hint parameter? Especially if we reuse the strbuf, it should be good enough to allocate a reasonable buffer first and then just assume that we do not have to reallocate it all that often anyway.

Doh! Right, the hint parameter is quite useless, since in am_load() we use the same strbuf anyway. (And strbuf_init() can set a hint as well) I've removed it on my side.

> - Since we only read files from the state directory, why not pass the basename as parameter? That way we can avoid calling `am_path()` explicitly over and over again (and yours truly cannot forget to call `am_path()` in future patches).
Makes sense. After all, this function is called read_STATE_file() ;-)
> - If you agree with these suggestions, the signature would become something like
>
> static void read_state_file(struct am_state *state, const char *basename, int trim);
So for now, my function signature is

static void read_state_file(struct strbuf *sb, const struct am_state *state, const char *basename, int trim);

Show 17 quoted lines
>> +/**
>> + * Remove the am_state directory.
>> + */
>> +static void am_destroy(const struct am_state *state)
>> +{
>> +     struct strbuf sb = STRBUF_INIT;
>> +
>> +     strbuf_addstr(&sb, state->dir.buf);
>> +     remove_dir_recursively(&sb, 0);
>> +     strbuf_release(&sb);
>> +}
>
> Given that `remove_dir_recursively()` has to reset the strbuf with the directory's path to the original value before it returns (because it recurses into itself, therefore the value *has* to be reset when returning), we can just call
>
>     remove_dir_recursively(&state->dir, 0);
>
> and do not need another temporary strbuf.

Ah right. Although, state->dir is not an strbuf anymore on my side. As Junio[3] rightfully noted, state->dir is not modified by the am_*() API, so it's been changed to a char*. Which means an strbuf is required to be passed to remove_dir_recursively();

Show 11 quoted lines
>> +/**
>> + * Increments the patch pointer, and cleans am_state for the application of the
>> + * next patch.
>> + */
>> +static void am_next(struct am_state *state)
>> +{
>> +     state->cur++;
>> +     write_file(am_path(state, "next"), 1, "%d", state->cur);
>> +}
>
> Locking and re-checking the contents of "next" before writing the incremented value would probably be a little too paranoid...

Yeah, Junio did bring something like that[3]. I'm still thinking about it, though I don't think I would like this issue to block the patch series since it's a delicate issue, and git-am.sh does not do anything special either.

For now though, I've moved all the write_file()s into a central am_save() function, so if we want to do any locking or syncing it would be easy to modify am_save(), and then all the callers will benefit.

[3] http://thread.gmane.org/gmane.comp.version-control.git/271967/focus=271972
Previous: Johannes SchindelinNext: Paul Tan
Message 17 of 64 in “Make git-am a builtin”
  1. 00/31 Make git-am a builtinPaul Tan, Jun 18, 2015
  2. 01/31 wrapper: implement xopen()Paul Tan, Jun 18, 2015
  3. Johannes SchindelinJun 24, 2015
  4. Stefan BellerJun 24, 2015
  5. Johannes SchindelinJun 24, 2015
  6. Paul TanJul 1, 2015
  7. Paul TanJul 1, 2015
  8. 02/31 wrapper: implement xfopen()Paul Tan, Jun 18, 2015
  9. 03/31 am: implement skeletal builtin amPaul Tan, Jun 18, 2015
  10. Junio C HamanoJun 18, 2015
  11. Paul TanJun 19, 2015
  12. 04/31 am: implement patch queue mechanismPaul Tan, Jun 18, 2015
  13. Stefan BellerJun 18, 2015
  14. Junio C HamanoJun 18, 2015
  15. Paul TanJun 19, 2015
  16. Johannes SchindelinJun 24, 2015
  17. Paul TanJun 25, 2015
  18. 05/31 am: split out mbox/maildir patches with git-mailsplitPaul Tan, Jun 18, 2015
  19. Junio C HamanoJun 18, 2015
  20. 06/31 am: detect mbox patchesPaul Tan, Jun 18, 2015
  21. Junio C HamanoJun 18, 2015
  22. Paul TanJun 24, 2015
  23. Johannes SchindelinJun 24, 2015
  24. Paul TanJun 25, 2015
  25. Paul TanJun 26, 2015
  26. 07/31 am: extract patch, message and authorship with git-mailinfoPaul Tan, Jun 18, 2015
  27. Junio C HamanoJun 18, 2015
  28. Paul TanJun 19, 2015
  29. Junio C HamanoJun 19, 2015
  30. Paul TanJun 24, 2015
  31. Junio C HamanoJun 24, 2015
  32. Paul TanJun 25, 2015
  33. Johannes SchindelinJun 24, 2015
  34. Paul TanJun 26, 2015
  35. Junio C HamanoJun 26, 2015
  36. 08/31 am: apply patch with git-applyPaul Tan, Jun 18, 2015
  37. Junio C HamanoJun 18, 2015
  38. 09/31 am: commit applied patchPaul Tan, Jun 18, 2015
  39. 10/31 am: refresh the index at startPaul Tan, Jun 18, 2015
  40. Junio C HamanoJun 18, 2015
  41. Paul TanJun 19, 2015
  42. 11/31 am: refuse to apply patches if index is dirtyPaul Tan, Jun 18, 2015
  43. 12/31 am: implement --resolved/--continuePaul Tan, Jun 18, 2015
  44. 13/31 am: implement --skipPaul Tan, Jun 18, 2015
  45. 14/31 am: implement --abortPaul Tan, Jun 18, 2015
  46. 15/31 am: don't accept patches when there's a session in progressPaul Tan, Jun 18, 2015
  47. 16/31 am: implement quiet optionPaul Tan, Jun 18, 2015
  48. 17/31 am: exit with user friendly message on patch failurePaul Tan, Jun 18, 2015
  49. 18/31 am: implement am --signoffPaul Tan, Jun 18, 2015
  50. 19/31 cache-tree: introduce write_index_as_tree()Paul Tan, Jun 18, 2015
  51. 20/31 am: implement 3-way mergePaul Tan, Jun 18, 2015
  52. 21/31 am: --rebasingPaul Tan, Jun 18, 2015
  53. 22/31 am: don't use git-mailinfo if --rebasingPaul Tan, Jun 18, 2015
  54. 23/31 am: handle stray state directoryPaul Tan, Jun 18, 2015
  55. 24/31 am: implement -k/--keep, --keep-non-patchPaul Tan, Jun 18, 2015
  56. 25/31 am: implement --[no-]message-id, am.messageidPaul Tan, Jun 18, 2015
  57. 26/31 am: support --keep-cr, am.keepcrPaul Tan, Jun 18, 2015
  58. 27/31 am: implement --[no-]scissorsPaul Tan, Jun 18, 2015
  59. 28/31 am: pass git-apply's options to git-applyPaul Tan, Jun 18, 2015
  60. 29/31 am: implement --ignore-datePaul Tan, Jun 18, 2015
  61. 30/31 am: implement --committer-date-is-author-datePaul Tan, Jun 18, 2015
  62. 31/31 am: implement -S/--gpg-sign, commit.gpgsignPaul Tan, Jun 18, 2015
  63. Paul TanJun 19, 2015
  64. Johannes SchindelinJun 19, 2015

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.