summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cmd.c3
-rw-r--r--ui-refs.c37
-rw-r--r--ui-shared.c17
-rw-r--r--ui-snapshot.c94
-rw-r--r--ui-snapshot.h3
5 files changed, 94 insertions, 60 deletions
diff --git a/cmd.c b/cmd.c
index 5b3c14c..8914fa5 100644
--- a/cmd.c
+++ b/cmd.c
@@ -83,50 +83,49 @@ static void objects_fn(struct cgit_context *ctx)
83} 83}
84 84
85static void repolist_fn(struct cgit_context *ctx) 85static void repolist_fn(struct cgit_context *ctx)
86{ 86{
87 cgit_print_repolist(); 87 cgit_print_repolist();
88} 88}
89 89
90static void patch_fn(struct cgit_context *ctx) 90static void patch_fn(struct cgit_context *ctx)
91{ 91{
92 cgit_print_patch(ctx->qry.sha1); 92 cgit_print_patch(ctx->qry.sha1);
93} 93}
94 94
95static void plain_fn(struct cgit_context *ctx) 95static void plain_fn(struct cgit_context *ctx)
96{ 96{
97 cgit_print_plain(ctx); 97 cgit_print_plain(ctx);
98} 98}
99 99
100static void refs_fn(struct cgit_context *ctx) 100static void refs_fn(struct cgit_context *ctx)
101{ 101{
102 cgit_print_refs(); 102 cgit_print_refs();
103} 103}
104 104
105static void snapshot_fn(struct cgit_context *ctx) 105static void snapshot_fn(struct cgit_context *ctx)
106{ 106{
107 cgit_print_snapshot(ctx->qry.head, ctx->qry.sha1, 107 cgit_print_snapshot(ctx->qry.head, ctx->qry.sha1, ctx->qry.path,
108 cgit_repobasename(ctx->repo->url), ctx->qry.path,
109 ctx->repo->snapshots, ctx->qry.nohead); 108 ctx->repo->snapshots, ctx->qry.nohead);
110} 109}
111 110
112static void summary_fn(struct cgit_context *ctx) 111static void summary_fn(struct cgit_context *ctx)
113{ 112{
114 cgit_print_summary(); 113 cgit_print_summary();
115} 114}
116 115
117static void tag_fn(struct cgit_context *ctx) 116static void tag_fn(struct cgit_context *ctx)
118{ 117{
119 cgit_print_tag(ctx->qry.sha1); 118 cgit_print_tag(ctx->qry.sha1);
120} 119}
121 120
122static void tree_fn(struct cgit_context *ctx) 121static void tree_fn(struct cgit_context *ctx)
123{ 122{
124 cgit_print_tree(ctx->qry.sha1, ctx->qry.path); 123 cgit_print_tree(ctx->qry.sha1, ctx->qry.path);
125} 124}
126 125
127#define def_cmd(name, want_repo, want_layout) \ 126#define def_cmd(name, want_repo, want_layout) \
128 {#name, name##_fn, want_repo, want_layout} 127 {#name, name##_fn, want_repo, want_layout}
129 128
130struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx) 129struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx)
131{ 130{
132 static struct cgit_cmd cmds[] = { 131 static struct cgit_cmd cmds[] = {
diff --git a/ui-refs.c b/ui-refs.c
index 32e0429..0805fc8 100644
--- a/ui-refs.c
+++ b/ui-refs.c
@@ -57,83 +57,114 @@ static int print_branch(struct refinfo *ref)
57 57
58 if (!info) 58 if (!info)
59 return 1; 59 return 1;
60 html("<tr><td>"); 60 html("<tr><td>");
61 cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL); 61 cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL);
62 html("</td><td>"); 62 html("</td><td>");
63 63
64 if (ref->object->type == OBJ_COMMIT) { 64 if (ref->object->type == OBJ_COMMIT) {
65 cgit_commit_link(info->subject, NULL, NULL, name, NULL); 65 cgit_commit_link(info->subject, NULL, NULL, name, NULL);
66 html("</td><td>"); 66 html("</td><td>");
67 html_txt(info->author); 67 html_txt(info->author);
68 html("</td><td colspan='2'>"); 68 html("</td><td colspan='2'>");
69 cgit_print_age(info->commit->date, -1, NULL); 69 cgit_print_age(info->commit->date, -1, NULL);
70 } else { 70 } else {
71 html("</td><td></td><td>"); 71 html("</td><td></td><td>");
72 cgit_object_link(ref->object); 72 cgit_object_link(ref->object);
73 } 73 }
74 html("</td></tr>\n"); 74 html("</td></tr>\n");
75 return 0; 75 return 0;
76} 76}
77 77
78static void print_tag_header() 78static void print_tag_header()
79{ 79{
80 html("<tr class='nohover'><th class='left'>Tag</th>" 80 html("<tr class='nohover'><th class='left'>Tag</th>"
81 "<th class='left'>Reference</th>" 81 "<th class='left'>Download</th>"
82 "<th class='left'>Author</th>" 82 "<th class='left'>Author</th>"
83 "<th class='left' colspan='2'>Age</th></tr>\n"); 83 "<th class='left' colspan='2'>Age</th></tr>\n");
84 header = 1; 84 header = 1;
85} 85}
86 86
87static void print_tag_downloads(const struct cgit_repo *repo, const char *ref)
88{
89 const struct cgit_snapshot_format* f;
90 char *filename;
91 const char *basename;
92
93 if (!ref || strlen(ref) < 2)
94 return;
95
96 basename = cgit_repobasename(repo->url);
97 if (prefixcmp(ref, basename) != 0) {
98 if ((ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1]))
99 ref++;
100 if (isdigit(ref[0]))
101 ref = xstrdup(fmt("%s-%s", basename, ref));
102 }
103
104 for (f = cgit_snapshot_formats; f->suffix; f++) {
105 if (!(repo->snapshots & f->bit))
106 continue;
107 filename = fmt("%s%s", ref, f->suffix);
108 cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename);
109 html("&nbsp;&nbsp;");
110 }
111}
87static int print_tag(struct refinfo *ref) 112static int print_tag(struct refinfo *ref)
88{ 113{
89 struct tag *tag; 114 struct tag *tag;
90 struct taginfo *info; 115 struct taginfo *info;
91 char *name = (char *)ref->refname; 116 char *name = (char *)ref->refname;
92 117
93 if (ref->object->type == OBJ_TAG) { 118 if (ref->object->type == OBJ_TAG) {
94 tag = (struct tag *)ref->object; 119 tag = (struct tag *)ref->object;
95 info = ref->tag; 120 info = ref->tag;
96 if (!tag || !info) 121 if (!tag || !info)
97 return 1; 122 return 1;
98 html("<tr><td>"); 123 html("<tr><td>");
99 cgit_tag_link(name, NULL, NULL, ctx.qry.head, name); 124 cgit_tag_link(name, NULL, NULL, ctx.qry.head, name);
100 html("</td><td>"); 125 html("</td><td>");
101 cgit_object_link(tag->tagged); 126 if (ctx.repo->snapshots && (tag->tagged->type == OBJ_COMMIT))
127 print_tag_downloads(ctx.repo, name);
128 else
129 cgit_object_link(tag->tagged);
102 html("</td><td>"); 130 html("</td><td>");
103 if (info->tagger) 131 if (info->tagger)
104 html(info->tagger); 132 html(info->tagger);
105 html("</td><td colspan='2'>"); 133 html("</td><td colspan='2'>");
106 if (info->tagger_date > 0) 134 if (info->tagger_date > 0)
107 cgit_print_age(info->tagger_date, -1, NULL); 135 cgit_print_age(info->tagger_date, -1, NULL);
108 html("</td></tr>\n"); 136 html("</td></tr>\n");
109 } else { 137 } else {
110 if (!header) 138 if (!header)
111 print_tag_header(); 139 print_tag_header();
112 html("<tr><td>"); 140 html("<tr><td>");
113 html_txt(name); 141 html_txt(name);
114 html("</td><td>"); 142 html("</td><td>");
115 cgit_object_link(ref->object); 143 if (ctx.repo->snapshots && (tag->tagged->type == OBJ_COMMIT))
144 print_tag_downloads(ctx.repo, name);
145 else
146 cgit_object_link(ref->object);
116 html("</td></tr>\n"); 147 html("</td></tr>\n");
117 } 148 }
118 return 0; 149 return 0;
119} 150}
120 151
121static void print_refs_link(char *path) 152static void print_refs_link(char *path)
122{ 153{
123 html("<tr class='nohover'><td colspan='4'>"); 154 html("<tr class='nohover'><td colspan='4'>");
124 cgit_refs_link("[...]", NULL, NULL, ctx.qry.head, NULL, path); 155 cgit_refs_link("[...]", NULL, NULL, ctx.qry.head, NULL, path);
125 html("</td></tr>"); 156 html("</td></tr>");
126} 157}
127 158
128void cgit_print_branches(int maxcount) 159void cgit_print_branches(int maxcount)
129{ 160{
130 struct reflist list; 161 struct reflist list;
131 int i; 162 int i;
132 163
133 html("<tr class='nohover'><th class='left'>Branch</th>" 164 html("<tr class='nohover'><th class='left'>Branch</th>"
134 "<th class='left'>Commit message</th>" 165 "<th class='left'>Commit message</th>"
135 "<th class='left'>Author</th>" 166 "<th class='left'>Author</th>"
136 "<th class='left' colspan='2'>Age</th></tr>\n"); 167 "<th class='left' colspan='2'>Age</th></tr>\n");
137 168
138 list.refs = NULL; 169 list.refs = NULL;
139 list.alloc = list.count = 0; 170 list.alloc = list.count = 0;
diff --git a/ui-shared.c b/ui-shared.c
index 224e5f3..9319881 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -344,63 +344,65 @@ void cgit_diff_link(char *name, char *title, char *class, char *head,
344 if (new_rev && strcmp(new_rev, ctx.qry.head)) { 344 if (new_rev && strcmp(new_rev, ctx.qry.head)) {
345 html(delim); 345 html(delim);
346 html("id="); 346 html("id=");
347 html_url_arg(new_rev); 347 html_url_arg(new_rev);
348 delim = "&amp;"; 348 delim = "&amp;";
349 } 349 }
350 if (old_rev) { 350 if (old_rev) {
351 html(delim); 351 html(delim);
352 html("id2="); 352 html("id2=");
353 html_url_arg(old_rev); 353 html_url_arg(old_rev);
354 } 354 }
355 html("'>"); 355 html("'>");
356 html_txt(name); 356 html_txt(name);
357 html("</a>"); 357 html("</a>");
358} 358}
359 359
360void cgit_patch_link(char *name, char *title, char *class, char *head, 360void cgit_patch_link(char *name, char *title, char *class, char *head,
361 char *rev) 361 char *rev)
362{ 362{
363 reporevlink("patch", name, title, class, head, rev, NULL); 363 reporevlink("patch", name, title, class, head, rev, NULL);
364} 364}
365 365
366void cgit_object_link(struct object *obj) 366void cgit_object_link(struct object *obj)
367{ 367{
368 char *page, *rev, *name; 368 char *page, *shortrev, *fullrev, *name;
369 369
370 fullrev = sha1_to_hex(obj->sha1);
371 shortrev = xstrdup(fullrev);
372 shortrev[10] = '\0';
370 if (obj->type == OBJ_COMMIT) { 373 if (obj->type == OBJ_COMMIT) {
371 cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL, 374 cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL,
372 ctx.qry.head, sha1_to_hex(obj->sha1)); 375 ctx.qry.head, fullrev);
373 return; 376 return;
374 } else if (obj->type == OBJ_TREE) 377 } else if (obj->type == OBJ_TREE)
375 page = "tree"; 378 page = "tree";
376 else if (obj->type == OBJ_TAG) 379 else if (obj->type == OBJ_TAG)
377 page = "tag"; 380 page = "tag";
378 else 381 else
379 page = "blob"; 382 page = "blob";
380 rev = sha1_to_hex(obj->sha1); 383 name = fmt("%s %s...", typename(obj->type), shortrev);
381 name = fmt("%s %s", typename(obj->type), rev); 384 reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL);
382 reporevlink(page, name, NULL, NULL, ctx.qry.head, rev, NULL);
383} 385}
384 386
385void cgit_print_date(time_t secs, char *format, int local_time) 387void cgit_print_date(time_t secs, char *format, int local_time)
386{ 388{
387 char buf[64]; 389 char buf[64];
388 struct tm *time; 390 struct tm *time;
389 391
390 if (!secs) 392 if (!secs)
391 return; 393 return;
392 if(local_time) 394 if(local_time)
393 time = localtime(&secs); 395 time = localtime(&secs);
394 else 396 else
395 time = gmtime(&secs); 397 time = gmtime(&secs);
396 strftime(buf, sizeof(buf)-1, format, time); 398 strftime(buf, sizeof(buf)-1, format, time);
397 html_txt(buf); 399 html_txt(buf);
398} 400}
399 401
400void cgit_print_age(time_t t, time_t max_relative, char *format) 402void cgit_print_age(time_t t, time_t max_relative, char *format)
401{ 403{
402 time_t now, secs; 404 time_t now, secs;
403 405
404 if (!t) 406 if (!t)
405 return; 407 return;
406 time(&now); 408 time(&now);
@@ -686,29 +688,28 @@ void cgit_print_filemode(unsigned short mode)
686 if (S_ISDIR(mode)) 688 if (S_ISDIR(mode))
687 html("d"); 689 html("d");
688 else if (S_ISLNK(mode)) 690 else if (S_ISLNK(mode))
689 html("l"); 691 html("l");
690 else if (S_ISGITLINK(mode)) 692 else if (S_ISGITLINK(mode))
691 html("m"); 693 html("m");
692 else 694 else
693 html("-"); 695 html("-");
694 html_fileperm(mode >> 6); 696 html_fileperm(mode >> 6);
695 html_fileperm(mode >> 3); 697 html_fileperm(mode >> 3);
696 html_fileperm(mode); 698 html_fileperm(mode);
697} 699}
698 700
699void cgit_print_snapshot_links(const char *repo, const char *head, 701void cgit_print_snapshot_links(const char *repo, const char *head,
700 const char *hex, int snapshots) 702 const char *hex, int snapshots)
701{ 703{
702 const struct cgit_snapshot_format* f; 704 const struct cgit_snapshot_format* f;
703 char *filename; 705 char *filename;
704 706
705 for (f = cgit_snapshot_formats; f->suffix; f++) { 707 for (f = cgit_snapshot_formats; f->suffix; f++) {
706 if (!(snapshots & f->bit)) 708 if (!(snapshots & f->bit))
707 continue; 709 continue;
708 filename = fmt("%s-%s%s", cgit_repobasename(repo), hex, 710 filename = fmt("%s-%s%s", cgit_repobasename(repo), hex,
709 f->suffix); 711 f->suffix);
710 cgit_snapshot_link(filename, NULL, NULL, (char *)head, 712 cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename);
711 (char *)hex, filename);
712 html("<br/>"); 713 html("<br/>");
713 } 714 }
714} 715}
diff --git a/ui-snapshot.c b/ui-snapshot.c
index 9c4d086..6f09151 100644
--- a/ui-snapshot.c
+++ b/ui-snapshot.c
@@ -93,96 +93,100 @@ static int make_snapshot(const struct cgit_snapshot_format *format,
93 return 1; 93 return 1;
94 } 94 }
95 commit = lookup_commit_reference(sha1); 95 commit = lookup_commit_reference(sha1);
96 if(!commit) { 96 if(!commit) {
97 cgit_print_error(fmt("Not a commit reference: %s", hex)); 97 cgit_print_error(fmt("Not a commit reference: %s", hex));
98 return 1; 98 return 1;
99 } 99 }
100 memset(&args, 0, sizeof(args)); 100 memset(&args, 0, sizeof(args));
101 if (prefix) { 101 if (prefix) {
102 args.base = fmt("%s/", prefix); 102 args.base = fmt("%s/", prefix);
103 args.baselen = strlen(prefix) + 1; 103 args.baselen = strlen(prefix) + 1;
104 } else { 104 } else {
105 args.base = ""; 105 args.base = "";
106 args.baselen = 0; 106 args.baselen = 0;
107 } 107 }
108 args.tree = commit->tree; 108 args.tree = commit->tree;
109 args.time = commit->date; 109 args.time = commit->date;
110 ctx.page.mimetype = xstrdup(format->mimetype); 110 ctx.page.mimetype = xstrdup(format->mimetype);
111 ctx.page.filename = xstrdup(filename); 111 ctx.page.filename = xstrdup(filename);
112 cgit_print_http_headers(&ctx); 112 cgit_print_http_headers(&ctx);
113 format->write_func(&args); 113 format->write_func(&args);
114 return 0; 114 return 0;
115} 115}
116 116
117char *dwim_filename = NULL; 117/* Try to guess the requested revision from the requested snapshot name.
118const char *dwim_refname = NULL; 118 * First the format extension is stripped, e.g. "cgit-0.7.2.tar.gz" become
119 119 * "cgit-0.7.2". If this is a valid commit object name we've got a winner.
120static int ref_cb(const char *refname, const unsigned char *sha1, int flags, 120 * Otherwise, if the snapshot name has a prefix matching the result from
121 void *cb_data) 121 * repo_basename(), we strip the basename and any following '-' and '_'
122{ 122 * characters ("cgit-0.7.2" -> "0.7.2") and check the resulting name once
123 const char *r = refname; 123 * more. If this still isn't a valid commit object name, we check if pre-
124 while (r && *r) { 124 * pending a 'v' to the remaining snapshot name ("0.7.2" -> "v0.7.2") gives
125 fprintf(stderr, " cmp %s with %s:", dwim_filename, r); 125 * us something valid.
126 if (!strcmp(dwim_filename, r)) {
127 fprintf(stderr, "MATCH!\n");
128 dwim_refname = refname;
129 return 1;
130 }
131 fprintf(stderr, "no match\n");
132 if (isdigit(*r))
133 break;
134 r++;
135 }
136 return 0;
137}
138
139/* Try to guess the requested revision by combining repo name and tag name
140 * and comparing this to the requested snapshot name. E.g. the requested
141 * snapshot is "cgit-0.7.2.tar.gz" while repo name is "cgit" and tag name
142 * is "v0.7.2". First, the reponame is stripped off, leaving "-0.7.2.tar.gz".
143 * Next, any '-' and '_' characters are stripped, leaving "0.7.2.tar.gz".
144 * Finally, the requested format suffix is removed and we end up with "0.7.2".
145 * Then we test each tag against this dwimmed filename, and for each tag
146 * we even try to remove any leading characters which are non-digits. I.e.
147 * we first compare with "v0.7.2", then with "0.7.2" and we've got a match.
148 */ 126 */
149static const char *get_ref_from_filename(const char *url, const char *filename, 127static const char *get_ref_from_filename(const char *url, const char *filename,
150 const struct cgit_snapshot_format *fmt) 128 const struct cgit_snapshot_format *format)
151{ 129{
152 const char *reponame = cgit_repobasename(url); 130 const char *reponame;
153 fprintf(stderr, "reponame=%s, filename=%s\n", reponame, filename); 131 unsigned char sha1[20];
154 if (prefixcmp(filename, reponame)) 132 char *snapshot;
155 return NULL; 133
156 filename += strlen(reponame); 134 snapshot = xstrdup(filename);
157 while (filename && (*filename == '-' || *filename == '_')) 135 snapshot[strlen(snapshot) - strlen(format->suffix)] = '\0';
158 filename++; 136 fprintf(stderr, "snapshot=%s\n", snapshot);
159 dwim_filename = xstrdup(filename); 137
160 dwim_filename[strlen(filename) - strlen(fmt->suffix)] = '\0'; 138 if (get_sha1(snapshot, sha1) == 0)
161 for_each_tag_ref(ref_cb, NULL); 139 return snapshot;
162 return dwim_refname; 140
141 reponame = cgit_repobasename(url);
142 fprintf(stderr, "reponame=%s\n", reponame);
143 if (prefixcmp(snapshot, reponame) == 0) {
144 snapshot += strlen(reponame);
145 while (snapshot && (*snapshot == '-' || *snapshot == '_'))
146 snapshot++;
147 }
148
149 if (get_sha1(snapshot, sha1) == 0)
150 return snapshot;
151
152 snapshot = fmt("v%s", snapshot);
153 if (get_sha1(snapshot, sha1) == 0)
154 return snapshot;
155
156 return NULL;
163} 157}
164 158
165void cgit_print_snapshot(const char *head, const char *hex, const char *prefix, 159void cgit_print_snapshot(const char *head, const char *hex,
166 const char *filename, int snapshots, int dwim) 160 const char *filename, int snapshots, int dwim)
167{ 161{
168 const struct cgit_snapshot_format* f; 162 const struct cgit_snapshot_format* f;
163 char *prefix = NULL;
169 164
170 f = get_format(filename); 165 f = get_format(filename);
171 if (!f) { 166 if (!f) {
172 ctx.page.mimetype = "text/html"; 167 ctx.page.mimetype = "text/html";
173 cgit_print_http_headers(&ctx); 168 cgit_print_http_headers(&ctx);
174 cgit_print_docstart(&ctx); 169 cgit_print_docstart(&ctx);
175 cgit_print_pageheader(&ctx); 170 cgit_print_pageheader(&ctx);
176 cgit_print_error(fmt("Unsupported snapshot format: %s", filename)); 171 cgit_print_error(fmt("Unsupported snapshot format: %s", filename));
177 cgit_print_docend(); 172 cgit_print_docend();
178 return; 173 return;
179 } 174 }
180 175
181 if (!hex && dwim) 176 if (!hex && dwim) {
182 hex = get_ref_from_filename(ctx.repo->url, filename, f); 177 hex = get_ref_from_filename(ctx.repo->url, filename, f);
178 if (hex != NULL) {
179 prefix = xstrdup(filename);
180 prefix[strlen(filename) - strlen(f->suffix)] = '\0';
181 }
182 }
183 183
184 if (!hex) 184 if (!hex)
185 hex = head; 185 hex = head;
186 186
187 if (!prefix)
188 prefix = xstrdup(cgit_repobasename(ctx.repo->url));
189
187 make_snapshot(f, hex, prefix, filename); 190 make_snapshot(f, hex, prefix, filename);
191 free(prefix);
188} 192}
diff --git a/ui-snapshot.h b/ui-snapshot.h
index 3540303..b6ede52 100644
--- a/ui-snapshot.h
+++ b/ui-snapshot.h
@@ -1,8 +1,7 @@
1#ifndef UI_SNAPSHOT_H 1#ifndef UI_SNAPSHOT_H
2#define UI_SNAPSHOT_H 2#define UI_SNAPSHOT_H
3 3
4extern void cgit_print_snapshot(const char *head, const char *hex, 4extern void cgit_print_snapshot(const char *head, const char *hex,
5 const char *prefix, const char *filename, 5 const char *filename, int snapshot, int dwim);
6 int snapshot, int dwim);
7 6
8#endif /* UI_SNAPSHOT_H */ 7#endif /* UI_SNAPSHOT_H */