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

Support customized reordering in version sort

From
Duy Nguyen <pclouds@gmail.com>
Date
Feb 21, 2015, 03:02 UTC
Message-ID
<20150221030209.GA567@lanh>
In-Reply-To
<CAPc5daVJ_nYk=tWqpUYPpsX6Z50H429jOh8QfMwUdNDdTDMq9w@mail.gmail.com>
On Fri, Feb 20, 2015 at 12:26:29AM -0800, Junio C Hamano wrote:
Show 16 quoted lines
> On Thu, Feb 19, 2015 at 11:13 PM, Jeff King <peff@peff.net> wrote:
> 
> >> There is debian bug 777690 [1] that's basically about making tag's
> >> version sort aware about -rc, -pre suffixes. I imagine it would touch
> >> versioncmp.c and builtin/tag.c (to retrieve the suffixes from config
> >> file).
> >>
> >> [1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=777690
> >
> > I think that's a reasonable thing to work on, but it's too big for a
> > microproject and too small for a GSoC.
> 
> That is certainly too big as a Micro, but I do not think it is too small
> for GSoC, if it is to be done right (meaning, not just implementing an
> arbitrary version comparison hardwired, but design how to make it
> extensible).

I did write "maybe more of mini-size than micro" then looked at the micro list again and somehow decided to delete that. Anyway while I still have my attention on it, might as well do it.

My idea is to make it easy for the user to change the sort algorithm. And it's probably intuitive to just substitute a string with something. So if "1-rc1" is put incorrectly before "1.1" and you realize that "1.999" ought to be the last one before "2". You could tell git to internally replace "1-rc1" with "1.999".

This patch does that. The user feeds substitution rules via versionsort.substitute config keys, e.g.

    git config versionsort.substitute "-rc .999"

Performance is not a concern because I don't think people would throw 100k tags to it. There are two issues I'm aware of but not addressed:

 - the order of substitution matters, but right now it's up in the air
 - case-sensitiveness may surprise users
-- 8< --
diff --git a/versioncmp.c b/versioncmp.c
index 7511e08..2419e38 100644
--- a/versioncmp.c
+++ b/versioncmp.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "strbuf.h"
 
 /*
  * versioncmp(): copied from string/strverscmp.c in glibc commit
@@ -20,6 +21,57 @@
 #define  CMP    2
 #define  LEN    3
 
+struct subst_rule
+{
+	const char *before;
+	const char *after;
+};
+static struct subst_rule *rules;
+static int rule_nr, rule_alloc;
+
+static int versioncmp_config(const char *k, const char *v, void *cb)
+{
+	char *p, *s;
+	if (strcmp(k, "versionsort.substitute"))
+		return 0;
+	ALLOC_GROW(rules, rule_nr + 1, rule_alloc);
+	s = xstrdup(v);
+	p = strchr(s, ' ');
+	if (!p)
+		return error("missing space in %s", v);
+	*p = '\0';
+	rules[rule_nr].before = s;
+	rules[rule_nr].after = p + 1;
+	rule_nr++;
+	return 0;
+}
+
+static char *substitute(const unsigned char **strp)
+{
+	struct strbuf sb = STRBUF_INIT;
+	const char *str = (const char *)*strp;
+	int i;
+	if (!rules) {
+		rules = xmalloc(sizeof(*rules));
+		rule_alloc = 1;
+		git_config(versioncmp_config, NULL);
+	}
+	for (i = 0; i < rule_nr; i++) {
+		const struct subst_rule *r = rules + i;
+		const char *p = strstr(str, r->before);
+		if (!p)
+			continue;
+		if (!sb.len)
+			strbuf_addstr(&sb, str);
+		strbuf_splice(&sb, p - str, strlen(r->before),
+			      r->after, strlen(r->after));
+		str = sb.buf;
+	}
+	if ((const unsigned char *)str == *strp)
+		return NULL;
+	*strp = (const unsigned char *)sb.buf;
+	return sb.buf;
+}
 
 /*
  * Compare S1 and S2 as strings holding indices/version numbers,
@@ -32,6 +84,7 @@ int versioncmp(const char *s1, const char *s2)
 {
 	const unsigned char *p1 = (const unsigned char *) s1;
 	const unsigned char *p2 = (const unsigned char *) s2;
+	char *free1, *free2;
 	unsigned char c1, c2;
 	int state, diff;
 
@@ -58,6 +111,8 @@ int versioncmp(const char *s1, const char *s2)
 
 	if (p1 == p2)
 		return 0;
+	free1 = substitute(&p1);
+	free2 = substitute(&p2);
 
 	c1 = *p1++;
 	c2 = *p2++;
@@ -75,6 +130,10 @@ int versioncmp(const char *s1, const char *s2)
 	}
 
 	state = result_type[state * 3 + (((c2 == '0') + (isdigit (c2) != 0)))];
+	if (state != LEN) {
+		free(free1);
+		free(free2);
+	}
 
 	switch (state) {
 	case CMP:
@@ -82,10 +141,16 @@ int versioncmp(const char *s1, const char *s2)
 
 	case LEN:
 		while (isdigit (*p1++))
-			if (!isdigit (*p2++))
+			if (!isdigit (*p2++)) {
+				free(free1);
+				free(free2);
 				return 1;
+			}
 
-		return isdigit (*p2) ? -1 : diff;
+		c2 = *p2;
+		free(free1);
+		free(free2);
+		return isdigit (c2) ? -1 : diff;
 
 	default:
 		return state;
-- 8< --
Previous: Junio C HamanoNext: Junio C Hamano
Message 36 of 74 in “[RFH] GSoC 2015 application”
  1. Jeff KingFeb 18, 2015
  2. Jeff KingFeb 18, 2015
  3. Johannes SchindelinFeb 24, 2015
  4. Jeff KingFeb 24, 2015
  5. Johannes SchindelinFeb 24, 2015
  6. Jeff KingFeb 24, 2015
  7. Johannes SchindelinFeb 25, 2015
  8. Matthieu MoyFeb 25, 2015
  9. Matthieu MoyFeb 25, 2015
  10. Johannes SchindelinFeb 25, 2015
  11. Matthieu MoyFeb 24, 2015
  12. Junio C HamanoFeb 24, 2015
  13. Johannes SchindelinFeb 24, 2015
  14. Junio C HamanoFeb 24, 2015
  15. Matthieu MoyFeb 24, 2015
  16. Stefan BellerFeb 25, 2015
  17. Michael J GruberFeb 25, 2015
  18. Johannes SchindelinFeb 25, 2015
  19. Christian CouderFeb 25, 2015
  20. Duy NguyenFeb 25, 2015
  21. Johannes SchindelinFeb 25, 2015
  22. Junio C HamanoFeb 18, 2015
  23. Junio C HamanoFeb 19, 2015
  24. Matthieu MoyFeb 19, 2015
  25. Jeff KingFeb 20, 2015
  26. Matthieu MoyFeb 20, 2015
  27. Dennis KaarsemakerFeb 20, 2015
  28. Matthieu MoyFeb 20, 2015
  29. Eric SunshineFeb 20, 2015
  30. 1/3 microprojects: tweaks after discussion with PeffMatthieu Moy, Feb 20, 2015
  31. 2/3 GSoC ideas: git bisect fixed/unfixedMatthieu Moy, Feb 20, 2015
  32. 3/3 idea: Be nicer to the user on tracked/untracked merge conflictsMatthieu Moy, Feb 20, 2015
  33. Duy NguyenFeb 20, 2015
  34. Jeff KingFeb 20, 2015
  35. Junio C HamanoFeb 20, 2015
  36. Support customized reordering in version sortDuy Nguyen, Feb 21, 2015
  37. Junio C HamanoFeb 21, 2015
  38. Duy NguyenFeb 21, 2015
  39. Junio C HamanoFeb 21, 2015
  40. Junio C HamanoFeb 21, 2015
  41. versionsort: support reorder prerelease suffixesNguyễn Thái Ngọc Duy, Feb 26, 2015
  42. Junio C HamanoFeb 27, 2015
  43. Junio C HamanoMar 5, 2015
  44. Duy NguyenMar 9, 2015
  45. Junio C HamanoMar 10, 2015
  46. Eric SunshineMar 10, 2015
  47. config.txt: update versioncmp.prereleaseSuffixNguyễn Thái Ngọc Duy, Mar 10, 2015
  48. Michael HaggertyFeb 20, 2015
  49. Jeff KingFeb 20, 2015
  50. Junio C HamanoFeb 20, 2015
  51. Matthieu MoyFeb 20, 2015
  52. Jeff KingFeb 20, 2015
  53. Jeff KingFeb 20, 2015
  54. Matthieu MoyFeb 23, 2015
  55. Jeff KingFeb 23, 2015
  56. Philip OakleyMar 4, 2015
  57. Stefan BellerMar 4, 2015
  58. Philip OakleyMar 4, 2015
  59. Junio C HamanoMar 5, 2015
  60. Stefan BellerMar 5, 2015
  61. Junio C HamanoMar 5, 2015
  62. Junio C HamanoMar 5, 2015
  63. Duy NguyenMar 6, 2015
  64. Duy NguyenMar 5, 2015
  65. Nguyễn Thái Ngọc DuyMar 5, 2015
  66. 1/6 upload-pack: move shallow deepen code out of receive_needs()Nguyễn Thái Ngọc Duy, Mar 5, 2015
  67. 2/6 upload-pack: move "shallow" sending code out of deepen()Nguyễn Thái Ngọc Duy, Mar 5, 2015
  68. 3/6 upload-pack: remove unused variable "backup"Nguyễn Thái Ngọc Duy, Mar 5, 2015
  69. 4/6 upload-pack: move "unshallow" sending code out of deepen()Nguyễn Thái Ngọc Duy, Mar 5, 2015
  70. 5/6 shallow.c: implement a generic shallow boundary finder based on rev-listNguyễn Thái Ngọc Duy, Mar 5, 2015
  71. 6/6 upload-pack: example code to use get_shallow_commits_by_rev_listNguyễn Thái Ngọc Duy, Mar 5, 2015
  72. Duy NguyenFeb 26, 2015
  73. Jeff KingMar 4, 2015
  74. Duy NguyenMar 4, 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.