diff mbox series

[v4,09/27] revisions API users: use release_revisions() needing REV_INFO_INIT

Message ID patch-v4-09.27-2f4e65fb534-20220331T005325Z-avarab@gmail.com (mailing list archive)
State Superseded
Headers show
Series revision.[ch]: add and use release_revisions() | expand

Commit Message

Ævar Arnfjörð Bjarmason March 31, 2022, 1:11 a.m. UTC
Use release_revisions() to various users of "struct rev_list" which
need to have their "struct rev_info" zero-initialized before we can
start using it.

To do this add a stub "REV_INFO_INIT" macro, ideally macro would be
able to fully initialize a "struct rev_info", but all it does is the
equivalent of assigning "{ 0 }" to the struct, the API user will still
need to use repo_init_revisions(). In some future follow-up work we'll
hopefully make REV_INFO_INIT be a "stand-alone" init likke STRBUF_INIT
and other similar macros.

For the bundle.c code see the early exit case added in
3bbbe467f29 (bundle verify: error out if called without an object
database, 2019-05-27).

For the relevant bisect.c code see 45b6370812c (bisect: libify
`check_good_are_ancestors_of_bad` and its dependents, 2020-02-17).

For the submodule.c code see the "goto" on "(!left || !right || !sub)"
added in 8e6df65015f (submodule: refactor show_submodule_summary with
helper function, 2016-08-31).

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 bisect.c                    | 18 ++++++++++++------
 builtin/submodule--helper.c |  3 ++-
 bundle.c                    | 12 ++++++++----
 revision.h                  | 13 ++++++++++++-
 submodule.c                 |  3 ++-
 5 files changed, 36 insertions(+), 13 deletions(-)

Comments

Junio C Hamano March 31, 2022, 9:14 p.m. UTC | #1
Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:

> Use release_revisions() to various users of "struct rev_list" which
> need to have their "struct rev_info" zero-initialized before we can
> start using it.
>
> To do this add a stub "REV_INFO_INIT" macro, ideally macro would be
> able to fully initialize a "struct rev_info", but all it does is the
> equivalent of assigning "{ 0 }" to the struct, the API user will still
> need to use repo_init_revisions(). In some future follow-up work we'll
> hopefully make REV_INFO_INIT be a "stand-alone" init likke STRBUF_INIT
> and other similar macros.

I do not think we want to leave such a misleading paragraph to
future developers.

Yes, We may want to move some of what init_revisions() does to
REV_INFO_INIT(), and for that, it helps to start using greppable
string REV_INFO_INT early rather than { 0 } to ease such transition,
and that is what we should be stressing, instead of ranting "it does
not do anything, so why are we stupidly introducing a name, instead
of writing { 0 }, which is what amounts to it anyway?" without
explicitly saying so but hinting with words like "stub", "all it
does is", and "will still need to".

Is that some kind of passive-aggressive thing?

You cannot use get_revision() even after calling init_revisions(),
and still need to use setup_revisions() before hand, but that does
not mean init_revisions() is not doing its job.  It may be
implemented as the zero-initialization right now, but it misses the
point to put a stress on the fact that it doesn't do much now.
Ævar Arnfjörð Bjarmason April 1, 2022, 10:31 a.m. UTC | #2
On Thu, Mar 31 2022, Junio C Hamano wrote:

> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:
>
>> Use release_revisions() to various users of "struct rev_list" which
>> need to have their "struct rev_info" zero-initialized before we can
>> start using it.
>>
>> To do this add a stub "REV_INFO_INIT" macro, ideally macro would be
>> able to fully initialize a "struct rev_info", but all it does is the
>> equivalent of assigning "{ 0 }" to the struct, the API user will still
>> need to use repo_init_revisions(). In some future follow-up work we'll
>> hopefully make REV_INFO_INIT be a "stand-alone" init likke STRBUF_INIT
>> and other similar macros.
>
> I do not think we want to leave such a misleading paragraph to
> future developers.
>
> Yes, We may want to move some of what init_revisions() does to
> REV_INFO_INIT(), and for that, it helps to start using greppable
> string REV_INFO_INT early rather than { 0 } to ease such transition,
> and that is what we should be stressing, instead of ranting "it does
> not do anything, so why are we stupidly introducing a name, instead
> of writing { 0 }, which is what amounts to it anyway?" without
> explicitly saying so but hinting with words like "stub", "all it
> does is", and "will still need to".
>
> Is that some kind of passive-aggressive thing?

