All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] rerere: Expose an API corresponding to 'clear' functionality
@ 2011-04-11  8:51 Ramkumar Ramachandra
  2011-04-11 18:36 ` Junio C Hamano
  0 siblings, 1 reply; 13+ messages in thread
From: Ramkumar Ramachandra @ 2011-04-11  8:51 UTC (permalink / raw)
  To: Git List; +Cc: Daniel Barkalow, Jonathan Nieder

Expose a new function called rerere_clear, and rework
'builtin/rerere.c' to use this when the corresponding command-line
argument is passed.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
Ref: http://thread.gmane.org/gmane.comp.version-control.git/171255/focus=171273

 builtin/rerere.c |   19 +++----------------
 rerere.c         |   24 ++++++++++++++++++++++++
 rerere.h         |    2 ++
 3 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/builtin/rerere.c b/builtin/rerere.c
index 8235885..f3956bf 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -28,14 +28,6 @@ static time_t rerere_last_used_at(const char *name)
 	return stat(rerere_path(name, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
 }
 
-static void unlink_rr_item(const char *name)
-{
-	unlink(rerere_path(name, "thisimage"));
-	unlink(rerere_path(name, "preimage"));
-	unlink(rerere_path(name, "postimage"));
-	rmdir(git_path("rr-cache/%s", name));
-}
-
 static int git_rerere_gc_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "gc.rerereresolved"))
@@ -142,19 +134,14 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
 		pathspec = get_pathspec(prefix, argv + 1);
 		return rerere_forget(pathspec);
 	}
+	if (!strcmp(argv[0], "clear"))
+		return rerere_clear();
 
 	fd = setup_rerere(&merge_rr, flags);
 	if (fd < 0)
 		return 0;
 
-	if (!strcmp(argv[0], "clear")) {
-		for (i = 0; i < merge_rr.nr; i++) {
-			const char *name = (const char *)merge_rr.items[i].util;
-			if (!has_rerere_resolution(name))
-				unlink_rr_item(name);
-		}
-		unlink_or_warn(git_path("MERGE_RR"));
-	} else if (!strcmp(argv[0], "gc"))
+	if (!strcmp(argv[0], "gc"))
 		garbage_collect(&merge_rr);
 	else if (!strcmp(argv[0], "status"))
 		for (i = 0; i < merge_rr.nr; i++)
diff --git a/rerere.c b/rerere.c
index 22dfc84..f8da9bd 100644
--- a/rerere.c
+++ b/rerere.c
@@ -25,6 +25,14 @@ const char *rerere_path(const char *hex, const char *file)
 	return git_path("rr-cache/%s/%s", hex, file);
 }
 
+void unlink_rr_item(const char *name)
+{
+	unlink(rerere_path(name, "thisimage"));
+	unlink(rerere_path(name, "preimage"));
+	unlink(rerere_path(name, "postimage"));
+	rmdir(git_path("rr-cache/%s", name));
+}
+
 int has_rerere_resolution(const char *hex)
 {
 	struct stat st;
@@ -671,3 +679,19 @@ int rerere_forget(const char **pathspec)
 	}
 	return write_rr(&merge_rr, fd);
 }
+
+int rerere_clear(void)
+{
+	int i, fd;
+	struct string_list merge_rr = STRING_LIST_INIT_DUP;
+
+	fd = setup_rerere(&merge_rr, RERERE_NOAUTOUPDATE);
+	for (i = 0; i < merge_rr.nr; i++) {
+		const char *name = (const char *)merge_rr.items[i].util;
+		if (!has_rerere_resolution(name))
+			unlink_rr_item(name);
+	}
+	string_list_clear(&merge_rr, 1);
+	unlink_or_warn(git_path("MERGE_RR"));
+	return 0;
+}
diff --git a/rerere.h b/rerere.h
index 595f49f..b9ab839 100644
--- a/rerere.h
+++ b/rerere.h
@@ -16,8 +16,10 @@ extern void *RERERE_RESOLVED;
 extern int setup_rerere(struct string_list *, int);
 extern int rerere(int);
 extern const char *rerere_path(const char *hex, const char *file);
+extern void unlink_rr_item(const char *name);
 extern int has_rerere_resolution(const char *hex);
 extern int rerere_forget(const char **);
+extern int rerere_clear(void);
 extern int rerere_remaining(struct string_list *);
 
 #define OPT_RERERE_AUTOUPDATE(v) OPT_UYN(0, "rerere-autoupdate", (v), \
-- 
1.7.4.rc1.7.g2cf08.dirty

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

* Re: [PATCH] rerere: Expose an API corresponding to 'clear' functionality
  2011-04-11  8:51 [PATCH] rerere: Expose an API corresponding to 'clear' functionality Ramkumar Ramachandra
@ 2011-04-11 18:36 ` Junio C Hamano
  2011-04-13 13:18   ` [PATCH v2] " Ramkumar Ramachandra
  0 siblings, 1 reply; 13+ messages in thread
From: Junio C Hamano @ 2011-04-11 18:36 UTC (permalink / raw)
  To: Ramkumar Ramachandra; +Cc: Git List, Daniel Barkalow, Jonathan Nieder

Ramkumar Ramachandra <artagnon@gmail.com> writes:

> Expose a new function called rerere_clear, and rework
> 'builtin/rerere.c' to use this when the corresponding command-line
> argument is passed.

> @@ -142,19 +134,14 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
>  		pathspec = get_pathspec(prefix, argv + 1);
>  		return rerere_forget(pathspec);
>  	}
> +	if (!strcmp(argv[0], "clear"))
> +		return rerere_clear();
>  
>  	fd = setup_rerere(&merge_rr, flags);
>  	if (fd < 0)
>  		return 0;
>  
> -	if (!strcmp(argv[0], "clear")) {
> -		for (i = 0; i < merge_rr.nr; i++) {
> -			const char *name = (const char *)merge_rr.items[i].util;
> -			if (!has_rerere_resolution(name))
> -				unlink_rr_item(name);
> -		}
> -		unlink_or_warn(git_path("MERGE_RR"));
> -	} else if (!strcmp(argv[0], "gc"))

In your version, the call of rerere_clear() is not protected by a check
that used to return early in a repository that is configured not to use
rerere.  I don't see there is a corresponding early return in the new
function rerere_clear() you created in rerere.c, either.

Would that cause a user-visible regression?

> diff --git a/rerere.h b/rerere.h
> index 595f49f..b9ab839 100644
> --- a/rerere.h
> +++ b/rerere.h
> @@ -16,8 +16,10 @@ extern void *RERERE_RESOLVED;
>  extern int setup_rerere(struct string_list *, int);
>  extern int rerere(int);
>  extern const char *rerere_path(const char *hex, const char *file);
> +extern void unlink_rr_item(const char *name);

The name was perfectly fine while it was a file-scope static, but is
unacceptable as a public function.  At least please spell "rerere" out
somewhere to ensure that even first-time readers can tell what area of the
system the function is about.

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

* [PATCH v2] rerere: Expose an API corresponding to 'clear' functionality
  2011-04-11 18:36 ` Junio C Hamano
