author | Lars Hjemli <hjemli@gmail.com> | 2007-06-16 23:23:08 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2007-06-16 23:39:05 (UTC) |
commit | 44947bfcdc0d6e8c7d673bea0538cbf2a182f289 (patch) (side-by-side diff) | |
tree | 3f65d6842738a8314ed72d5575a0b523061556b7 | |
parent | f91b9696a36008c245a3195800ba0c5fa3e890f9 (diff) | |
download | cgit-44947bfcdc0d6e8c7d673bea0538cbf2a182f289.zip cgit-44947bfcdc0d6e8c7d673bea0538cbf2a182f289.tar.gz cgit-44947bfcdc0d6e8c7d673bea0538cbf2a182f289.tar.bz2 |
Add and use cgit_tree_link()
This creates a new function used to generate links to 'tree' page and uses
the function everywhere a link to the 'tree' page is generated.
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | cgit.h | 3 | ||||
-rw-r--r-- | ui-commit.c | 10 | ||||
-rw-r--r-- | ui-repolist.c | 35 | ||||
-rw-r--r-- | ui-shared.c | 64 | ||||
-rw-r--r-- | ui-tree.c | 33 |
5 files changed, 107 insertions, 38 deletions
@@ -156,71 +156,74 @@ 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 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); extern char *fmt(const char *format,...); extern void html(const char *txt); extern void htmlf(const char *format,...); extern void html_txt(char *txt); extern void html_ntxt(int len, char *txt); extern void html_attr(char *txt); extern void html_hidden(char *name, char *value); extern void html_link_open(char *url, char *title, char *class); extern void html_link_close(void); extern void html_filemode(unsigned short mode); extern int html_include(const char *filename); extern int cgit_read_config(const char *filename, configfn fn); extern int cgit_parse_query(char *txt, configfn fn); extern struct commitinfo *cgit_parse_commit(struct commit *commit); extern struct taginfo *cgit_parse_tag(struct tag *tag); extern void cgit_parse_url(const char *url); extern char *cache_safe_filename(const char *unsafe); 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_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, const char *filename, struct cacheitem *item); extern void cgit_print_repolist(struct cacheitem *item); extern void cgit_print_summary(); extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path, int pager); extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path); extern void cgit_print_tree(const char *rev, char *path); extern void cgit_print_commit(const char *hex); extern void cgit_print_diff(const char *head, const char *old_hex, const char *new_hex, char *path); extern void cgit_print_snapshot(struct cacheitem *item, const char *hex, const char *format, const char *prefix, const char *filename); #endif /* CGIT_H */ diff --git a/ui-commit.c b/ui-commit.c index ed5384d..885f870 100644 --- a/ui-commit.c +++ b/ui-commit.c @@ -108,128 +108,130 @@ void print_fileinfo(struct fileinfo *info) void cgit_count_diff_lines(char *line, int len) { if (line && (len > 0)) { if (line[0] == '+') lines_added++; else if (line[0] == '-') lines_removed++; } } void inspect_filepair(struct diff_filepair *pair) { files++; lines_added = 0; lines_removed = 0; cgit_diff_files(pair->one->sha1, pair->two->sha1, cgit_count_diff_lines); if (files >= slots) { if (slots == 0) slots = 4; else slots = slots * 2; items = xrealloc(items, slots * sizeof(struct fileinfo)); } items[files-1].status = pair->status; hashcpy(items[files-1].old_sha1, pair->one->sha1); hashcpy(items[files-1].new_sha1, pair->two->sha1); items[files-1].old_mode = pair->one->mode; items[files-1].new_mode = pair->two->mode; items[files-1].old_path = xstrdup(pair->one->path); items[files-1].new_path = xstrdup(pair->two->path); items[files-1].added = lines_added; items[files-1].removed = lines_removed; if (lines_added + lines_removed > max_changes) max_changes = lines_added + lines_removed; total_adds += lines_added; total_rems += lines_removed; } void cgit_print_commit(const char *hex) { struct commit *commit, *parent; struct commitinfo *info; struct commit_list *p; unsigned char sha1[20]; char *query; char *filename; + char *tmp; int i; if (get_sha1(hex, sha1)) { cgit_print_error(fmt("Bad object id: %s", hex)); return; } commit = lookup_commit_reference(sha1); if (!commit) { cgit_print_error(fmt("Bad commit reference: %s", hex)); return; } info = cgit_parse_commit(commit); html("<table class='commit-info'>\n"); html("<tr><th>author</th><td>"); html_txt(info->author); html(" "); html_txt(info->author_email); html("</td><td class='right'>"); cgit_print_date(info->author_date, FMT_LONGDATE); html("</td></tr>\n"); html("<tr><th>committer</th><td>"); html_txt(info->committer); html(" "); html_txt(info->committer_email); html("</td><td class='right'>"); cgit_print_date(info->committer_date, FMT_LONGDATE); html("</td></tr>\n"); - html("<tr><th>tree</th><td colspan='2' class='sha1'><a href='"); - query = fmt("h=%s", sha1_to_hex(commit->object.sha1)); - html_attr(cgit_pageurl(cgit_query_repo, "tree", query)); - htmlf("'>%s</a></td></tr>\n", sha1_to_hex(commit->tree->object.sha1)); + html("<tr><th>tree</th><td colspan='2' class='sha1'>"); + tmp = xstrdup(hex); + cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL, + cgit_query_head, tmp, NULL); + html("</td></tr>\n"); for (p = commit->parents; p ; p = p->next) { parent = lookup_commit_reference(p->item->object.sha1); if (!parent) { html("<tr><td colspan='3'>"); cgit_print_error("Error reading parent commit"); html("</td></tr>"); continue; } html("<tr><th>parent</th>" "<td colspan='2' class='sha1'>" "<a href='"); query = fmt("h=%s", sha1_to_hex(p->item->object.sha1)); html_attr(cgit_pageurl(cgit_query_repo, "commit", query)); htmlf("'>%s</a> (<a href='", sha1_to_hex(p->item->object.sha1)); query = fmt("id=%s&id2=%s", sha1_to_hex(parent->tree->object.sha1), sha1_to_hex(commit->tree->object.sha1)); html_attr(cgit_pageurl(cgit_query_repo, "diff", query)); html("'>diff</a>)</td></tr>"); } if (cgit_repo->snapshots) { htmlf("<tr><th>download</th><td colspan='2' class='sha1'><a href='"); filename = fmt("%s-%s.zip", cgit_query_repo, hex); html_attr(cgit_pageurl(cgit_query_repo, "snapshot", fmt("id=%s&name=%s", hex, filename))); htmlf("'>%s</a></td></tr>", filename); } html("</table>\n"); html("<div class='commit-subject'>"); html_txt(info->subject); html("</div>"); html("<div class='commit-msg'>"); html_txt(info->msg); html("</div>"); if (!(commit->parents && commit->parents->next && commit->parents->next->next)) { html("<div class='diffstat-header'>Diffstat</div>"); html("<table class='diffstat'>"); max_changes = 0; cgit_diff_commit(commit, inspect_filepair); for(i = 0; i<files; i++) print_fileinfo(&items[i]); html("</table>"); html("<div class='diffstat-summary'>"); htmlf("%d files changed, %d insertions, %d deletions (", files, total_adds, total_rems); query = fmt("h=%s", hex); html_link_open(cgit_pageurl(cgit_query_repo, "diff", query), NULL, NULL); html("show diff</a>)"); diff --git a/ui-repolist.c b/ui-repolist.c index e5c6c20..8ade91a 100644 --- a/ui-repolist.c +++ b/ui-repolist.c @@ -1,103 +1,100 @@ /* ui-repolist.c: functions for generating the repolist page * * Copyright (C) 2006 Lars Hjemli * * Licensed under GNU General Public License v2 * (see COPYING for full license text) */ #include "cgit.h" #include <time.h> time_t read_agefile(char *path) { FILE *f; static char buf[64], buf2[64]; if (!(f = fopen(path, "r"))) return -1; fgets(buf, sizeof(buf), f); fclose(f); if (parse_date(buf, buf2, sizeof(buf2))) return strtoul(buf2, NULL, 10); else return 0; } static void print_modtime(struct repoinfo *repo) { char *path; struct stat s; path = fmt("%s/%s", repo->path, cgit_agefile); if (stat(path, &s) == 0) { 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) { - struct repoinfo *repo; int i; char *last_group = NULL; 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'>"); 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"); for (i=0; i<cgit_repolist.count; i++) { - repo = &cgit_repolist.repos[i]; - if ((last_group == NULL && repo->group != NULL) || - (last_group != NULL && repo->group == NULL) || - (last_group != NULL && repo->group!= NULL && - strcmp(repo->group, last_group))) { + 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'>"); - html_txt(repo->group); + html_txt(cgit_repo->group); html("</td></tr>"); - last_group = repo->group; + last_group = cgit_repo->group; } htmlf("<tr><td class='%s'>", - repo->group ? "sublevel-repo" : "toplevel-repo"); - html_link_open(cgit_repourl(repo->url), repo->desc, NULL); - html_txt(repo->name); + 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, repo->desc); + html_ntxt(cgit_max_repodesc_len, cgit_repo->desc); html("</td><td>"); - html_txt(repo->owner); + html_txt(cgit_repo->owner); html("</td><td>"); - print_modtime(repo); + print_modtime(cgit_repo); html("</td><td>"); - html_link_open(cgit_repourl(repo->url), + html_link_open(cgit_repourl(cgit_repo->url), "Summary", "button"); html("S</a>"); - html_link_open(cgit_pageurl(repo->name, "log", NULL), + html_link_open(cgit_pageurl(cgit_repo->name, "log", NULL), "Log", "button"); html("L</a>"); - html_link_open(cgit_pageurl(repo->name, "tree", NULL), - "Files", "button"); - html("F</a>"); + cgit_tree_link("F", "Files", "button", NULL, NULL, NULL); html("</td></tr>\n"); } html("</table>"); cgit_print_docend(); } diff --git a/ui-shared.c b/ui-shared.c index aba93e8..9ab6409 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -42,96 +42,160 @@ void cgit_print_error(char *msg) char *cgit_rooturl() { if (cgit_virtual_root) return fmt("%s/", cgit_virtual_root); else return cgit_script_name; } char *cgit_repourl(const char *reponame) { if (cgit_virtual_root) { return fmt("%s/%s/", cgit_virtual_root, reponame); } else { return fmt("?r=%s", reponame); } } char *cgit_pageurl(const char *reponame, const char *pagename, const char *query) { if (cgit_virtual_root) { if (query) return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame, pagename, query); else return fmt("%s/%s/%s/", cgit_virtual_root, reponame, pagename); } else { if (query) return fmt("?r=%s&p=%s&%s", reponame, pagename, query); else return fmt("?r=%s&p=%s", reponame, pagename); } } char *cgit_currurl() { if (!cgit_virtual_root) return cgit_script_name; else if (cgit_query_page) return fmt("%s/%s/%s/", cgit_virtual_root, cgit_query_repo, cgit_query_page); else if (cgit_query_repo) return fmt("%s/%s/", cgit_virtual_root, cgit_query_repo); else return fmt("%s/", cgit_virtual_root); } +static char *repolink(char *title, char *class, char *page, char *head, + char *path) +{ + char *delim = "?"; + + html("<a"); + if (title) { + html(" title='"); + html_attr(title); + html("'"); + } + if (class) { + 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("/"); + 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("/"); + html(page); + html("/"); + if (path) + html_attr(path); + delim = "&"; + } + if (head && head != cgit_query_head) { + html(delim); + html("h="); + html_attr(head); + delim = "&"; + } + return fmt("%s", delim); +} + +void cgit_tree_link(char *name, char *title, char *class, char *head, + char *rev, char *path) +{ + char *delim; + + delim = repolink(title, class, "tree", head, path); + if (rev && rev != cgit_query_head) { + html(delim); + html("id="); + html_attr(rev); + } + html("'>"); + html_txt(name); + html("</a>"); +} void cgit_print_date(time_t secs, char *format) { char buf[64]; struct tm *time; time = gmtime(&secs); strftime(buf, sizeof(buf)-1, format, time); html_txt(buf); } void cgit_print_age(time_t t, time_t max_relative, char *format) { time_t now, secs; time(&now); secs = now - t; if (secs > max_relative && max_relative >= 0) { cgit_print_date(t, format); return; } if (secs < TM_HOUR * 2) { htmlf("<span class='age-mins'>%.0f min.</span>", secs * 1.0 / TM_MIN); return; } if (secs < TM_DAY * 2) { htmlf("<span class='age-hours'>%.0f hours</span>", secs * 1.0 / TM_HOUR); return; } if (secs < TM_WEEK * 2) { htmlf("<span class='age-days'>%.0f days</span>", secs * 1.0 / TM_DAY); return; } if (secs < TM_MONTH * 2) { htmlf("<span class='age-weeks'>%.0f weeks</span>", secs * 1.0 / TM_WEEK); return; } if (secs < TM_YEAR * 2) { htmlf("<span class='age-months'>%.0f months</span>", secs * 1.0 / TM_MONTH); return; } @@ -10,196 +10,199 @@ char *curr_rev; char *match_path; int header = 0; static void print_object(const unsigned char *sha1, char *path) { enum object_type type; unsigned char *buf; unsigned long size, lineno, start, idx; type = sha1_object_info(sha1, &size); if (type == OBJ_BAD) { cgit_print_error(fmt("Bad object name: %s", sha1_to_hex(sha1))); return; } buf = read_sha1_file(sha1, &type, &size); if (!buf) { cgit_print_error(fmt("Error reading object %s", sha1_to_hex(sha1))); return; } html("<table class='blob'>\n"); idx = 0; start = 0; lineno = 0; while(idx < size) { if (buf[idx] == '\n') { buf[idx] = '\0'; htmlf("<tr><td class='no'>%d</td><td class='txt'>", ++lineno); html_txt(buf + start); html("</td></tr>\n"); start = idx + 1; } idx++; } html("</table>\n"); } static int ls_item(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned int mode, int stage) { char *name; + char *fullpath; enum object_type type; unsigned long size = 0; char *url, *qry; name = xstrdup(pathname); + fullpath = fmt("%s%s%s", cgit_query_path ? cgit_query_path : "", + cgit_query_path ? "/" : "", name); + type = sha1_object_info(sha1, &size); if (type == OBJ_BAD && !S_ISDIRLNK(mode)) { htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", name, sha1_to_hex(sha1)); return 0; } - qry = fmt("h=%s&path=%s%s%s", curr_rev, - cgit_query_path ? cgit_query_path : "", - cgit_query_path ? "/" : "", pathname); - url = cgit_pageurl(cgit_query_repo, "tree", qry); + html("<tr><td class='filemode'>"); html_filemode(mode); html("</td><td "); if (S_ISDIRLNK(mode)) { htmlf("class='ls-mod'><a href='"); html_attr(fmt(cgit_repo->module_link, name, sha1_to_hex(sha1))); + html("'>"); + html_txt(name); + html("</a>"); } else if (S_ISDIR(mode)) { - html("class='ls-dir'><a href='"); - html_attr(url); + html("class='ls-dir'>"); + cgit_tree_link(name, NULL, NULL, cgit_query_head, + curr_rev, fullpath); } else { - html("class='ls-blob'><a href='"); - html_attr(url); + html("class='ls-blob'>"); + cgit_tree_link(name, NULL, NULL, cgit_query_head, + curr_rev, fullpath); } - htmlf("'>%s</a></td>", name); - htmlf("<td class='filesize'>%li</td>", size); + htmlf("</td><td class='filesize'>%li</td>", size); html("<td class='links'><a href='"); qry = fmt("h=%s&path=%s%s%s", curr_rev, cgit_query_path ? cgit_query_path : "", cgit_query_path ? "/" : "", pathname); url = cgit_pageurl(cgit_query_repo, "log", qry); html_attr(url); html("' class='button'>H</a></td>"); html("</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>"); html("<th/>"); html("</tr>\n"); header = 1; } static void ls_tail() { if (!header) return; html("</table>\n"); header = 0; } static void ls_tree(const unsigned char *sha1, char *path) { struct tree *tree; tree = parse_tree_indirect(sha1); if (!tree) { cgit_print_error(fmt("Not a tree object: %s", sha1_to_hex(sha1))); return; } ls_head(); read_tree_recursive(tree, "", 0, 1, NULL, ls_item); ls_tail(); } static int walk_tree(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage) { static int state; static char buffer[PATH_MAX]; char *url; if (state == 0) { memcpy(buffer, base, baselen); strcpy(buffer+baselen, pathname); url = cgit_pageurl(cgit_query_repo, "tree", fmt("h=%s&path=%s", curr_rev, buffer)); - htmlf(" / <a href='"); - html_attr(url); - html("'>"); - html_txt(xstrdup(pathname)); - html("</a>"); + html("/"); + cgit_tree_link(xstrdup(pathname), NULL, NULL, cgit_query_head, + curr_rev, buffer); if (strcmp(match_path, buffer)) return READ_TREE_RECURSIVE; if (S_ISDIR(mode)) { state = 1; ls_head(); return READ_TREE_RECURSIVE; } else { print_object(sha1, buffer); return 0; } } ls_item(sha1, base, baselen, pathname, mode, stage); return 0; } /* * Show a tree or a blob * rev: the commit pointing at the root tree object * path: path to tree or blob */ void cgit_print_tree(const char *rev, char *path) { unsigned char sha1[20]; struct commit *commit; const char *paths[] = {path, NULL}; if (!rev) rev = cgit_query_head; curr_rev = xstrdup(rev); if (get_sha1(rev, sha1)) { cgit_print_error(fmt("Invalid revision name: %s", rev)); return; } commit = lookup_commit_reference(sha1); if (!commit || parse_commit(commit)) { cgit_print_error(fmt("Invalid commit reference: %s", rev)); return; } html("path: <a href='"); html_attr(cgit_pageurl(cgit_query_repo, "tree", fmt("h=%s", rev))); html("'>root</a>"); if (path == NULL) { |