No, I'm not trying to be a dick. I'm just confused, sorry :)

I.e. I didn't grok what you really wanted from that REV_INFO_INIT
pattern in the beginning, and I largely draft my commit messages as a
way to adequately explain things to myself.

The "stub" and "not sufficient (yet!)" part of the docs is a (probably
too leaky) artifact of having (after the whole thread about
REV_INFO_INIT started) gotten that mostly working as a "real"
initializer.

Which I figured I'd submit at some point after this lands. The grep.c
case was quite tricky, but the rest look pretty easy, I just didn't
finish them.

I can re-roll & omit this entirely from the commit message, and the
API docs.

I just thought, and still think, that it's worth drawing the API user's
attention to the fact that unlike most stand-alone *_INIT macros this
one isn't sufficient to be up & running with a "struct rev_info".

Which isn't the case with {STRBUF,STRVEC}_INIT, CHILD_PROCESS_INIT,
STRING_LIST_INIT_* etc. etc., i.e. if you've used any of these:

    git grep -h -o '\S+_INIT;' | sort | uniq -c | sort -nr

You're likely to expect them to "flow" a certain way when it comes to
initializing the struct on the stack, but this one will be a bit of an
odd case while repo_init_revisions() is still required, which seems to
me to be worth explaining.

But not enough to argue about it, so whatever you'd prefer...

> You cannot use get_revision() even after calling init_revisions(),
> and still need to use setup_revisions() before hand, but that does
> not mean init_revisions() is not doing its job.  It may be
> implemented as the zero-initialization right now, but it misses the
> point to put a stress on the fact that it doesn't do much now.

I don't think it's broken, having gotten most of the way towards
rewriting it to be macro-init'd there are some tricky edge cases where
we might always need to call a function to fully initialize it.

But per the above I thought it made sense to explain that this
particular *_INIT is a bit of an odd case if you've gotten used to other
such macros.
diff mbox series

Patch

diff --git a/bisect.c b/bisect.c
index cc6b8b6230d..b63669cc9d7 100644
--- a/bisect.c
+++ b/bisect.c
@@ -1010,7 +1010,7 @@  void read_bisect_terms(const char **read_bad, const char **read_good)
  */
 enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
 {
-	struct rev_info revs;
+	struct rev_info revs = REV_INFO_INIT;
 	struct commit_list *tried;
 	int reaches = 0, all = 0, nr, steps;
 	enum bisect_error res = BISECT_OK;
@@ -1035,7 +1035,7 @@  enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
 
 	res = check_good_are_ancestors_of_bad(r, prefix, no_checkout);
 	if (res)
-		return res;
+		goto cleanup;
 
 	bisect_rev_setup(r, &revs, prefix, "%s", "^%s", 1);
 
@@ -1060,14 +1060,16 @@  enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
 		       term_good,
 		       term_bad);
 
-		return BISECT_FAILED;
+		res = BISECT_FAILED;
+		goto cleanup;
 	}
 
 	if (!all) {
 		fprintf(stderr, _("No testable commit found.\n"
 			"Maybe you started with bad path arguments?\n"));
 
-		return BISECT_NO_TESTABLE_COMMIT;
+		res = BISECT_NO_TESTABLE_COMMIT;
+		goto cleanup;
 	}
 
 	bisect_rev = &revs.commits->item->object.oid;
@@ -1087,7 +1089,8 @@  enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
 		 * for negative return values for early returns up
 		 * until the cmd_bisect__helper() caller.
 		 */
-		return BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
+		res = BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
+		goto cleanup;
 	}
 
 	nr = all - reaches - 1;
@@ -1106,7 +1109,10 @@  enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
 	/* Clean up objects used, as they will be reused. */
 	repo_clear_commit_marks(r, ALL_REV_FLAGS);
 