@ 2011-04-13 13:18   ` Ramkumar Ramachandra
  2011-04-13 20:38     ` Jonathan Nieder
  0 siblings, 1 reply; 13+ messages in thread
From: Ramkumar Ramachandra @ 2011-04-13 13:18 UTC (permalink / raw)
  To: Git List; +Cc: Daniel Barkalow, Jonathan Nieder, Junio C Hamano

Expose a new function called rerere_clear, and make 'builtin/rerere.c'
use this when the corresponding command-line argument is passed.  As a
side-effect, also expose unlink_rr_item as unlink_rerere_item.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
Junio: Thanks for the review.  Is this version alright?

 builtin/rerere.c |   21 ++++-----------------
 rerere.c         |   27 +++++++++++++++++++++++++++
 rerere.h         |    2 ++
 3 files changed, 33 insertions(+), 17 deletions(-)

diff --git a/builtin/rerere.c b/builtin/rerere.c
index 8235885..8f939b3 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -28,14 +28,6 @@ static time_t rerere_last_used_at(const char *name)
 	return stat(rerere_path(name, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
 }
 
-static void unlink_rr_item(const char *name)
-{
-	unlink(rerere_path(name, "thisimage"));
-	unlink(rerere_path(name, "preimage"));
-	unlink(rerere_path(name, "postimage"));
-	rmdir(git_path("rr-cache/%s", name));
-}
-
 static int git_rerere_gc_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "gc.rerereresolved"))
@@ -76,7 +68,7 @@ static void garbage_collect(struct string_list *rr)
 			string_list_append(&to_remove, e->d_name);
 	}
 	for (i = 0; i < to_remove.nr; i++)
-		unlink_rr_item(to_remove.items[i].string);
+		unlink_rerere_item(to_remove.items[i].string);
 	string_list_clear(&to_remove, 0);
 }
 
@@ -142,19 +134,14 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
 		pathspec = get_pathspec(prefix, argv + 1);
 		return rerere_forget(pathspec);
 	}
+	if (!strcmp(argv[0], "clear"))
+		return rerere_clear();
 
 	fd = setup_rerere(&merge_rr, flags);
 	if (fd < 0)
 		return 0;
 
-	if (!strcmp(argv[0], "clear")) {
-		for (i = 0; i < merge_rr.nr; i++) {
-			const char *name = (const char *)merge_rr.items[i].util;
-			if (!has_rerere_resolution(name))
-				unlink_rr_item(name);
-		}
-		unlink_or_warn(git_path("MERGE_RR"));
-	} else if (!strcmp(argv[0], "gc"))
+	if (!strcmp(argv[0], "gc"))
 		garbage_collect(&merge_rr);
 	else if (!strcmp(argv[0], "status"))
 		for (i = 0; i < merge_rr.nr; i++)
diff --git a/rerere.c b/rerere.c
index 22dfc84..6821f33 100644
--- a/rerere.c
+++ b/rerere.c
@@ -25,6 +25,14 @@ const char *rerere_path(const char *hex, const char *file)
 	return git_path("rr-cache/%s/%s", hex, file);
 }
 
+void unlink_rerere_item(const char *name)
+{
+	unlink(rerere_path(name, "thisimage"));
+	unlink(rerere_path(name, "preimage"));
+	unlink(rerere_path(name, "postimage"));
+	rmdir(git_path("rr-cache/%s", name));
+}
+
 int has_rerere_resolution(const char *hex)
 {
 	struct stat st;
@@ -671,3 +679,22 @@ int rerere_forget(const char **pathspec)
 	}
 	return write_rr(&merge_rr, fd);
 }
+
+int rerere_clear(void)
+{
+	int i, fd;
+	struct string_list merge_rr = STRING_LIST_INIT_DUP;
+
+	fd = setup_rerere(&merge_rr, RERERE_NOAUTOUPDATE);
+	if (fd < 0)
+		return 0;
+
+	for (i = 0; i < merge_rr.nr; i++) {
+		const char *name = (const char *)merge_rr.items[i].util;
+		if (!has_rerere_resolution(name))
+			unlink_rerere_item(name);
+	}
+	string_list_clear(&merge_rr, 1);
+	unlink_or_warn(git_path("MERGE_RR"));
+	return 0;
+}
diff --git a/rerere.h b/rerere.h
index 595f49f..cd2cdb2 100644
--- a/rerere.h
+++ b/rerere.h
@@ -16,8 +16,10 @@ extern void *RERERE_RESOLVED;
 extern int setup_rerere(struct string_list *, int);
 extern int rerere(int);
 extern const char *rerere_path(const char *hex, const char *file);
+extern void unlink_rerere_item(const char *name);
 extern int has_rerere_resolution(const char *hex);
 extern int rerere_forget(const char **);
+extern int rerere_clear(void);
 extern int rerere_remaining(struct string_list *);
 
 #define OPT_RERERE_AUTOUPDATE(v) OPT_UYN(0, "rerere-autoupdate", (v), \
-- 
1.7.4.rc1.7.g2cf08.dirty

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

