all repos — cgit @ 8f208794318f83826e98168b8b430f2d9a68bcce

a hyperfast web frontend for git written in c

ui-refs.c (view raw)

  1/* ui-refs.c: browse symbolic refs
  2 *
  3 * Copyright (C) 2006 Lars Hjemli
  4 *
  5 * Licensed under GNU General Public License v2
  6 *   (see COPYING for full license text)
  7 */
  8
  9#include "cgit.h"
 10#include "ui-refs.h"
 11#include "html.h"
 12#include "ui-shared.h"
 13
 14static int header;
 15
 16static int cmp_age(int age1, int age2)
 17{
 18	if (age1 != 0 && age2 != 0)
 19		return age2 - age1;
 20
 21	if (age1 == 0 && age2 == 0)
 22		return 0;
 23
 24	if (age1 == 0)
 25		return +1;
 26
 27	return -1;
 28}
 29
 30static int cmp_ref_name(const void *a, const void *b)
 31{
 32	struct refinfo *r1 = *(struct refinfo **)a;
 33	struct refinfo *r2 = *(struct refinfo **)b;
 34
 35	return strcmp(r1->refname, r2->refname);
 36}
 37
 38static int cmp_branch_age(const void *a, const void *b)
 39{
 40	struct refinfo *r1 = *(struct refinfo **)a;
 41	struct refinfo *r2 = *(struct refinfo **)b;
 42
 43	return cmp_age(r1->commit->committer_date, r2->commit->committer_date);
 44}
 45
 46static int get_ref_age(struct refinfo *ref)
 47{
 48	if (!ref->object)
 49		return 0;
 50	switch (ref->object->type) {
 51	case OBJ_TAG:
 52		return ref->tag ? ref->tag->tagger_date : 0;
 53	case OBJ_COMMIT:
 54		return ref->commit ? ref->commit->committer_date : 0;
 55	}
 56	return 0;
 57}
 58
 59static int cmp_tag_age(const void *a, const void *b)
 60{
 61	struct refinfo *r1 = *(struct refinfo **)a;
 62	struct refinfo *r2 = *(struct refinfo **)b;
 63
 64	return cmp_age(get_ref_age(r1), get_ref_age(r2));
 65}
 66
 67static int print_branch(struct refinfo *ref)
 68{
 69	struct commitinfo *info = ref->commit;
 70	char *name = (char *)ref->refname;
 71
 72	if (!info)
 73		return 1;
 74	html("<tr><td>");
 75	cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL,
 76		      ctx.qry.showmsg);
 77	html("</td><td>");
 78
 79	if (ref->object->type == OBJ_COMMIT) {
 80		cgit_commit_link(info->subject, NULL, NULL, name, NULL, NULL, 0);
 81		html("</td><td>");
 82		html_txt(info->author);
 83		html("</td><td colspan='2'>");
 84		cgit_print_age(info->commit->date, -1, NULL);
 85	} else {
 86		html("</td><td></td><td>");
 87		cgit_object_link(ref->object);
 88	}
 89	html("</td></tr>\n");
 90	return 0;
 91}
 92
 93static void print_tag_header()
 94{
 95	html("<tr class='nohover'><th class='left'>Tag</th>"
 96	     "<th class='left'>Download</th>"
 97	     "<th class='left'>Author</th>"
 98	     "<th class='left' colspan='2'>Age</th></tr>\n");
 99	header = 1;
100}
101
102static void print_tag_downloads(const struct cgit_repo *repo, const char *ref)
103{
104	const struct cgit_snapshot_format* f;
105    	char *filename;
106	const char *basename;
107	int free_ref = 0;
108
109	if (!ref || strlen(ref) < 2)
110		return;
111
112	basename = cgit_repobasename(repo->url);
113	if (prefixcmp(ref, basename) != 0) {
114		if ((ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1]))
115			ref++;
116		if (isdigit(ref[0])) {
117			ref = xstrdup(fmt("%s-%s", basename, ref));
118			free_ref = 1;
119		}
120	}
121
122	for (f = cgit_snapshot_formats; f->suffix; f++) {
123		if (!(repo->snapshots & f->bit))
124			continue;
125		filename = fmt("%s%s", ref, f->suffix);
126		cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename);
127		html("&nbsp;&nbsp;");
128	}
129
130	if (free_ref)
131		free((char *)ref);
132}
133static int print_tag(struct refinfo *ref)
134{
135	struct tag *tag;
136	struct taginfo *info;
137	char *name = (char *)ref->refname;
138
139	if (ref->object->type == OBJ_TAG) {
140		tag = (struct tag *)ref->object;
141		info = ref->tag;
142		if (!tag || !info)
143			return 1;
144		html("<tr><td>");
145		cgit_tag_link(name, NULL, NULL, ctx.qry.head, name);
146		html("</td><td>");
147		if (ctx.repo->snapshots && (tag->tagged->type == OBJ_COMMIT))
148			print_tag_downloads(ctx.repo, name);
149		else
150			cgit_object_link(tag->tagged);
151		html("</td><td>");
152		if (info->tagger)
153			html(info->tagger);
154		html("</td><td colspan='2'>");
155		if (info->tagger_date > 0)
156			cgit_print_age(info->tagger_date, -1, NULL);
157		html("</td></tr>\n");
158	} else {
159		if (!header)
160			print_tag_header();
161		html("<tr><td>");
162		cgit_tag_link(name, NULL, NULL, ctx.qry.head, name);
163		html("</td><td>");
164		if (ctx.repo->snapshots && (ref->object->type == OBJ_COMMIT))
165			print_tag_downloads(ctx.repo, name);
166		else
167			cgit_object_link(ref->object);
168		html("</td><td>");
169		if (ref->object->type == OBJ_COMMIT)
170			html(ref->commit->author);
171		html("</td><td colspan='2'>");
172		if (ref->object->type == OBJ_COMMIT)
173			cgit_print_age(ref->commit->commit->date, -1, NULL);
174		html("</td></tr>\n");
175	}
176	return 0;
177}
178
179static void print_refs_link(char *path)
180{
181	html("<tr class='nohover'><td colspan='5'>");
182	cgit_refs_link("[...]", NULL, NULL, ctx.qry.head, NULL, path);
183	html("</td></tr>");
184}
185
186void cgit_print_branches(int maxcount)
187{
188	struct reflist list;
189	int i;
190
191	html("<tr class='nohover'><th class='left'>Branch</th>"
192	     "<th class='left'>Commit message</th>"
193	     "<th class='left'>Author</th>"
194	     "<th class='left' colspan='2'>Age</th></tr>\n");
195
196	list.refs = NULL;
197	list.alloc = list.count = 0;
198	for_each_branch_ref(cgit_refs_cb, &list);
199	if (ctx.repo->enable_remote_branches)
200		for_each_remote_ref(cgit_refs_cb, &list);
201
202	if (maxcount == 0 || maxcount > list.count)
203		maxcount = list.count;
204
205	if (maxcount < list.count) {
206		qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age);
207		qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name);
208	}
209
210	for (i = 0; i < maxcount; i++)
211		print_branch(list.refs[i]);
212
213	if (maxcount < list.count)
214		print_refs_link("heads");
215
216	cgit_free_reflist_inner(&list);
217}
218
219void cgit_print_tags(int maxcount)
220{
221	struct reflist list;
222	int i;
223
224	header = 0;
225	list.refs = NULL;
226	list.alloc = list.count = 0;
227	for_each_tag_ref(cgit_refs_cb, &list);
228	if (list.count == 0)
229		return;
230	qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age);
231	if (!maxcount)
232		maxcount = list.count;
233	else if (maxcount > list.count)
234		maxcount = list.count;
235	print_tag_header();
236	for (i = 0; i < maxcount; i++)
237		print_tag(list.refs[i]);
238
239	if (maxcount < list.count)
240		print_refs_link("tags");
241
242	cgit_free_reflist_inner(&list);
243}
244
245void cgit_print_refs()
246{
247
248	html("<table class='list nowrap'>");
249
250	if (ctx.qry.path && !strncmp(ctx.qry.path, "heads", 5))
251		cgit_print_branches(0);
252	else if (ctx.qry.path && !strncmp(ctx.qry.path, "tags", 4))
253		cgit_print_tags(0);
254	else {
255		cgit_print_branches(0);
256		html("<tr class='nohover'><td colspan='5'>&nbsp;</td></tr>");
257		cgit_print_tags(0);
258	}
259	html("</table>");
260}