diff options
-rw-r--r-- | cgit.c | 4 | ||||
-rw-r--r-- | cgit.css | 15 | ||||
-rw-r--r-- | cgit.h | 3 | ||||
-rw-r--r-- | cmd.c | 3 | ||||
-rw-r--r-- | shared.c | 1 | ||||
-rw-r--r-- | ui-log.c | 35 | ||||
-rw-r--r-- | ui-refs.c | 40 | ||||
-rw-r--r-- | ui-repolist.c | 137 | ||||
-rw-r--r-- | ui-shared.c | 29 | ||||
-rw-r--r-- | ui-shared.h | 2 | ||||
-rw-r--r-- | ui-snapshot.c | 94 | ||||
-rw-r--r-- | ui-snapshot.h | 3 | ||||
-rw-r--r-- | ui-tree.c | 2 |
13 files changed, 281 insertions, 87 deletions
@@ -154,6 +154,10 @@ static void querystring_cb(const char *name, const char *value) | |||
154 | ctx.qry.name = xstrdup(value); | 154 | ctx.qry.name = xstrdup(value); |
155 | } else if (!strcmp(name, "mimetype")) { | 155 | } else if (!strcmp(name, "mimetype")) { |
156 | ctx.qry.mimetype = xstrdup(value); | 156 | ctx.qry.mimetype = xstrdup(value); |
157 | } else if (!strcmp(name, "s")){ | ||
158 | ctx.qry.sort = xstrdup(value); | ||
159 | } else if (!strcmp(name, "showmsg")) { | ||
160 | ctx.qry.showmsg = atoi(value); | ||
157 | } | 161 | } |
158 | } | 162 | } |
159 | 163 | ||
@@ -120,6 +120,10 @@ table.list tr { | |||
120 | background: white; | 120 | background: white; |
121 | } | 121 | } |
122 | 122 | ||
123 | table.list tr.logheader { | ||
124 | background: #eee; | ||
125 | } | ||
126 | |||
123 | table.list tr:hover { | 127 | table.list tr:hover { |
124 | background: #eee; | 128 | background: #eee; |
125 | } | 129 | } |
@@ -143,6 +147,17 @@ table.list td { | |||
143 | padding: 0.1em 0.5em 0.1em 0.5em; | 147 | padding: 0.1em 0.5em 0.1em 0.5em; |
144 | } | 148 | } |
145 | 149 | ||
150 | table.list td.logsubject { | ||
151 | font-family: monospace; | ||
152 | font-weight: bold; | ||
153 | } | ||
154 | |||
155 | table.list td.logmsg { | ||
156 | font-family: monospace; | ||
157 | white-space: pre; | ||
158 | padding: 1em 0em 2em 0em; | ||
159 | } | ||
160 | |||
146 | table.list td a { | 161 | table.list td a { |
147 | color: black; | 162 | color: black; |
148 | } | 163 | } |
@@ -61,6 +61,7 @@ struct cgit_repo { | |||
61 | int snapshots; | 61 | int snapshots; |
62 | int enable_log_filecount; | 62 | int enable_log_filecount; |
63 | int enable_log_linecount; | 63 | int enable_log_linecount; |
64 | time_t mtime; | ||
64 | }; | 65 | }; |
65 | 66 | ||
66 | struct cgit_repolist { | 67 | struct cgit_repolist { |
@@ -121,6 +122,8 @@ struct cgit_query { | |||
121 | char *url; | 122 | char *url; |
122 | int ofs; | 123 | int ofs; |
123 | int nohead; | 124 | int nohead; |
125 | char *sort; | ||
126 | int showmsg; | ||
124 | }; | 127 | }; |
125 | 128 | ||
126 | struct cgit_config { | 129 | struct cgit_config { |
@@ -104,8 +104,7 @@ static void refs_fn(struct cgit_context *ctx) | |||
104 | 104 | ||
105 | static void snapshot_fn(struct cgit_context *ctx) | 105 | static 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 | ||
@@ -60,6 +60,7 @@ struct cgit_repo *cgit_add_repo(const char *url) | |||
60 | ret->enable_log_linecount = ctx.cfg.enable_log_linecount; | 60 | ret->enable_log_linecount = ctx.cfg.enable_log_linecount; |
61 | ret->module_link = ctx.cfg.module_link; | 61 | ret->module_link = ctx.cfg.module_link; |
62 | ret->readme = NULL; | 62 | ret->readme = NULL; |
63 | ret->mtime = -1; | ||
63 | return ret; | 64 | return ret; |
64 | } | 65 | } |
65 | 66 | ||
@@ -35,15 +35,18 @@ void print_commit(struct commit *commit) | |||
35 | { | 35 | { |
36 | struct commitinfo *info; | 36 | struct commitinfo *info; |
37 | char *tmp; | 37 | char *tmp; |
38 | int cols = 2; | ||
38 | 39 | ||
39 | info = cgit_parse_commit(commit); | 40 | info = cgit_parse_commit(commit); |
40 | html("<tr><td>"); | 41 | htmlf("<tr%s><td>", |
42 | ctx.qry.showmsg ? " class='logheader'" : ""); | ||
41 | tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1)); | 43 | tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1)); |
42 | tmp = cgit_pageurl(ctx.repo->url, "commit", tmp); | 44 | tmp = cgit_pageurl(ctx.repo->url, "commit", tmp); |
43 | html_link_open(tmp, NULL, NULL); | 45 | html_link_open(tmp, NULL, NULL); |
44 | cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE); | 46 | cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE); |
45 | html_link_close(); | 47 | html_link_close(); |
46 | html("</td><td>"); | 48 | htmlf("</td><td%s>", |
49 | ctx.qry.showmsg ? " class='logsubject'" : ""); | ||
47 | cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, | 50 | cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, |
48 | sha1_to_hex(commit->object.sha1)); | 51 | sha1_to_hex(commit->object.sha1)); |
49 | html("</td><td>"); | 52 | html("</td><td>"); |
@@ -61,6 +64,17 @@ void print_commit(struct commit *commit) | |||
61 | } | 64 | } |
62 | } | 65 | } |
63 | html("</td></tr>\n"); | 66 | html("</td></tr>\n"); |
67 | if (ctx.qry.showmsg) { | ||
68 | if (ctx.repo->enable_log_filecount) { | ||
69 | cols++; | ||
70 | if (ctx.repo->enable_log_linecount) | ||
71 | cols++; | ||
72 | } | ||
73 | htmlf("<tr class='nohover'><td/><td colspan='%d' class='logmsg'>", | ||
74 | cols); | ||
75 | html_txt(info->msg); | ||
76 | html("</td></tr>\n"); | ||
77 | } | ||
64 | cgit_free_commitinfo(info); | 78 | cgit_free_commitinfo(info); |
65 | } | 79 | } |
66 | 80 | ||
@@ -113,8 +127,15 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern | |||
113 | html("<table class='list nowrap'>"); | 127 | html("<table class='list nowrap'>"); |
114 | 128 | ||
115 | html("<tr class='nohover'><th class='left'>Age</th>" | 129 | html("<tr class='nohover'><th class='left'>Age</th>" |
116 | "<th class='left'>Commit message</th>" | 130 | "<th class='left'>Commit message"); |
117 | "<th class='left'>Author</th>"); | 131 | if (pager) { |
132 | html(" ("); | ||
133 | cgit_log_link("toggle", NULL, NULL, ctx.qry.head, ctx.qry.sha1, | ||
134 | ctx.qry.path, ctx.qry.ofs, ctx.qry.grep, | ||
135 | ctx.qry.search, ctx.qry.showmsg ? 0 : 1); | ||
136 | html(")"); | ||
137 | } | ||
138 | html("</th><th class='left'>Author</th>"); | ||
118 | if (ctx.repo->enable_log_filecount) { | 139 | if (ctx.repo->enable_log_filecount) { |
119 | html("<th class='left'>Files</th>"); | 140 | html("<th class='left'>Files</th>"); |
120 | columns++; | 141 | columns++; |
@@ -149,20 +170,20 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern | |||
149 | cgit_log_link("[prev]", NULL, NULL, ctx.qry.head, | 170 | cgit_log_link("[prev]", NULL, NULL, ctx.qry.head, |
150 | ctx.qry.sha1, ctx.qry.path, | 171 | ctx.qry.sha1, ctx.qry.path, |
151 | ofs - cnt, ctx.qry.grep, | 172 | ofs - cnt, ctx.qry.grep, |
152 | ctx.qry.search); | 173 | ctx.qry.search, ctx.qry.showmsg); |
153 | html(" "); | 174 | html(" "); |
154 | } | 175 | } |
155 | if ((commit = get_revision(&rev)) != NULL) { | 176 | if ((commit = get_revision(&rev)) != NULL) { |
156 | cgit_log_link("[next]", NULL, NULL, ctx.qry.head, | 177 | cgit_log_link("[next]", NULL, NULL, ctx.qry.head, |
157 | ctx.qry.sha1, ctx.qry.path, | 178 | ctx.qry.sha1, ctx.qry.path, |
158 | ofs + cnt, ctx.qry.grep, | 179 | ofs + cnt, ctx.qry.grep, |
159 | ctx.qry.search); | 180 | ctx.qry.search, ctx.qry.showmsg); |
160 | } | 181 | } |
161 | html("</div>"); | 182 | html("</div>"); |
162 | } else if ((commit = get_revision(&rev)) != NULL) { | 183 | } else if ((commit = get_revision(&rev)) != NULL) { |
163 | html("<tr class='nohover'><td colspan='3'>"); | 184 | html("<tr class='nohover'><td colspan='3'>"); |
164 | cgit_log_link("[...]", NULL, NULL, ctx.qry.head, NULL, NULL, 0, | 185 | cgit_log_link("[...]", NULL, NULL, ctx.qry.head, NULL, NULL, 0, |
165 | NULL, NULL); | 186 | NULL, NULL, ctx.qry.showmsg); |
166 | html("</td></tr>\n"); | 187 | html("</td></tr>\n"); |
167 | } | 188 | } |
168 | } | 189 | } |
@@ -58,7 +58,8 @@ static int print_branch(struct refinfo *ref) | |||
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 | ctx.qry.showmsg); | ||
62 | html("</td><td>"); | 63 | html("</td><td>"); |
63 | 64 | ||
64 | if (ref->object->type == OBJ_COMMIT) { | 65 | if (ref->object->type == OBJ_COMMIT) { |
@@ -78,12 +79,37 @@ static int print_branch(struct refinfo *ref) | |||
78 | static void print_tag_header() | 79 | static void print_tag_header() |
79 | { | 80 | { |
80 | html("<tr class='nohover'><th class='left'>Tag</th>" | 81 | html("<tr class='nohover'><th class='left'>Tag</th>" |
81 | "<th class='left'>Reference</th>" | 82 | "<th class='left'>Download</th>" |
82 | "<th class='left'>Author</th>" | 83 | "<th class='left'>Author</th>" |
83 | "<th class='left' colspan='2'>Age</th></tr>\n"); | 84 | "<th class='left' colspan='2'>Age</th></tr>\n"); |
84 | header = 1; | 85 | header = 1; |
85 | } | 86 | } |
86 | 87 | ||
88 | static void print_tag_downloads(const struct cgit_repo *repo, const char *ref) | ||
89 | { | ||
90 | const struct cgit_snapshot_format* f; | ||
91 | char *filename; | ||
92 | const char *basename; | ||
93 | |||
94 | if (!ref || strlen(ref) < 2) | ||
95 | return; | ||
96 | |||
97 | basename = cgit_repobasename(repo->url); | ||
98 | if (prefixcmp(ref, basename) != 0) { | ||
99 | if ((ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1])) | ||
100 | ref++; | ||
101 | if (isdigit(ref[0])) | ||
102 | ref = xstrdup(fmt("%s-%s", basename, ref)); | ||
103 | } | ||
104 | |||
105 | for (f = cgit_snapshot_formats; f->suffix; f++) { | ||
106 | if (!(repo->snapshots & f->bit)) | ||
107 | continue; | ||
108 | filename = fmt("%s%s", ref, f->suffix); | ||
109 | cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename); | ||
110 | html(" "); | ||
111 | } | ||
112 | } | ||
87 | static int print_tag(struct refinfo *ref) | 113 | static int print_tag(struct refinfo *ref) |
88 | { | 114 | { |
89 | struct tag *tag; | 115 | struct tag *tag; |
@@ -98,7 +124,10 @@ static int print_tag(struct refinfo *ref) | |||
98 | html("<tr><td>"); | 124 | html("<tr><td>"); |
99 | cgit_tag_link(name, NULL, NULL, ctx.qry.head, name); | 125 | cgit_tag_link(name, NULL, NULL, ctx.qry.head, name); |
100 | html("</td><td>"); | 126 | html("</td><td>"); |
101 | cgit_object_link(tag->tagged); | 127 | if (ctx.repo->snapshots && (tag->tagged->type == OBJ_COMMIT)) |
128 | print_tag_downloads(ctx.repo, name); | ||
129 | else | ||
130 | cgit_object_link(tag->tagged); | ||
102 | html("</td><td>"); | 131 | html("</td><td>"); |
103 | if (info->tagger) | 132 | if (info->tagger) |
104 | html(info->tagger); | 133 | html(info->tagger); |
@@ -112,7 +141,10 @@ static int print_tag(struct refinfo *ref) | |||
112 | html("<tr><td>"); | 141 | html("<tr><td>"); |
113 | html_txt(name); | 142 | html_txt(name); |
114 | html("</td><td>"); | 143 | html("</td><td>"); |
115 | cgit_object_link(ref->object); | 144 | if (ctx.repo->snapshots && (tag->tagged->type == OBJ_COMMIT)) |
145 | print_tag_downloads(ctx.repo, name); | ||
146 | else | ||
147 | cgit_object_link(ref->object); | ||
116 | html("</td></tr>\n"); | 148 | html("</td></tr>\n"); |
117 | } | 149 | } |
118 | return 0; | 150 | return 0; |
diff --git a/ui-repolist.c b/ui-repolist.c index 2324273..2c13d50 100644 --- a/ui-repolist.c +++ b/ui-repolist.c | |||
@@ -32,21 +32,38 @@ time_t read_agefile(char *path) | |||
32 | return 0; | 32 | return 0; |
33 | } | 33 | } |
34 | 34 | ||
35 | static void print_modtime(struct cgit_repo *repo) | 35 | static int get_repo_modtime(const struct cgit_repo *repo, time_t *mtime) |
36 | { | 36 | { |
37 | char *path; | 37 | char *path; |
38 | struct stat s; | 38 | struct stat s; |
39 | struct cgit_repo *r = (struct cgit_repo *)repo; | ||
39 | 40 | ||
41 | if (repo->mtime != -1) { | ||
42 | *mtime = repo->mtime; | ||
43 | return 1; | ||
44 | } | ||
40 | path = fmt("%s/%s", repo->path, ctx.cfg.agefile); | 45 | path = fmt("%s/%s", repo->path, ctx.cfg.agefile); |
41 | if (stat(path, &s) == 0) { | 46 | if (stat(path, &s) == 0) { |
42 | cgit_print_age(read_agefile(path), -1, NULL); | 47 | *mtime = read_agefile(path); |
43 | return; | 48 | r->mtime = *mtime; |
49 | return 1; | ||
44 | } | 50 | } |
45 | 51 | ||
46 | path = fmt("%s/refs/heads/%s", repo->path, repo->defbranch); | 52 | path = fmt("%s/refs/heads/%s", repo->path, repo->defbranch); |
47 | if (stat(path, &s) != 0) | 53 | if (stat(path, &s) == 0) |
48 | return; | 54 | *mtime = s.st_mtime; |
49 | cgit_print_age(s.st_mtime, -1, NULL); | 55 | else |
56 | *mtime = 0; | ||
57 | |||