* Re: [PATCH v2] rerere: Expose an API corresponding to 'clear' functionality
  2011-04-13 13:18   ` [PATCH v2] " Ramkumar Ramachandra
@ 2011-04-13 20:38     ` Jonathan Nieder
  2011-05-06  6:36       ` [PATCH v3] " Ramkumar Ramachandra
  0 siblings, 1 reply; 13+ messages in thread
From: Jonathan Nieder @ 2011-04-13 20:38 UTC (permalink / raw)
  To: Ramkumar Ramachandra; +Cc: Git List, Daniel Barkalow, Junio C Hamano

Hi,

Ramkumar Ramachandra wrote:

> Expose a new function called rerere_clear,

The commit message is a good chance to quickly explain the API.  What
does the function do?  When would one call it?  Is it equivalent to
running "git rerere clear"?  Any gotchas?

> and make 'builtin/rerere.c'
> use this when the corresponding command-line argument is passed.

Didn't "git rerere" already use the functionality of this function?
I'm not sure what this part means.

> As a
> side-effect, also expose unlink_rr_item as unlink_rerere_item.

This is not a side-effect; you did it directly.

I think the reason for this is that rerere_gc is not being exposed at
the same time, right?  I suppose if I were doing it, I would have
moved that to rerere.c, too and kept unlink_rr_item static, but there
is also appeal in a minimal patch.  It would be clearer to say
something to the effect that we

	Also export unlink_rr_item as unlink_rerere_item so
	rerere_clear and the un-libified "git rerere gc" can
	both use it.

[...]
> +++ b/builtin/rerere.c
> @@ -142,19 +134,14 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
>  		pathspec = get_pathspec(prefix, argv + 1);
>  		return rerere_forget(pathspec);
>  	}
> +	if (!strcmp(argv[0], "clear"))
> +		return rerere_clear();
>  
>  	fd = setup_rerere(&merge_rr, flags);
[...]
> +++ b/rerere.c
> @@ -671,3 +679,22 @@ int rerere_clear(void)
[...]
> +	fd = setup_rerere(&merge_rr, RERERE_NOAUTOUPDATE);
> +	if (fd < 0)
> +		return 0;

Why RERERE_NOAUTOUPDATE instead of 0?  (Of course it doesn't matter in
practice.   Maybe "0" would convey that more clearly?)

> +
> +	for (i = 0; i < merge_rr.nr; i++) {
> +		const char *name = (const char *)merge_rr.items[i].util;
> +		if (!has_rerere_resolution(name))
> +			unlink_rerere_item(name);
> +	}
> +	string_list_clear(&merge_rr, 1);
> +	unlink_or_warn(git_path("MERGE_RR"));
> +	return 0;
> +}

The write_lock is never rolled back.  "git rerere" won't care since it
exits moments later and the atexit handler is called, but others might
mind that they can't perform any more rerere operations afterwards. :)

Thanks and hope that helps.
Jonathan

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

* [PATCH v3] rerere: Expose an API corresponding to 'clear' functionality
  2011-04-13 20:38     ` Jonathan Nieder
@ 2011-05-06  6:36       ` Ramkumar Ramachandra
  2011-05-06 16:51         ` Junio C Hamano
  0 siblings, 1 reply; 13+ messages in thread
From: Ramkumar Ramachandra @ 2011-05-06  6:36 UTC (permalink / raw)
  To: Git List; +Cc: Daniel Barkalow, Jonathan Nieder, Junio C Hamano

Libify the "rerere clear" into a simple function called rerere_clear
that takes no arguments, and returns the exit status.  Also export
unlink_rr_item as unlink_rerere_item so rerere_clear and the
un-libified "git rerere gc" can both use it.

Helped-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 What changed since v2: Jonathan's review.

 builtin/rerere.c |   21 ++++-----------------
 rerere.c         |   27 +++++++++++++++++++++++++++
 rerere.h         |    2 ++
 3 files changed, 33 insertions(+), 17 deletions(-)

diff --git a/builtin/rerere.c b/builtin/rerere.c
index 8235885..8f939b3 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -28,14 +28,6 @@ static time_t rerere_last_used_at(const char *name)
 	return stat(rerere_path(name, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
 }
 
-static void unlink_rr_item(const char *name)
-{
-	unlink(rerere_path(name, "thisimage"));
-	unlink(rerere_path(name, "preimage"));
-	unlink(rerere_path(name, "postimage"));
-	rmdir(git_path("rr-cache/%s", name));
-}
-
 static int git_rerere_gc_config(const char *var, const char *value, void *cb)
 {
 	if (!strcmp(var, "gc.rerereresolved"))
@@ -76,7 +68,7 @@ static void garbage_collect(struct string_list *rr)
 			string_list_append(&to_remove, e->d_name);
 	}
 	for (i = 0; i < to_remove.nr; i++)
-		unlink_rr_item(to_remove.items[i].string);
+		unlink_rerere_item(to_remove.items[i].string);
 	string_list_clear(&to_remove, 0);
 }
 
@@ -142,19 +134,14 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
 		pathspec = get_pathspec(prefix, argv + 1);
 		return rerere_forget(pathspec);
 	}
+	if (!strcmp(argv[0], "clear"))
+		return rerere_clear();
 
 	fd = setup_rerere(&merge_rr, flags);
 	if (fd < 0)
 		return 0;
 
-	if (!strcmp(argv[0], "clear")) {
-		for (i = 0; i < merge_rr.nr; i++) {
-			const char *name = (const char *)merge_rr.items[i].util;
-			if (!has_rerere_resolution(name))
-				unlink_rr_item(name);
-		}
-		unlink_or_warn(git_path("MERGE_RR"));
-	} else if (!strcmp(argv[0], "gc"))
+	if (!strcmp(argv[0], "gc"))
 		garbage_collect(&merge_rr);
 	else if (!strcmp(argv[0], "status"))
 		for (i = 0; i < merge_rr.nr; i++)
diff --git a/rerere.c b/rerere.c
index 22dfc84..aaca3b0 100644
--- a/rerere.c
+++ b/rerere.c
@@ -25,6 +25,14 @@ const char *rerere_path(const char *hex, const char *file)
 	return git_path("rr-cache/%s/%s", hex, file);
 }
 
+void unlink_rerere_item(const char *name)
+{
+	unlink(rerere_path(name, "thisimage"));
+	unlink(rerere_path(name, "preimage"));
+	unlink(rerere_path(name, "postimage"));
+	rmdir(git_path("rr-cache/%s", name));
+}
+
 int has_rerere_resolution(const char *hex)
 {
 	struct stat st;
@@ -671,3 +679,22 @@ int rerere_forget(const char **pathspec)
 	}
 	return write_rr(&merge_rr, fd);
 }
+
+int rerere_clear(void)
+{
+	int i, fd;
+	struct string_list merge_rr = STRING_LIST_INIT_DUP;
+
+	fd = setup_rerere(&merge_rr, 0);
+	if (fd < 0)
+		return -1;
+	for (i = 0; i < merge_rr.nr; i++) {
+		const char *name = (const char *)merge_rr.items[i].util;
+		if (!has_rerere_resolution(name))
+			unlink_rerere_item(name);
+	}
+	string_list_clear(&merge_rr, 1);
+	unlink_or_warn(git_path("MERGE_RR"));
+	rollback_lock_file(&write_lock);
+	return 0;
+}
diff --git a/rerere.h b/rerere.h
index 595f49f..cd2cdb2 100644
--- a/rerere.h
+++ b/rerere.h
@@ -16,8 +16,10 @@ extern void *RERERE_RESOLVED;
 extern int setup_rerere(struct string_list *, int);
 extern int rerere(int);
 extern const char *rerere_path(const char *hex, const char *file);
+extern void unlink_rerere_item(const char *name);
 extern int has_rerere_resolution(const char *hex);
 extern int rerere_forget(const char **);
+extern int rerere_clear(void);
 extern int rerere_remaining(struct string_list *);
 
 #define OPT_RERERE_AUTOUPDATE(v) OPT_UYN(0, "rerere-autoupdate", (v), \
