Re: [PATCH] worktree: add -z option for list subcommand

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Eric & Rafael

On 07/01/2021 03:34, Eric Sunshine wrote:
On Tue, Jan 5, 2021 at 6:02 AM Phillip Wood <phillip.wood123@xxxxxxxxx> wrote:
Add a -z option to be used in conjunction with --porcelain that gives
NUL-terminated output. This enables 'worktree list --porcelain' to
handle worktree paths that contain newlines.

Adding a -z mode makes a lot of sense. This, along with a fix to call
quote_c_style() on paths in normal (not `-z`) porcelain mode,

I'm concerned that starting to quote paths will break backwards compatibility. Even if we restricted the quoting to just those paths that contain '\n' there is no way to distinguish between a quoted path and one that begins and ends with ". This is the reason I prefer to add `-z` instead of taking Rafael's patch to quote the lock reason as that patch still leaves the output of `git worktree list --porcelain` ambiguous and it cannot be fixed without breaking existing users. A counter argument to all this is that there are thousands of users on file systems that cannot have newlines in paths and Rafael's patch is definitely a net win for them.

can
easily be done after Rafael's series lands. Or they could be done
before his series, though that might make a lot of extra work for him.

I would definitely be easiest to wait for Rafael's series to land if we want to add `-z` separately

Signed-off-by: Phillip Wood <phillip.wood@xxxxxxxxxxxxx>
---
I found an old patch that added NUL termination. I've rebased it
but the new test fails as there seems to be another worktree thats
been added since I wrote this, anyway I thought it might be a useful
start for adding a `-z` option.

The test failure is fallout from a "bug" in a test added by Rafael's
earlier series[1] which was not caught by the reviewer[2]. In fact,
his current series has a drive-by fix[3] for this bug in patch [6/7].
Applying that fix (or the refinement[4] I suggested in my review)
makes your test work.

Thanks ever so much for taking the time to track down the cause of the test failure.

Best Wishes

Phillip

[1]: https://lore.kernel.org/git/20201011101152.5291-2-rafaeloliveira.cs@xxxxxxxxx/
[2]: https://lore.kernel.org/git/CAPig+cS8hvX4GCsnfLBnQ4Q_AkUad=bw7rjVcaOqSEqcLZvx8w@xxxxxxxxxxxxxx/
[3]: https://lore.kernel.org/git/20210104162128.95281-7-rafaeloliveira.cs@xxxxxxxxx/
[4]: https://lore.kernel.org/git/CAPig+cRysXpK0e1xXOuVd+EtkeyTk8FR6MUrL=Bg3W4ve8jdNA@xxxxxxxxxxxxxx/

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
@@ -217,7 +217,13 @@ This can also be set up as the default behaviour by using the
+-z::
+       When `--porcelain` is specified with `list` terminate each line with a
+       NUL rather than a newline. This makes it possible to parse the output
+       when a worktree path contains a newline character.

If we fix normal-mode porcelain to call quote_c_style(), then we can
drop the last sentence or refine it to say something along the lines
of it being easier to deal with paths with embedded newlines than in
normal porcelain mode.

diff --git a/builtin/worktree.c b/builtin/worktree.c
@@ -640,19 +640,25 @@ static int add(int ac, const char **av, const char *prefix)
+static void show_worktree_porcelain(struct worktree *wt, int line_terminator)
  {
+       printf("worktree %s", wt->path);
+       fputc(line_terminator, stdout);
+       if (wt->is_bare) {
+               printf("bare");
+               fputc(line_terminator, stdout);
+       } else {
+               printf("HEAD %s", oid_to_hex(&wt->head_oid));
+               fputc(line_terminator, stdout);
+               if (wt->is_detached) {
+                       printf("detached");
+                       fputc(line_terminator, stdout);
+               } else if (wt->head_ref) {
+                       printf("branch %s", wt->head_ref);
+                       fputc(line_terminator, stdout);
+               }

Perhaps this could all be done a bit more concisely with printf()
alone rather than combining it with fputc(). For instance:

     printf("worktree %s%c", wt->path, line_terminator);

and so on.

-       printf("\n");
+       fputc(line_terminator, stdout);

This use of fputc() makes sense.

@@ -720,15 +726,20 @@ static void pathsort(struct worktree **wt)
  static int list(int ac, const char **av, const char *prefix)
  {
+               OPT_SET_INT('z', NULL, &line_terminator,
+                           N_("fields are separated with NUL character"), '\0'),

"fields" sounds a little odd. "lines" might make more sense. "records"
might be even better and matches the wording of some other Git
commands accepting `-z`.

+       else if (!line_terminator && !porcelain)
+               die(_("'-z' requires '--porcelain'"));

Other error messages in this file don't quote command-line options, so:

     die(_("-z requires --porcelain"));

would be more consistent.

diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh
@@ -71,6 +71,28 @@ test_expect_success '"list" all worktrees with locked annotation' '
+test_expect_success '"list" all worktrees --porcelain -z' '
+       test_when_finished "rm -rf here _actual actual expect &&
+                               git worktree prune" &&
+       printf "worktree %sQHEAD %sQbranch %sQQ" \
+               "$(git rev-parse --show-toplevel)" \
+               "$(git rev-parse HEAD)" \
+               "$(git symbolic-ref HEAD)" >expect &&
+       git worktree add --detach here master &&
+       printf "worktree %sQHEAD %sQdetachedQQ" \
+               "$(git -C here rev-parse --show-toplevel)" \
+               "$(git rev-parse HEAD)" >>expect &&
+       git worktree list --porcelain -z >_actual &&
+       cat _actual | tr "\0" Q >actual &&

Or just use nul_to_q():

     nul_to_q <_actual >actual &&

(And there's no need to `cat` the file.)

+       test_cmp expect actual
+'
+
+test_expect_success '"list" -z fails without --porcelain' '
+       test_when_finished "rm -rf here && git worktree prune" &&
+       git worktree add --detach here master &&
+       test_must_fail git worktree list -z
+'

I don't think there's any need for this test to create (and cleanup) a
worktree. So, the entire test could collapse to:

     test_expect_success '"list" -z fails without --porcelain' '
         test_must_fail git worktree list -z
     '




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux