git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v7 0/4] difftool: dir-diff improvements and refactoring
@ 2021-10-01  1:37 David Aguilar
  2021-10-01  1:37 ` [PATCH v7 1/4] difftool: create a tmpdir path without repeated slashes David Aguilar
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: David Aguilar @ 2021-10-01  1:37 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Junio C Hamano, Ævar Arnfjörð Bjarmason,
	Johannes Schindelin

Changes since v6:

- avoid returning -1 to cmd_main() by adjusting the return site in
  "create a tmpdir path without repeated slashes".

- "refactor dir-diff to write files using helper functions" was
  reworked to add two helper functions instead of one so that the
  common checks for *entry->{left,right} can be handled in a single place.

- write_entry() was renamed to write_file_in_directory() and its
  signature was adjusted to match how write_file() takes its parameters.

- write_file_in_directory() gets called from the newly added
  write_standin_files() helper which encompases the guts of
  the symlinks and submodules hashmap loops.

- Comments were added describing the purpose of the helper functions.

David Aguilar (4):
  difftool: create a tmpdir path without repeated slashes
  difftool: refactor dir-diff to write files using helper functions
  difftool: remove an unnecessary call to strbuf_release()
  difftool: add a missing space to the run_dir_diff() comments

 builtin/difftool.c  | 104 ++++++++++++++++++++++----------------------
 t/t7800-difftool.sh |   7 +++
 2 files changed, 60 insertions(+), 51 deletions(-)

Range-diff against v6:
1:  121186ca0f ! 1:  14b5618945 difftool: create a tmpdir path without repeated slashes
    @@ Commit message
         Strip trailing slashes from the value read from TMPDIR to avoid
         repeated slashes in the generated paths.
     
    -    Adjust the error handling to avoid leaking strbufs.
    +    Adjust the error handling to avoid leaking strbufs and to avoid
    +    returning -1 to cmd_main().
     
         Signed-off-by: David Aguilar <davvid@gmail.com>
     
    @@ builtin/difftool.c: static int run_dir_diff(const char *extcmd, int symlinks, co
      	strbuf_release(&buf);
     +	strbuf_release(&tmpdir);
      
    - 	return ret;
    +-	return ret;
    ++	return (ret < 0) ? 1 : ret;
      }
    + 
    + static int run_file_diff(int prompt, const char *prefix,
     
      ## t/t7800-difftool.sh ##
     @@ t/t7800-difftool.sh: run_dir_diff_test 'difftool --dir-diff' '
4:  8e7d54616f ! 2:  0824321eb9 difftool: refactor dir-diff to write files using a helper function
    @@ Metadata
     Author: David Aguilar <davvid@gmail.com>
     
      ## Commit message ##
    -    difftool: refactor dir-diff to write files using a helper function
    +    difftool: refactor dir-diff to write files using helper functions
     
    -    Add a write_entry() helper function to handle the unlinking and writing
    +    Add a helpers function to handle the unlinking and writing
         of the dir-diff submodule and symlink stand-in files.
     
    -    Use write_entry() inside of the hashmap loops to eliminate duplicate
    -    code and to safeguard the submodules hashmap loop against the
    -    symlink-chasing behavior that 5bafb3576a (difftool: fix symlink-file
    -    writing in dir-diff mode, 2021-09-22) addressed.
    +    Use the helpers to implement the guts of the hashmap loops.
    +    This eliminate duplicate code and safeguards the submodules
    +    hashmap loop against the symlink-chasing behavior that 5bafb3576a
    +    (difftool: fix symlink-file writing in dir-diff mode, 2021-09-22)
    +    addressed.
     
         The submodules loop should not strictly require the unlink() call that
         this is introducing to them, but it does not necessarily hurt them
    @@ builtin/difftool.c: static int checkout_path(unsigned mode, struct object_id *oi
      	return ret;
      }
      
    -+static void write_entry(const char *path, const char *content,
    -+			struct strbuf *buf, size_t len)
    ++static void write_file_in_directory(struct strbuf *dir, size_t dir_len,
    ++			const char *path, const char *content)
     +{
    -+	if (!*content)
    -+		return;
    -+	add_path(buf, len, path);
    -+	ensure_leading_directories(buf->buf);
    -+	unlink(buf->buf);
    -+	write_file(buf->buf, "%s", content);
    ++	add_path(dir, dir_len, path);
    ++	ensure_leading_directories(dir->buf);
    ++	unlink(dir->buf);
    ++	write_file(dir->buf, "%s", content);
    ++}
    ++
    ++/* Write the file contents for the left and right sides of the difftool
    ++ * dir-diff representation for submodules and symlinks. Symlinks and submodules
    ++ * are written as regular text files so that external diff tools can diff them
    ++ * as text files, resulting in behavior that is analogous to to what "git diff"
    ++ * displays for symlink and submodule diffs.
    ++ */
    ++static void write_standin_files(struct pair_entry *entry,
    ++			struct strbuf *ldir, size_t ldir_len,
    ++			struct strbuf *rdir, size_t rdir_len)
    ++{
    ++	if (*entry->left)
    ++		write_file_in_directory(ldir, ldir_len, entry->path, entry->left);
    ++	if (*entry->right)
    ++		write_file_in_directory(rdir, rdir_len, entry->path, entry->right);
     +}
     +
      static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
    @@ builtin/difftool.c: static int run_dir_diff(const char *extcmd, int symlinks, co
     -			ensure_leading_directories(rdir.buf);
     -			write_file(rdir.buf, "%s", entry->right);
     -		}
    -+		write_entry(entry->path, entry->left, &ldir, ldir_len);
    -+		write_entry(entry->path, entry->right, &rdir, rdir_len);
    ++		write_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);
      	}
      
      	/*
    @@ builtin/difftool.c: static int run_dir_diff(const char *extcmd, int symlinks, co
     -			write_file(rdir.buf, "%s", entry->right);
     -		}
     +
    -+		write_entry(entry->path, entry->left, &ldir, ldir_len);
    -+		write_entry(entry->path, entry->right, &rdir, rdir_len);
    ++		write_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);
      	}
      
      	strbuf_release(&buf);
5:  8db6ae3373 ! 3:  94ad86157e difftool: remove an unnecessary call to strbuf_release()
    @@ Commit message
     
      ## builtin/difftool.c ##
     @@ builtin/difftool.c: static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
    - 		write_entry(entry->path, entry->right, &rdir, rdir_len);
    + 		write_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);
      	}
      
     -	strbuf_release(&buf);
2:  080a113917 = 4:  5b6dfe5e5c difftool: add a missing space to the run_dir_diff() comments
3:  1fbc47a58d < -:  ---------- difftool: avoid returning -1 to cmd_main() from run_dir_diff()
-- 
2.33.0.886.g5b6dfe5e5c


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v7 1/4] difftool: create a tmpdir path without repeated slashes
  2021-10-01  1:37 [PATCH v7 0/4] difftool: dir-diff improvements and refactoring David Aguilar
@ 2021-10-01  1:37 ` David Aguilar
  2021-10-01  1:37 ` [PATCH v7 2/4] difftool: refactor dir-diff to write files using helper functions David Aguilar
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: David Aguilar @ 2021-10-01  1:37 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Junio C Hamano, Ævar Arnfjörð Bjarmason,
	Johannes Schindelin

The paths generated by difftool are passed to user-facing diff tools.
Using paths with repeated slashes in them is a cosmetic blemish that
is exposed to users and can be avoided.

Use a strbuf to create the buffer used for the dir-diff tmpdir.
Strip trailing slashes from the value read from TMPDIR to avoid
repeated slashes in the generated paths.

Adjust the error handling to avoid leaking strbufs and to avoid
returning -1 to cmd_main().

Signed-off-by: David Aguilar <davvid@gmail.com>
---
 builtin/difftool.c  | 50 ++++++++++++++++++++++-----------------------
 t/t7800-difftool.sh |  7 +++++++
 2 files changed, 31 insertions(+), 26 deletions(-)

diff --git a/builtin/difftool.c b/builtin/difftool.c
index 210da03908..0e24421682 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -252,16 +252,6 @@ static void changed_files(struct hashmap *result, const char *index_path,
 	strbuf_release(&buf);
 }
 
-static NORETURN void exit_cleanup(const char *tmpdir, int exit_code)
-{
-	struct strbuf buf = STRBUF_INIT;
-	strbuf_addstr(&buf, tmpdir);
-	remove_dir_recursively(&buf, 0);
-	if (exit_code)
-		warning(_("failed: %d"), exit_code);
-	exit(exit_code);
-}
-
 static int ensure_leading_directories(char *path)
 {
 	switch (safe_create_leading_directories(path)) {
@@ -333,16 +323,16 @@ static int checkout_path(unsigned mode, struct object_id *oid,
 static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 			struct child_process *child)
 {
-	char tmpdir[PATH_MAX];
 	struct strbuf info = STRBUF_INIT, lpath = STRBUF_INIT;
 	struct strbuf rpath = STRBUF_INIT, buf = STRBUF_INIT;
 	struct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT;
 	struct strbuf wtdir = STRBUF_INIT;
-	char *lbase_dir, *rbase_dir;
+	struct strbuf tmpdir = STRBUF_INIT;
+	char *lbase_dir = NULL, *rbase_dir = NULL;
 	size_t ldir_len, rdir_len, wtdir_len;
 	const char *workdir, *tmp;
 	int ret = 0, i;
-	FILE *fp;
+	FILE *fp = NULL;
 	struct hashmap working_tree_dups = HASHMAP_INIT(working_tree_entry_cmp,
 							NULL);
 	struct hashmap submodules = HASHMAP_INIT(pair_cmp, NULL);
@@ -351,7 +341,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	struct pair_entry *entry;
 	struct index_state wtindex;
 	struct checkout lstate, rstate;
-	int rc, flags = RUN_GIT_CMD, err = 0;
+	int flags = RUN_GIT_CMD, err = 0;
 	const char *helper_argv[] = { "difftool--helper", NULL, NULL, NULL };
 	struct hashmap wt_modified, tmp_modified;
 	int indices_loaded = 0;
@@ -360,11 +350,15 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 
 	/* Setup temp directories */
 	tmp = getenv("TMPDIR");
-	xsnprintf(tmpdir, sizeof(tmpdir), "%s/git-difftool.XXXXXX", tmp ? tmp : "/tmp");
-	if (!mkdtemp(tmpdir))
-		return error("could not create '%s'", tmpdir);
-	strbuf_addf(&ldir, "%s/left/", tmpdir);
-	strbuf_addf(&rdir, "%s/right/", tmpdir);
+	strbuf_add_absolute_path(&tmpdir, tmp ? tmp : "/tmp");
+	strbuf_trim_trailing_dir_sep(&tmpdir);
+	strbuf_addstr(&tmpdir, "/git-difftool.XXXXXX");
+	if (!mkdtemp(tmpdir.buf)) {
+		ret = error("could not create '%s'", tmpdir.buf);
+		goto finish;
+	}
+	strbuf_addf(&ldir, "%s/left/", tmpdir.buf);
+	strbuf_addf(&rdir, "%s/right/", tmpdir.buf);
 	strbuf_addstr(&wtdir, workdir);
 	if (!wtdir.len || !is_dir_sep(wtdir.buf[wtdir.len - 1]))
 		strbuf_addch(&wtdir, '/');
@@ -580,7 +574,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		flags = 0;
 	} else
 		setenv("GIT_DIFFTOOL_DIRDIFF", "true", 1);
-	rc = run_command_v_opt(helper_argv, flags);
+	ret = run_command_v_opt(helper_argv, flags);
 
 	/* TODO: audit for interaction with sparse-index. */
 	ensure_full_index(&wtindex);
@@ -614,7 +608,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		if (!indices_loaded) {
 			struct lock_file lock = LOCK_INIT;
 			strbuf_reset(&buf);
-			strbuf_addf(&buf, "%s/wtindex", tmpdir);
+			strbuf_addf(&buf, "%s/wtindex", tmpdir.buf);
 			if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 ||
 			    write_locked_index(&wtindex, &lock, COMMIT_LOCK)) {
 				ret = error("could not write %s", buf.buf);
@@ -644,11 +638,14 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	}
 
 	if (err) {
-		warning(_("temporary files exist in '%s'."), tmpdir);
+		warning(_("temporary files exist in '%s'."), tmpdir.buf);
 		warning(_("you may want to cleanup or recover these."));
-		exit(1);
-	} else
-		exit_cleanup(tmpdir, rc);
+		ret = 1;
+	} else {
+		remove_dir_recursively(&tmpdir, 0);
+		if (ret)
+			warning(_("failed: %d"), ret);
+	}
 
 finish:
 	if (fp)
@@ -660,8 +657,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	strbuf_release(&rdir);
 	strbuf_release(&wtdir);
 	strbuf_release(&buf);
+	strbuf_release(&tmpdir);
 
-	return ret;
+	return (ret < 0) ? 1 : ret;
 }
 
 static int run_file_diff(int prompt, const char *prefix,
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 528e0dabf0..096456292c 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -453,6 +453,13 @@ run_dir_diff_test 'difftool --dir-diff' '
 	grep "^file$" output
 '
 
+run_dir_diff_test 'difftool --dir-diff avoids repeated slashes in TMPDIR' '
+	TMPDIR="${TMPDIR:-/tmp}////" \
+		git difftool --dir-diff $symlinks --extcmd echo branch >output &&
+	grep -v // output >actual &&
+	test_line_count = 1 actual
+'
+
 run_dir_diff_test 'difftool --dir-diff ignores --prompt' '
 	git difftool --dir-diff $symlinks --prompt --extcmd ls branch >output &&
 	grep "^sub$" output &&
-- 
2.33.0.886.g5b6dfe5e5c


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v7 2/4] difftool: refactor dir-diff to write files using helper functions
  2021-10-01  1:37 [PATCH v7 0/4] difftool: dir-diff improvements and refactoring David Aguilar
  2021-10-01  1:37 ` [PATCH v7 1/4] difftool: create a tmpdir path without repeated slashes David Aguilar