-- 
1.7.5.GIT

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

* Re: [PATCH v3] rerere: Expose an API corresponding to 'clear' functionality
  2011-05-06  6:36       ` [PATCH v3] " Ramkumar Ramachandra
@ 2011-05-06 16:51         ` Junio C Hamano
  2011-05-07 13:17           ` Ramkumar Ramachandra
  2011-05-08  7:30           ` [PATCH v4 0/2] Libify rerere: clear and gc Ramkumar Ramachandra
  0 siblings, 2 replies; 13+ messages in thread
From: Junio C Hamano @ 2011-05-06 16:51 UTC (permalink / raw)
  To: Ramkumar Ramachandra; +Cc: Git List, Daniel Barkalow, Jonathan Nieder

Ramkumar Ramachandra <artagnon@gmail.com> writes:

> Libify the "rerere clear" into a simple function called rerere_clear
> that takes no arguments, and returns the exit status.  Also export
> unlink_rr_item as unlink_rerere_item so rerere_clear and the
> un-libified "git rerere gc" can both use it.
>
> Helped-by: Jonathan Nieder <jrnieder@gmail.com>
> Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
> ---
>  What changed since v2: Jonathan's review.

Are you sure this is the version you wanted to send?

You now return -1 from rerere_clear() when setup_rerere() says that the
feature is not enabled, and this is propagated back to cmd_rerere(),
causing the whole command to report a failure in its exit status, which
seems to me a grave regression.  Your previous round got this part right,
but it is broken in this round.

Also I seem to recall that Jonathan suggested that you do not have to
expose unlink_rr_item() as an external symbol if you moved the garbage
collection part from builtin/rerere.c to rerere.c but I do not see such a
change in this patch.  I think the gc interface is a lot more reasonable
API to expose to external callers ("git gc" may want to make an internal
call to rerere_gc() moved to rerere.c, instead of spawning "git rerere gc"
as an external command) than unlink_rerere_item() that is only useful for
callers that are deep inside rerere specific codepath.

What is going on?

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

* Re: [PATCH v3] rerere: Expose an API corresponding to 'clear' functionality
  2011-05-06 16:51         ` Junio C Hamano
@ 2011-05-07 13:17           ` Ramkumar Ramachandra
  2011-05-08  7:30           ` [PATCH v4 0/2] Libify rerere: clear and gc Ramkumar Ramachandra
  1 sibling, 0 replies; 13+ messages in thread
From: Ramkumar Ramachandra @ 2011-05-07 13:17 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List, Daniel Barkalow, Jonathan Nieder

Hi Junio,

Junio C Hamano writes:
> Ramkumar Ramachandra <artagnon@gmail.com> writes:
> 
> > Libify the "rerere clear" into a simple function called rerere_clear
> > that takes no arguments, and returns the exit status.  Also export
> > unlink_rr_item as unlink_rerere_item so rerere_clear and the
> > un-libified "git rerere gc" can both use it.
> >
> > Helped-by: Jonathan Nieder <jrnieder@gmail.com>
> > Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
> > ---
> >  What changed since v2: Jonathan's review.
> 
> Are you sure this is the version you wanted to send?
> 
> You now return -1 from rerere_clear() when setup_rerere() says that the
> feature is not enabled, and this is propagated back to cmd_rerere(),
> causing the whole command to report a failure in its exit status, which
> seems to me a grave regression.  Your previous round got this part right,
> but it is broken in this round.

Ugh, I'm not sure how this change crept in- sorry :|
Could you please squash this diff into the patch?

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>

diff --git a/rerere.c b/rerere.c
index aaca3b0..fda02f6 100644
--- a/rerere.c
+++ b/rerere.c
@@ -687,7 +687,7 @@ int rerere_clear(void)
 
 	fd = setup_rerere(&merge_rr, 0);
 	if (fd < 0)
-		return -1;
+		return 0;
 	for (i = 0; i < merge_rr.nr; i++) {
 		const char *name = (const char *)merge_rr.items[i].util;
 		if (!has_rerere_resolution(name))

> Also I seem to recall that Jonathan suggested that you do not have to
> expose unlink_rr_item() as an external symbol if you moved the garbage
> collection part from builtin/rerere.c to rerere.c but I do not see such a
> change in this patch.  I think the gc interface is a lot more reasonable
> API to expose to external callers ("git gc" may want to make an internal
> call to rerere_gc() moved to rerere.c, instead of spawning "git rerere gc"
> as an external command) than unlink_rerere_item() that is only useful for
> callers that are deep inside rerere specific codepath.

I'll quote Jonathan from the previous review:

"
I think the reason for this is that rerere_gc is not being exposed at
the same time, right?  I suppose if I were doing it, I would have
moved that to rerere.c, too and kept unlink_rr_item static, but there
is also appeal in a minimal patch.  It would be clearer to say
something to the effect that we

	Also export unlink_rr_item as unlink_rerere_item so
	rerere_clear and the un-libified "git rerere gc" can
	both use it.
"

To the first part of the question: yes, that's the reason for exposing
unlink_rr_item as unlink_rerere_item.  Yet, I followed the latter
approach for the appeal of the minimal patch -- I should have said
this explicitly.  Anyway, I plan to post another patch cleaning up and
libifying rerere shortly.

Junio: If you feel that garbage_collect should be exposed in this
patch, I'll post an alternative version now, and you can pick the one
you like :)

-- Ram

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

* [PATCH v4 0/2] Libify rerere: clear and gc
  2011-05-06 16:51         ` Junio C Hamano
  2011-05-07 13:17           ` Ramkumar Ramachandra
@ 2011-05-08  7:30           ` Ramkumar Ramachandra
  2011-05-08  7:30             ` [PATCH v4 1/2] usage: Introduce error_errno corresponding to die_errno Ramkumar Ramachandra
  2011-05-08  7:30             ` [PATCH v4 2/2] rerere: Libify "rerere clear" and "rerere gc" Ramkumar Ramachandra
  1 sibling, 2 replies; 13+ messages in thread
From: Ramkumar Ramachandra @ 2011-05-08  7:30 UTC (permalink / raw)
  To: Git List; +Cc: Daniel Barkalow, Jonathan Nieder, Junio C Hamano

Hi,

This is an alternate version of the v3 patch: Instead of exposing
unlink_rr_item, I have chosen to libify "rerere gc" in order to libify
"rerere clear", and it may be argued that this is a pleasant
side-effect.  I've also included another patch to replace the
"die_errno" call with a new "error_errno" call, and I hope this will
be used in other places as well.  Note one more subtle change: I've
chosen to pass "flags" as an argument to both functions for the sake
of consistency; if and when rerere grows more command-line options,
"flags" can be replaced by a struct containing those parsed options.

Cons: This patch is much larger than v3.

Thanks to: Junio and Jonathan.

Ramkumar Ramachandra (2):
  usage: Introduce error_errno corresponding to die_errno
  rerere: Libify "rerere clear" and "rerere gc"

 builtin/rerere.c  |   81 ++-----------------------------------------
 git-compat-util.h |    1 +
 rerere.c          |   99 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 rerere.h          |    2 +
 usage.c           |   10 +++++
 5 files changed, 116 insertions(+), 77 deletions(-)

-- 
1.7.5.GIT

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

* [PATCH v4 1/2] usage: Introduce error_errno corresponding to die_errno
  2011-05-08  7:30           ` [PATCH v4 0/2] Libify rerere: clear and gc Ramkumar Ramachandra
@ 2011-05-08  7:30             ` Ramkumar Ramachandra
  2011-05-08  9:46               ` Ramkumar Ramachandra
  2011-05-08 18:10               ` Junio C Hamano
  2011-05-08  7:30             ` [PATCH v4 2/2] rerere: Libify "rerere clear" and "rerere gc" Ramkumar Ramachandra
  1 sibling, 2 replies; 13+ messages in thread
From: Ramkumar Ramachandra @ 2011-05-08  7:30 UTC (permalink / raw)
  To: Git List; +Cc: Daniel Barkalow, Jonathan Nieder, Junio C Hamano

The error function always returns the constant value -1, and this does
not convey enough information about the nature of the error.  This
patch introduces a new function error_errno that functions exactly
like the error function, except that it returns `errorno` instead of a
constant value.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 Is "-errno" correct? This will determine how error-handling will be
 in a more libified version of Git, and I think it's important to get
 this right.

 git-compat-util.h |    1 +
 usage.c           |   10 ++++++++++
 2 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/git-compat-util.h b/git-compat-util.h
index 40498b3..7b82038 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -241,6 +241,7 @@ extern NORETURN void usagef(const char *err, ...) __attribute__((format (printf,
 extern NORETURN void die(const char *err, ...) __attribute__((format (printf, 1, 2)));
 extern NORETURN void die_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));
 extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
+extern int error_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));
 extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
 
 extern void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params));
diff --git a/usage.c b/usage.c
index b5e67e3..c89efcc 100644
--- a/usage.c
+++ b/usage.c
@@ -107,6 +107,16 @@ int error(const char *err, ...)
 	return -1;
 }
 
+int error_errno(const char *err, ...)
+{
+	va_list params;
+
+	va_start(params, err);
+	error_routine(err, params);
+	va_end(params);
+	return -errno;
+}
+
 void warning(const char *warn, ...)
 {
 	va_list params;
-- 
1.7.5.GIT

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

* [PATCH v4 2/2] rerere: Libify "rerere clear" and "rerere gc"
  2011-05-08  7:30           ` [PATCH v4 0/2] Libify rerere: clear and gc Ramkumar Ramachandra
  2011-05-08  7:30             ` [PATCH v4 1/2] usage: Introduce error_errno corresponding to die_errno Ramkumar Ramachandra
@ 2011-05-08  7:30             ` Ramkumar Ramachandra
  2011-05-08 20:06               ` Junio C Hamano
  1 sibling, 1 reply; 13+ messages in thread
From: Ramkumar Ramachandra @ 2011-05-08  7:30 UTC (permalink / raw)
  To: Git List; +Cc: Daniel Barkalow, Jonathan Nieder, Junio C Hamano

Libify "rerere clear" and "rerere gc" into simple functions called
rerere_clear and rerere_garbage_collect; both functions take flags as
a lone argument and return the exit status.

Helped-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 Have I cleaned up all the locks correctly? The tests should probably
 be updated to catch unclean exists- I'll probably work on this
 shortly.

 builtin/rerere.c |   81 ++------------------------------------------
 rerere.c         |   99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 rerere.h         |    2 +
 3 files changed, 105 insertions(+), 77 deletions(-)

diff --git a/builtin/rerere.c b/builtin/rerere.c
index 8235885..e2abdaa 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -12,74 +12,6 @@ static const char * const rerere_usage[] = {
 	NULL,
 };
 
-/* these values are days */
-static int cutoff_noresolve = 15;
-static int cutoff_resolve = 60;
-
-static time_t rerere_created_at(const char *name)
-{
-	struct stat st;
-	return stat(rerere_path(name, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
-}
-
-static time_t rerere_last_used_at(const char *name)
-{
-	struct stat st;
-	return stat(rerere_path(name, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
-}
-
-static void unlink_rr_item(const char *name)
-{
-	unlink(rerere_path(name, "thisimage"));
-	unlink(rerere_path(name, "preimage"));
-	unlink(rerere_path(name, "postimage"));
-	rmdir(git_path("rr-cache/%s", name));
-}
-
-static int git_rerere_gc_config(const char *var, const char *value, void *cb)
-{
-	if (!strcmp(var, "gc.rerereresolved"))
-		cutoff_resolve = git_config_int(var, value);
-	else if (!strcmp(var, "gc.rerereunresolved"))
-		cutoff_noresolve = git_config_int(var, value);
-	else
-		return git_default_config(var, value, cb);
-	return 0;
-}
-
-static void garbage_collect(struct string_list *rr)
-{
-	struct string_list to_remove = STRING_LIST_INIT_DUP;
-	DIR *dir;
-	struct dirent *e;
-	int i, cutoff;
-	time_t now = time(NULL), then;
-
-	git_config(git_rerere_gc_config, NULL);
-	dir = opendir(git_path("rr-cache"));
-	if (!dir)
-		die_errno("unable to open rr-cache directory");
-	while ((e = readdir(dir))) {
-		if (is_dot_or_dotdot(e->d_name))
-			continue;
-
-		then = rerere_last_used_at(e->d_name);
-		if (then) {
-			cutoff = cutoff_resolve;
-		} else {
-			then = rerere_created_at(e->d_name);
-			if (!then)
-				continue;
-			cutoff = cutoff_noresolve;
-		}
-		if (then < now - cutoff * 86400)
-			string_list_append(&to_remove, e->d_name);
-	}
-	for (i = 0; i < to_remove.nr; i++)
-		unlink_rr_item(to_remove.items[i].string);
-	string_list_clear(&to_remove, 0);
-}
-
 static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)
 {
 	int i;
@@ -142,20 +74,15 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
 		pathspec = get_pathspec(prefix, argv + 1);
 		return rerere_forget(pathspec);
 	}
+	else if (!strcmp(argv[0], "clear"))
+		return rerere_clear(flags);
+	else if (!strcmp(argv[0], "gc"))
+		return rerere_garbage_collect(flags);
 
 	fd = setup_rerere(&merge_rr, flags);
 	if (fd < 0)
 		return 0;
 
-	if (!strcmp(argv[0], "clear")) {
-		for (i = 0; i < merge_rr.nr; i++) {
-			const char *name = (const char *)merge_rr.items[i].util;
-			if (!has_rerere_resolution(name))
-				unlink_rr_item(name);
-		}
-		unlink_or_warn(git_path("MERGE_RR"));
-	} else if (!strcmp(argv[0], "gc"))
-		garbage_collect(&merge_rr);
 	else if (!strcmp(argv[0], "status"))
 		for (i = 0; i < merge_rr.nr; i++)
 			printf("%s\n", merge_rr.items[i].string);
diff --git a/rerere.c b/rerere.c
index 22dfc84..18c7413 100644
--- a/rerere.c
+++ b/rerere.c
@@ -20,6 +20,10 @@ static int rerere_autoupdate;
 
 static char *merge_rr_path;
 
+/* these values are days */
+static int cutoff_noresolve = 15;
+static int cutoff_resolve = 60;
+
 const char *rerere_path(const char *hex, const char *file)
 {
 	return git_path("rr-cache/%s/%s", hex, file);
@@ -31,6 +35,37 @@ int has_rerere_resolution(const char *hex)
 	return !stat(rerere_path(hex, "postimage"), &st);
 }
 
+static time_t rerere_created_at(const char *name)
+{
+	struct stat st;
+	return stat(rerere_path(name, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
+}
+
+static time_t rerere_last_used_at(const char *name)
+{
+	struct stat st;
+	return stat(rerere_path(name, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
+}
+
+static void unlink_rr_item(const char *name)
+{
+	unlink(rerere_path(name, "thisimage"));
+	unlink(rerere_path(name, "preimage"));
+	unlink(rerere_path(name, "postimage"));
+	rmdir(git_path("rr-cache/%s", name));
+}
+
+static int git_rerere_gc_config(const char *var, const char *value, void *cb)
+{
+	if (!strcmp(var, "gc.rerereresolved"))
+		cutoff_resolve = git_config_int(var, value);
+	else if (!strcmp(var, "gc.rerereunresolved"))
+		cutoff_noresolve = git_config_int(var, value);
+	else
+		return git_default_config(var, value, cb);
+	return 0;
+}
+
 static void read_rr(struct string_list *rr)
 {
 	unsigned char sha1[20];
@@ -623,6 +658,51 @@ int rerere(int flags)
 	return do_plain_rerere(&merge_rr, fd);
 }
 
+int rerere_garbage_collect(int flags)
+{
+	struct string_list merge_rr = STRING_LIST_INIT_DUP;
+	struct string_list to_remove = STRING_LIST_INIT_DUP;
+
+	DIR *dir;
+	struct dirent *e;
+	int i, fd, cutoff;
+	time_t now = time(NULL), then;
+
+	fd = setup_rerere(&merge_rr, flags);
+	if (fd < 0)
+		return 0;
+
+	git_config(git_rerere_gc_config, NULL);
+	dir = opendir(git_path("rr-cache"));
+	if (!dir) {
+		rollback_lock_file(&write_lock);
+		return error_errno("Unable to open rr-cache directory");
+	}
+	while ((e = readdir(dir))) {
+		if (is_dot_or_dotdot(e->d_name))
+			continue;
+
+		then = rerere_last_used_at(e->d_name);
+		if (then)
+			cutoff = cutoff_resolve;
+		else {
+			then = rerere_created_at(e->d_name);
+			if (!then)
+				continue;
+			cutoff = cutoff_noresolve;
+		}
+		if (then < now - cutoff * 86400)
+			string_list_append(&to_remove, e->d_name);
+	}
+	for (i = 0; i < to_remove.nr; i++)
+		unlink_rr_item(to_remove.items[i].string);
+
+	string_list_clear(&merge_rr, 1);
+	string_list_clear(&to_remove, 0);
+	rollback_lock_file(&write_lock);
+	return 0;
+}
+
 static int rerere_forget_one_path(const char *path, struct string_list *rr)
 {
 	const char *filename;
@@ -671,3 +751,22 @@ int rerere_forget(const char **pathspec)
 	}
 	return write_rr(&merge_rr, fd);
 }
+
+int rerere_clear(int flags)
+{
+	int i, fd;
+	struct string_list merge_rr = STRING_LIST_INIT_DUP;
+
+	fd = setup_rerere(&merge_rr, flags);
+	if (fd < 0)
+		return 0;
+	for (i = 0; i < merge_rr.nr; i++) {
+		const char *name = (const char *)merge_rr.items[i].util;
+		if (!has_rerere_resolution(name))
+			unlink_rr_item(name);
+	}
+	string_list_clear(&merge_rr, 1);
+	unlink_or_warn(git_path("MERGE_RR"));
+	rollback_lock_file(&write_lock);
+	return 0;
+}
diff --git a/rerere.h b/rerere.h
index 595f49f..59849f6 100644
--- a/rerere.h
+++ b/rerere.h
@@ -15,10 +15,12 @@ extern void *RERERE_RESOLVED;
 
 extern int setup_rerere(struct string_list *, int);
 extern int rerere(int);
+extern int rerere_garbage_collect(int);
 extern const char *rerere_path(const char *hex, const char *file);
 extern int has_rerere_resolution(const char *hex);
 extern int rerere_forget(const char **);
 extern int rerere_remaining(struct string_list *);
+extern int rerere_clear(int);
 
 #define OPT_RERERE_AUTOUPDATE(v) OPT_UYN(0, "rerere-autoupdate", (v), \
 	"update the index with reused conflict resolution if possible")
-- 
1.7.5.GIT

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

* Re: [PATCH v4 1/2] usage: Introduce error_errno corresponding to die_errno
  2011-05-08  7:30             ` [PATCH v4 1/2] usage: Introduce error_errno corresponding to die_errno Ramkumar Ramachandra
@ 2011-05-08  9:46               ` Ramkumar Ramachandra
  2011-05-08 18:10               ` Junio C Hamano
  1 sibling, 0 replies; 13+ messages in thread
From: Ramkumar Ramachandra @ 2011-05-08  9:46 UTC (permalink / raw)
  To: Git List; +Cc: Daniel Barkalow, Jonathan Nieder, Junio C Hamano

Hi,

Ramkumar Ramachandra writes:
> The error function always returns the constant value -1, and this does
> not convey enough information about the nature of the error.  This
> patch introduces a new function error_errno that functions exactly
> like the error function, except that it returns `errorno` instead of a
> constant value.

An extra note: this could have been implemented differently, as seen
in my sequencer series [1].  However, after some thought, I think this
is how we want error handling to work.  The name may be a little
troubling because it doesn't behave like die_errno: does anyone have
suggestions for a different name?

[1]: http://article.gmane.org/gmane.comp.version-control.git/171262

-- Ram

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

* Re: [PATCH v4 1/2] usage: Introduce error_errno corresponding to die_errno
  2011-05-08  7:30             ` [PATCH v4 1/2] usage: Introduce error_errno corresponding to die_errno Ramkumar Ramachandra
  2011-05-08  9:46               ` Ramkumar Ramachandra
