{"thread":{"id":"17955","subject":"[PATCH/RFC 5/6] builtin-tag: add sort by date -D","startedAt":"2009-02-22T18:06:45Z","lastAt":"2009-02-22T18:38:10Z","messageCount":3,"participants":["Marc-André Lureau","Junio C Hamano","Felipe Contreras"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"105799","messageId":"e29894ca0902221006j3d602553x15807b41698f51a1@mail.gmail.com","threadId":"17955","inReplyTo":null,"subject":"[PATCH/RFC 5/6] builtin-tag: add sort by date -D","fromName":"Marc-André Lureau","fromEmail":"marcandre.lureau@gmail.com","sentAt":"2009-02-22T18:06:45Z","receivedAt":"2009-02-22T18:06:45Z","isPatch":true,"sender":{"key":"marcandre.lureau@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9381?v=4"},"body":"Signed-off-by: Marc-Andre Lureau <marcandre.lureau@gmail.com>\n---\n builtin-tag.c |  162 +++++++++++++++++++++++++++++++++++++++++++++------------\n 1 files changed, 129 insertions(+), 33 deletions(-)\n\ndiff --git a/builtin-tag.c b/builtin-tag.c\nindex 01e7374..8ff9d03 100644\n--- a/builtin-tag.c\n+++ b/builtin-tag.c\n@@ -16,7 +16,7 @@\n static const char * const git_tag_usage[] = {\n \t\"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]\",\n \t\"git tag -d <tagname>...\",\n-\t\"git tag -l [-n[<num>]] [<pattern>]\",\n+\t\"git tag -l [-n[<num>] -D] [<pattern>]\",\n \t\"git tag -v <tagname>...\",\n \tNULL\n };\n@@ -27,21 +27,108 @@ struct tag_filter {\n \tconst char *pattern;\n \tint lines;\n \tstruct commit_list *with_commit;\n+\tint sort;\n+\tstruct object_list *sorted_tags;\n };\n\n+struct light_tag {\n+\tstruct object object;\n+\tstruct object *tagged;\n+\tchar *refname;\n+};\n+\n+#define OBJ_LIGHT_TAG (OBJ_MAX + 1)\n #define PGP_SIGNATURE \"-----BEGIN PGP SIGNATURE-----\"\n\n+static unsigned long object_date(struct object *object)\n+{\n+\tif (object->type == OBJ_TAG)\n+\t\treturn ((struct tag*)object)->date;\n+\telse if (object->type == OBJ_COMMIT)\n+\t\treturn ((struct commit*)object)->date;\n+\telse if (object->type == OBJ_TREE)\n+\t\treturn 0;\n+\telse if (object->type == OBJ_BLOB)\n+\t\treturn 0;\n+\telse if (object->type == OBJ_LIGHT_TAG)\n+\t\treturn object_date(((struct light_tag*)object)->tagged);\n+\n+\treturn 0;\n+}\n+\n+static struct object_list *object_list_insert_by_date(struct object\n*item, struct object_list **list)\n+{\n+\tstruct object_list **pp = list;\n+\tstruct object_list *p;\n+\tunsigned long item_date;\n+\tunsigned long p_date;\n+\n+\tif (!item->parsed)\n+\t\treturn NULL;\n+\n+\twhile ((p = *pp) != NULL) {\n+\t\tp_date = object_date(p->item);\n+\t\titem_date = object_date(item);\n+\n+\t\tif (p_date > item_date)\n+\t\t\tbreak;\n+\n+\t\tpp = &p->next;\n+\t}\n+\treturn object_list_insert(item, pp);\n+}\n+\n+static void pretty_print_tag(const struct object *object, int lines)\n+{\n+\tint i;\n+\tchar *sp, *eol;\n+\tsize_t len;\n+\n+\tif (!lines) {\n+\t\tif (object->type == OBJ_TAG)\n+\t\t\tprintf(\"%s\\n\", ((struct tag*)object)->tag);\n+\t\telse if (object->type == OBJ_LIGHT_TAG)\n+\t\t\tprintf(\"%s\\n\", ((struct light_tag*)object)->refname);\n+\t\t/* other not implemented */\n+\t\treturn;\n+\t}\n+\n+\tif (object->type == OBJ_TAG) {\n+\t\tstruct tag *tag;\n+\n+\t\ttag = (struct tag*)object;\n+\t\tprintf(\"%-15s \", tag->tag);\n+\n+\t\t/* skip header */\n+\t\tsp = strstr(tag->buffer, \"\\n\\n\");\n+\t\tif (!sp)\n+\t\t\treturn;\n+\n+\t\t/* only take up to \"lines\" lines, and strip the signature */\n+\t\tfor (i = 0, sp += 2;\n+\t\t     i < lines && sp < tag->buffer + tag->size &&\n+\t\t\t     prefixcmp(sp, PGP_SIGNATURE \"\\n\");\n+\t\t     i++) {\n+\t\t\tif (i)\n+\t\t\t\tprintf(\"\\n    \");\n+\t\t\teol = memchr(sp, '\\n', tag->size - (sp - tag->buffer));\n+\t\t\tlen = eol ? eol - sp : tag->size - (sp - tag->buffer);\n+\t\t\tfwrite(sp, len, 1, stdout);\n+\t\t\tif (!eol)\n+\t\t\t\tbreak;\n+\t\t\tsp = eol + 1;\n+\t\t}\n+\t\tputchar('\\n');\n+\t}\n+}\n+\n static int show_reference(const char *refname, const unsigned char *sha1,\n \t\t\t  int flag, void *cb_data)\n {\n \tstruct tag_filter *filter = cb_data;\n+\tstruct object *object;\n\n \tif (!fnmatch(filter->pattern, refname, 0)) {\n-\t\tint i;\n-\t\tunsigned long size;\n-\t\tenum object_type type;\n-\t\tchar *buf, *sp, *eol;\n-\t\tsize_t len;\n\n \t\tif (filter->with_commit) {\n \t\t\tstruct commit *commit;\n@@ -53,45 +140,43 @@ static int show_reference(const char *refname,\nconst unsigned char *sha1,\n \t\t\t\treturn 0;\n \t\t}\n\n-\t\tif (!filter->lines) {\n+\t\tif (!filter->lines && !filter->sort) {\n \t\t\tprintf(\"%s\\n\", refname);\n \t\t\treturn 0;\n \t\t}\n-\t\tprintf(\"%-15s \", refname);\n\n-\t\tbuf = read_sha1_file(sha1, &type, &size);\n-\t\tif (!buf || !size)\n+\t\tobject = parse_object(sha1);\n+\t\tif (!object)\n \t\t\treturn 0;\n\n-\t\t/* skip header */\n-\t\tsp = strstr(buf, \"\\n\\n\");\n-\t\tif (!sp) {\n-\t\t\tfree(buf);\n-\t\t\treturn 0;\n+\t\tif (object->type != OBJ_TAG) {\n+\t\t\tstruct light_tag *light_tag;\n+\t\t\tstruct object *o;\n+\n+\t\t\to = xmalloc(sizeof(struct light_tag));\n+\t\t\tlight_tag = (struct light_tag*)o;\n+\t\t\to->parsed = 1;\n+\t\t\to->used = 0;\n+\t\t\to->type = OBJ_LIGHT_TAG;\n+\t\t\to->flags = 0;\n+\t\t\tlight_tag->tagged = object;\n+\t\t\tlight_tag->refname = xstrdup(refname);\n+\t\t\tobject = o;\n \t\t}\n-\t\t/* only take up to \"lines\" lines, and strip the signature */\n-\t\tfor (i = 0, sp += 2;\n-\t\t\t\ti < filter->lines && sp < buf + size &&\n-\t\t\t\tprefixcmp(sp, PGP_SIGNATURE \"\\n\");\n-\t\t\t\ti++) {\n-\t\t\tif (i)\n-\t\t\t\tprintf(\"\\n    \");\n-\t\t\teol = memchr(sp, '\\n', size - (sp - buf));\n-\t\t\tlen = eol ? eol - sp : size - (sp - buf);\n-\t\t\tfwrite(sp, len, 1, stdout);\n-\t\t\tif (!eol)\n-\t\t\t\tbreak;\n-\t\t\tsp = eol + 1;\n+\n+\t\tif (filter->sort) {\n+\t\t\tobject_list_insert_by_date(object, &filter->sorted_tags);\n+\t\t\treturn 0;\n \t\t}\n-\t\tputchar('\\n');\n-\t\tfree(buf);\n+\n+\t\tpretty_print_tag(object, filter->lines);\n \t}\n\n \treturn 0;\n }\n\n static int list_tags(const char *pattern, int lines,\n-\t\t\tstruct commit_list *with_commit)\n+\t\t\tstruct commit_list *with_commit, int sort)\n {\n \tstruct tag_filter filter;\n\n@@ -101,9 +186,19 @@ static int list_tags(const char *pattern, int lines,\n \tfilter.pattern = pattern;\n \tfilter.lines = lines;\n \tfilter.with_commit = with_commit;\n+\tfilter.sort = sort;\n+\tfilter.sorted_tags = NULL;\n\n \tfor_each_tag_ref(show_reference, (void *) &filter);\n\n+\tif (filter.sort) {\n+\t\tstruct object_list *l;\n+\t\tfor (l = filter.sorted_tags; l; l = l->next) {\n+\t\t\tpretty_print_tag(l->item, lines);\n+\t\t}\n+\t\t/* free_object_list(filter.sorted_tags); */\n+\t}\n+\n \treturn 0;\n }\n\n@@ -370,12 +465,13 @@ int cmd_tag(int argc, const char **argv, const\nchar *prefix)\n \tstruct ref_lock *lock;\n\n \tint annotate = 0, sign = 0, force = 0, lines = -1,\n-\t\tlist = 0, delete = 0, verify = 0;\n+\t\tlist = 0, delete = 0, verify = 0, sort = 0;\n \tconst char *msgfile = NULL, *keyid = NULL;\n \tstruct msg_arg msg = { 0, STRBUF_INIT };\n \tstruct commit_list *with_commit = NULL;\n \tstruct option options[] = {\n \t\tOPT_BOOLEAN('l', NULL, &list, \"list tag names\"),\n+\t\tOPT_BOOLEAN('D', NULL, &sort, \"sort tag by date\"),\n \t\t{ OPTION_INTEGER, 'n', NULL, &lines, NULL,\n \t\t\t\t\"print n lines of each tag message\",\n \t\t\t\tPARSE_OPT_OPTARG, NULL, 1 },\n@@ -425,7 +521,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_tag_usage, options);\n \tif (list)\n \t\treturn list_tags(argv[0], lines == -1 ? 0 : lines,\n-\t\t\t\t with_commit);\n+\t\t\t\t with_commit, sort);\n \tif (lines != -1)\n \t\tdie(\"-n option is only allowed with -l.\");\n \tif (with_commit)\n-- \n1.6.2.rc1.28.g05ef4.dirty\n"},{"id":"105806","messageId":"7vhc2mxqwa.fsf@gitster.siamese.dyndns.org","threadId":"17955","inReplyTo":"e29894ca0902221006j3d602553x15807b41698f51a1@mail.gmail.com","subject":"Re: [PATCH/RFC 5/6] builtin-tag: add sort by date -D","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-22T18:33:57Z","receivedAt":"2009-02-22T18:33:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Marc-André Lureau <marcandre.lureau@gmail.com> writes:\n\n> Signed-off-by: Marc-Andre Lureau <marcandre.lureau@gmail.com>\n> ---\n>  builtin-tag.c |  162 +++++++++++++++++++++++++++++++++++++++++++++------------\n>  1 files changed, 129 insertions(+), 33 deletions(-)\n>\n> diff --git a/builtin-tag.c b/builtin-tag.c\n> index 01e7374..8ff9d03 100644\n> --- a/builtin-tag.c\n> +++ b/builtin-tag.c\n> @@ -16,7 +16,7 @@\n>  static const char * const git_tag_usage[] = {\n>  \t\"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]\",\n>  \t\"git tag -d <tagname>...\",\n> -\t\"git tag -l [-n[<num>]] [<pattern>]\",\n> +\t\"git tag -l [-n[<num>] -D] [<pattern>]\",\n\nPlease don't use a short-and-sweet \"-D\" for something whose usefulness is\nnot proven yet.  Especially this risks grief from typo-confusion with the\nexisting \"-d\" option that is destructive.\n\n> +\t\tif (object->type != OBJ_TAG) {\n> +\t\t\tstruct light_tag *light_tag;\n> +\t\t\tstruct object *o;\n> +\n> +\t\t\to = xmalloc(sizeof(struct light_tag));\n> +\t\t\tlight_tag = (struct light_tag*)o;\n> +\t\t\to->parsed = 1;\n> +\t\t\to->used = 0;\n> +\t\t\to->type = OBJ_LIGHT_TAG;\n> +\t\t\to->flags = 0;\n> +\t\t\tlight_tag->tagged = object;\n> +\t\t\tlight_tag->refname = xstrdup(refname);\n> +\t\t\tobject = o;\n\nI really do not like this.  The only place you need a stand-in tag object\nis inside this \"sort tag objects and commits together\", and you cannot\neven handle lightweight tags that point at blobs or trees sanely with this\ncode anyway. It is not a good excuse to contaminate the object layer.\n\nI think it might be a lot more sensible to introduce a structure like\nthis:\n\n\tstruct tag_entry {\n        \tstruct object *object;\n                unsigned long date_for_sorting;\n\t};\n\nand allocate and queue this structure in your for_each_ref callback\nfunction, instead of the low-level objects.  If object *is* not a tag, you\ncan at that point find a suitable timestamp to stuff in date_for_sorting\n(and if it is a tag, you can find a tagger field and parse the date into\ndate_for_sorting, which implies you do not necessarily need your patch 2/6\neither and we can keep sizeof(struct tag) to the minimum as before).\n\nThen your sort and output functions can sort and iterate over a list of\nthis structure.\n\nYou still need to think about what to do with lightweight tag that points\nat a blob or a tree, though.\n"},{"id":"105810","messageId":"94a0d4530902221038j6614bfacl223c0fa7b7be396@mail.gmail.com","threadId":"17955","inReplyTo":"e29894ca0902221006j3d602553x15807b41698f51a1@mail.gmail.com","subject":"Re: [PATCH/RFC 5/6] builtin-tag: add sort by date -D","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2009-02-22T18:38:10Z","receivedAt":"2009-02-22T18:38:10Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Sun, Feb 22, 2009 at 8:06 PM, Marc-André Lureau\n<marcandre.lureau@gmail.com> wrote:\n> Signed-off-by: Marc-Andre Lureau <marcandre.lureau@gmail.com>\n> ---\n>  builtin-tag.c |  162 +++++++++++++++++++++++++++++++++++++++++++++------------\n>  1 files changed, 129 insertions(+), 33 deletions(-)\n>\n> diff --git a/builtin-tag.c b/builtin-tag.c\n> index 01e7374..8ff9d03 100644\n> --- a/builtin-tag.c\n> +++ b/builtin-tag.c\n> @@ -16,7 +16,7 @@\n>  static const char * const git_tag_usage[] = {\n>        \"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]\",\n>        \"git tag -d <tagname>...\",\n> -       \"git tag -l [-n[<num>]] [<pattern>]\",\n> +       \"git tag -l [-n[<num>] -D] [<pattern>]\",\n>        \"git tag -v <tagname>...\",\n>        NULL\n>  };\n\nHmm, the -D option is independent of -n, so \"[-D]\". Also, it must be documented.\n\n<snip/>\n\nWouldn't it make sense to split this patch so the first part adds the\noption to filter, even if there are not filters functional, and the\nsecond one adds the date filter?\n\n-- \nFelipe Contreras\n"}]}