@ 2021-10-01  1:37 ` David Aguilar
  2021-10-01  1:37 ` [PATCH v7 3/4] difftool: remove an unnecessary call to strbuf_release() David Aguilar
  2021-10-01  1:37 ` [PATCH v7 4/4] difftool: add a missing space to the run_dir_diff() comments David Aguilar
  3 siblings, 0 replies; 5+ messages in thread
From: David Aguilar @ 2021-10-01  1:37 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Junio C Hamano, Ævar Arnfjörð Bjarmason,
	Johannes Schindelin

Add a helpers function to handle the unlinking and writing
of the dir-diff submodule and symlink stand-in files.

Use the helpers to implement the guts of the hashmap loops.
This eliminate duplicate code and safeguards the submodules
hashmap loop against the symlink-chasing behavior that 5bafb3576a
(difftool: fix symlink-file writing in dir-diff mode, 2021-09-22)
addressed.

The submodules loop should not strictly require the unlink() call that
this is introducing to them, but it does not necessarily hurt them
either beyond the cost of the extra unlink().

Signed-off-by: David Aguilar <davvid@gmail.com>
---
 builtin/difftool.c | 50 ++++++++++++++++++++++++++--------------------
 1 file changed, 28 insertions(+), 22 deletions(-)

diff --git a/builtin/difftool.c b/builtin/difftool.c
index 0e24421682..f3cd1e5b53 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -320,6 +320,31 @@ static int checkout_path(unsigned mode, struct object_id *oid,
 	return ret;
 }
 
+static void write_file_in_directory(struct strbuf *dir, size_t dir_len,
+			const char *path, const char *content)
+{
+	add_path(dir, dir_len, path);
+	ensure_leading_directories(dir->buf);
+	unlink(dir->buf);
+	write_file(dir->buf, "%s", content);
+}
+
+/* Write the file contents for the left and right sides of the difftool
+ * dir-diff representation for submodules and symlinks. Symlinks and submodules
+ * are written as regular text files so that external diff tools can diff them
+ * as text files, resulting in behavior that is analogous to to what "git diff"
+ * displays for symlink and submodule diffs.
+ */
+static void write_standin_files(struct pair_entry *entry,
+			struct strbuf *ldir, size_t ldir_len,
+			struct strbuf *rdir, size_t rdir_len)
+{
+	if (*entry->left)
+		write_file_in_directory(ldir, ldir_len, entry->path, entry->left);
+	if (*entry->right)
+		write_file_in_directory(rdir, rdir_len, entry->path, entry->right);
+}
+
 static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 			struct child_process *child)
 {
@@ -529,16 +554,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	 */
 	hashmap_for_each_entry(&submodules, &iter, entry,
 				entry /* member name */) {
-		if (*entry->left) {
-			add_path(&ldir, ldir_len, entry->path);
-			ensure_leading_directories(ldir.buf);
-			write_file(ldir.buf, "%s", entry->left);
-		}
-		if (*entry->right) {
-			add_path(&rdir, rdir_len, entry->path);
-			ensure_leading_directories(rdir.buf);
-			write_file(rdir.buf, "%s", entry->right);
-		}
+		write_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);
 	}
 
 	/*
@@ -548,18 +564,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	 */
 	hashmap_for_each_entry(&symlinks2, &iter, entry,
 				entry /* member name */) {
-		if (*entry->left) {
-			add_path(&ldir, ldir_len, entry->path);
-			ensure_leading_directories(ldir.buf);
-			unlink(ldir.buf);
-			write_file(ldir.buf, "%s", entry->left);
-		}
-		if (*entry->right) {
-			add_path(&rdir, rdir_len, entry->path);
-			ensure_leading_directories(rdir.buf);
-			unlink(rdir.buf);
-			write_file(rdir.buf, "%s", entry->right);
-		}
+
+		write_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);
 	}
 
 	strbuf_release(&buf);
-- 
2.33.0.886.g5b6dfe5e5c


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v7 3/4] difftool: remove an unnecessary call to strbuf_release()
  2021-10-01  1:37 [PATCH v7 0/4] difftool: dir-diff improvements and refactoring David Aguilar
  2021-10-01  1:37 ` [PATCH v7 1/4] difftool: create a tmpdir path without repeated slashes David Aguilar
  2021-10-01  1:37 ` [PATCH v7 2/4] difftool: refactor dir-diff to write files using helper functions David Aguilar
@ 2021-10-01  1:37 ` David Aguilar
  2021-10-01  1:37 ` [PATCH v7 4/4] difftool: add a missing space to the run_dir_diff() comments David Aguilar
  3 siblings, 0 replies; 5+ messages in thread
From: David Aguilar @ 2021-10-01  1:37 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Junio C Hamano, Ævar Arnfjörð Bjarmason,
	Johannes Schindelin

The `buf` strbuf is reused again later in the same function, so there
is no benefit to calling strbuf_release(). The subsequent usage is
already using strbuf_reset() to reset the buffer, so releasing it
early is only going to lead to a wasteful reallocation.

Remove the early call to strbuf_release(). The same strbuf is already
cleaned up in the "finish:" section so nothing is leaked, either.

Signed-off-by: David Aguilar <davvid@gmail.com>
---
 builtin/difftool.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/builtin/difftool.c b/builtin/difftool.c
index f3cd1e5b53..437474fea0 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -568,8 +568,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		write_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);
 	}
 
-	strbuf_release(&buf);
-
 	strbuf_setlen(&ldir, ldir_len);
 	helper_argv[1] = ldir.buf;
 	strbuf_setlen(&rdir, rdir_len);
-- 
2.33.0.886.g5b6dfe5e5c


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v7 4/4] difftool: add a missing space to the run_dir_diff() comments
  2021-10-01  1:37 [PATCH v7 0/4] difftool: dir-diff improvements and refactoring David Aguilar
                   ` (2 preceding siblings ...)
  2021-10-01  1:37 ` [PATCH v7 3/4] difftool: remove an unnecessary call to strbuf_release() David Aguilar
@ 2021-10-01  1:37 ` David Aguilar
  3 siblings, 0 replies; 5+ messages in thread