@ 2011-05-08 18:10               ` Junio C Hamano
  1 sibling, 0 replies; 13+ messages in thread
From: Junio C Hamano @ 2011-05-08 18:10 UTC (permalink / raw)
  To: Ramkumar Ramachandra; +Cc: Git List, Daniel Barkalow, Jonathan Nieder

Ramkumar Ramachandra <artagnon@gmail.com> writes:

> diff --git a/git-compat-util.h b/git-compat-util.h
> index 40498b3..7b82038 100644
> --- a/git-compat-util.h
> +++ b/git-compat-util.h
> @@ -241,6 +241,7 @@ extern NORETURN void usagef(const char *err, ...) __attribute__((format (printf,
>  extern NORETURN void die(const char *err, ...) __attribute__((format (printf, 1, 2)));
>  extern NORETURN void die_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));
>  extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
> +extern int error_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));
>  extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));

Anybody remotely familiar with die_errno() would at least expect that the
new and improved error_errno() function would give the errno neatly
formatted via strerror() in the message, but that is not what the function
does.

> diff --git a/usage.c b/usage.c
> index b5e67e3..c89efcc 100644
> --- a/usage.c
> +++ b/usage.c
> @@ -107,6 +107,16 @@ int error(const char *err, ...)
>  	return -1;
>  }
>  
> +int error_errno(const char *err, ...)
> +{
> +	va_list params;
> +
> +	va_start(params, err);
> +	error_routine(err, params);
> +	va_end(params);
> +	return -errno;
> +}

Can error_routine() do something to cause errno to change?

For that matter, I suspect that the caller who would _care_ about what
kind of error it got would need to save it away itself anyway.  For
example, it is not entirely clear if the callsite of this function in your
other patch is correct.  Can rollback_lock_file() cause errno to change?

	git_config(git_rerere_gc_config, NULL);
	dir = opendir(git_path("rr-cache"));
	if (!dir) {
+		int err = errno;
-		rollback_lock_file(&write_lock);
-		return error_errno("Unable to open rr-cache directory");
+		error("Untable to open rr-cache directory: %s", strerror(err));
+		return -err;
	}

I would prefer to do without introducing a confusingly named API function
whose first and only usecase does not even suggest it would be useful.

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

* Re: [PATCH v4 2/2] rerere: Libify "rerere clear" and "rerere gc"
  2011-05-08  7:30             ` [PATCH v4 2/2] rerere: Libify "rerere clear" and "rerere gc" Ramkumar Ramachandra