-	return bisect_checkout(bisect_rev, no_checkout);
+	res = bisect_checkout(bisect_rev, no_checkout);
+cleanup:
+	release_revisions(&revs);
+	return res;
 }
 
 static inline int log2i(int n)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 24980863f68..cda33ee4d2b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -766,7 +766,7 @@  static void status_submodule(const char *path, const struct object_id *ce_oid,
 {
 	char *displaypath;
 	struct strvec diff_files_args = STRVEC_INIT;
-	struct rev_info rev;
+	struct rev_info rev = REV_INFO_INIT;
 	int diff_files_result;
 	struct strbuf buf = STRBUF_INIT;
 	const char *git_dir;
@@ -853,6 +853,7 @@  static void status_submodule(const char *path, const struct object_id *ce_oid,
 cleanup:
 	strvec_clear(&diff_files_args);
 	free(displaypath);
+	release_revisions(&rev);
 }
 
 static void status_submodule_cb(const struct cache_entry *list_item,
diff --git a/bundle.c b/bundle.c
index d50cfb5aa7e..6a870a6edb7 100644
--- a/bundle.c
+++ b/bundle.c
@@ -196,14 +196,16 @@  int verify_bundle(struct repository *r,
 	 * to be verbose about the errors
 	 */
 	struct string_list *p = &header->prerequisites;
-	struct rev_info revs;
+	struct rev_info revs = REV_INFO_INIT;
 	const char *argv[] = {NULL, "--all", NULL};
 	struct commit *commit;
 	int i, ret = 0, req_nr;
 	const char *message = _("Repository lacks these prerequisite commits:");
 
-	if (!r || !r->objects || !r->objects->odb)
-		return error(_("need a repository to verify a bundle"));
+	if (!r || !r->objects || !r->objects->odb) {
+		ret = error(_("need a repository to verify a bundle"));
+		goto cleanup;
+	}
 
 	repo_init_revisions(r, &revs, NULL);
 	for (i = 0; i < p->nr; i++) {
@@ -221,7 +223,7 @@  int verify_bundle(struct repository *r,
 		error("%s %s", oid_to_hex(oid), name);
 	}
 	if (revs.pending.nr != p->nr)
-		return ret;
+		goto cleanup;
 	req_nr = revs.pending.nr;
 	setup_revisions(2, argv, &revs, NULL);
 
@@ -284,6 +286,8 @@  int verify_bundle(struct repository *r,
 			printf_ln("The bundle uses this filter: %s",
 				  list_objects_filter_spec(&header->filter));
 	}
+cleanup:
+	release_revisions(&revs);
 	return ret;
 }
 
diff --git a/revision.h b/revision.h
index 19f886472aa..c920753e8b9 100644
--- a/revision.h
+++ b/revision.h
@@ -329,6 +329,17 @@  struct rev_info {
 	struct tmp_objdir *remerge_objdir;
 };
 
+/**
+ * Initialize the "struct rev_info" structure with a macro.
+ *
+ * This is not sufficient (yet!) to initialize a "struct rev_info",
+ * but it's OK (but redundant) to use it before a call to
+ * repo_init_revisions(), which does the real initialization. By using
+ * this it's safe to call release_revisions() on the "struct rev_info"
+ * without having called repo_init_revisions().
+ */
+#define REV_INFO_INIT { 0 }
+
 /**
  * Initialize a rev_info structure with default values. The third parameter may
  * be NULL or can be prefix path, and then the `.prefix` variable will be set
@@ -363,7 +374,7 @@  int setup_revisions(int argc, const char **argv, struct rev_info *revs,
 
 /**
  * Free data allocated in a "struct rev_info" after it's been
- * initialized with repo_init_revisions().
+ * initialized with repo_init_revisions() or REV_INFO_INIT.
  */
 void release_revisions(struct rev_info *revs);
 
diff --git a/submodule.c b/submodule.c
index 4df04ae14e4..e796151ac6f 100644
--- a/submodule.c
+++ b/submodule.c
@@ -619,7 +619,7 @@  void show_submodule_diff_summary(struct diff_options *o, const char *path,
 		struct object_id *one, struct object_id *two,
 		unsigned dirty_submodule)
 {
-	struct rev_info rev;
+	struct rev_info rev = REV_INFO_INIT;
 	struct commit *left = NULL, *right = NULL;
 	struct commit_list *merge_bases = NULL;
 	struct repository *sub;
@@ -645,6 +645,7 @@  void show_submodule_diff_summary(struct diff_options *o, const char *path,
 	print_submodule_diff_summary(sub, &rev, o);
 
 out:
+	release_revisions(&rev);
 	if (merge_bases)
 		free_commit_list(merge_bases);
 	clear_commit_marks(left, ~0);