From: David Aguilar @ 2021-10-01  1:37 UTC (permalink / raw)
  To: Git Mailing List
  Cc: Junio C Hamano, Ævar Arnfjörð Bjarmason,
	Johannes Schindelin

Signed-off-by: David Aguilar <davvid@gmail.com>
---
 builtin/difftool.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/difftool.c b/builtin/difftool.c
index 437474fea0..4931c10845 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -558,7 +558,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	}
 
 	/*
-	 * Symbolic links require special treatment.The standard "git diff"
+	 * Symbolic links require special treatment. The standard "git diff"
 	 * shows only the link itself, not the contents of the link target.
 	 * This loop replicates that behavior.
 	 */
-- 
2.33.0.886.g5b6dfe5e5c


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-10-01  1:38 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-01  1:37 [PATCH v7 0/4] difftool: dir-diff improvements and refactoring David Aguilar
2021-10-01  1:37 ` [PATCH v7 1/4] difftool: create a tmpdir path without repeated slashes David Aguilar
2021-10-01  1:37 ` [PATCH v7 2/4] difftool: refactor dir-diff to write files using helper functions David Aguilar
2021-10-01  1:37 ` [PATCH v7 3/4] difftool: remove an unnecessary call to strbuf_release() David Aguilar
2021-10-01  1:37 ` [PATCH v7 4/4] difftool: add a missing space to the run_dir_diff() comments David Aguilar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).