@ 2011-05-08 20:06               ` Junio C Hamano
  0 siblings, 0 replies; 13+ messages in thread
From: Junio C Hamano @ 2011-05-08 20:06 UTC (permalink / raw)
  To: Ramkumar Ramachandra; +Cc: Git List, Daniel Barkalow, Jonathan Nieder

Ramkumar Ramachandra <artagnon@gmail.com> writes:

> diff --git a/rerere.c b/rerere.c
> index 22dfc84..18c7413 100644
> --- a/rerere.c
> +++ b/rerere.c
> @@ -623,6 +658,51 @@ int rerere(int flags)
>  	return do_plain_rerere(&merge_rr, fd);
>  }
>  
> +int rerere_garbage_collect(int flags)
> +{
> +	struct string_list merge_rr = STRING_LIST_INIT_DUP;
> +	struct string_list to_remove = STRING_LIST_INIT_DUP;
> +
> +	DIR *dir;
> +	struct dirent *e;
> +	int i, fd, cutoff;
> +	time_t now = time(NULL), then;
> +
> +	fd = setup_rerere(&merge_rr, flags);
> +	if (fd < 0)
> +		return 0;

Not a good taste in API design, I would have to say.  The callers may
already want to have interacted with the rerere mechanism before calling
into this function and that is exactly why setup_rerere() is a public API
from the beginning.  I would prefer to see you make it the caller's
responsibility just like the original code you moved from builtin/rerere.c
did.

> +	git_config(git_rerere_gc_config, NULL);
> +	dir = opendir(git_path("rr-cache"));
> +	if (!dir) {
> +		rollback_lock_file(&write_lock);
> +		return error_errno("Unable to open rr-cache directory");
> +	}

I have already commented on this part and showed an alternative.

Whatever you do, how about starting from just a simple code movement,
without any change in behaviour?

That not only makes it easier to review your subsequent changes on top of
the result, but the original "large code movement" patch infinitely easier
to review, as "blame rerere.c" can tell us that almost all the lines came
from builtin/rerere.c without any new bug slipping in.

-- >8 --
Subject: [PATCH] rerere: libify rerere_clear() and rerere_gc()

This moves the two features from builtin/rerere.c to a more library-ish
portion of the codebase.  No behaviour change.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/rerere.c |   77 +------------------------------------------------
 rerere.c         |   84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 rerere.h         |    2 +
 3 files changed, 88 insertions(+), 75 deletions(-)

diff --git a/builtin/rerere.c b/builtin/rerere.c
index 8235885..08213c7 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -12,74 +12,6 @@ static const char * const rerere_usage[] = {
 	NULL,
 };
 
-/* these values are days */
-static int cutoff_noresolve = 15;
-static int cutoff_resolve = 60;
-
-static time_t rerere_created_at(const char *name)
-{
-	struct stat st;
-	return stat(rerere_path(name, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
-}
-
-static time_t rerere_last_used_at(const char *name)
-{
-	struct stat st;
-	return stat(rerere_path(name, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
-}
-
-static void unlink_rr_item(const char *name)
-{
-	unlink(rerere_path(name, "thisimage"));
-	unlink(rerere_path(name, "preimage"));
-	unlink(rerere_path(name, "postimage"));
-	rmdir(git_path("rr-cache/%s", name));
-}
-
-static int git_rerere_gc_config(const char *var, const char *value, void *cb)
-{
-	if (!strcmp(var, "gc.rerereresolved"))
-		cutoff_resolve = git_config_int(var, value);
-	else if (!strcmp(var, "gc.rerereunresolved"))
-		cutoff_noresolve = git_config_int(var, value);
-	else
-		return git_default_config(var, value, cb);
-	return 0;
-}
-
-static void garbage_collect(struct string_list *rr)
-{
-	struct string_list to_remove = STRING_LIST_INIT_DUP;
-	DIR *dir;
-	struct dirent *e;
-	int i, cutoff;
-	time_t now = time(NULL), then;
-
-	git_config(git_rerere_gc_config, NULL);
-	dir = opendir(git_path("rr-cache"));
-	if (!dir)
-		die_errno("unable to open rr-cache directory");
-	while ((e = readdir(dir))) {
-		if (is_dot_or_dotdot(e->d_name))
-			continue;
-
-		then = rerere_last_used_at(e->d_name);
-		if (then) {
-			cutoff = cutoff_resolve;
-		} else {
-			then = rerere_created_at(e->d_name);
-			if (!then)
-				continue;
-			cutoff = cutoff_noresolve;
-		}
-		if (then < now - cutoff * 86400)
-			string_list_append(&to_remove, e->d_name);
-	}
-	for (i = 0; i < to_remove.nr; i++)
-		unlink_rr_item(to_remove.items[i].string);
-	string_list_clear(&to_remove, 0);
-}
-
 static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)
 {
 	int i;
@@ -148,14 +80,9 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
 		return 0;
 
 	if (!strcmp(argv[0], "clear")) {
-		for (i = 0; i < merge_rr.nr; i++) {
-			const char *name = (const char *)merge_rr.items[i].util;
-			if (!has_rerere_resolution(name))
-				unlink_rr_item(name);
-		}
-		unlink_or_warn(git_path("MERGE_RR"));
+		rerere_clear(&merge_rr);
 	} else if (!strcmp(argv[0], "gc"))
-		garbage_collect(&merge_rr);
+		rerere_gc(&merge_rr);
 	else if (!strcmp(argv[0], "status"))
 		for (i = 0; i < merge_rr.nr; i++)
 			printf("%s\n", merge_rr.items[i].string);
diff --git a/rerere.c b/rerere.c
index 22dfc84..dee2cb1 100644
--- a/rerere.c
+++ b/rerere.c
@@ -671,3 +671,87 @@ int rerere_forget(const char **pathspec)
 	}
 	return write_rr(&merge_rr, fd);
 }
+
+static time_t rerere_created_at(const char *name)
+{
+	struct stat st;
+	return stat(rerere_path(name, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
+}
+
+static time_t rerere_last_used_at(const char *name)
+{
+	struct stat st;
+	return stat(rerere_path(name, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
+}
+
+static void unlink_rr_item(const char *name)
+{
+	unlink(rerere_path(name, "thisimage"));
+	unlink(rerere_path(name, "preimage"));
+	unlink(rerere_path(name, "postimage"));
+	rmdir(git_path("rr-cache/%s", name));
+}
+
+struct rerere_gc_config_cb {
+	int cutoff_noresolve;
+	int cutoff_resolve;
+};
+
+static int git_rerere_gc_config(const char *var, const char *value, void *cb)
+{
+	struct rerere_gc_config_cb *cf = cb;
+
+	if (!strcmp(var, "gc.rerereresolved"))
+		cf->cutoff_resolve = git_config_int(var, value);
+	else if (!strcmp(var, "gc.rerereunresolved"))
+		cf->cutoff_noresolve = git_config_int(var, value);
+	else
+		return git_default_config(var, value, cb);
+	return 0;
+}
+
+void rerere_gc(struct string_list *rr)
+{
+	struct string_list to_remove = STRING_LIST_INIT_DUP;
+	DIR *dir;
+	struct dirent *e;
+	int i, cutoff;
+	time_t now = time(NULL), then;
+	struct rerere_gc_config_cb cf = { 15, 60 };
+
+	git_config(git_rerere_gc_config, &cf);
+	dir = opendir(git_path("rr-cache"));
+	if (!dir)
+		die_errno("unable to open rr-cache directory");
+	while ((e = readdir(dir))) {
+		if (is_dot_or_dotdot(e->d_name))
+			continue;
+
+		then = rerere_last_used_at(e->d_name);
+		if (then) {
+			cutoff = cf.cutoff_resolve;
+		} else {
+			then = rerere_created_at(e->d_name);
+			if (!then)
+				continue;
+			cutoff = cf.cutoff_noresolve;
+		}
+		if (then < now - cutoff * 86400)
+			string_list_append(&to_remove, e->d_name);
+	}
+	for (i = 0; i < to_remove.nr; i++)
+		unlink_rr_item(to_remove.items[i].string);
+	string_list_clear(&to_remove, 0);
+}
+
+void rerere_clear(struct string_list *merge_rr)
+{
+	int i;
+
+	for (i = 0; i < merge_rr->nr; i++) {
+		const char *name = (const char *)merge_rr->items[i].util;
+		if (!has_rerere_resolution(name))
+			unlink_rr_item(name);
+	}
+	unlink_or_warn(git_path("MERGE_RR"));
+}
diff --git a/rerere.h b/rerere.h
index 595f49f..fcd8bc1 100644
--- a/rerere.h
+++ b/rerere.h
@@ -19,6 +19,8 @@ extern const char *rerere_path(const char *hex, const char *file);
 extern int has_rerere_resolution(const char *hex);
 extern int rerere_forget(const char **);
 extern int rerere_remaining(struct string_list *);
+extern void rerere_clear(struct string_list *);
+extern void rerere_gc(struct string_list *);
 
 #define OPT_RERERE_AUTOUPDATE(v) OPT_UYN(0, "rerere-autoupdate", (v), \
 	"update the index with reused conflict resolution if possible")
-- 
1.7.5.1.268.gce5bd

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

end of thread, other threads:[~2011-05-08 20:07 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-04-11  8:51 [PATCH] rerere: Expose an API corresponding to 'clear' functionality Ramkumar Ramachandra
2011-04-11 18:36 ` Junio C Hamano
2011-04-13 13:18   ` [PATCH v2] " Ramkumar Ramachandra
2011-04-13 20:38     ` Jonathan Nieder
2011-05-06  6:36       ` [PATCH v3] " Ramkumar Ramachandra
2011-05-06 16:51         ` Junio C Hamano
2011-05-07 13:17           ` Ramkumar Ramachandra
2011-05-08  7:30           ` [PATCH v4 0/2] Libify rerere: clear and gc Ramkumar Ramachandra
2011-05-08  7:30             ` [PATCH v4 1/2] usage: Introduce error_errno corresponding to die_errno Ramkumar Ramachandra
2011-05-08  9:46               ` Ramkumar Ramachandra
2011-05-08 18:10               ` Junio C Hamano
2011-05-08  7:30             ` [PATCH v4 2/2] rerere: Libify "rerere clear" and "rerere gc" Ramkumar Ramachandra
2011-05-08 20:06               ` Junio C Hamano

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.