summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.gitmodules8
-rw-r--r--Makefile102
-rw-r--r--cgit.c36
-rw-r--r--cgit.css75
-rw-r--r--cgit.h47
-rw-r--r--cgitrc9
-rwxr-xr-xgen-version.sh20
m---------git0
-rw-r--r--parsing.c2
-rw-r--r--shared.c45
-rwxr-xr-xsubmodules.sh181
-rw-r--r--ui-commit.c78
-rw-r--r--ui-diff.c66
-rw-r--r--ui-log.c26
-rw-r--r--ui-repolist.c66
-rw-r--r--ui-shared.c234
-rw-r--r--ui-snapshot.c156
-rw-r--r--ui-summary.c49
-rw-r--r--ui-tag.c74
-rw-r--r--ui-tree.c213
-rw-r--r--ui-view.c55
22 files changed, 929 insertions, 614 deletions
diff --git a/.gitignore b/.gitignore
index c4c9ac3..5664962 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
# Files I don't care to see in git-status/commit
cgit
+VERSION
*.o
*~
diff --git a/.gitmodules b/.gitmodules
index 51dd1ef..1daea94 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,5 +1,3 @@
-# This file maps a submodule path to an url from where the submodule
-# can be obtained. The script "submodules.sh" finds the url in this file
-# when invoked with -i to clone the submodules.
-
-git git://git.kernel.org/pub/scm/git/git.git
+[submodule "git"]
+ url = git://git.kernel.org/pub/scm/git/git.git
+ path = git
diff --git a/Makefile b/Makefile
index 57f80f8..fcbe3e4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,87 +1,71 @@
-CGIT_VERSION = 0.5
-
-prefix = /var/www/htdocs/cgit
-
-SHA1_HEADER = <openssl/sha.h>
-CACHE_ROOT = /var/cache/cgit
-CGIT_CONFIG = /etc/cgitrc
+CGIT_VERSION = v0.5
CGIT_SCRIPT_NAME = cgit.cgi
+CGIT_SCRIPT_PATH = /var/www/htdocs/cgit
+CGIT_CONFIG = /etc/cgitrc
+CACHE_ROOT = /var/cache/cgit
+SHA1_HEADER = <openssl/sha.h>
+GIT_VER = 1.5.2
+GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2
#
# Let the user override the above settings.
#
-include cgit.conf
+
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-view.o ui-tree.o ui-commit.o ui-diff.o \
- ui-snapshot.o ui-blob.o
+ ui-summary.o ui-log.o ui-tree.o ui-commit.o ui-diff.o \
+ ui-snapshot.o ui-blob.o ui-tag.o
+
+
+.PHONY: all git install clean distclean force-version get-git
-CFLAGS += -Wall
+all: cgit git
-ifdef DEBUG
- CFLAGS += -g
-endif
+VERSION: force-version
+ @./gen-version.sh "$(CGIT_VERSION)"
+-include VERSION
-CFLAGS += -Igit
+
+CFLAGS += -g -Wall -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
-
-
-#
-# basic build rules
-#
-all: cgit
-
-cgit: cgit.c cgit.h $(OBJECTS)
+cgit: cgit.c $(OBJECTS)
$(CC) $(CFLAGS) cgit.c -o cgit $(OBJECTS) $(EXTLIBS)
-$(OBJECTS): cgit.h git/libgit.a
+$(OBJECTS): cgit.h git/xdiff/lib.a git/libgit.a VERSION
-git/libgit.a:
- $(INITGIT)
- $(MAKE) -C git
+git/xdiff/lib.a: | git
-#
-# phony targets
-#
-install: all clean-cache
- mkdir -p $(prefix)
- install cgit $(prefix)/$(CGIT_SCRIPT_NAME)
- install cgit.css $(prefix)/cgit.css
+git/libgit.a: | git
-clean-cgit:
- rm -f cgit *.o
+git:
+ cd git && $(MAKE) xdiff/lib.a
+ cd git && $(MAKE) libgit.a
-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:
+install: all
+ mkdir -p $(CGIT_SCRIPT_PATH)
+ install cgit $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
+ install cgit.css $(CGIT_SCRIPT_PATH)/cgit.css
rm -rf $(CACHE_ROOT)/*
-clean: clean-cgit clean-sub
+uninstall:
+ rm -f $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
+ rm -f $(CGIT_SCRIPT_PATH)/cgit.css
+ rm -rf $(CACHE_ROOT)
+
+clean:
+ rm -f cgit VERSION *.o
+ cd git && $(MAKE) clean
-distclean: distclean-cgit distclean-sub
+distclean: clean
+ git clean -d -x
+ cd git && git clean -d -x
-.PHONY: all install clean clean-cgit clean-sub clean-cache \
- distclean distclean-cgit distclean-sub
+get-git:
+ curl $(GIT_URL) | tar -xj && rm -rf git && mv git-$(GIT_VER) git
diff --git a/cgit.c b/cgit.c
index 34e590e..c86d290 100644
--- a/cgit.c
+++ b/cgit.c
@@ -8,9 +8,6 @@
#include "cgit.h"
-const char cgit_version[] = CGIT_VERSION;
-
-
static int cgit_prepare_cache(struct cacheitem *item)
{
if (!cgit_repo && cgit_query_repo) {
@@ -29,13 +26,15 @@ static int cgit_prepare_cache(struct cacheitem *item)
}
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_querystring)));
+ 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)
@@ -69,8 +68,10 @@ static void cgit_print_repo_page(struct cacheitem *item)
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);
+ cgit_print_snapshot(item, cgit_query_head, cgit_query_sha1,
+ cgit_repobasename(cgit_repo->url),
+ cgit_query_path,
+ cgit_repo->snapshots );
return;
}
@@ -92,22 +93,21 @@ static void cgit_print_repo_page(struct cacheitem *item)
switch(cgit_cmd) {
case CMD_LOG:
- cgit_print_log(cgit_query_head, cgit_query_ofs,
+ 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_head, cgit_query_sha1, cgit_query_path);
+ cgit_print_tree(cgit_query_sha1, cgit_query_path);
break;
case CMD_COMMIT:
- cgit_print_commit(cgit_query_head);
+ cgit_print_commit(cgit_query_sha1);
break;
- case CMD_VIEW:
- cgit_print_view(cgit_query_sha1, cgit_query_path);
+ case CMD_TAG:
+ cgit_print_tag(cgit_query_sha1);
break;
case CMD_DIFF:
- cgit_print_diff(cgit_query_head, cgit_query_sha1, cgit_query_sha2,
- cgit_query_path);
+ cgit_print_diff(cgit_query_sha1, cgit_query_sha2);
break;
default:
cgit_print_error("Invalid request");
@@ -227,6 +227,7 @@ static void cgit_parse_args(int argc, const char **argv)
int main(int argc, const char **argv)
{
struct cacheitem item;
+ const char *cgit_config_env = getenv("CGIT_CONFIG");
htmlfd = STDOUT_FILENO;
item.st.st_mtime = time(NULL);
@@ -234,7 +235,8 @@ int main(int argc, const char **argv)
cgit_repolist.count = 0;
cgit_repolist.repos = NULL;
- cgit_read_config(CGIT_CONFIG, cgit_global_config_cb);
+ cgit_read_config(cgit_config_env ? cgit_config_env : CGIT_CONFIG,
+ cgit_global_config_cb);
cgit_repo = NULL;
if (getenv("SCRIPT_NAME"))
cgit_script_name = xstrdup(getenv("SCRIPT_NAME"));
diff --git a/cgit.css b/cgit.css
index 8977533..54bbfcc 100644
--- a/cgit.css
+++ b/cgit.css
@@ -1,6 +1,7 @@
body {
- font-family: arial;
+ font-family: arial, sans-serif;
font-size: 11pt;
+ color: black;
background: white;
}
@@ -94,6 +95,14 @@ td#header {
vertical-align: text-bottom;
}
+td#header a {
+ color: #666;
+}
+
+td#header a:hoved {
+ text-decoration: underline;
+}
+
td#logo {
text-align: right;
vertical-align: middle;
@@ -114,15 +123,19 @@ td#crumb {
td#crumb a {
color: #ccc;
+ background-color: #666;
+ padding: 0em 0.5em 0em 0.5em;
}
td#crumb a:hover {
- color: #eee;
+ color: #666;
+ background-color: #ccc;
+ text-decoration: none;
}
td#search {
text-align: right;
- vertical-align: center;
+ vertical-align: middle;
padding-right: 0.5em;
}
@@ -171,35 +184,47 @@ div.error {
margin: 1em 2em;
}
-td.ls-blob, td.ls-dir, td.ls-mod {
+a.ls-blob, a.ls-dir, a.ls-mod {
font-family: monospace;
}
-div.ls-dir a {
- font-weight: bold;
+td.ls-size {
+ text-align: right;
}
-th.filesize, td.filesize {
- text-align: right;
+td.ls-size {
+ font-family: monospace;
}
-td.filesize {
+td.ls-mode {
font-family: monospace;
}
-td.links {
- font-size: 80%;
- padding-left: 2em;
+table.blob {
+ margin-top: 0.5em;
+ border-top: solid 1px black;
}
-td.filemode {
- font-family: monospace;
+table.blob td.no {
+ border-right: solid 1px black;
+ color: black;
+ background-color: #eee;
+ text-align: right;
+}
+
+table.blob td.no a {
+ color: black;
}
-td.blob {
+table.blob td.no a:hover {
+ color: black;
+ text-decoration: none;
+}
+
+table.blob td.txt {
white-space: pre;
font-family: monospace;
- background-color: white;
+ padding-left: 0.5em;
}
table.nowrap td {
@@ -215,6 +240,7 @@ table.commit-info th {
text-align: left;
font-weight: normal;
padding: 0.1em 1em 0.1em 0.1em;
+ vertical-align: top;
}
table.commit-info td {
@@ -287,7 +313,7 @@ table.diffstat td.upd a {
table.diffstat td.graph {
width: 75%;
- vertical-align: center;
+ vertical-align: middle;
}
table.diffstat td.graph table {
@@ -308,10 +334,6 @@ table.diffstat td.graph td.rem {
background-color: #c55;
}
-table.diffstat td.graph td.none {
- background-color: none;
-}
-
div.diffstat-summary {
color: #888;
padding-top: 0.5em;
@@ -340,7 +362,7 @@ table.diff td div.del {
}
.sha1 {
- font-family: courier;
+ font-family: monospace;
font-size: 90%;
}
@@ -359,16 +381,17 @@ table.list td.repogroup {
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 {
diff --git a/cgit.h b/cgit.h
index 2f3fca1..e3d9cb8 100644
--- a/cgit.h
+++ b/cgit.h
@@ -25,10 +25,9 @@
#define CMD_COMMIT 2
#define CMD_DIFF 3
#define CMD_TREE 4
-#define CMD_VIEW 5
-#define CMD_BLOB 6
-#define CMD_SNAPSHOT 7
-
+#define CMD_BLOB 5
+#define CMD_SNAPSHOT 6
+#define CMD_TAG 7
/*
* Dateformats used on misc. pages
@@ -99,7 +98,7 @@ struct taginfo {
char *msg;
};
-extern const char cgit_version[];
+extern const char *cgit_version;
extern struct repolist cgit_repolist;
extern struct repoinfo *cgit_repo;
@@ -119,6 +118,7 @@ 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;
@@ -157,8 +157,10 @@ 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 chk_non_negative(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);
@@ -199,9 +201,26 @@ extern int cache_exist(struct cacheitem *item);
extern int cache_expired(struct cacheitem *item);
extern char *cgit_repourl(const char *reponame);
+extern char *cgit_fileurl(const char *reponame, const char *pagename,
+ const char *filename, const char *query);
extern char *cgit_pageurl(const char *reponame, const char *pagename,
const char *query);
+extern const char *cgit_repobasename(const char *reponame);
+
+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_snapshot_link(char *name, char *title, char *class,
+ char *head, char *rev, char *archivename);
+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);
@@ -215,14 +234,16 @@ extern void cgit_print_snapshot_start(const char *mimetype,
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_view(const char *hex, char *path);
extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path);
-extern void cgit_print_tree(const char *rev, const char *hex, 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);
+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 *head,
+ const char *hex, const char *prefix,
+ const char *filename, int snapshot);
+extern void cgit_print_snapshot_links(const char *repo, const char *head,
+ const char *hex, int snapshots);
+extern int cgit_parse_snapshots_mask(const char *str);
#endif /* CGIT_H */
diff --git a/cgitrc b/cgitrc
index 0f602e4..1040997 100644
--- a/cgitrc
+++ b/cgitrc
@@ -8,10 +8,15 @@
#nocache=0
-## Enable/disable snapshots by default. This can be overridden per repo
+## Set allowed snapshot types by default. Can be overridden per repo
+# can be any combination of zip/tar.gz/tar.bz2/tar
#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
@@ -109,7 +114,7 @@
#repo.desc=the caching cgi for git
#repo.path=/pub/git/cgit
#repo.owner=Lars Hjemli
-#repo.snapshots=1 # override a sitewide snapshot-setting
+#repo.snapshots=tar.bz2 # override a sitewide snapshot-setting
#repo.enable-log-filecount=0 # override the default filecount setting
#repo.enable-log-linecount=0 # override the default linecount setting
#repo.module-link=/git/%s/commit/?id=%s # override the standard module-link
diff --git a/gen-version.sh b/gen-version.sh
new file mode 100755
index 0000000..739c83e
--- /dev/null
+++ b/gen-version.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# Get version-info specified in Makefile
+V=$1
+
+# Use `git describe` to get current version if we're inside a git repo
+if test -d .git
+then
+ V=$(git describe --abbrev=4 HEAD 2>/dev/null | sed -e 's/-/./g')
+fi
+
+new="CGIT_VERSION = $V"
+old=$(cat VERSION 2>/dev/null)
+
+# Exit if VERSION is uptodate
+test "$old" = "$new" && exit 0
+
+# Update VERSION with new version-info
+echo "$new" > VERSION
+cat VERSION
diff --git a/git b/git
-Subproject aba170cdb4874b72dd619e6f7bbc13c33295f83
+Subproject 86bab9615c3516d4ac7756ae3c1285d331b78f0
diff --git a/parsing.c b/parsing.c
index 74a2484..2c05c09 100644
--- a/parsing.c
+++ b/parsing.c
@@ -168,7 +168,7 @@ void cgit_parse_url(const char *url)
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);
diff --git a/shared.c b/shared.c
index b6d2fa1..077934f 100644
--- a/shared.c
+++ b/shared.c
@@ -12,6 +12,8 @@ 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";
@@ -26,6 +28,7 @@ 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;
@@ -59,7 +62,8 @@ int htmlfd = 0;
int cgit_get_cmd_index(const char *cmd)
{
- static char *cmds[] = {"log", "commit", "diff", "tree", "view", "blob", "snapshot", NULL};
+ static char *cmds[] = {"log", "commit", "diff", "tree", "blob",
+ "snapshot", "tag", NULL};
int i;
for(i = 0; cmds[i]; i++)
@@ -82,6 +86,13 @@ int chk_positive(int result, char *msg)
return result;
}
+int chk_non_negative(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;
@@ -144,7 +155,9 @@ void cgit_global_config_cb(const char *name, const char *value)
else if (!strcmp(name, "nocache"))
cgit_nocache = atoi(value);
else if (!strcmp(name, "snapshots"))
- cgit_snapshots = atoi(value);
+ cgit_snapshots = cgit_parse_snapshots_mask(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"))
@@ -184,7 +197,7 @@ void cgit_global_config_cb(const char *name, const char *value)
else if (cgit_repo && !strcmp(name, "repo.defbranch"))
cgit_repo->defbranch = xstrdup(value);
else if (cgit_repo && !strcmp(name, "repo.snapshots"))
- cgit_repo->snapshots = cgit_snapshots * atoi(value);
+ cgit_repo->snapshots = cgit_snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */
else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount"))
cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value);
else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount"))
@@ -224,7 +237,7 @@ void cgit_querystring_cb(const char *name, const char *value)
} 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);
}
@@ -253,6 +266,28 @@ int hextoint(char c)
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)
{
@@ -359,7 +394,7 @@ void cgit_diff_tree(const unsigned char *old_sha1,
opt.format_callback_data = fn;
diff_setup_done(&opt);
- if (old_sha1)
+ if (old_sha1 && !is_null_sha1(old_sha1))
ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt);
else
ret = diff_root_tree_sha1(new_sha1, "", &opt);
diff --git a/submodules.sh b/submodules.sh
deleted file mode 100755
index 1d7b13f..0000000
--- a/submodules.sh
+++ /dev/null
@@ -1,181 +0,0 @@
-#!/bin/sh
-#
-# submodules.sh: init, update or list git submodules
-#
-# Copyright (C) 2006 Lars Hjemli
-#
-# Licensed under GNU General Public License v2
-# (see COPYING for full license text)
-#
-
-
-usage="submodules.sh [-i | -u] [-q] [--cached] [path...]"
-init=
-update=
-quiet=
-cached=
-
-
-say()
-{
- if test -z "$quiet"
- then
- echo -e "$@"
- fi
-}
-
-
-die()
-{
- echo >&2 -e "$@"
- exit 1
-}
-
-
-
-#
-# Silently checkout specified submodule revision, return exit status of git-checkout
-#
-# $1 = local path
-# $2 = requested sha1
-#
-module_checkout()
-{
- $(cd "$1" && git checkout "$2" 1>/dev/null 2>/dev/null)
-}
-
-
-#
-# Find all (requested) submodules, run clone + checkout on missing paths
-#
-# $@ = requested paths (default to all)
-#
-modules_init()
-{
- git ls-files --stage -- $@ | grep -e '^160000 ' |
- while read mode sha1 stage path
- do
- test -d "$path/.git" && continue
-
- if test -d "$path"
- then
- rmdir "$path" 2>/dev/null ||
- die "Directory '$path' exist, but not as a submodule"
- fi
-
- test -e "$path" && die "A file already exist at path '$path'"
-
- url=$(sed -nre "s/^$path[ \t]+//p" .gitmodules)
- test -z "$url" && die "No url found for $path in .gitmodules"
-
- git clone "$url" "$path" || die "Clone of submodule '$path' failed"
- module_checkout "$path" "$sha1" || die "Checkout of submodule '$path' failed"
- say "Submodule '$path' initialized"
- done
-}
-
-#
-# Checkout correct revision of each initialized submodule
-#
-# $@ = requested paths (default to all)
-#
-modules_update()
-{
- git ls-files --stage -- $@ | grep -e '^160000 ' |
- while read mode sha1 stage path
- do
- if ! test -d "$path/.git"
- then
- say "Submodule '$path' not initialized"
- continue;
- fi
- subsha1=$(cd "$path" && git rev-parse --verify HEAD) ||
- die "Unable to find current revision of submodule '$path'"
- if test "$subsha1" != "$sha1"
- then
- module_checkout "$path" "$sha1" ||
- die "Unable to checkout revision $sha1 of submodule '$path'"
- say "Submodule '$path' reset to revision $sha1"
- fi
- done
-}
-
-#
-# List all registered submodules, prefixed with:
-# - submodule not initialized
-# + different version checked out
-#
-# If --cached was specified the revision in the index will be printed
-# instead of the currently checked out revision.
-#
-# $@ = requested paths (default to all)
-#
-modules_list()
-{
- git ls-files --stage -- $@ | grep -e '^160000 ' |
- while read mode sha1 stage path
- do
- if ! test -d "$path/.git"
- then
- say "-$sha1 $path"
- continue;
- fi
- revname=$(cd "$path" && git describe $sha1)
- if git diff-files --quiet -- "$path"
- then
- say " $sha1 $path\t($revname)"
- else
- if test -z "$cached"
- then
- sha1=$(cd "$path" && git rev-parse HEAD)
- revname=$(cd "$path" && git describe HEAD)
- fi
- say "+$sha1 $path\t($revname)"
- fi
- done
-}
-
-
-while case "$#" in 0) break ;; esac
-do
- case "$1" in
- -i)
- init=1
- ;;
- -u)
- update=1
- ;;
- -q)
- quiet=1
- ;;
- --cached)
- cached=1
- ;;
- --)
- break
- ;;
- -*)
- echo "Usage: $usage"
- exit 1
- ;;
- --*)
- echo "Usage: $usage"
- exit 1
- ;;
- *)
- break
- ;;
- esac
- shift
-done
-
-
-if test "$init" = "1"
-then
- modules_init $@
-elif test "$update" = "1"
-then
- modules_update $@
-else
- modules_list $@
-fi
diff --git a/ui-commit.c b/ui-commit.c
index 1d12bbb..90e09ed 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -11,6 +11,7 @@
static int files, slots;
static int total_adds, total_rems, max_changes;
static int lines_added, lines_removed;
+static char *curr_rev;
static struct fileinfo {
char status;
@@ -27,7 +28,6 @@ static struct fileinfo {
void print_fileinfo(struct fileinfo *info)
{
- char *query, *query2;
char *class;
switch (info->status) {
@@ -75,24 +75,12 @@ void print_fileinfo(struct fileinfo *info)
html("]</span>");
}
htmlf("</td><td class='%s'>", class);
- query = fmt("id=%s&amp;id2=%s&amp;path=%s", sha1_to_hex(info->old_sha1),
- sha1_to_hex(info->new_sha1), info->new_path);
- html_link_open(cgit_pageurl(cgit_query_repo, "diff", query),
- NULL, NULL);
- if (info->status == DIFF_STATUS_COPIED ||
- info->status == DIFF_STATUS_RENAMED) {
- html_txt(info->new_path);
- htmlf("</a> (%s from ", info->status == DIFF_STATUS_COPIED ?
- "copied" : "renamed");
- query2 = fmt("id=%s", sha1_to_hex(info->old_sha1));
- html_link_open(cgit_pageurl(cgit_query_repo, "view", query2),
- NULL, NULL);
- html_txt(info->old_path);
- html("</a>)");
- } else {
- html_txt(info->new_path);
- html("</a>");
- }
+ cgit_tree_link(info->new_path, NULL, NULL, cgit_query_head, curr_rev,
+ info->new_path);
+ if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED)
+ htmlf(" (%s from %s)",
+ info->status == DIFF_STATUS_COPIED ? "copied" : "renamed",
+ info->old_path);
html("</td><td class='right'>");
htmlf("%d", info->added + info->removed);
html("</td><td class='graph'>");
@@ -145,16 +133,19 @@ void inspect_filepair(struct diff_filepair *pair)
}
-void cgit_print_commit(const char *hex)
+void cgit_print_commit(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 (!hex)
+ hex = cgit_query_head;
+ curr_rev = hex;
+
if (get_sha1(hex, sha1)) {
cgit_print_error(fmt("Bad object id: %s", hex));
return;
@@ -181,11 +172,11 @@ void cgit_print_commit(const char *hex)
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&amp;id=%s", sha1_to_hex(commit->object.sha1),
- sha1_to_hex(commit->tree->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) {
@@ -195,23 +186,19 @@ void cgit_print_commit(const char *hex)
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&amp;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>");
+ "<td colspan='2' class='sha1'>");
+ cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL,
+ cgit_query_head, sha1_to_hex(p->item->object.sha1));
+ html(" (");
+ cgit_diff_link("diff", NULL, NULL, cgit_query_head, hex,
+ sha1_to_hex(p->item->object.sha1), NULL);
+ html(")</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&amp;name=%s", hex, filename)));
- htmlf("'>%s</a></td></tr>", filename);
+ html("<tr><th>download</th><td colspan='2' class='sha1'>");
+ cgit_print_snapshot_links(cgit_query_repo, cgit_query_head,
+ hex, cgit_repo->snapshots);
+ html("</td></tr>");
}
html("</table>\n");
html("<div class='commit-subject'>");
@@ -231,10 +218,9 @@ void cgit_print_commit(const char *hex)
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>)");
- html("</div>");
+ cgit_diff_link("show diff", NULL, NULL, cgit_query_head, hex,
+ NULL, NULL);
+ html(")</div>");
}
cgit_free_commitinfo(info);
}
diff --git a/ui-diff.c b/ui-diff.c
index 4695e3a..0be845f 100644
--- a/ui-diff.c
+++ b/ui-diff.c
@@ -89,54 +89,52 @@ static void filepair_cb(struct diff_filepair *pair)
cgit_print_error("Error running diff");
}
-void cgit_print_diff(const char *head, const char *old_hex, const char *new_hex, char *path)
+void cgit_print_diff(const char *new_rev, const char *old_rev)
{
unsigned char sha1[20], sha2[20];
enum object_type type;
unsigned long size;
- struct commit *commit;
-
- if (head && !old_hex && !new_hex) {
- get_sha1(head, sha1);
- commit = lookup_commit_reference(sha1);
- if (commit && !parse_commit(commit)) {
- html("<table class='diff'>");
- html("<tr><td>");
- cgit_diff_commit(commit, filepair_cb);
- html("</td></tr>");
- html("</table>");
- }
+ struct commit *commit, *commit2;
+
+ if (!new_rev)
+ new_rev = cgit_query_head;
+ get_sha1(new_rev, sha1);
+ type = sha1_object_info(sha1, &size);
+ if (type == OBJ_BAD) {
+ cgit_print_error(fmt("Bad object name: %s", new_rev));
+ return;
+ }
+ if (type != OBJ_COMMIT) {
+ cgit_print_error(fmt("Unhandled object type: %s",
+ typename(type)));
return;
}
- get_sha1(old_hex, sha1);
- get_sha1(new_hex, sha2);
+ commit = lookup_commit_reference(sha1);
+ if (!commit || parse_commit(commit))
+ cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(sha1)));
- type = sha1_object_info(sha1, &size);
- if (type == OBJ_BAD) {
+ if (old_rev)
+ get_sha1(old_rev, sha2);
+ else if (commit->parents && commit->parents->item)
+ hashcpy(sha2, commit->parents->item->object.sha1);
+ else
+ hashclr(sha2);
+
+ if (!is_null_sha1(sha2)) {
type = sha1_object_info(sha2, &size);
if (type == OBJ_BAD) {
- cgit_print_error(fmt("Bad object names: %s, %s", old_hex, new_hex));
+ cgit_print_error(fmt("Bad object name: %s", sha1_to_hex(sha2)));
return;
}
+ commit2 = lookup_commit_reference(sha2);
+ if (!commit2 || parse_commit(commit2))
+ cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(sha2)));
}
html("<table class='diff'>");
- switch(type) {
- case OBJ_BLOB:
- html("<tr><td>");
- header(sha1, path, 0644, sha2, path, 0644);
- if (cgit_diff_files(sha1, sha2, print_line))
- cgit_print_error("Error running diff");
- html("</td></tr>");
- break;
- case OBJ_TREE:
- cgit_diff_tree(sha1, sha2, filepair_cb);
- break;
- default:
- cgit_print_error(fmt("Unhandled object type: %s",
- typename(type)));
- break;
- }
+ html("<tr><td>");
+ cgit_diff_tree(sha2, sha1, filepair_cb);
+ html("</td></tr>");
html("</table>");
}
diff --git a/ui-log.c b/ui-log.c
index bb17e1d..d38e40a 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -31,11 +31,8 @@ void print_commit(struct commit *commit)
html("<tr><td>");
cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);
html("</td><td>");
- char *qry = fmt("h=%s", sha1_to_hex(commit->object.sha1));
- char *url = cgit_pageurl(cgit_query_repo, "commit", qry);
- html_link_open(url, NULL, NULL);
- html_ntxt(cgit_max_msg_len, info->subject);
- html_link_close();
+ cgit_commit_link(info->subject, NULL, NULL, cgit_query_head,
+ sha1_to_hex(commit->object.sha1));
if (cgit_repo->enable_log_filecount) {
files = 0;
lines = 0;
@@ -62,6 +59,9 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path, i
int argc = 2;
int i;
+ if (!tip)
+ argv[1] = cgit_query_head;
+
if (grep)
argv[argc++] = fmt("--grep=%s", grep);
if (path) {
@@ -113,17 +113,15 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path, i
if (pager) {
html("<div class='pager'>");
if (ofs > 0) {
- html("&nbsp;<a href='");
- html(cgit_pageurl(cgit_query_repo, cgit_query_page,
- fmt("h=%s&amp;ofs=%d", tip, ofs-cnt)));
- html("'>[prev]</a>&nbsp;");
+ cgit_log_link("[prev]", NULL, NULL, cgit_query_head,
+ cgit_query_sha1, cgit_query_path,
+ ofs - cnt);
+ html("&nbsp;");
}
-
if ((commit = get_revision(&rev)) != NULL) {
- html("&nbsp;<a href='");
- html(cgit_pageurl(cgit_query_repo, "log",
- fmt("h=%s&amp;ofs=%d", tip, ofs+cnt)));
- html("'>[next]</a>&nbsp;");
+ 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 e5c6c20..4c86543 100644
--- a/ui-repolist.c
+++ b/ui-repolist.c
@@ -44,16 +44,19 @@ static void print_modtime(struct repoinfo *repo)
void cgit_print_repolist(struct cacheitem *item)
{
- struct repoinfo *repo;
- 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>");
}
@@ -61,42 +64,45 @@ void cgit_print_repolist(struct cacheitem *item)
"<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++) {
- 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))) {
- html("<tr class='nohover'><td colspan='4' class='repogroup'>");
- html_txt(repo->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))) {
+ htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>",
+ columns);
+ 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("</td><td>");
- html_txt(repo->owner);
+ html_ntxt(cgit_max_repodesc_len, cgit_repo->desc);
html("</td><td>");
- print_modtime(repo);
+ html_txt(cgit_repo->owner);
html("</td><td>");
- html_link_open(cgit_repourl(repo->url),
- "Summary", "button");
- html("S</a>");
- html_link_open(cgit_pageurl(repo->name, "log", NULL),
- "Log", "button");
- html("L</a>");
- html_link_open(cgit_pageurl(repo->name, "tree", NULL),
- "Files", "button");
- html("F</a>");
- html("</td></tr>\n");
+ print_modtime(cgit_repo);
+ html("</td>");
+ if (cgit_enable_index_links) {
+ html("<td>");
+ html_link_open(cgit_repourl(cgit_repo->url),
+ 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 aba93e8..5c5bcf3 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -57,13 +57,13 @@ char *cgit_repourl(const char *reponame)
}
}
-char *cgit_pageurl(const char *reponame, const char *pagename,
- const char *query)
+char *cgit_fileurl(const char *reponame, const char *pagename,
+ const char *filename, const char *query)
{
if (cgit_virtual_root) {
if (query)
- return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame,
- pagename, query);
+ return fmt("%s/%s/%s/%s?%s", cgit_virtual_root, reponame,
+ pagename, filename?filename:"", query);
else
return fmt("%s/%s/%s/", cgit_virtual_root, reponame,
pagename);
@@ -75,6 +75,37 @@ char *cgit_pageurl(const char *reponame, const char *pagename,
}
}
+char *cgit_pageurl(const char *reponame, const char *pagename,
+ const char *query)
+{
+ return cgit_fileurl(reponame,pagename,0,query);
+}
+
+const char *cgit_repobasename(const char *reponame)
+{
+ /* I assume we don't need to store more than one repo basename */
+ static char rvbuf[1024];
+ int p;
+ const char *rv;
+ strncpy(rvbuf,reponame,sizeof(rvbuf));
+ if(rvbuf[sizeof(rvbuf)-1])
+ die("cgit_repobasename: truncated repository name '%s'", reponame);
+ p = strlen(rvbuf)-1;
+ /* strip trailing slashes */
+ while(p && rvbuf[p]=='/') rvbuf[p--]=0;
+ /* strip trailing .git */
+ if(p>=3 && !strncmp(&rvbuf[p-3],".git",4)) {
+ p -= 3; rvbuf[p--] = 0;
+ }
+ /* strip more trailing slashes if any */
+ while( p && rvbuf[p]=='/') rvbuf[p--]=0;
+ /* find last slash in the remaining string */
+ rv = strrchr(rvbuf,'/');
+ if(rv)
+ return ++rv;
+ return rvbuf;
+}
+
char *cgit_currurl()
{
if (!cgit_virtual_root)
@@ -87,6 +118,166 @@ char *cgit_currurl()
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("/");
+ 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 = "&amp;";
+ }
+ if (head && strcmp(head, cgit_repo->defbranch)) {
+ html(delim);
+ html("h=");
+ html_attr(head);
+ delim = "&amp;";
+ }
+ return fmt("%s", delim);
+}
+
+static void reporevlink(char *page, char *name, char *title, char *class,
+ char *head, char *rev, char *path)
+{
+ char *delim;
+
+ delim = repolink(title, class, page, head, path);
+ if (rev && strcmp(rev, cgit_query_head)) {
+ html(delim);
+ html("id=");
+ html_attr(rev);
+ }
+ 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, 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_snapshot_link(char *name, char *title, char *class, char *head,
+ char *rev, char *archivename)
+{
+ reporevlink("snapshot", name, title, class, head, rev, archivename);
+}
+
+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)
{
@@ -152,7 +343,7 @@ void cgit_print_docstart(char *title, struct cacheitem *item)
html("<title>");
html_txt(title);
html("</title>\n");
- htmlf("<meta name='generator' content='cgit v%s'/>\n", cgit_version);
+ htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version);
html("<link rel='stylesheet' type='text/css' href='");
html_attr(cgit_css);
html("'/>\n");
@@ -169,19 +360,38 @@ void cgit_print_docend()
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(") : &nbsp;");
+ 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'>");
@@ -219,3 +429,5 @@ void cgit_print_snapshot_start(const char *mimetype, const char *filename,
ttl_seconds(item->ttl)));
html("\n");
}
+
+/* vim:set sw=8: */
diff --git a/ui-snapshot.c b/ui-snapshot.c
index 2257d6b..bd34a28 100644
--- a/ui-snapshot.c
+++ b/ui-snapshot.c
@@ -8,40 +8,148 @@
#include "cgit.h"
-static void cgit_print_zip(struct cacheitem *item, const char *hex,
- const char *prefix, const char *filename)
+static int write_compressed_tar_archive(struct archiver_args *args,const char *filter)
{
+ int rw[2];
+ pid_t gzpid;
+ int stdout2;
+ int status;
+ int rv;
+
+ stdout2 = chk_non_negative(dup(STDIN_FILENO), "Preserving STDOUT before compressing");
+ chk_zero(pipe(rw), "Opening pipe from compressor subprocess");
+ gzpid = chk_non_negative(fork(), "Forking compressor subprocess");
+ if(gzpid==0) {
+ /* child */
+ chk_zero(close(rw[1]), "Closing write end of pipe in child");
+ chk_zero(close(STDIN_FILENO), "Closing STDIN");
+ chk_non_negative(dup2(rw[0],STDIN_FILENO), "Redirecting compressor input to stdin");
+ execlp(filter,filter,NULL);
+ _exit(-1);
+ }
+ /* parent */
+ chk_zero(close(rw[0]), "Closing read end of pipe");
+ chk_non_negative(dup2(rw[1],STDOUT_FILENO), "Redirecting output to compressor");
+
+ rv = write_tar_archive(args);
+
+ chk_zero(close(STDOUT_FILENO), "Closing STDOUT redirected to compressor");
+ chk_non_negative(dup2(stdout2,STDOUT_FILENO), "Restoring uncompressed STDOUT");
+ chk_zero(close(stdout2), "Closing uncompressed STDOUT");
+ chk_zero(close(rw[1]), "Closing write end of pipe in parent");
+ chk_positive(waitpid(gzpid,&status,0), "Waiting on compressor process");
+ if(! ( WIFEXITED(status) && WEXITSTATUS(status)==0 ) )
+ cgit_print_error("Failed to compress archive");
+
+ return rv;
+}
+
+static int write_tar_gzip_archive(struct archiver_args *args)
+{
+ return write_compressed_tar_archive(args,"gzip");
+}
+
+static int write_tar_bzip2_archive(struct archiver_args *args)
+{
+ return write_compressed_tar_archive(args,"bzip2");
+}
+
+static const struct snapshot_archive_t {
+ const char *suffix;
+ const char *mimetype;
+ write_archive_fn_t write_func;
+ int bit;
+} snapshot_archives[] = {
+ { ".zip", "application/x-zip", write_zip_archive, 0x1 },
+ { ".tar.gz", "application/x-tar", write_tar_gzip_archive, 0x2 },
+ { ".tar.bz2", "application/x-tar", write_tar_bzip2_archive, 0x4 },
+ { ".tar", "application/x-tar", write_tar_archive, 0x8 }
+};
+
+#define snapshot_archives_len (sizeof(snapshot_archives) / sizeof(*snapshot_archives))
+
+void cgit_print_snapshot(struct cacheitem *item, const char *head,
+ const char *hex, const char *prefix,
+ const char *filename, int snapshots)
+{
+ const struct snapshot_archive_t* sat;
struct archiver_args args;
struct commit *commit;
unsigned char sha1[20];
+ int f, sl, fnl = strlen(filename);
- if (get_sha1(hex, sha1)) {
- cgit_print_error(fmt("Bad object id: %s", hex));
+ for(f=0; f<snapshot_archives_len; f++) {
+ sat = &snapshot_archives[f];
+ if(!(snapshots & sat->bit))
+ continue;
+ sl = strlen(sat->suffix);
+ if(fnl<sl || strcmp(&filename[fnl-sl],sat->suffix))
+ continue;
+ if (!hex)
+ hex = head;
+ 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("Not a commit reference: %s", hex));
+ return;;
+ }
+ memset(&args,0,sizeof(args));
+ args.base = fmt("%s/", prefix);
+ args.tree = commit->tree;
+ cgit_print_snapshot_start(sat->mimetype, filename, item);
+ (*sat->write_func)(&args);
return;
}
- commit = lookup_commit_reference(sha1);
+ cgit_print_error(fmt("Unsupported snapshot format: %s", filename));
+}
- if (!commit) {
- cgit_print_error(fmt("Not a commit reference: %s", hex));
- return;
- }
+void cgit_print_snapshot_links(const char *repo, const char *head,
+ const char *hex, int snapshots)
+{
+ const struct snapshot_archive_t* sat;
+ char *filename;
+ int f;
- memset(&args, 0, sizeof(args));
- args.base = fmt("%s/", prefix);
- args.tree = commit->tree;
-
- cgit_print_snapshot_start("application/x-zip", filename, item);
- write_zip_archive(&args);
+ for(f=0; f<snapshot_archives_len; f++) {
+ sat = &snapshot_archives[f];
+ if(!(snapshots & sat->bit))
+ continue;
+ filename = fmt("%s-%s%s", cgit_repobasename(repo), hex,
+ sat->suffix);
+ cgit_snapshot_link(filename, NULL, NULL, (char *)head,
+ (char *)hex, filename);
+ html("<br/>");
+ }
}
-
-void cgit_print_snapshot(struct cacheitem *item, const char *hex,
- const char *format, const char *prefix,
- const char *filename)
+int cgit_parse_snapshots_mask(const char *str)
{
- if (!strcmp(format, "zip"))
- cgit_print_zip(item, hex, prefix, filename);
- else
- cgit_print_error(fmt("Unsupported snapshot format: %s",
- format));
+ const struct snapshot_archive_t* sat;
+ static const char *delim = " \t,:/|;";
+ int f, tl, rv = 0;
+
+ /* favor legacy setting */
+ if(atoi(str))
+ return 1;
+ for(;;) {
+ str += strspn(str,delim);
+ tl = strcspn(str,delim);
+ if(!tl)
+ break;
+ for(f=0; f<snapshot_archives_len; f++) {
+ sat = &snapshot_archives[f];
+ if(!(strncmp(sat->suffix, str, tl) &&
+ strncmp(sat->suffix+1, str, tl-1))) {
+ rv |= sat->bit;
+ break;
+ }
+ }
+ str += tl;
+ }
+ return rv;
}
+
+/* vim:set sw=8: */
diff --git a/ui-summary.c b/ui-summary.c
index 4bda4c2..de8a180 100644
--- a/ui-summary.c
+++ b/ui-summary.c
@@ -15,8 +15,10 @@ static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1,
{
struct commit *commit;
struct commitinfo *info;
- char buf[256], *url;
+ 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
@@ -25,21 +27,13 @@ static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1,
if (commit && !parse_commit(commit)){
info = cgit_parse_commit(commit);
html("<tr><td>");
- url = cgit_pageurl(cgit_query_repo, "log",
- fmt("h=%s", refname));
- html_link_open(url, NULL, NULL);
- html_txt(buf);
- html_link_close();
+ 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>");
- url = cgit_pageurl(cgit_query_repo, "commit",
- fmt("h=%s", sha1_to_hex(sha1)));
- html_link_open(url, NULL, NULL);
- html_ntxt(cgit_max_msg_len, info->subject);
- html_link_close();
+ cgit_commit_link(info->subject, NULL, NULL, ref, NULL);
html("</td></tr>\n");
cgit_free_commitinfo(info);
} else {
@@ -49,33 +43,10 @@ static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1,
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) {
- page = "commit";
- arg = "h";
- } 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>"
@@ -104,8 +75,8 @@ static int cgit_print_tag_cb(const char *refname, const unsigned char *sha1,
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();
@@ -116,7 +87,7 @@ static int cgit_print_tag_cb(const char *refname, const unsigned char *sha1,
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)
@@ -124,7 +95,7 @@ static int cgit_print_tag_cb(const char *refname, const unsigned char *sha1,
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;
diff --git a/ui-tag.c b/ui-tag.c
new file mode 100644
index 0000000..6d761f3
--- /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;
+}
diff --git a/ui-tree.c b/ui-tree.c
index 21dd533..1cb09f7 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -9,16 +9,64 @@
#include "cgit.h"
char *curr_rev;
+char *match_path;
+int header = 0;
-static int print_entry(const unsigned char *sha1, const char *base,
- int baselen, const char *pathname, unsigned int mode,
- int stage)
+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(" blob: <a href='");
+ html_attr(cgit_pageurl(cgit_query_repo, "blob", fmt("id=%s", sha1_to_hex(sha1))));
+ htmlf("'>%s</a>",sha1_to_hex(sha1));
+
+ 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'><a name='%d'>%1$d</a></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;
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_ISGITLINK(mode)) {
htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>",
@@ -26,79 +74,140 @@ static int print_entry(const unsigned char *sha1, const char *base,
sha1_to_hex(sha1));
return 0;
}
- html("<tr><td class='filemode'>");
+
+ html("<tr><td class='ls-mode'>");
html_filemode(mode);
- html("</td><td ");
+ html("</td><td>");
if (S_ISGITLINK(mode)) {
- htmlf("class='ls-mod'><a href='");
+ htmlf("<a class='ls-mod' 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(cgit_pageurl(cgit_query_repo, "tree",
- fmt("h=%s&amp;id=%s&amp;path=%s%s/",
- curr_rev,
- sha1_to_hex(sha1),
- cgit_query_path ? cgit_query_path : "",
- pathname)));
+ cgit_tree_link(name, NULL, "ls-dir", cgit_query_head,
+ curr_rev, fullpath);
} else {
- html("class='ls-blob'><a href='");
- html_attr(cgit_pageurl(cgit_query_repo, "view",
- fmt("h=%s&amp;id=%s&amp;path=%s%s", curr_rev,
- sha1_to_hex(sha1),
- cgit_query_path ? cgit_query_path : "",
- pathname)));
+ cgit_tree_link(name, NULL, "ls-blob", cgit_query_head,
+ curr_rev, fullpath);
}
- htmlf("'>%s</a></td>", name);
- htmlf("<td class='filesize'>%li</td>", size);
-
- html("<td class='links'><a href='");
- html_attr(cgit_pageurl(cgit_query_repo, "log",
- fmt("h=%s&amp;path=%s%s",
- curr_rev,
- cgit_query_path ? cgit_query_path : "",
- pathname)));
- html("'>history</a></td>");
- html("</tr>\n");
+ htmlf("</td><td class='ls-size'>%li</td>", size);
+
+ html("<td>");
+ cgit_log_link("log", NULL, "button", cgit_query_head, curr_rev,
+ fullpath, 0);
+ html("</td></tr>\n");
free(name);
return 0;
}
-void cgit_print_tree(const char *rev, const char *hex, char *path)
+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&amp;path=%s", curr_rev, buffer));
+ 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);
- get_sha1(rev, sha1);
+ 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 head: %s", rev));
+ cgit_print_error(fmt("Invalid commit reference: %s", rev));
return;
}
- if (!hex)
- hex = sha1_to_hex(commit->tree->object.sha1);
- if (get_sha1_hex(hex, sha1)) {
- cgit_print_error(fmt("Invalid object id: %s", hex));
- return;
- }
- tree = parse_tree_indirect(sha1);
- if (!tree) {
- cgit_print_error(fmt("Not a tree object: %s", hex));
+ html("path: <a href='");
+ html_attr(cgit_pageurl(cgit_query_repo, "tree", fmt("h=%s", rev)));
+ html("'>root</a>");
+
+ if (path == NULL) {
+ ls_tree(commit->tree->object.sha1, NULL);
return;
}
- html_txt(path);
- 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");
- read_tree_recursive(tree, "", 0, 1, NULL, print_entry);
- html("</table>\n");
+ match_path = path;
+ read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree);
+ ls_tail();
}
diff --git a/ui-view.c b/ui-view.c
deleted file mode 100644
index 8873415..0000000
--- a/ui-view.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/* ui-view.c: functions to output _any_ object, given it's sha1
- *
- * Copyright (C) 2006 Lars Hjemli
- *
- * Licensed under GNU General Public License v2
- * (see COPYING for full license text)
- */
-
-#include "cgit.h"
-
-void cgit_print_view(const char *hex, char *path)
-{
- unsigned char sha1[20];
- enum object_type type;
- unsigned char *buf;
- unsigned long size;
-
- if (get_sha1_hex(hex, sha1)){
- cgit_print_error(fmt("Bad hex value: %s", hex));
- return;
- }
-
- type = sha1_object_info(sha1, &size);
- if (type == OBJ_BAD) {
- cgit_print_error(fmt("Bad object name: %s", hex));
- return;
- }
-
- buf = read_sha1_file(sha1, &type, &size);
- if (!buf) {
- cgit_print_error(fmt("Error reading object %s", hex));
- return;
- }
-
- buf[size] = '\0';
- html("<table class='list'>\n");
- html("<tr class='nohover'><th class='left'>");
- if (path)
- htmlf("%s (", path);
- htmlf("%s %s, %li bytes", typename(type), hex, size);
- if (path)
- html(")");
-
- html(" <a href='");
- html_attr(cgit_pageurl(cgit_query_repo, "blob",
- fmt("id=%s&amp;path=%s",
- hex,
- path)));
- html("'>download</a>");
- html("</th></tr>\n");
- html("<tr><td class='blob'>\n");
- html_txt(buf);
- html("\n</td></tr>\n");
- html("</table>\n");
-}