-rw-r--r-- | cgit.c | 8 | ||||
-rw-r--r-- | cgit.css | 23 | ||||
-rw-r--r-- | cgit.h | 4 | ||||
-rw-r--r-- | cgitrc | 4 | ||||
-rw-r--r-- | parsing.c | 2 | ||||
-rw-r--r-- | shared.c | 27 | ||||
-rw-r--r-- | ui-log.c | 16 | ||||
-rw-r--r-- | ui-repolist.c | 33 | ||||
-rw-r--r-- | ui-shared.c | 55 | ||||
-rw-r--r-- | ui-summary.c | 2 | ||||
-rw-r--r-- | ui-tree.c | 4 |
11 files changed, 135 insertions, 43 deletions
@@ -17,30 +17,32 @@ static int cgit_prepare_cache(struct cacheitem *item) cgit_print_error(fmt("Unknown repo: %s", cgit_query_repo)); cgit_print_docend(); return 0; } if (!cgit_repo) { item->name = xstrdup(fmt("%s/index.html", cgit_cache_root)); item->ttl = cgit_cache_root_ttl; return 1; } if (!cgit_cmd) { - item->name = xstrdup(fmt("%s/%s/index.html", cgit_cache_root, - cache_safe_filename(cgit_repo->url))); + item->name = xstrdup(fmt("%s/%s/index.%s.html", cgit_cache_root, + cache_safe_filename(cgit_repo->url), + cache_safe_filename(cgit_querystring))); item->ttl = cgit_cache_repo_ttl; } else { item->name = xstrdup(fmt("%s/%s/%s/%s.html", cgit_cache_root, - cache_safe_filename(cgit_repo->url), cgit_query_page, + cache_safe_filename(cgit_repo->url), + cgit_query_page, cache_safe_filename(cgit_querystring))); if (cgit_query_has_symref) item->ttl = cgit_cache_dynamic_ttl; else if (cgit_query_has_sha1) item->ttl = cgit_cache_static_ttl; else item->ttl = cgit_cache_repo_ttl; } return 1; } static void cgit_print_repo_page(struct cacheitem *item) @@ -86,50 +86,60 @@ td#header, td#logo { color: #666; background-color: #ddd; border-bottom: solid 1px #000; } td#header { font-size: 150%; font-weight: bold; padding: 0.2em 0.5em; vertical-align: text-bottom; } +td#header a { + color: #666; +} + +td#header a:hoved { + text-decoration: underline; +} + td#logo { text-align: right; vertical-align: middle; padding-right: 0.5em; } td#crumb, td#search { color: #ccc; border-top: solid 3px #555; background-color: #666; border-bottom: solid 1px #333; padding: 2px 1em; } td#crumb { font-weight: bold; } td#crumb a { color: #ccc; background-color: #666; + padding: 0em 0.5em 0em 0.5em; } td#crumb a:hover { - color: #eee; - background-color: #666; + color: #666; + background-color: #ccc; + text-decoration: none; } td#search { text-align: right; vertical-align: middle; padding-right: 0.5em; } td#search form { margin: 0px; padding: 0px; } @@ -352,34 +362,35 @@ table.diff td div.del { .right { text-align: right; } table.list td.repogroup { font-style: italic; color: #888; } a.button { font-size: 80%; - color: #333; - background-color: #ccc; - border: solid 1px #999; + color: #aaa; + background-color: #eee; + border: solid 1px #aaa; padding: 0em 0.5em; margin: 0.1em 0.25em; } a.button:hover { text-decoration: none; - background-color: #eee; + color: #333; + background-color: #ccc; } a.primary { font-size: 100%; } a.secondary { font-size: 90%; } td.toplevel-repo { @@ -109,24 +109,25 @@ extern char *cgit_css; extern char *cgit_logo; extern char *cgit_index_header; extern char *cgit_logo_link; extern char *cgit_module_link; extern char *cgit_agefile; extern char *cgit_virtual_root; extern char *cgit_script_name; extern char *cgit_cache_root; extern char *cgit_repo_group; extern int cgit_nocache; extern int cgit_snapshots; +extern int cgit_enable_index_links; extern int cgit_enable_log_filecount; extern int cgit_enable_log_linecount; extern int cgit_max_lock_attempts; extern int cgit_cache_root_ttl; extern int cgit_cache_repo_ttl; extern int cgit_cache_dynamic_ttl; extern int cgit_cache_static_ttl; extern int cgit_cache_max_create_time; extern int cgit_summary_log; extern int cgit_max_msg_len; extern int cgit_max_repodesc_len; @@ -149,24 +150,25 @@ extern int cgit_query_ofs; extern int htmlfd; extern int cgit_get_cmd_index(const char *cmd); extern struct repoinfo *cgit_get_repoinfo(const char *url); extern void cgit_global_config_cb(const char *name, const char *value); extern void cgit_repo_config_cb(const char *name, const char *value); extern void cgit_querystring_cb(const char *name, const char *value); extern int chk_zero(int result, char *msg); extern int chk_positive(int result, char *msg); extern int hextoint(char c); +extern char *trim_end(const char *str, char c); extern void *cgit_free_commitinfo(struct commitinfo *info); extern int cgit_diff_files(const unsigned char *old_sha1, const unsigned char *new_sha1, linediff_fn fn); extern void cgit_diff_tree(const unsigned char *old_sha1, const unsigned char *new_sha1, filepair_fn fn); extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); @@ -195,25 +197,25 @@ extern int cache_lock(struct cacheitem *item); extern int cache_unlock(struct cacheitem *item); extern int cache_cancel_lock(struct cacheitem *item); extern int cache_exist(struct cacheitem *item); extern int cache_expired(struct cacheitem *item); extern char *cgit_repourl(const char *reponame); extern char *cgit_pageurl(const char *reponame, const char *pagename, const char *query); extern void cgit_tree_link(char *name, char *title, char *class, char *head, char *rev, char *path); extern void cgit_log_link(char *name, char *title, char *class, char *head, - char *rev, char *path); + char *rev, char *path, int ofs); extern void cgit_commit_link(char *name, char *title, char *class, char *head, char *rev); extern void cgit_diff_link(char *name, char *title, char *class, char *head, char *new_rev, char *old_rev, char *path); extern void cgit_print_error(char *msg); extern void cgit_print_date(time_t secs, char *format); extern void cgit_print_age(time_t t, time_t max_relative, char *format); extern void cgit_print_docstart(char *title, struct cacheitem *item); extern void cgit_print_docend(); extern void cgit_print_pageheader(char *title, int show_search); extern void cgit_print_snapshot_start(const char *mimetype, @@ -3,24 +3,28 @@ ## ## Uncomment and set to 1 to deactivate caching of generated pages. Mostly ## usefull for testing. #nocache=0 ## Enable/disable snapshots by default. This can be overridden per repo #snapshots=0 +## Enable/disable extra links to summary/log/tree per repo on index page +#enable-index-links=0 + + ## Enable/disable display of 'number of files changed' in log view #enable-log-filecount=0 ## Enable/disable display of 'number of lines changed' in log view #enable-log-linecount=0 ## Enable/disable display of HEAD shortlog in summary view. Set it to maximum ## number of commits that should be displayed #summary-log=0 @@ -159,25 +159,25 @@ void cgit_parse_url(const char *url) cgit_repo = cgit_get_repoinfo(url); if (cgit_repo == NULL) { cmd[0] = '/'; cmd = strchr(cmd + 1, '/'); continue; } cgit_query_repo = cgit_repo->url; p = strchr(cmd + 1, '/'); if (p) { p[0] = '\0'; if (p[1]) - cgit_query_path = xstrdup(p + 1); + cgit_query_path = trim_end(p + 1, '/'); } cgit_cmd = cgit_get_cmd_index(cmd + 1); cgit_query_page = xstrdup(cmd + 1); return; } } char *substr(const char *head, const char *tail) { char *buf; buf = xmalloc(tail - head + 1); @@ -19,24 +19,25 @@ char *cgit_css = "/cgit.css"; char *cgit_logo = "/git-logo.png"; char *cgit_index_header = NULL; char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/"; char *cgit_module_link = "./?repo=%s&page=commit&id=%s"; char *cgit_agefile = "info/web/last-modified"; char *cgit_virtual_root = NULL; char *cgit_script_name = CGIT_SCRIPT_NAME; char *cgit_cache_root = "/var/cache/cgit"; char *cgit_repo_group = NULL; int cgit_nocache = 0; int cgit_snapshots = 0; +int cgit_enable_index_links = 0; int cgit_enable_log_filecount = 0; int cgit_enable_log_linecount = 0; int cgit_max_lock_attempts = 5; int cgit_cache_root_ttl = 5; int cgit_cache_repo_ttl = 5; int cgit_cache_dynamic_ttl = 5; int cgit_cache_static_ttl = -1; int cgit_cache_max_create_time = 5; int cgit_summary_log = 0; int cgit_max_msg_len = 60; int cgit_max_repodesc_len = 60; @@ -139,24 +140,26 @@ void cgit_global_config_cb(const char *name, const char *value) else if (!strcmp(name, "index-header")) cgit_index_header = xstrdup(value); else if (!strcmp(name, "logo-link")) cgit_logo_link = xstrdup(value); else if (!strcmp(name, "module-link")) cgit_module_link = xstrdup(value); else if (!strcmp(name, "virtual-root")) cgit_virtual_root = xstrdup(value); else if (!strcmp(name, "nocache")) cgit_nocache = atoi(value); else if (!strcmp(name, "snapshots")) cgit_snapshots = atoi(value); + else if (!strcmp(name, "enable-index-links")) + cgit_enable_index_links = atoi(value); else if (!strcmp(name, "enable-log-filecount")) cgit_enable_log_filecount = atoi(value); else if (!strcmp(name, "enable-log-linecount")) cgit_enable_log_linecount = atoi(value); else if (!strcmp(name, "cache-root")) cgit_cache_root = xstrdup(value); else if (!strcmp(name, "cache-root-ttl")) cgit_cache_root_ttl = atoi(value); else if (!strcmp(name, "cache-repo-ttl")) cgit_cache_repo_ttl = atoi(value); else if (!strcmp(name, "cache-static-ttl")) cgit_cache_static_ttl = atoi(value); @@ -218,25 +221,25 @@ void cgit_querystring_cb(const char *name, const char *value) } else if (!strcmp(name, "h")) { cgit_query_head = xstrdup(value); cgit_query_has_symref = 1; } else if (!strcmp(name, "id")) { cgit_query_sha1 = xstrdup(value); cgit_query_has_sha1 = 1; } else if (!strcmp(name, "id2")) { cgit_query_sha2 = xstrdup(value); cgit_query_has_sha1 = 1; } else if (!strcmp(name, "ofs")) { cgit_query_ofs = atoi(value); } else if (!strcmp(name, "path")) { - cgit_query_path = xstrdup(value); + cgit_query_path = trim_end(value, '/'); } else if (!strcmp(name, "name")) { cgit_query_name = xstrdup(value); } } void *cgit_free_commitinfo(struct commitinfo *info) { free(info->author); free(info->author_email); free(info->committer); free(info->committer_email); free(info->subject); @@ -247,24 +250,46 @@ void *cgit_free_commitinfo(struct commitinfo *info) int hextoint(char c) { if (c >= 'a' && c <= 'f') return 10 + c - 'a'; else if (c >= 'A' && c <= 'F') return 10 + c - 'A'; else if (c >= '0' && c <= '9') return c - '0'; else return -1; } +char *trim_end(const char *str, char c) +{ + int len; + char *s, *t; + + if (str == NULL) + return NULL; + t = (char *)str; + len = strlen(t); + while(len > 0 && t[len - 1] == c) + len--; + + if (len == 0) + return NULL; + + c = t[len]; + t[len] = '\0'; + s = xstrdup(t); + t[len] = c; + return s; +} + void cgit_diff_tree_cb(struct diff_queue_struct *q, struct diff_options *options, void *data) { int i; for (i = 0; i < q->nr; i++) { if (q->queue[i]->status == 'U') continue; ((filepair_fn)data)(q->queue[i]); } } @@ -104,27 +104,25 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path, i for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) { print_commit(commit); free(commit->buffer); commit->buffer = NULL; free_commit_list(commit->parents); commit->parents = NULL; } html("</table>\n"); if (pager) { html("<div class='pager'>"); if (ofs > 0) { - html(" <a href='"); - html(cgit_pageurl(cgit_query_repo, cgit_query_page, - fmt("h=%s&ofs=%d", tip, ofs-cnt))); - html("'>[prev]</a> "); + cgit_log_link("[prev]", NULL, NULL, cgit_query_head, + cgit_query_sha1, cgit_query_path, + ofs - cnt); + html(" "); } - if ((commit = get_revision(&rev)) != NULL) { - html(" <a href='"); - html(cgit_pageurl(cgit_query_repo, "log", - fmt("h=%s&ofs=%d", tip, ofs+cnt))); - html("'>[next]</a> "); + cgit_log_link("[next]", NULL, NULL, cgit_query_head, + cgit_query_sha1, cgit_query_path, + ofs + cnt); } html("</div>"); } } diff --git a/ui-repolist.c b/ui-repolist.c index 2018dab..4c86543 100644 --- a/ui-repolist.c +++ b/ui-repolist.c @@ -35,64 +35,75 @@ static void print_modtime(struct repoinfo *repo) cgit_print_age(read_agefile(path), -1, NULL); return; } path = fmt("%s/refs/heads/%s", repo->path, repo->defbranch); if (stat(path, &s) != 0) return; cgit_print_age(s.st_mtime, -1, NULL); } void cgit_print_repolist(struct cacheitem *item) { - int i; + int i, columns = 4; char *last_group = NULL; + if (cgit_enable_index_links) + columns++; + cgit_print_docstart(cgit_root_title, item); cgit_print_pageheader(cgit_root_title, 0); html("<table class='list nowrap'>"); if (cgit_index_header) { - html("<tr class='nohover'><td colspan='5' class='include-block'>"); + htmlf("<tr class='nohover'><td colspan='%d' class='include-block'>", + columns); html_include(cgit_index_header); html("</td></tr>"); } html("<tr class='nohover'>" "<th class='left'>Name</th>" "<th class='left'>Description</th>" "<th class='left'>Owner</th>" - "<th class='left'>Idle</th>" - "<th>Links</th></tr>\n"); + "<th class='left'>Idle</th>"); + if (cgit_enable_index_links) + html("<th>Links</th>"); + html("</tr>\n"); for (i=0; i<cgit_repolist.count; i++) { cgit_repo = &cgit_repolist.repos[i]; if ((last_group == NULL && cgit_repo->group != NULL) || (last_group != NULL && cgit_repo->group == NULL) || (last_group != NULL && cgit_repo->group != NULL && strcmp(cgit_repo->group, last_group))) { - html("<tr class='nohover'><td colspan='4' class='repogroup'>"); + htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>", + columns); html_txt(cgit_repo->group); html("</td></tr>"); last_group = cgit_repo->group; } htmlf("<tr><td class='%s'>", cgit_repo->group ? "sublevel-repo" : "toplevel-repo"); html_link_open(cgit_repourl(cgit_repo->url), NULL, NULL); html_txt(cgit_repo->name); html_link_close(); html("</td><td>"); html_ntxt(cgit_max_repodesc_len, cgit_repo->desc); html("</td><td>"); html_txt(cgit_repo->owner); html("</td><td>"); print_modtime(cgit_repo); - html("</td><td>"); + html("</td>"); + if (cgit_enable_index_links) { + html("<td>"); html_link_open(cgit_repourl(cgit_repo->url), - "Summary", "button"); - html("S</a>"); - cgit_log_link("L", "Log", "button", NULL, NULL, NULL); - cgit_tree_link("F", "Files", "button", NULL, NULL, NULL); - html("</td></tr>\n"); + NULL, "button"); + html("summary</a>"); + cgit_log_link("log", NULL, "button", NULL, NULL, NULL, 0); + cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); + html("</td>"); + } + html("</tr>\n"); } html("</table>"); cgit_print_docend(); } diff --git a/ui-shared.c b/ui-shared.c index 110c696..d4376ce 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -102,38 +102,42 @@ static char *repolink(char *title, char *class, char *page, char *head, html(" class='"); html_attr(class); html("'"); } html(" href='"); if (cgit_virtual_root) { html_attr(cgit_virtual_root); if (cgit_virtual_root[strlen(cgit_virtual_root) - 1] != '/') html("/"); html_attr(cgit_repo->url); if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/') html("/"); + if (page) { html(page); html("/"); if (path) html_attr(path); + } } else { html(cgit_script_name); html("?url="); html_attr(cgit_repo->url); if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/') html("/"); + if (page) { html(page); html("/"); if (path) html_attr(path); + } delim = "&"; } if (head && strcmp(head, cgit_repo->defbranch)) { html(delim); html("h="); html_attr(head); delim = "&"; } return fmt("%s", delim); } static void reporevlink(char *page, char *name, char *title, char *class, @@ -150,27 +154,43 @@ static void reporevlink(char *page, char *name, char *title, char *class, html("'>"); html_txt(name); html("</a>"); } void cgit_tree_link(char *name, char *title, char *class, char *head, char *rev, char *path) { reporevlink("tree", name, title, class, head, rev, path); } void cgit_log_link(char *name, char *title, char *class, char *head, - char *rev, char *path) + char *rev, char *path, int ofs) { - reporevlink("log", name, title, class, head, rev, path); + char *delim; + + delim = repolink(title, class, "log", head, path); + if (rev && strcmp(rev, cgit_query_head)) { + html(delim); + html("id="); + html_attr(rev); + delim = "&"; + } + if (ofs > 0) { + html(delim); + html("ofs="); + htmlf("%d", ofs); + } + html("'>"); + html_txt(name); + html("</a>"); } void cgit_commit_link(char *name, char *title, char *class, char *head, char *rev) { if (strlen(name) > cgit_max_msg_len && cgit_max_msg_len >= 15) { name[cgit_max_msg_len] = '\0'; name[cgit_max_msg_len - 1] = '.'; name[cgit_max_msg_len - 2] = '.'; name[cgit_max_msg_len - 3] = '.'; } reporevlink("commit", name, title, class, head, rev, NULL); @@ -270,37 +290,56 @@ void cgit_print_docstart(char *title, struct cacheitem *item) html("<body>\n"); } void cgit_print_docend() { html("</td></tr></table>"); html("</body>\n</html>\n"); } void cgit_print_pageheader(char *title, int show_search) { html("<table id='layout'>"); - html("<tr><td id='header'>"); - html(cgit_root_title); - html("</td><td id='logo'>"); + html("<tr><td id='header'><a href='"); + html_attr(cgit_rooturl()); + html("'>"); + html_txt(cgit_root_title); + html("</a></td><td id='logo'>"); html("<a href='"); html_attr(cgit_logo_link); htmlf("'><img src='%s' alt='logo'/></a>", cgit_logo); html("</td></tr>"); html("<tr><td id='crumb'>"); - htmlf("<a href='%s'>root</a>", cgit_rooturl()); if (cgit_query_repo) { - htmlf(" : <a href='%s'>", cgit_repourl(cgit_repo->url)); html_txt(cgit_repo->name); - htmlf("</a> : %s", title); + html(" ("); + html_txt(cgit_query_head); + html(") : "); + reporevlink(NULL, "summary", NULL, NULL, cgit_query_head, + NULL, NULL); + html(" "); + cgit_log_link("log", NULL, NULL, cgit_query_head, + cgit_query_sha1, cgit_query_path, 0); + html(" "); + cgit_tree_link("tree", NULL, NULL, cgit_query_head, + cgit_query_sha1, NULL); + html(" "); + cgit_commit_link("commit", NULL, NULL, cgit_query_head, + cgit_query_sha1); + html(" "); + cgit_diff_link("diff", NULL, NULL, cgit_query_head, + cgit_query_sha1, cgit_query_sha2, + cgit_query_path); + } else { + html_txt("Index of repositories"); } html("</td>"); html("<td id='search'>"); if (show_search) { html("<form method='get' action='"); html_attr(cgit_currurl()); html("'>"); if (!cgit_virtual_root) { if (cgit_query_repo) html_hidden("r", cgit_query_repo); if (cgit_query_page) html_hidden("p", cgit_query_page); diff --git a/ui-summary.c b/ui-summary.c index 03dd078..b4bc6d8 100644 --- a/ui-summary.c +++ b/ui-summary.c @@ -18,25 +18,25 @@ static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1, char buf[256]; char *ref; ref = xstrdup(refname); strncpy(buf, refname, sizeof(buf)); commit = lookup_commit(sha1); // object is not really parsed at this point, because of some fallout // from previous calls to git functions in cgit_print_log() commit->object.parsed = 0; if (commit && !parse_commit(commit)){ info = cgit_parse_commit(commit); html("<tr><td>"); - cgit_log_link(ref, NULL, NULL, ref, NULL, NULL); + cgit_log_link(ref, NULL, NULL, ref, NULL, NULL, 0); html("</td><td>"); cgit_print_age(commit->date, -1, NULL); html("</td><td>"); html_txt(info->author); html("</td><td>"); cgit_commit_link(info->subject, NULL, NULL, ref, NULL); html("</td></tr>\n"); cgit_free_commitinfo(info); } else { html("<tr><td>"); html_txt(buf); html("</td><td colspan='3'>"); @@ -83,26 +83,26 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen, html_txt(name); html("</a>"); } else if (S_ISDIR(mode)) { cgit_tree_link(name, NULL, "ls-dir", cgit_query_head, curr_rev, fullpath); } else { cgit_tree_link(name, NULL, "ls-blob", cgit_query_head, curr_rev, fullpath); } htmlf("</td><td class='ls-size'>%li</td>", size); html("<td>"); - cgit_log_link("L", "Log", "button", cgit_query_head, curr_rev, - fullpath); + cgit_log_link("log", NULL, "button", cgit_query_head, curr_rev, + fullpath, 0); html("</td></tr>\n"); free(name); return 0; } static void ls_head() { html("<table class='list'>\n"); html("<tr class='nohover'>"); html("<th class='left'>Mode</th>"); html("<th class='left'>Name</th>"); html("<th class='right'>Size</th>"); |