summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--Makefile2
-rw-r--r--cgit.c3
-rw-r--r--cgit.h5
-rw-r--r--shared.c2
-rw-r--r--ui-shared.c24
-rw-r--r--ui-summary.c33
-rw-r--r--ui-tag.c74
7 files changed, 111 insertions, 32 deletions
diff --git a/Makefile b/Makefile
index cea09f1..50d0011 100644
--- a/Makefile
+++ b/Makefile
@@ -1,90 +1,90 @@
prefix = /var/www/htdocs/cgit
SHA1_HEADER = <openssl/sha.h>
CACHE_ROOT = /var/cache/cgit
CGIT_CONFIG = /etc/cgitrc
CGIT_SCRIPT_NAME = cgit.cgi
#
# Let the user override the above settings.
#
-include cgit.conf
CGIT_VERSION = 0.5
all: cgit
VERSION:
sh gen-version.sh
-include VERSION
EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lcrypto
OBJECTS = shared.o cache.o parsing.o html.o ui-shared.o ui-repolist.o \
ui-summary.o ui-log.o ui-tree.o ui-commit.o ui-diff.o \
- ui-snapshot.o ui-blob.o
+ ui-snapshot.o ui-blob.o ui-tag.o
CFLAGS += -Wall
ifdef DEBUG
CFLAGS += -g
endif
CFLAGS += -Igit
CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER)'
CFLAGS += -DCGIT_VERSION='"$(CGIT_VERSION)"'
CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"'
CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"'
#
# If make is run on a nongit platform, get the git sources as a tarball.
#
GITVER = $(shell git version 2>/dev/null || echo nogit)
ifeq ($(GITVER),nogit)
GITURL = http://www.kernel.org/pub/software/scm/git/git-1.5.2.tar.bz2
INITGIT = test -e git/git.c || ((curl "$(GITURL)" | tar -xj) && mv git-1.5.2 git)
else
INITGIT = ./submodules.sh -i
endif
cgit: cgit.c cgit.h VERSION $(OBJECTS)
$(CC) $(CFLAGS) cgit.c -o cgit $(OBJECTS) $(EXTLIBS)
$(OBJECTS): cgit.h git/libgit.a
git/libgit.a:
$(INITGIT)
$(MAKE) -C git
#
# phony targets
#
install: all clean-cache
mkdir -p $(prefix)
install cgit $(prefix)/$(CGIT_SCRIPT_NAME)
install cgit.css $(prefix)/cgit.css
clean-cgit:
rm -f cgit VERSION *.o
distclean-cgit: clean-cgit
git clean -d -x
clean-sub:
$(MAKE) -C git clean
distclean-sub: clean-sub
$(shell cd git && git clean -d -x)
clean-cache:
rm -rf $(CACHE_ROOT)/*
clean: clean-cgit clean-sub
distclean: distclean-cgit distclean-sub
version: clean-cgit
./gen-version.sh
diff --git a/cgit.c b/cgit.c
index 1281bfa..4b91829 100644
--- a/cgit.c
+++ b/cgit.c
@@ -40,128 +40,131 @@ static int cgit_prepare_cache(struct cacheitem *item)
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)
{
char *title;
int show_search;
if (!cgit_query_head)
cgit_query_head = cgit_repo->defbranch;
if (chdir(cgit_repo->path)) {
title = fmt("%s - %s", cgit_root_title, "Bad request");
cgit_print_docstart(title, item);
cgit_print_pageheader(title, 0);
cgit_print_error(fmt("Unable to scan repository: %s",
strerror(errno)));
cgit_print_docend();
return;
}
title = fmt("%s - %s", cgit_repo->name, cgit_repo->desc);
show_search = 0;
setenv("GIT_DIR", cgit_repo->path, 1);
if ((cgit_cmd == CMD_SNAPSHOT) && cgit_repo->snapshots) {
cgit_print_snapshot(item, cgit_query_sha1, "zip",
cgit_repo->url, cgit_query_name);
return;
}
if (cgit_cmd == CMD_BLOB) {
cgit_print_blob(item, cgit_query_sha1, cgit_query_path);
return;
}
show_search = (cgit_cmd == CMD_LOG);
cgit_print_docstart(title, item);
if (!cgit_cmd) {
cgit_print_pageheader("summary", show_search);
cgit_print_summary();
cgit_print_docend();
return;
}
cgit_print_pageheader(cgit_query_page, show_search);
switch(cgit_cmd) {
case CMD_LOG:
cgit_print_log(cgit_query_sha1, cgit_query_ofs,
cgit_max_commit_count, cgit_query_search,
cgit_query_path, 1);
break;
case CMD_TREE:
cgit_print_tree(cgit_query_sha1, cgit_query_path);
break;
case CMD_COMMIT:
cgit_print_commit(cgit_query_sha1);
break;
+ case CMD_TAG:
+ cgit_print_tag(cgit_query_sha1);
+ break;
case CMD_DIFF:
cgit_print_diff(cgit_query_sha1, cgit_query_sha2);
break;
default:
cgit_print_error("Invalid request");
}
cgit_print_docend();
}
static void cgit_fill_cache(struct cacheitem *item, int use_cache)
{
static char buf[PATH_MAX];
int stdout2;
getcwd(buf, sizeof(buf));
item->st.st_mtime = time(NULL);
if (use_cache) {
stdout2 = chk_positive(dup(STDOUT_FILENO),
"Preserving STDOUT");
chk_zero(close(STDOUT_FILENO), "Closing STDOUT");
chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)");
}
if (cgit_repo)
cgit_print_repo_page(item);
else
cgit_print_repolist(item);
if (use_cache) {
chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT");
chk_positive(dup2(stdout2, STDOUT_FILENO),
"Restoring original STDOUT");
chk_zero(close(stdout2), "Closing temporary STDOUT");
}
chdir(buf);
}
static void cgit_check_cache(struct cacheitem *item)
{
int i = 0;
top:
if (++i > cgit_max_lock_attempts) {
die("cgit_refresh_cache: unable to lock %s: %s",
item->name, strerror(errno));
}
if (!cache_exist(item)) {
if (!cache_lock(item)) {
sleep(1);
goto top;
}
if (!cache_exist(item)) {
cgit_fill_cache(item, 1);
cache_unlock(item);
} else {
cache_cancel_lock(item);
}
} else if (cache_expired(item) && cache_lock(item)) {
if (cache_expired(item)) {
cgit_fill_cache(item, 1);
cache_unlock(item);
} else {
diff --git a/cgit.h b/cgit.h
index 2ff5340..610a16d 100644
--- a/cgit.h
+++ b/cgit.h
@@ -1,94 +1,94 @@
#ifndef CGIT_H
#define CGIT_H
#include <git-compat-util.h>
#include <cache.h>
#include <grep.h>
#include <object.h>
#include <tree.h>
#include <commit.h>
#include <tag.h>
#include <diff.h>
#include <diffcore.h>
#include <refs.h>
#include <revision.h>
#include <log-tree.h>
#include <archive.h>
#include <xdiff/xdiff.h>
/*
* The valid cgit repo-commands
*/
#define CMD_LOG 1
#define CMD_COMMIT 2
#define CMD_DIFF 3
#define CMD_TREE 4
#define CMD_BLOB 5
#define CMD_SNAPSHOT 6
-
+#define CMD_TAG 7
/*
* Dateformats used on misc. pages
*/
#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S"
#define FMT_SHORTDATE "%Y-%m-%d"
/*
* Limits used for relative dates
*/
#define TM_MIN 60
#define TM_HOUR (TM_MIN * 60)
#define TM_DAY (TM_HOUR * 24)
#define TM_WEEK (TM_DAY * 7)
#define TM_YEAR (TM_DAY * 365)
#define TM_MONTH (TM_YEAR / 12.0)
typedef void (*configfn)(const char *name, const char *value);
typedef void (*filepair_fn)(struct diff_filepair *pair);
typedef void (*linediff_fn)(char *line, int len);
struct cacheitem {
char *name;
struct stat st;
int ttl;
int fd;
};
struct repoinfo {
char *url;
char *name;
char *path;
char *desc;
char *owner;
char *defbranch;
char *group;
char *module_link;
char *readme;
int snapshots;
int enable_log_filecount;
int enable_log_linecount;
};
struct repolist {
int length;
int count;
struct repoinfo *repos;
};
struct commitinfo {
struct commit *commit;
char *author;
char *author_email;
unsigned long author_date;
char *committer;
char *committer_email;
unsigned long committer_date;
char *subject;
char *msg;
};
struct taginfo {
@@ -151,86 +151,89 @@ 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);
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_log_link(char *name, char *title, char *class, char *head,
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_object_link(struct object *obj);
+
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(char *hex);
+extern void cgit_print_tag(char *revname);
extern void cgit_print_diff(const char *new_hex, const char *old_hex);
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/shared.c b/shared.c
index 1a5b866..06693b0 100644
--- a/shared.c
+++ b/shared.c
@@ -2,129 +2,129 @@
*
* Copyright (C) 2006 Lars Hjemli
*
* Licensed under GNU General Public License v2
* (see COPYING for full license text)
*/
#include "cgit.h"
struct repolist cgit_repolist;
struct repoinfo *cgit_repo;
int cgit_cmd;
const char *cgit_version = CGIT_VERSION;
char *cgit_root_title = "Git repository browser";
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;
int cgit_max_commit_count = 50;
int cgit_query_has_symref = 0;
int cgit_query_has_sha1 = 0;
char *cgit_querystring = NULL;
char *cgit_query_repo = NULL;
char *cgit_query_page = NULL;
char *cgit_query_head = NULL;
char *cgit_query_search = NULL;
char *cgit_query_sha1 = NULL;
char *cgit_query_sha2 = NULL;
char *cgit_query_path = NULL;
char *cgit_query_name = NULL;
int cgit_query_ofs = 0;
int htmlfd = 0;
int cgit_get_cmd_index(const char *cmd)
{
static char *cmds[] = {"log", "commit", "diff", "tree", "blob",
- "snapshot", NULL};
+ "snapshot", "tag", NULL};
int i;
for(i = 0; cmds[i]; i++)
if (!strcmp(cmd, cmds[i]))
return i + 1;
return 0;
}
int chk_zero(int result, char *msg)
{
if (result != 0)
die("%s: %s", msg, strerror(errno));
return result;
}
int chk_positive(int result, char *msg)
{
if (result <= 0)
die("%s: %s", msg, strerror(errno));
return result;
}
struct repoinfo *add_repo(const char *url)
{
struct repoinfo *ret;
if (++cgit_repolist.count > cgit_repolist.length) {
if (cgit_repolist.length == 0)
cgit_repolist.length = 8;
else
cgit_repolist.length *= 2;
cgit_repolist.repos = xrealloc(cgit_repolist.repos,
cgit_repolist.length *
sizeof(struct repoinfo));
}
ret = &cgit_repolist.repos[cgit_repolist.count-1];
ret->url = xstrdup(url);
ret->name = ret->url;
ret->path = NULL;
ret->desc = NULL;
ret->owner = NULL;
ret->group = cgit_repo_group;
ret->defbranch = "master";
ret->snapshots = cgit_snapshots;
ret->enable_log_filecount = cgit_enable_log_filecount;
ret->enable_log_linecount = cgit_enable_log_linecount;
ret->module_link = cgit_module_link;
ret->readme = NULL;
return ret;
}
struct repoinfo *cgit_get_repoinfo(const char *url)
{
int i;
struct repoinfo *repo;
for (i=0; i<cgit_repolist.count; i++) {
repo = &cgit_repolist.repos[i];
if (!strcmp(repo->url, url))
return repo;
}
return NULL;
}
diff --git a/ui-shared.c b/ui-shared.c
index d4376ce..fd71c12 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -157,128 +157,152 @@ static void reporevlink(char *page, char *name, char *title, char *class,
}
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, int ofs)
{
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);
}
void cgit_diff_link(char *name, char *title, char *class, char *head,
char *new_rev, char *old_rev, char *path)
{
char *delim;
delim = repolink(title, class, "diff", head, path);
if (new_rev && strcmp(new_rev, cgit_query_head)) {
html(delim);
html("id=");
html_attr(new_rev);
delim = "&amp;";
}
if (old_rev) {
html(delim);
html("id2=");
html_attr(old_rev);
}
html("'>");
html_txt(name);
html("</a>");
}
+void cgit_object_link(struct object *obj)
+{
+ char *page, *arg, *url;
+
+ if (obj->type == OBJ_COMMIT) {
+ cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL,
+ cgit_query_head, sha1_to_hex(obj->sha1));
+ return;
+ } else if (obj->type == OBJ_TREE) {
+ page = "tree";
+ arg = "id";
+ } else {
+ page = "blob";
+ arg = "id";
+ }
+
+ url = cgit_pageurl(cgit_query_repo, page,
+ fmt("%s=%s", arg, sha1_to_hex(obj->sha1)));
+ html_link_open(url, NULL, NULL);
+ htmlf("%s %s", typename(obj->type),
+ sha1_to_hex(obj->sha1));
+ html_link_close();
+}
+
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;
}
htmlf("<span class='age-years'>%.0f years</span>",
secs * 1.0 / TM_YEAR);
}
void cgit_print_docstart(char *title, struct cacheitem *item)
{
html("Content-Type: text/html; charset=utf-8\n");
htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime));
htmlf("Expires: %s\n", http_date(item->st.st_mtime +
ttl_seconds(item->ttl)));
html("\n");
html(cgit_doctype);
html("<html>\n");
html("<head>\n");
html("<title>");
html_txt(title);
html("</title>\n");
diff --git a/ui-summary.c b/ui-summary.c
index b4bc6d8..de8a180 100644
--- a/ui-summary.c
+++ b/ui-summary.c
@@ -1,187 +1,162 @@
/* ui-summary.c: functions for generating repo summary page
*
* Copyright (C) 2006 Lars Hjemli
*
* Licensed under GNU General Public License v2
* (see COPYING for full license text)
*/
#include "cgit.h"
static int header;
static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1,
int flags, void *cb_data)
{
struct commit *commit;
struct commitinfo *info;
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, 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'>");
htmlf("*** bad ref %s ***", sha1_to_hex(sha1));
html("</td></tr>\n");
}
free(ref);
return 0;
}
-
-static void cgit_print_object_ref(struct object *obj)
-{
- char *page, *arg, *url;
-
- if (obj->type == OBJ_COMMIT) {
- cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL,
- cgit_query_head, sha1_to_hex(obj->sha1));
- return;
- } else if (obj->type == OBJ_TREE) {
- page = "tree";
- arg = "id";
- } else {
- page = "view";
- arg = "id";
- }
-
- url = cgit_pageurl(cgit_query_repo, page,
- fmt("%s=%s", arg, sha1_to_hex(obj->sha1)));
- html_link_open(url, NULL, NULL);
- htmlf("%s %s", typename(obj->type),
- sha1_to_hex(obj->sha1));
- html_link_close();
-}
-
static void print_tag_header()
{
html("<tr class='nohover'><th class='left'>Tag</th>"
"<th class='left'>Age</th>"
"<th class='left'>Author</th>"
"<th class='left'>Reference</th></tr>\n");
header = 1;
}
static int cgit_print_tag_cb(const char *refname, const unsigned char *sha1,
int flags, void *cb_data)
{
struct tag *tag;
struct taginfo *info;
struct object *obj;
char buf[256], *url;
strncpy(buf, refname, sizeof(buf));
obj = parse_object(sha1);
if (!obj)
return 1;
if (obj->type == OBJ_TAG) {
tag = lookup_tag(sha1);
if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
return 2;
if (!header)
print_tag_header();
html("<tr><td>");
- url = cgit_pageurl(cgit_query_repo, "view",
- fmt("id=%s", sha1_to_hex(sha1)));
+ url = cgit_pageurl(cgit_query_repo, "tag",
+ fmt("id=%s", refname));
html_link_open(url, NULL, NULL);
html_txt(buf);
html_link_close();
html("</td><td>");
if (info->tagger_date > 0)
cgit_print_age(info->tagger_date, -1, NULL);
html("</td><td>");
if (info->tagger)
html(info->tagger);
html("</td><td>");
- cgit_print_object_ref(tag->tagged);
+ cgit_object_link(tag->tagged);
html("</td></tr>\n");
} else {
if (!header)
print_tag_header();
html("<tr><td>");
html_txt(buf);
html("</td><td colspan='2'/><td>");
- cgit_print_object_ref(obj);
+ cgit_object_link(obj);
html("</td></tr>\n");
}
return 0;
}
static int cgit_print_archive_cb(const char *refname, const unsigned char *sha1,
int flags, void *cb_data)
{
struct tag *tag;
struct taginfo *info;
struct object *obj;
char buf[256], *url;
unsigned char fileid[20];
if (prefixcmp(refname, "refs/archives"))
return 0;
strncpy(buf, refname+14, sizeof(buf));
obj = parse_object(sha1);
if (!obj)
return 1;
if (obj->type == OBJ_TAG) {
tag = lookup_tag(sha1);
if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
return 0;
hashcpy(fileid, tag->tagged->sha1);
} else if (obj->type != OBJ_BLOB) {
return 0;
} else {
hashcpy(fileid, sha1);
}
if (!header) {
html("<table id='downloads'>");
html("<tr><th>Downloads</th></tr>");
header = 1;
}
html("<tr><td>");
url = cgit_pageurl(cgit_query_repo, "blob",
fmt("id=%s&amp;path=%s", sha1_to_hex(fileid),
buf));
html_link_open(url, NULL, NULL);
html_txt(buf);
html_link_close();
html("</td></tr>");
return 0;
}
static void cgit_print_branches()
{
html("<tr class='nohover'><th class='left'>Branch</th>"
"<th class='left'>Idle</th>"
"<th class='left'>Author</th>"
"<th class='left'>Head commit</th></tr>\n");
for_each_branch_ref(cgit_print_branch_cb, NULL);
}
static void cgit_print_tags()
{
header = 0;
for_each_tag_ref(cgit_print_tag_cb, NULL);
}
static void cgit_print_archives()
{
header = 0;
diff --git a/ui-tag.c b/ui-tag.c
new file mode 100644
index 0000000..a6989ff
--- a/dev/null
+++ b/ui-tag.c
@@ -0,0 +1,74 @@
+/* ui-tag.c: display a tag
+ *
+ * Copyright (C) 2007 Lars Hjemli
+ *
+ * Licensed under GNU General Public License v2
+ * (see COPYING for full license text)
+ */
+
+#include "cgit.h"
+
+
+static void print_tag_content(char *buf)
+{
+ char *p;
+
+ if (!buf)
+ return;
+
+ html("<div class='commit-subject'>");
+ p = strchr(buf, '\n');
+ if (p)
+ *p = '\0';
+ html_txt(buf);
+ html("</div>");
+ if (p) {
+ html("<div class='commit-msg'>");
+ html_txt(++p);
+ html("</div>");
+ }
+}
+
+void cgit_print_tag(char *revname)
+{
+ unsigned char sha1[20];
+ struct object *obj;
+ struct tag *tag;
+ struct taginfo *info;
+
+ if (get_sha1(revname, sha1)) {
+ cgit_print_error(fmt("Bad tag reference: %s", revname));
+ return;
+ }
+ obj = parse_object(sha1);
+ if (!obj) {
+ cgit_print_error(fmt("Bad object id: %s", sha1_to_hex(sha1)));
+ return;
+ }
+ if (obj->type == OBJ_TAG) {
+ tag = lookup_tag(sha1);
+ if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) {
+ cgit_print_error(fmt("Bad tag object: %s", revname));
+ return;
+ }
+ html("<table class='commit-info'>\n");
+ htmlf("<tr><td>Tag name</td><td>%s (%s)</td></tr>\n",
+ revname, sha1_to_hex(sha1));
+ if (info->tagger_date > 0) {
+ html("<tr><td>Tag date</td><td>");
+ cgit_print_date(info->tagger_date, FMT_LONGDATE);
+ html("</td><tr>\n");
+ }
+ if (info->tagger) {
+ html("<tr><td>Tagged by</td><td>");
+ html_txt(info->tagger);
+ html("</td></tr>\n");
+ }
+ html("<tr><td>Tagged object</td><td>");
+ cgit_object_link(tag->tagged);
+ html("</td></tr>\n");
+ html("</table>\n");
+ print_tag_content(info->msg);
+ }
+ return;
+}