mirror of
https://git.zx2c4.com/cgit
synced 2024-11-25 18:08:41 +00:00
Merge branch 'lh/cleanup'
* lh/cleanup: (21 commits) Reset ctx.repo to NULL when the config parser is finished Move cgit_parse_query() from parsing.c to html.c as http_parse_querystring() Move function for configfile parsing into configfile.[ch] Add cache.h Remove global and obsolete cgit_cmd Makefile: copy the QUIET constructs from the Makefile in git.git Move cgit_version from shared.c to cgit.c Makefile: autobuild dependency rules Initial Makefile cleanup Move non-generic functions from shared.c to cgit.c Add ui-shared.h Add separate header-files for each page/view Refactor snapshot support Add command dispatcher Remove obsolete cacheitem parameter to ui-functions Add struct cgit_page to cgit_context Introduce html.h Improve initialization of git directory Move cgit_repo into cgit_context Add all config variables into struct cgit_context ...
This commit is contained in:
commit
23296ad648
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ cgit
|
|||||||
cgit.conf
|
cgit.conf
|
||||||
VERSION
|
VERSION
|
||||||
*.o
|
*.o
|
||||||
|
*.d
|
||||||
|
75
Makefile
75
Makefile
@ -12,12 +12,61 @@ GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2
|
|||||||
#
|
#
|
||||||
-include cgit.conf
|
-include cgit.conf
|
||||||
|
|
||||||
|
#
|
||||||
|
# Define a way to invoke make in subdirs quietly, shamelessly ripped
|
||||||
|
# from git.git
|
||||||
|
#
|
||||||
|
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
|
||||||
|
QUIET_SUBDIR1 =
|
||||||
|
|
||||||
|
ifneq ($(findstring $(MAKEFLAGS),w),w)
|
||||||
|
PRINT_DIR = --no-print-directory
|
||||||
|
else # "make -w"
|
||||||
|
NO_SUBDIR = :
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef V
|
||||||
|
QUIET_CC = @echo ' ' CC $@;
|
||||||
|
QUIET_MM = @echo ' ' MM $@;
|
||||||
|
QUIET_SUBDIR0 = +@subdir=
|
||||||
|
QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
|
||||||
|
$(MAKE) $(PRINT_DIR) -C $$subdir
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# Define a pattern rule for automatic dependency building
|
||||||
|
#
|
||||||
|
%.d: %.c
|
||||||
|
$(QUIET_MM)$(CC) $(CFLAGS) -MM $< | sed -e 's/\($*\)\.o:/\1.o $@:/g' >$@
|
||||||
|
|
||||||
|
#
|
||||||
|
# Define a pattern rule for silent object building
|
||||||
|
#
|
||||||
|
%.o: %.c
|
||||||
|
$(QUIET_CC)$(CC) -o $*.o -c $(CFLAGS) $<
|
||||||
|
|
||||||
|
|
||||||
EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lcrypto
|
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 \
|
OBJECTS =
|
||||||
ui-summary.o ui-log.o ui-tree.o ui-commit.o ui-diff.o \
|
OBJECTS += cache.o
|
||||||
ui-snapshot.o ui-blob.o ui-tag.o ui-refs.o ui-patch.o
|
OBJECTS += cgit.o
|
||||||
|
OBJECTS += cmd.o
|
||||||
|
OBJECTS += configfile.o
|
||||||
|
OBJECTS += html.o
|
||||||
|
OBJECTS += parsing.o
|
||||||
|
OBJECTS += shared.o
|
||||||
|
OBJECTS += ui-blob.o
|
||||||
|
OBJECTS += ui-commit.o
|
||||||
|
OBJECTS += ui-diff.o
|
||||||
|
OBJECTS += ui-log.o
|
||||||
|
OBJECTS += ui-patch.o
|
||||||
|
OBJECTS += ui-refs.o
|
||||||
|
OBJECTS += ui-repolist.o
|
||||||
|
OBJECTS += ui-shared.o
|
||||||
|
OBJECTS += ui-snapshot.o
|
||||||
|
OBJECTS += ui-summary.o
|
||||||
|
OBJECTS += ui-tag.o
|
||||||
|
OBJECTS += ui-tree.o
|
||||||
|
|
||||||
ifdef NEEDS_LIBICONV
|
ifdef NEEDS_LIBICONV
|
||||||
EXTLIBS += -liconv
|
EXTLIBS += -liconv
|
||||||
@ -41,21 +90,25 @@ CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"'
|
|||||||
CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"'
|
CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"'
|
||||||
|
|
||||||
|
|
||||||
cgit: cgit.c $(OBJECTS)
|
cgit: $(OBJECTS)
|
||||||
$(CC) $(CFLAGS) cgit.c -o cgit $(OBJECTS) $(EXTLIBS)
|
$(QUIET_CC)$(CC) $(CFLAGS) -o cgit $(OBJECTS) $(EXTLIBS)
|
||||||
|
|
||||||
$(OBJECTS): cgit.h git/xdiff/lib.a git/libgit.a VERSION
|
$(OBJECTS): git/xdiff/lib.a git/libgit.a
|
||||||
|
|
||||||
|
cgit.o: VERSION
|
||||||
|
|
||||||
|
-include $(OBJECTS:.o=.d)
|
||||||
|
|
||||||
git/xdiff/lib.a: | git
|
git/xdiff/lib.a: | git
|
||||||
|
|
||||||
git/libgit.a: | git
|
git/libgit.a: | git
|
||||||
|
|
||||||
git:
|
git:
|
||||||
cd git && $(MAKE) xdiff/lib.a
|
$(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) xdiff/lib.a
|
||||||
cd git && $(MAKE) libgit.a
|
$(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) libgit.a
|
||||||
|
|
||||||
test: all
|
test: all
|
||||||
$(MAKE) -C tests
|
$(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
mkdir -p $(DESTDIR)$(CGIT_SCRIPT_PATH)
|
mkdir -p $(DESTDIR)$(CGIT_SCRIPT_PATH)
|
||||||
@ -69,7 +122,7 @@ uninstall:
|
|||||||
rm -f $(CGIT_SCRIPT_PATH)/cgit.png
|
rm -f $(CGIT_SCRIPT_PATH)/cgit.png
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f cgit VERSION *.o
|
rm -f cgit VERSION *.o *.d
|
||||||
cd git && $(MAKE) clean
|
cd git && $(MAKE) clean
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
|
21
cache.c
21
cache.c
@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
#include "cache.h"
|
||||||
|
|
||||||
const int NOLOCK = -1;
|
const int NOLOCK = -1;
|
||||||
|
|
||||||
@ -44,23 +45,23 @@ int cache_create_dirs()
|
|||||||
{
|
{
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
path = fmt("%s", cgit_cache_root);
|
path = fmt("%s", ctx.cfg.cache_root);
|
||||||
if (mkdir(path, S_IRWXU) && errno!=EEXIST)
|
if (mkdir(path, S_IRWXU) && errno!=EEXIST)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!cgit_repo)
|
if (!ctx.repo)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
path = fmt("%s/%s", cgit_cache_root,
|
path = fmt("%s/%s", ctx.cfg.cache_root,
|
||||||
cache_safe_filename(cgit_repo->url));
|
cache_safe_filename(ctx.repo->url));
|
||||||
|
|
||||||
if (mkdir(path, S_IRWXU) && errno!=EEXIST)
|
if (mkdir(path, S_IRWXU) && errno!=EEXIST)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (cgit_query_page) {
|
if (ctx.qry.page) {
|
||||||
path = fmt("%s/%s/%s", cgit_cache_root,
|
path = fmt("%s/%s/%s", ctx.cfg.cache_root,
|
||||||
cache_safe_filename(cgit_repo->url),
|
cache_safe_filename(ctx.repo->url),
|
||||||
cgit_query_page);
|
ctx.qry.page);
|
||||||
if (mkdir(path, S_IRWXU) && errno!=EEXIST)
|
if (mkdir(path, S_IRWXU) && errno!=EEXIST)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -74,7 +75,7 @@ int cache_refill_overdue(const char *lockfile)
|
|||||||
if (stat(lockfile, &st))
|
if (stat(lockfile, &st))
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return (time(NULL) - st.st_mtime > cgit_cache_max_create_time);
|
return (time(NULL) - st.st_mtime > ctx.cfg.cache_max_create_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cache_lock(struct cacheitem *item)
|
int cache_lock(struct cacheitem *item)
|
||||||
@ -83,7 +84,7 @@ int cache_lock(struct cacheitem *item)
|
|||||||
char *lockfile = xstrdup(fmt("%s.lock", item->name));
|
char *lockfile = xstrdup(fmt("%s.lock", item->name));
|
||||||
|
|
||||||
top:
|
top:
|
||||||
if (++i > cgit_max_lock_attempts)
|
if (++i > ctx.cfg.max_lock_attempts)
|
||||||
die("cache_lock: unable to lock %s: %s",
|
die("cache_lock: unable to lock %s: %s",
|
||||||
item->name, strerror(errno));
|
item->name, strerror(errno));
|
||||||
|
|
||||||
|
23
cache.h
Normal file
23
cache.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Since git has it's own cache.h which we include,
|
||||||
|
* lets test on CGIT_CACHE_H to avoid confusion
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CGIT_CACHE_H
|
||||||
|
#define CGIT_CACHE_H
|
||||||
|
|
||||||
|
struct cacheitem {
|
||||||
|
char *name;
|
||||||
|
struct stat st;
|
||||||
|
int ttl;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
#endif /* CGIT_CACHE_H */
|
397
cgit.c
397
cgit.c
@ -7,40 +7,199 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
#include "cache.h"
|
||||||
|
#include "cmd.h"
|
||||||
|
#include "configfile.h"
|
||||||
|
#include "html.h"
|
||||||
|
#include "ui-shared.h"
|
||||||
|
|
||||||
|
const char *cgit_version = CGIT_VERSION;
|
||||||
|
|
||||||
|
void config_cb(const char *name, const char *value)
|
||||||
|
{
|
||||||
|
if (!strcmp(name, "root-title"))
|
||||||
|
ctx.cfg.root_title = xstrdup(value);
|
||||||
|
else if (!strcmp(name, "css"))
|
||||||
|
ctx.cfg.css = xstrdup(value);
|
||||||
|
else if (!strcmp(name, "logo"))
|
||||||
|
ctx.cfg.logo = xstrdup(value);
|
||||||
|
else if (!strcmp(name, "index-header"))
|
||||||
|
ctx.cfg.index_header = xstrdup(value);
|
||||||
|
else if (!strcmp(name, "index-info"))
|
||||||
|
ctx.cfg.index_info = xstrdup(value);
|
||||||
|
else if (!strcmp(name, "logo-link"))
|
||||||
|
ctx.cfg.logo_link = xstrdup(value);
|
||||||
|
else if (!strcmp(name, "module-link"))
|
||||||
|
ctx.cfg.module_link = xstrdup(value);
|
||||||
|
else if (!strcmp(name, "virtual-root")) {
|
||||||
|
ctx.cfg.virtual_root = trim_end(value, '/');
|
||||||
|
if (!ctx.cfg.virtual_root && (!strcmp(value, "/")))
|
||||||
|
ctx.cfg.virtual_root = "";
|
||||||
|
} else if (!strcmp(name, "nocache"))
|
||||||
|
ctx.cfg.nocache = atoi(value);
|
||||||
|
else if (!strcmp(name, "snapshots"))
|
||||||
|
ctx.cfg.snapshots = cgit_parse_snapshots_mask(value);
|
||||||
|
else if (!strcmp(name, "enable-index-links"))
|
||||||
|
ctx.cfg.enable_index_links = atoi(value);
|
||||||
|
else if (!strcmp(name, "enable-log-filecount"))
|
||||||
|
ctx.cfg.enable_log_filecount = atoi(value);
|
||||||
|
else if (!strcmp(name, "enable-log-linecount"))
|
||||||
|
ctx.cfg.enable_log_linecount = atoi(value);
|
||||||
|
else if (!strcmp(name, "cache-root"))
|
||||||
|
ctx.cfg.cache_root = xstrdup(value);
|
||||||
|
else if (!strcmp(name, "cache-root-ttl"))
|
||||||
|
ctx.cfg.cache_root_ttl = atoi(value);
|
||||||
|
else if (!strcmp(name, "cache-repo-ttl"))
|
||||||
|
ctx.cfg.cache_repo_ttl = atoi(value);
|
||||||
|
else if (!strcmp(name, "cache-static-ttl"))
|
||||||
|
ctx.cfg.cache_static_ttl = atoi(value);
|
||||||
|
else if (!strcmp(name, "cache-dynamic-ttl"))
|
||||||
|
ctx.cfg.cache_dynamic_ttl = atoi(value);
|
||||||
|
else if (!strcmp(name, "max-message-length"))
|
||||||
|
ctx.cfg.max_msg_len = atoi(value);
|
||||||
|
else if (!strcmp(name, "max-repodesc-length"))
|
||||||
|
ctx.cfg.max_repodesc_len = atoi(value);
|
||||||
|
else if (!strcmp(name, "max-commit-count"))
|
||||||
|
ctx.cfg.max_commit_count = atoi(value);
|
||||||
|
else if (!strcmp(name, "summary-log"))
|
||||||
|
ctx.cfg.summary_log = atoi(value);
|
||||||
|
else if (!strcmp(name, "summary-branches"))
|
||||||
|
ctx.cfg.summary_branches = atoi(value);
|
||||||
|
else if (!strcmp(name, "summary-tags"))
|
||||||
|
ctx.cfg.summary_tags = atoi(value);
|
||||||
|
else if (!strcmp(name, "agefile"))
|
||||||
|
ctx.cfg.agefile = xstrdup(value);
|
||||||
|
else if (!strcmp(name, "renamelimit"))
|
||||||
|
ctx.cfg.renamelimit = atoi(value);
|
||||||
|
else if (!strcmp(name, "robots"))
|
||||||
|
ctx.cfg.robots = xstrdup(value);
|
||||||
|
else if (!strcmp(name, "clone-prefix"))
|
||||||
|
ctx.cfg.clone_prefix = xstrdup(value);
|
||||||
|
else if (!strcmp(name, "repo.group"))
|
||||||
|
ctx.cfg.repo_group = xstrdup(value);
|
||||||
|
else if (!strcmp(name, "repo.url"))
|
||||||
|
ctx.repo = cgit_add_repo(value);
|
||||||
|
else if (!strcmp(name, "repo.name"))
|
||||||
|
ctx.repo->name = xstrdup(value);
|
||||||
|
else if (ctx.repo && !strcmp(name, "repo.path"))
|
||||||
|
ctx.repo->path = trim_end(value, '/');
|
||||||
|
else if (ctx.repo && !strcmp(name, "repo.clone-url"))
|
||||||
|
ctx.repo->clone_url = xstrdup(value);
|
||||||
|
else if (ctx.repo && !strcmp(name, "repo.desc"))
|
||||||
|
ctx.repo->desc = xstrdup(value);
|
||||||
|
else if (ctx.repo && !strcmp(name, "repo.owner"))
|
||||||
|
ctx.repo->owner = xstrdup(value);
|
||||||
|
else if (ctx.repo && !strcmp(name, "repo.defbranch"))
|
||||||
|
ctx.repo->defbranch = xstrdup(value);
|
||||||
|
else if (ctx.repo && !strcmp(name, "repo.snapshots"))
|
||||||
|
ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */
|
||||||
|
else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount"))
|
||||||
|
ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
|
||||||
|
else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount"))
|
||||||
|
ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
|
||||||
|
else if (ctx.repo && !strcmp(name, "repo.module-link"))
|
||||||
|
ctx.repo->module_link= xstrdup(value);
|
||||||
|
else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) {
|
||||||
|
if (*value == '/')
|
||||||
|
ctx.repo->readme = xstrdup(value);
|
||||||
|
else
|
||||||
|
ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value));
|
||||||
|
} else if (!strcmp(name, "include"))
|
||||||
|
parse_configfile(value, config_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void querystring_cb(const char *name, const char *value)
|
||||||
|
{
|
||||||
|
if (!strcmp(name,"r")) {
|
||||||
|
ctx.qry.repo = xstrdup(value);
|
||||||
|
ctx.repo = cgit_get_repoinfo(value);
|
||||||
|
} else if (!strcmp(name, "p")) {
|
||||||
|
ctx.qry.page = xstrdup(value);
|
||||||
|
} else if (!strcmp(name, "url")) {
|
||||||
|
cgit_parse_url(value);
|
||||||
|
} else if (!strcmp(name, "qt")) {
|
||||||
|
ctx.qry.grep = xstrdup(value);
|
||||||
|
} else if (!strcmp(name, "q")) {
|
||||||
|
ctx.qry.search = xstrdup(value);
|
||||||
|
} else if (!strcmp(name, "h")) {
|
||||||
|
ctx.qry.head = xstrdup(value);
|
||||||
|
ctx.qry.has_symref = 1;
|
||||||
|
} else if (!strcmp(name, "id")) {
|
||||||
|
ctx.qry.sha1 = xstrdup(value);
|
||||||
|
ctx.qry.has_sha1 = 1;
|
||||||
|
} else if (!strcmp(name, "id2")) {
|
||||||
|
ctx.qry.sha2 = xstrdup(value);
|
||||||
|
ctx.qry.has_sha1 = 1;
|
||||||
|
} else if (!strcmp(name, "ofs")) {
|
||||||
|
ctx.qry.ofs = atoi(value);
|
||||||
|
} else if (!strcmp(name, "path")) {
|
||||||
|
ctx.qry.path = trim_end(value, '/');
|
||||||
|
} else if (!strcmp(name, "name")) {
|
||||||
|
ctx.qry.name = xstrdup(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prepare_context(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
|
memset(ctx, 0, sizeof(ctx));
|
||||||
|
ctx->cfg.agefile = "info/web/last-modified";
|
||||||
|
ctx->cfg.cache_dynamic_ttl = 5;
|
||||||
|
ctx->cfg.cache_max_create_time = 5;
|
||||||
|
ctx->cfg.cache_repo_ttl = 5;
|
||||||
|
ctx->cfg.cache_root = CGIT_CACHE_ROOT;
|
||||||
|
ctx->cfg.cache_root_ttl = 5;
|
||||||
|
ctx->cfg.cache_static_ttl = -1;
|
||||||
|
ctx->cfg.css = "/cgit.css";
|
||||||
|
ctx->cfg.logo = "/git-logo.png";
|
||||||
|
ctx->cfg.max_commit_count = 50;
|
||||||
|
ctx->cfg.max_lock_attempts = 5;
|
||||||
|
ctx->cfg.max_msg_len = 60;
|
||||||
|
ctx->cfg.max_repodesc_len = 60;
|
||||||
|
ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
|
||||||
|
ctx->cfg.renamelimit = -1;
|
||||||
|
ctx->cfg.robots = "index, nofollow";
|
||||||
|
ctx->cfg.root_title = "Git repository browser";
|
||||||
|
ctx->cfg.script_name = CGIT_SCRIPT_NAME;
|
||||||
|
ctx->page.mimetype = "text/html";
|
||||||
|
ctx->page.charset = PAGE_ENCODING;
|
||||||
|
ctx->page.filename = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int cgit_prepare_cache(struct cacheitem *item)
|
static int cgit_prepare_cache(struct cacheitem *item)
|
||||||
{
|
{
|
||||||
if (!cgit_repo && cgit_query_repo) {
|
if (!ctx.repo && ctx.qry.repo) {
|
||||||
char *title = fmt("%s - %s", cgit_root_title, "Bad request");
|
ctx.page.title = fmt("%s - %s", ctx.cfg.root_title,
|
||||||
cgit_print_docstart(title, item);
|
"Bad request");
|
||||||
cgit_print_pageheader(title, 0);
|
cgit_print_http_headers(&ctx);
|
||||||
cgit_print_error(fmt("Unknown repo: %s", cgit_query_repo));
|
cgit_print_docstart(&ctx);
|
||||||
|
cgit_print_pageheader(&ctx);
|
||||||
|
cgit_print_error(fmt("Unknown repo: %s", ctx.qry.repo));
|
||||||
cgit_print_docend();
|
cgit_print_docend();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cgit_repo) {
|
if (!ctx.repo) {
|
||||||
item->name = xstrdup(fmt("%s/index.html", cgit_cache_root));
|
item->name = xstrdup(fmt("%s/index.html", ctx.cfg.cache_root));
|
||||||
item->ttl = cgit_cache_root_ttl;
|
item->ttl = ctx.cfg.cache_root_ttl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cgit_cmd) {
|
if (!ctx.qry.page) {
|
||||||
item->name = xstrdup(fmt("%s/%s/index.%s.html", cgit_cache_root,
|
item->name = xstrdup(fmt("%s/%s/index.%s.html", ctx.cfg.cache_root,
|
||||||
cache_safe_filename(cgit_repo->url),
|
cache_safe_filename(ctx.repo->url),
|
||||||
cache_safe_filename(cgit_querystring)));
|
cache_safe_filename(ctx.qry.raw)));
|
||||||
item->ttl = cgit_cache_repo_ttl;
|
item->ttl = ctx.cfg.cache_repo_ttl;
|
||||||
} else {
|
} else {
|
||||||
item->name = xstrdup(fmt("%s/%s/%s/%s.html", cgit_cache_root,
|
item->name = xstrdup(fmt("%s/%s/%s/%s.html", ctx.cfg.cache_root,
|
||||||
cache_safe_filename(cgit_repo->url),
|
cache_safe_filename(ctx.repo->url),
|
||||||
cgit_query_page,
|
ctx.qry.page,
|
||||||
cache_safe_filename(cgit_querystring)));
|
cache_safe_filename(ctx.qry.raw)));
|
||||||
if (cgit_query_has_symref)
|
if (ctx.qry.has_symref)
|
||||||
item->ttl = cgit_cache_dynamic_ttl;
|
item->ttl = ctx.cfg.cache_dynamic_ttl;
|
||||||
else if (cgit_query_has_sha1)
|
else if (ctx.qry.has_sha1)
|
||||||
item->ttl = cgit_cache_static_ttl;
|
item->ttl = ctx.cfg.cache_static_ttl;
|
||||||
else
|
else
|
||||||
item->ttl = cgit_cache_repo_ttl;
|
item->ttl = ctx.cfg.cache_repo_ttl;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -64,7 +223,7 @@ int find_current_ref(const char *refname, const unsigned char *sha1,
|
|||||||
return info->match;
|
return info->match;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *find_default_branch(struct repoinfo *repo)
|
char *find_default_branch(struct cgit_repo *repo)
|
||||||
{
|
{
|
||||||
struct refmatch info;
|
struct refmatch info;
|
||||||
|
|
||||||
@ -78,113 +237,98 @@ char *find_default_branch(struct repoinfo *repo)
|
|||||||
return info.first_ref;
|
return info.first_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cgit_print_repo_page(struct cacheitem *item)
|
static int prepare_repo_cmd(struct cgit_context *ctx)
|
||||||
{
|
{
|
||||||
char *title, *tmp;
|
char *tmp;
|
||||||
int show_search;
|
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
|
int nongit = 0;
|
||||||
|
|
||||||
if (chdir(cgit_repo->path)) {
|
setenv("GIT_DIR", ctx->repo->path, 1);
|
||||||
title = fmt("%s - %s", cgit_root_title, "Bad request");
|
setup_git_directory_gently(&nongit);
|
||||||
cgit_print_docstart(title, item);
|
if (nongit) {
|
||||||
cgit_print_pageheader(title, 0);
|
ctx->page.title = fmt("%s - %s", ctx->cfg.root_title,
|
||||||
cgit_print_error(fmt("Unable to scan repository: %s",
|
"config error");
|
||||||
strerror(errno)));
|
tmp = fmt("Not a git repository: '%s'", ctx->repo->path);
|
||||||
|
ctx->repo = NULL;
|
||||||
|
cgit_print_http_headers(ctx);
|
||||||
|
cgit_print_docstart(ctx);
|
||||||
|
cgit_print_pageheader(ctx);
|
||||||
|
cgit_print_error(tmp);
|
||||||
cgit_print_docend();
|
cgit_print_docend();
|
||||||
return;
|
return 1;
|
||||||
|
}
|
||||||
|
ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc);
|
||||||
|
|
||||||
|
if (!ctx->qry.head) {
|
||||||
|
ctx->qry.head = xstrdup(find_default_branch(ctx->repo));
|
||||||
|
ctx->repo->defbranch = ctx->qry.head;
|
||||||
}
|
}
|
||||||
|
|
||||||
title = fmt("%s - %s", cgit_repo->name, cgit_repo->desc);
|
if (!ctx->qry.head) {
|
||||||
show_search = 0;
|
cgit_print_http_headers(ctx);
|
||||||
setenv("GIT_DIR", cgit_repo->path, 1);
|
cgit_print_docstart(ctx);
|
||||||
|
cgit_print_pageheader(ctx);
|
||||||
if (!cgit_query_head) {
|
|
||||||
cgit_query_head = xstrdup(find_default_branch(cgit_repo));
|
|
||||||
cgit_repo->defbranch = cgit_query_head;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cgit_query_head) {
|
|
||||||
cgit_print_docstart(title, item);
|
|
||||||
cgit_print_pageheader(title, 0);
|
|
||||||
cgit_print_error("Repository seems to be empty");
|
cgit_print_error("Repository seems to be empty");
|
||||||
cgit_print_docend();
|
cgit_print_docend();
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_sha1(cgit_query_head, sha1)) {
|
if (get_sha1(ctx->qry.head, sha1)) {
|
||||||
tmp = xstrdup(cgit_query_head);
|
tmp = xstrdup(ctx->qry.head);
|
||||||
cgit_query_head = cgit_repo->defbranch;
|
ctx->qry.head = ctx->repo->defbranch;
|
||||||
cgit_print_docstart(title, item);
|
cgit_print_http_headers(ctx);
|
||||||
cgit_print_pageheader(title, 0);
|
cgit_print_docstart(ctx);
|
||||||
|
cgit_print_pageheader(ctx);
|
||||||
cgit_print_error(fmt("Invalid branch: %s", tmp));
|
cgit_print_error(fmt("Invalid branch: %s", tmp));
|
||||||
cgit_print_docend();
|
cgit_print_docend();
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((cgit_cmd == CMD_SNAPSHOT) && cgit_repo->snapshots) {
|
static void process_request(struct cgit_context *ctx)
|
||||||
cgit_print_snapshot(item, cgit_query_head, cgit_query_sha1,
|
{
|
||||||
cgit_repobasename(cgit_repo->url),
|
struct cgit_cmd *cmd;
|
||||||
cgit_query_path,
|
|
||||||
cgit_repo->snapshots );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cgit_cmd == CMD_PATCH) {
|
cmd = cgit_get_cmd(ctx);
|
||||||
cgit_print_patch(cgit_query_sha1, item);
|
if (!cmd) {
|
||||||
return;
|
ctx->page.title = "cgit error";
|
||||||
}
|
ctx->repo = NULL;
|
||||||
|
cgit_print_http_headers(ctx);
|
||||||
if (cgit_cmd == CMD_BLOB) {
|
cgit_print_docstart(ctx);
|
||||||
cgit_print_blob(item, cgit_query_sha1, cgit_query_path);
|
cgit_print_pageheader(ctx);
|
||||||
return;
|
cgit_print_error("Invalid request");
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
cgit_print_docend();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cgit_print_pageheader(cgit_query_page, show_search);
|
if (cmd->want_repo && prepare_repo_cmd(ctx))
|
||||||
|
return;
|
||||||
|
|
||||||
switch(cgit_cmd) {
|
if (cmd->want_layout) {
|
||||||
case CMD_LOG:
|
cgit_print_http_headers(ctx);
|
||||||
cgit_print_log(cgit_query_sha1, cgit_query_ofs,
|
cgit_print_docstart(ctx);
|
||||||
cgit_max_commit_count, cgit_query_grep, cgit_query_search,
|
cgit_print_pageheader(ctx);
|
||||||
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_REFS:
|
|
||||||
cgit_print_refs();
|
|
||||||
break;
|
|
||||||
case CMD_TAG:
|
|
||||||
cgit_print_tag(cgit_query_sha1);
|
|
||||||
break;
|
|
||||||
case CMD_DIFF:
|
|
||||||
cgit_print_diff(cgit_query_sha1, cgit_query_sha2, cgit_query_path);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cgit_print_error("Invalid request");
|
|
||||||
}
|
}
|
||||||
cgit_print_docend();
|
|
||||||
|
cmd->fn(ctx);
|
||||||
|
|
||||||
|
if (cmd->want_layout)
|
||||||
|
cgit_print_docend();
|
||||||
|
}
|
||||||
|
|
||||||
|
static long ttl_seconds(long ttl)
|
||||||
|
{
|
||||||
|
if (ttl<0)
|
||||||
|
return 60 * 60 * 24 * 365;
|
||||||
|
else
|
||||||
|
return ttl * 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cgit_fill_cache(struct cacheitem *item, int use_cache)
|
static void cgit_fill_cache(struct cacheitem *item, int use_cache)
|
||||||
{
|
{
|
||||||
static char buf[PATH_MAX];
|
|
||||||
int stdout2;
|
int stdout2;
|
||||||
|
|
||||||
getcwd(buf, sizeof(buf));
|
|
||||||
item->st.st_mtime = time(NULL);
|
|
||||||
|
|
||||||
if (use_cache) {
|
if (use_cache) {
|
||||||
stdout2 = chk_positive(dup(STDOUT_FILENO),
|
stdout2 = chk_positive(dup(STDOUT_FILENO),
|
||||||
"Preserving STDOUT");
|
"Preserving STDOUT");
|
||||||
@ -192,10 +336,9 @@ static void cgit_fill_cache(struct cacheitem *item, int use_cache)
|
|||||||
chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)");
|
chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cgit_repo)
|
ctx.page.modified = time(NULL);
|
||||||
cgit_print_repo_page(item);
|
ctx.page.expires = ctx.page.modified + ttl_seconds(item->ttl);
|
||||||
else
|
process_request(&ctx);
|
||||||
cgit_print_repolist(item);
|
|
||||||
|
|
||||||
if (use_cache) {
|
if (use_cache) {
|
||||||
chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT");
|
chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT");
|
||||||
@ -203,8 +346,6 @@ static void cgit_fill_cache(struct cacheitem *item, int use_cache)
|
|||||||
"Restoring original STDOUT");
|
"Restoring original STDOUT");
|
||||||
chk_zero(close(stdout2), "Closing temporary STDOUT");
|
chk_zero(close(stdout2), "Closing temporary STDOUT");
|
||||||
}
|
}
|
||||||
|
|
||||||
chdir(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cgit_check_cache(struct cacheitem *item)
|
static void cgit_check_cache(struct cacheitem *item)
|
||||||
@ -212,7 +353,7 @@ static void cgit_check_cache(struct cacheitem *item)
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
top:
|
top:
|
||||||
if (++i > cgit_max_lock_attempts) {
|
if (++i > ctx.cfg.max_lock_attempts) {
|
||||||
die("cgit_refresh_cache: unable to lock %s: %s",
|
die("cgit_refresh_cache: unable to lock %s: %s",
|
||||||
item->name, strerror(errno));
|
item->name, strerror(errno));
|
||||||
}
|
}
|
||||||
@ -258,30 +399,30 @@ static void cgit_parse_args(int argc, const char **argv)
|
|||||||
|
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
if (!strncmp(argv[i], "--cache=", 8)) {
|
if (!strncmp(argv[i], "--cache=", 8)) {
|
||||||
cgit_cache_root = xstrdup(argv[i]+8);
|
ctx.cfg.cache_root = xstrdup(argv[i]+8);
|
||||||
}
|
}
|
||||||
if (!strcmp(argv[i], "--nocache")) {
|
if (!strcmp(argv[i], "--nocache")) {
|
||||||
cgit_nocache = 1;
|
ctx.cfg.nocache = 1;
|
||||||
}
|
}
|
||||||
if (!strncmp(argv[i], "--query=", 8)) {
|
if (!strncmp(argv[i], "--query=", 8)) {
|
||||||
cgit_querystring = xstrdup(argv[i]+8);
|
ctx.qry.raw = xstrdup(argv[i]+8);
|
||||||
}
|
}
|
||||||
if (!strncmp(argv[i], "--repo=", 7)) {
|
if (!strncmp(argv[i], "--repo=", 7)) {
|
||||||
cgit_query_repo = xstrdup(argv[i]+7);
|
ctx.qry.repo = xstrdup(argv[i]+7);
|
||||||
}
|
}
|
||||||
if (!strncmp(argv[i], "--page=", 7)) {
|
if (!strncmp(argv[i], "--page=", 7)) {
|
||||||
cgit_query_page = xstrdup(argv[i]+7);
|
ctx.qry.page = xstrdup(argv[i]+7);
|
||||||
}
|
}
|
||||||
if (!strncmp(argv[i], "--head=", 7)) {
|
if (!strncmp(argv[i], "--head=", 7)) {
|
||||||
cgit_query_head = xstrdup(argv[i]+7);
|
ctx.qry.head = xstrdup(argv[i]+7);
|
||||||
cgit_query_has_symref = 1;
|
ctx.qry.has_symref = 1;
|
||||||
}
|
}
|
||||||
if (!strncmp(argv[i], "--sha1=", 7)) {
|
if (!strncmp(argv[i], "--sha1=", 7)) {
|
||||||
cgit_query_sha1 = xstrdup(argv[i]+7);
|
ctx.qry.sha1 = xstrdup(argv[i]+7);
|
||||||
cgit_query_has_sha1 = 1;
|
ctx.qry.has_sha1 = 1;
|
||||||
}
|
}
|
||||||
if (!strncmp(argv[i], "--ofs=", 6)) {
|
if (!strncmp(argv[i], "--ofs=", 6)) {
|
||||||
cgit_query_ofs = atoi(argv[i]+6);
|
ctx.qry.ofs = atoi(argv[i]+6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,24 +432,24 @@ int main(int argc, const char **argv)
|
|||||||
struct cacheitem item;
|
struct cacheitem item;
|
||||||
const char *cgit_config_env = getenv("CGIT_CONFIG");
|
const char *cgit_config_env = getenv("CGIT_CONFIG");
|
||||||
|
|
||||||
htmlfd = STDOUT_FILENO;
|
prepare_context(&ctx);
|
||||||
item.st.st_mtime = time(NULL);
|
item.st.st_mtime = time(NULL);
|
||||||
cgit_repolist.length = 0;
|
cgit_repolist.length = 0;
|
||||||
cgit_repolist.count = 0;
|
cgit_repolist.count = 0;
|
||||||
cgit_repolist.repos = NULL;
|
cgit_repolist.repos = NULL;
|
||||||
|
|
||||||
cgit_read_config(cgit_config_env ? cgit_config_env : CGIT_CONFIG,
|
parse_configfile(cgit_config_env ? cgit_config_env : CGIT_CONFIG,
|
||||||
cgit_global_config_cb);
|
config_cb);
|
||||||
cgit_repo = NULL;
|
ctx.repo = NULL;
|
||||||
if (getenv("SCRIPT_NAME"))
|
if (getenv("SCRIPT_NAME"))
|
||||||
cgit_script_name = xstrdup(getenv("SCRIPT_NAME"));
|
ctx.cfg.script_name = xstrdup(getenv("SCRIPT_NAME"));
|
||||||
if (getenv("QUERY_STRING"))
|
if (getenv("QUERY_STRING"))
|
||||||
cgit_querystring = xstrdup(getenv("QUERY_STRING"));
|
ctx.qry.raw = xstrdup(getenv("QUERY_STRING"));
|
||||||
cgit_parse_args(argc, argv);
|
cgit_parse_args(argc, argv);
|
||||||
cgit_parse_query(cgit_querystring, cgit_querystring_cb);
|
http_parse_querystring(ctx.qry.raw, querystring_cb);
|
||||||
if (!cgit_prepare_cache(&item))
|
if (!cgit_prepare_cache(&item))
|
||||||
return 0;
|
return 0;
|
||||||
if (cgit_nocache) {
|
if (ctx.cfg.nocache) {
|
||||||
cgit_fill_cache(&item, 0);
|
cgit_fill_cache(&item, 0);
|
||||||
} else {
|
} else {
|
||||||
cgit_check_cache(&item);
|
cgit_check_cache(&item);
|
||||||
|
235
cgit.h
235
cgit.h
@ -19,19 +19,6 @@
|
|||||||
#include <utf8.h>
|
#include <utf8.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
|
|
||||||
#define CMD_REFS 8
|
|
||||||
#define CMD_PATCH 9
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dateformats used on misc. pages
|
* Dateformats used on misc. pages
|
||||||
*/
|
*/
|
||||||
@ -59,14 +46,7 @@ typedef void (*configfn)(const char *name, const char *value);
|
|||||||
typedef void (*filepair_fn)(struct diff_filepair *pair);
|
typedef void (*filepair_fn)(struct diff_filepair *pair);
|
||||||
typedef void (*linediff_fn)(char *line, int len);
|
typedef void (*linediff_fn)(char *line, int len);
|
||||||
|
|
||||||
struct cacheitem {
|
struct cgit_repo {
|
||||||
char *name;
|
|
||||||
struct stat st;
|
|
||||||
int ttl;
|
|
||||||
int fd;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct repoinfo {
|
|
||||||
char *url;
|
char *url;
|
||||||
char *name;
|
char *name;
|
||||||
char *path;
|
char *path;
|
||||||
@ -82,10 +62,10 @@ struct repoinfo {
|
|||||||
int enable_log_linecount;
|
int enable_log_linecount;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct repolist {
|
struct cgit_repolist {
|
||||||
int length;
|
int length;
|
||||||
int count;
|
int count;
|
||||||
struct repoinfo *repos;
|
struct cgit_repo *repos;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct commitinfo {
|
struct commitinfo {
|
||||||
@ -123,74 +103,94 @@ struct reflist {
|
|||||||
int count;
|
int count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cgit_query {
|
||||||
|
int has_symref;
|
||||||
|
int has_sha1;
|
||||||
|
char *raw;
|
||||||
|
char *repo;
|
||||||
|
char *page;
|
||||||
|
char *search;
|
||||||
|
char *grep;
|
||||||
|
char *head;
|
||||||
|
char *sha1;
|
||||||
|
char *sha2;
|
||||||
|
char *path;
|
||||||
|
char *name;
|
||||||
|
int ofs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cgit_config {
|
||||||
|
char *agefile;
|
||||||
|
char *cache_root;
|
||||||
|
char *clone_prefix;
|
||||||
|
char *css;
|
||||||
|
char *index_header;
|
||||||
|
char *index_info;
|
||||||
|
char *logo;
|
||||||
|
char *logo_link;
|
||||||
|
char *module_link;
|
||||||
|
char *repo_group;
|
||||||
|
char *robots;
|
||||||
|
char *root_title;
|
||||||
|
char *script_name;
|
||||||
|
char *virtual_root;
|
||||||
|
int cache_dynamic_ttl;
|
||||||
|
int cache_max_create_time;
|
||||||
|
int cache_repo_ttl;
|
||||||
|
int cache_root_ttl;
|
||||||
|
int cache_static_ttl;
|
||||||
|
int enable_index_links;
|
||||||
|
int enable_log_filecount;
|
||||||
|
int enable_log_linecount;
|
||||||
|
int max_commit_count;
|
||||||
|
int max_lock_attempts;
|
||||||
|
int max_msg_len;
|
||||||
|
int max_repodesc_len;
|
||||||
|
int nocache;
|
||||||
|
int renamelimit;
|
||||||
|
int snapshots;
|
||||||
|
int summary_branches;
|
||||||
|
int summary_log;
|
||||||
|
int summary_tags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cgit_page {
|
||||||
|
time_t modified;
|
||||||
|
time_t expires;
|
||||||
|
char *mimetype;
|
||||||
|
char *charset;
|
||||||
|
char *filename;
|
||||||
|
char *title;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cgit_context {
|
||||||
|
struct cgit_query qry;
|
||||||
|
struct cgit_config cfg;
|
||||||
|
struct cgit_repo *repo;
|
||||||
|
struct cgit_page page;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cgit_snapshot_format {
|
||||||
|
const char *suffix;
|
||||||
|
const char *mimetype;
|
||||||
|
write_archive_fn_t write_func;
|
||||||
|
int bit;
|
||||||
|
};
|
||||||
|
|
||||||
extern const char *cgit_version;
|
extern const char *cgit_version;
|
||||||
|
|
||||||
extern struct repolist cgit_repolist;
|
extern struct cgit_repolist cgit_repolist;
|
||||||
extern struct repoinfo *cgit_repo;
|
extern struct cgit_context ctx;
|
||||||
extern int cgit_cmd;
|
extern const struct cgit_snapshot_format cgit_snapshot_formats[];
|
||||||
|
|
||||||
extern char *cgit_root_title;
|
extern struct cgit_repo *cgit_add_repo(const char *url);
|
||||||
extern char *cgit_css;
|
extern struct cgit_repo *cgit_get_repoinfo(const char *url);
|
||||||
extern char *cgit_logo;
|
|
||||||
extern char *cgit_index_header;
|
|
||||||
extern char *cgit_index_info;
|
|
||||||
extern char *cgit_logo_link;
|
|
||||||
extern char *cgit_module_link;
|
|
||||||
extern char *cgit_agefile;
|
|
||||||
extern char *cgit_virtual_root;
|
|
||||||
extern char *cgit_script_name;
|
|
||||||
extern char *cgit_cache_root;
|
|
||||||
extern char *cgit_repo_group;
|
|
||||||
extern char *cgit_robots;
|
|
||||||
extern char *cgit_clone_prefix;
|
|
||||||
|
|
||||||
extern int cgit_nocache;
|
|
||||||
extern int cgit_snapshots;
|
|
||||||
extern int cgit_enable_index_links;
|
|
||||||
extern int cgit_enable_log_filecount;
|
|
||||||
extern int cgit_enable_log_linecount;
|
|
||||||
extern int cgit_max_lock_attempts;
|
|
||||||
extern int cgit_cache_root_ttl;
|
|
||||||
extern int cgit_cache_repo_ttl;
|
|
||||||
extern int cgit_cache_dynamic_ttl;
|
|
||||||
extern int cgit_cache_static_ttl;
|
|
||||||
extern int cgit_cache_max_create_time;
|
|
||||||
extern int cgit_summary_log;
|
|
||||||
extern int cgit_summary_tags;
|
|
||||||
extern int cgit_summary_branches;
|
|
||||||
|
|
||||||
extern int cgit_max_msg_len;
|
|
||||||
extern int cgit_max_repodesc_len;
|
|
||||||
extern int cgit_max_commit_count;
|
|
||||||
|
|
||||||
extern int cgit_query_has_symref;
|
|
||||||
extern int cgit_query_has_sha1;
|
|
||||||
|
|
||||||
extern char *cgit_querystring;
|
|
||||||
extern char *cgit_query_repo;
|
|
||||||
extern char *cgit_query_page;
|
|
||||||
extern char *cgit_query_search;
|
|
||||||
extern char *cgit_query_grep;
|
|
||||||
extern char *cgit_query_head;
|
|
||||||
extern char *cgit_query_sha1;
|
|
||||||
extern char *cgit_query_sha2;
|
|
||||||
extern char *cgit_query_path;
|
|
||||||
extern char *cgit_query_name;
|
|
||||||
extern int cgit_query_ofs;
|
|
||||||
|
|
||||||
extern int htmlfd;
|
|
||||||
|
|
||||||
extern int cgit_get_cmd_index(const char *cmd);
|
|
||||||
extern struct repoinfo *cgit_get_repoinfo(const char *url);
|
|
||||||
extern void cgit_global_config_cb(const char *name, const char *value);
|
|
||||||
extern void cgit_repo_config_cb(const char *name, const char *value);
|
extern void cgit_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_zero(int result, char *msg);
|
||||||
extern int chk_positive(int result, char *msg);
|
extern int chk_positive(int result, char *msg);
|
||||||
extern int chk_non_negative(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 char *trim_end(const char *str, char c);
|
||||||
extern char *strlpart(char *txt, int maxlen);
|
extern char *strlpart(char *txt, int maxlen);
|
||||||
extern char *strrpart(char *txt, int maxlen);
|
extern char *strrpart(char *txt, int maxlen);
|
||||||
@ -213,83 +213,12 @@ extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);
|
|||||||
|
|
||||||
extern char *fmt(const char *format,...);
|
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_option(char *value, char *text, char *selected_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 commitinfo *cgit_parse_commit(struct commit *commit);
|
||||||
extern struct taginfo *cgit_parse_tag(struct tag *tag);
|
extern struct taginfo *cgit_parse_tag(struct tag *tag);
|
||||||
extern void cgit_parse_url(const char *url);
|
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_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 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, char *grep,
|
|
||||||
char *pattern);
|
|
||||||
extern void cgit_commit_link(char *name, char *title, char *class, char *head,
|
|
||||||
char *rev);
|
|
||||||
extern void cgit_refs_link(char *name, char *title, char *class, char *head,
|
|
||||||
char *rev, char *path);
|
|
||||||
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);
|
|
||||||
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_branches(int maxcount);
|
|
||||||
extern void cgit_print_tags(int maxcount);
|
|
||||||
|
|
||||||
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 *pattern, 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_refs();
|
|
||||||
extern void cgit_print_tag(char *revname);
|
|
||||||
extern void cgit_print_diff(const char *new_hex, const char *old_hex, const char *prefix);
|
|
||||||
extern void cgit_print_patch(char *hex, struct cacheitem *item);
|
|
||||||
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);
|
extern int cgit_parse_snapshots_mask(const char *str);
|
||||||
|
|
||||||
#endif /* CGIT_H */
|
#endif /* CGIT_H */
|
||||||
|
112
cmd.c
Normal file
112
cmd.c
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/* cmd.c: the cgit command dispatcher
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Lars Hjemli
|
||||||
|
*
|
||||||
|
* Licensed under GNU General Public License v2
|
||||||
|
* (see COPYING for full license text)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cgit.h"
|
||||||
|
#include "cmd.h"
|
||||||
|
#include "ui-blob.h"
|
||||||
|
#include "ui-commit.h"
|
||||||
|
#include "ui-diff.h"
|
||||||
|
#include "ui-log.h"
|
||||||
|
#include "ui-patch.h"
|
||||||
|
#include "ui-refs.h"
|
||||||
|
#include "ui-repolist.h"
|
||||||
|
#include "ui-snapshot.h"
|
||||||
|
#include "ui-summary.h"
|
||||||
|
#include "ui-tag.h"
|
||||||
|
#include "ui-tree.h"
|
||||||
|
|
||||||
|
static void blob_fn(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
|
cgit_print_blob(ctx->qry.sha1, ctx->qry.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void commit_fn(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
|
cgit_print_commit(ctx->qry.sha1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void diff_fn(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
|
cgit_print_diff(ctx->qry.sha1, ctx->qry.sha2, ctx->qry.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void repolist_fn(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
|
cgit_print_repolist();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_fn(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
|
cgit_print_log(ctx->qry.sha1, ctx->qry.ofs, ctx->cfg.max_commit_count,
|
||||||
|
ctx->qry.grep, ctx->qry.search, ctx->qry.path, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void patch_fn(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
|
cgit_print_patch(ctx->qry.sha1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void refs_fn(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
|
cgit_print_refs();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void snapshot_fn(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
|
cgit_print_snapshot(ctx->qry.head, ctx->qry.sha1,
|
||||||
|
cgit_repobasename(ctx->repo->url), ctx->qry.path,
|
||||||
|
ctx->repo->snapshots);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void summary_fn(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
|
cgit_print_summary();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tag_fn(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
|
cgit_print_tag(ctx->qry.sha1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tree_fn(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
|
cgit_print_tree(ctx->qry.sha1, ctx->qry.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define def_cmd(name, want_repo, want_layout) \
|
||||||
|
{#name, name##_fn, want_repo, want_layout}
|
||||||
|
|
||||||
|
struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
|
static struct cgit_cmd cmds[] = {
|
||||||
|
def_cmd(blob, 1, 0),
|
||||||
|
def_cmd(commit, 1, 1),
|
||||||
|
def_cmd(diff, 1, 1),
|
||||||
|
def_cmd(log, 1, 1),
|
||||||
|
def_cmd(patch, 1, 0),
|
||||||
|
def_cmd(refs, 1, 1),
|
||||||
|
def_cmd(repolist, 0, 0),
|
||||||
|
def_cmd(snapshot, 1, 0),
|
||||||
|
def_cmd(summary, 1, 1),
|
||||||
|
def_cmd(tag, 1, 1),
|
||||||
|
def_cmd(tree, 1, 1),
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (ctx->qry.page == NULL) {
|
||||||
|
if (ctx->repo)
|
||||||
|
ctx->qry.page = "summary";
|
||||||
|
else
|
||||||
|
ctx->qry.page = "repolist";
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < sizeof(cmds)/sizeof(*cmds); i++)
|
||||||
|
if (!strcmp(ctx->qry.page, cmds[i].name))
|
||||||
|
return &cmds[i];
|
||||||
|
return NULL;
|
||||||
|
}
|
15
cmd.h
Normal file
15
cmd.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef CMD_H
|
||||||
|
#define CMD_H
|
||||||
|
|
||||||
|
typedef void (*cgit_cmd_fn)(struct cgit_context *ctx);
|
||||||
|
|
||||||
|
struct cgit_cmd {
|
||||||
|
const char *name;
|
||||||
|
cgit_cmd_fn fn;
|
||||||
|
unsigned int want_repo:1,
|
||||||
|
want_layout:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx);
|
||||||
|
|
||||||
|
#endif /* CMD_H */
|
87
configfile.c
Normal file
87
configfile.c
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/* configfile.c: parsing of config files
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Lars Hjemli
|
||||||
|
*
|
||||||
|
* Licensed under GNU General Public License v2
|
||||||
|
* (see COPYING for full license text)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "configfile.h"
|
||||||
|
|
||||||
|
int next_char(FILE *f)
|
||||||
|
{
|
||||||
|
int c = fgetc(f);
|
||||||
|
if (c=='\r') {
|
||||||
|
c = fgetc(f);
|
||||||
|
if (c!='\n') {
|
||||||
|
ungetc(c, f);
|
||||||
|
c = '\r';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void skip_line(FILE *f)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
while((c=next_char(f)) && c!='\n' && c!=EOF)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_config_line(FILE *f, char *line, const char **value, int bufsize)
|
||||||
|
{
|
||||||
|
int i = 0, isname = 0;
|
||||||
|
|
||||||
|
*value = NULL;
|
||||||
|
while(i<bufsize-1) {
|
||||||
|
int c = next_char(f);
|
||||||
|
if (!isname && (c=='#' || c==';')) {
|
||||||
|
skip_line(f);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!isname && isspace(c))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (c=='=' && !*value) {
|
||||||
|
line[i] = 0;
|
||||||
|
*value = &line[i+1];
|
||||||
|
} else if (c=='\n' && !isname) {
|
||||||
|
i = 0;
|
||||||
|
continue;
|
||||||
|
} else if (c=='\n' || c==EOF) {
|
||||||
|
line[i] = 0;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
line[i]=c;
|
||||||
|
}
|
||||||
|
isname = 1;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
line[i+1] = 0;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_configfile(const char *filename, configfile_value_fn fn)
|
||||||
|
{
|
||||||
|
static int nesting;
|
||||||
|
int len;
|
||||||
|
char line[256];
|
||||||
|
const char *value;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
/* cancel deeply nested include-commands */
|
||||||
|
if (nesting > 8)
|
||||||
|
return -1;
|
||||||
|
if (!(f = fopen(filename, "r")))
|
||||||
|
return -1;
|
||||||
|
nesting++;
|
||||||
|
while((len = read_config_line(f, line, &value, sizeof(line))) > 0)
|
||||||
|
fn(line, value);
|
||||||
|
nesting--;
|
||||||
|
fclose(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
8
configfile.h
Normal file
8
configfile.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef CONFIGFILE_H
|
||||||
|
#define CONFIGFILE_H
|
||||||
|
|
||||||
|
typedef void (*configfile_value_fn)(const char *name, const char *value);
|
||||||
|
|
||||||
|
extern int parse_configfile(const char *filename, configfile_value_fn fn);
|
||||||
|
|
||||||
|
#endif /* CONFIGFILE_H */
|
95
html.c
95
html.c
@ -6,7 +6,13 @@
|
|||||||
* (see COPYING for full license text)
|
* (see COPYING for full license text)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int htmlfd = STDOUT_FILENO;
|
||||||
|
|
||||||
char *fmt(const char *format, ...)
|
char *fmt(const char *format, ...)
|
||||||
{
|
{
|
||||||
@ -21,8 +27,10 @@ char *fmt(const char *format, ...)
|
|||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
len = vsnprintf(buf[bufidx], sizeof(buf[bufidx]), format, args);
|
len = vsnprintf(buf[bufidx], sizeof(buf[bufidx]), format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
if (len>sizeof(buf[bufidx]))
|
if (len>sizeof(buf[bufidx])) {
|
||||||
die("[html.c] string truncated: %s", format);
|
fprintf(stderr, "[html.c] string truncated: %s\n", format);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
return buf[bufidx];
|
return buf[bufidx];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,25 +158,10 @@ void html_link_close(void)
|
|||||||
|
|
||||||
void html_fileperm(unsigned short mode)
|
void html_fileperm(unsigned short mode)
|
||||||
{
|
{
|
||||||
htmlf("%c%c%c", (mode & 4 ? 'r' : '-'),
|
htmlf("%c%c%c", (mode & 4 ? 'r' : '-'),
|
||||||
(mode & 2 ? 'w' : '-'), (mode & 1 ? 'x' : '-'));
|
(mode & 2 ? 'w' : '-'), (mode & 1 ? 'x' : '-'));
|
||||||
}
|
}
|
||||||
|
|
||||||
void html_filemode(unsigned short mode)
|
|
||||||
{
|
|
||||||
if (S_ISDIR(mode))
|
|
||||||
html("d");
|
|
||||||
else if (S_ISLNK(mode))
|
|
||||||
html("l");
|
|
||||||
else if (S_ISGITLINK(mode))
|
|
||||||
html("m");
|
|
||||||
else
|
|
||||||
html("-");
|
|
||||||
html_fileperm(mode >> 6);
|
|
||||||
html_fileperm(mode >> 3);
|
|
||||||
html_fileperm(mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
int html_include(const char *filename)
|
int html_include(const char *filename)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
@ -182,3 +175,67 @@ int html_include(const char *filename)
|
|||||||
fclose(f);
|
fclose(f);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hextoint(char c)
|
||||||
|
{
|
||||||
|
if (c >= 'a' && c <= 'f')
|
||||||
|
return 10 + c - 'a';
|
||||||
|
else if (c >= 'A' && c <= 'F')
|
||||||
|
return 10 + c - 'A';
|
||||||
|
else if (c >= '0' && c <= '9')
|
||||||
|
return c - '0';
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *convert_query_hexchar(char *txt)
|
||||||
|
{
|
||||||
|
int d1, d2;
|
||||||
|
if (strlen(txt) < 3) {
|
||||||
|
*txt = '\0';
|
||||||
|
return txt-1;
|
||||||
|
}
|
||||||
|
d1 = hextoint(*(txt+1));
|
||||||
|
d2 = hextoint(*(txt+2));
|
||||||
|
if (d1<0 || d2<0) {
|
||||||
|
strcpy(txt, txt+3);
|
||||||
|
return txt-1;
|
||||||
|
} else {
|
||||||
|
*txt = d1 * 16 + d2;
|
||||||
|
strcpy(txt+1, txt+3);
|
||||||
|
return txt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int http_parse_querystring(char *txt, void (*fn)(const char *name, const char *value))
|
||||||
|
{
|
||||||
|
char *t, *value = NULL, c;
|
||||||
|
|
||||||
|
if (!txt)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
t = txt = strdup(txt);
|
||||||
|
if (t == NULL) {
|
||||||
|
printf("Out of memory\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
while((c=*t) != '\0') {
|
||||||
|
if (c=='=') {
|
||||||
|
*t = '\0';
|
||||||
|
value = t+1;
|
||||||
|
} else if (c=='+') {
|
||||||
|
*t = ' ';
|
||||||
|
} else if (c=='%') {
|
||||||
|
t = convert_query_hexchar(t);
|
||||||
|
} else if (c=='&') {
|
||||||
|
*t = '\0';
|
||||||
|
(*fn)(txt, value);
|
||||||
|
txt = t+1;
|
||||||
|
value = NULL;
|
||||||
|
}
|
||||||
|
t++;
|
||||||
|
}
|
||||||
|
if (t!=txt)
|
||||||
|
(*fn)(txt, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
20
html.h
Normal file
20
html.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef HTML_H
|
||||||
|
#define HTML_H
|
||||||
|
|
||||||
|
extern int htmlfd;
|
||||||
|
|
||||||
|
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_option(char *value, char *text, char *selected_value);
|
||||||
|
extern void html_link_open(char *url, char *title, char *class);
|
||||||
|
extern void html_link_close(void);
|
||||||
|
extern void html_fileperm(unsigned short mode);
|
||||||
|
extern int html_include(const char *filename);
|
||||||
|
|
||||||
|
extern int http_parse_querystring(char *txt, void (*fn)(const char *name, const char *value));
|
||||||
|
|
||||||
|
#endif /* HTML_H */
|
146
parsing.c
146
parsing.c
@ -8,130 +8,6 @@
|
|||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
|
||||||
int next_char(FILE *f)
|
|
||||||
{
|
|
||||||
int c = fgetc(f);
|
|
||||||
if (c=='\r') {
|
|
||||||
c = fgetc(f);
|
|
||||||
if (c!='\n') {
|
|
||||||
ungetc(c, f);
|
|
||||||
c = '\r';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void skip_line(FILE *f)
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
|
|
||||||
while((c=next_char(f)) && c!='\n' && c!=EOF)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
int read_config_line(FILE *f, char *line, const char **value, int bufsize)
|
|
||||||
{
|
|
||||||
int i = 0, isname = 0;
|
|
||||||
|
|
||||||
*value = NULL;
|
|
||||||
while(i<bufsize-1) {
|
|
||||||
int c = next_char(f);
|
|
||||||
if (!isname && (c=='#' || c==';')) {
|
|
||||||
skip_line(f);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!isname && isspace(c))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (c=='=' && !*value) {
|
|
||||||
line[i] = 0;
|
|
||||||
*value = &line[i+1];
|
|
||||||
} else if (c=='\n' && !isname) {
|
|
||||||
i = 0;
|
|
||||||
continue;
|
|
||||||
} else if (c=='\n' || c==EOF) {
|
|
||||||
line[i] = 0;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
line[i]=c;
|
|
||||||
}
|
|
||||||
isname = 1;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
line[i+1] = 0;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cgit_read_config(const char *filename, configfn fn)
|
|
||||||
{
|
|
||||||
static int nesting;
|
|
||||||
int len;
|
|
||||||
char line[256];
|
|
||||||
const char *value;
|
|
||||||
FILE *f;
|
|
||||||
|
|
||||||
/* cancel deeply nested include-commands */
|
|
||||||
if (nesting > 8)
|
|
||||||
return -1;
|
|
||||||
if (!(f = fopen(filename, "r")))
|
|
||||||
return -1;
|
|
||||||
nesting++;
|
|
||||||
while((len = read_config_line(f, line, &value, sizeof(line))) > 0)
|
|
||||||
(*fn)(line, value);
|
|
||||||
nesting--;
|
|
||||||
fclose(f);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *convert_query_hexchar(char *txt)
|
|
||||||
{
|
|
||||||
int d1, d2;
|
|
||||||
if (strlen(txt) < 3) {
|
|
||||||
*txt = '\0';
|
|
||||||
return txt-1;
|
|
||||||
}
|
|
||||||
d1 = hextoint(*(txt+1));
|
|
||||||
d2 = hextoint(*(txt+2));
|
|
||||||
if (d1<0 || d2<0) {
|
|
||||||
strcpy(txt, txt+3);
|
|
||||||
return txt-1;
|
|
||||||
} else {
|
|
||||||
*txt = d1 * 16 + d2;
|
|
||||||
strcpy(txt+1, txt+3);
|
|
||||||
return txt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int cgit_parse_query(char *txt, configfn fn)
|
|
||||||
{
|
|
||||||
char *t, *value = NULL, c;
|
|
||||||
|
|
||||||
if (!txt)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
t = txt = xstrdup(txt);
|
|
||||||
|
|
||||||
while((c=*t) != '\0') {
|
|
||||||
if (c=='=') {
|
|
||||||
*t = '\0';
|
|
||||||
value = t+1;
|
|
||||||
} else if (c=='+') {
|
|
||||||
*t = ' ';
|
|
||||||
} else if (c=='%') {
|
|
||||||
t = convert_query_hexchar(t);
|
|
||||||
} else if (c=='&') {
|
|
||||||
*t = '\0';
|
|
||||||
(*fn)(txt, value);
|
|
||||||
txt = t+1;
|
|
||||||
value = NULL;
|
|
||||||
}
|
|
||||||
t++;
|
|
||||||
}
|
|
||||||
if (t!=txt)
|
|
||||||
(*fn)(txt, value);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* url syntax: [repo ['/' cmd [ '/' path]]]
|
* url syntax: [repo ['/' cmd [ '/' path]]]
|
||||||
* repo: any valid repo url, may contain '/'
|
* repo: any valid repo url, may contain '/'
|
||||||
@ -143,35 +19,35 @@ void cgit_parse_url(const char *url)
|
|||||||
{
|
{
|
||||||
char *cmd, *p;
|
char *cmd, *p;
|
||||||
|
|
||||||
cgit_repo = NULL;
|
ctx.repo = NULL;
|
||||||
if (!url || url[0] == '\0')
|
if (!url || url[0] == '\0')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cgit_repo = cgit_get_repoinfo(url);
|
ctx.repo = cgit_get_repoinfo(url);
|
||||||
if (cgit_repo) {
|
if (ctx.repo) {
|
||||||
cgit_query_repo = cgit_repo->url;
|
ctx.qry.repo = ctx.repo->url;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = strchr(url, '/');
|
cmd = strchr(url, '/');
|
||||||
while (!cgit_repo && cmd) {
|
while (!ctx.repo && cmd) {
|
||||||
cmd[0] = '\0';
|
cmd[0] = '\0';
|
||||||
cgit_repo = cgit_get_repoinfo(url);
|
ctx.repo = cgit_get_repoinfo(url);
|
||||||
if (cgit_repo == NULL) {
|
if (ctx.repo == NULL) {
|
||||||
cmd[0] = '/';
|
cmd[0] = '/';
|
||||||
cmd = strchr(cmd + 1, '/');
|
cmd = strchr(cmd + 1, '/');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
cgit_query_repo = cgit_repo->url;
|
ctx.qry.repo = ctx.repo->url;
|
||||||
p = strchr(cmd + 1, '/');
|
p = strchr(cmd + 1, '/');
|
||||||
if (p) {
|
if (p) {
|
||||||
p[0] = '\0';
|
p[0] = '\0';
|
||||||
if (p[1])
|
if (p[1])
|
||||||
cgit_query_path = trim_end(p + 1, '/');
|
ctx.qry.path = trim_end(p + 1, '/');
|
||||||
}
|
}
|
||||||
cgit_cmd = cgit_get_cmd_index(cmd + 1);
|
if (cmd[1])
|
||||||
cgit_query_page = xstrdup(cmd + 1);
|
ctx.qry.page = xstrdup(cmd + 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
257
shared.c
257
shared.c
@ -8,77 +8,10 @@
|
|||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
|
||||||
struct repolist cgit_repolist;
|
struct cgit_repolist cgit_repolist;
|
||||||
struct repoinfo *cgit_repo;
|
struct cgit_context ctx;
|
||||||
int cgit_cmd;
|
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_index_info = 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 = CGIT_CACHE_ROOT;
|
|
||||||
char *cgit_repo_group = NULL;
|
|
||||||
char *cgit_robots = "index, nofollow";
|
|
||||||
char *cgit_clone_prefix = 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_summary_tags = 0;
|
|
||||||
int cgit_summary_branches = 0;
|
|
||||||
int cgit_renamelimit = -1;
|
|
||||||
|
|
||||||
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_grep = 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", "tag", "refs", "patch", 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)
|
int chk_zero(int result, char *msg)
|
||||||
{
|
{
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
@ -100,9 +33,9 @@ int chk_non_negative(int result, char *msg)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct repoinfo *add_repo(const char *url)
|
struct cgit_repo *cgit_add_repo(const char *url)
|
||||||
{
|
{
|
||||||
struct repoinfo *ret;
|
struct cgit_repo *ret;
|
||||||
|
|
||||||
if (++cgit_repolist.count > cgit_repolist.length) {
|
if (++cgit_repolist.count > cgit_repolist.length) {
|
||||||
if (cgit_repolist.length == 0)
|
if (cgit_repolist.length == 0)
|
||||||
@ -111,7 +44,7 @@ struct repoinfo *add_repo(const char *url)
|
|||||||
cgit_repolist.length *= 2;
|
cgit_repolist.length *= 2;
|
||||||
cgit_repolist.repos = xrealloc(cgit_repolist.repos,
|
cgit_repolist.repos = xrealloc(cgit_repolist.repos,
|
||||||
cgit_repolist.length *
|
cgit_repolist.length *
|
||||||
sizeof(struct repoinfo));
|
sizeof(struct cgit_repo));
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = &cgit_repolist.repos[cgit_repolist.count-1];
|
ret = &cgit_repolist.repos[cgit_repolist.count-1];
|
||||||
@ -120,20 +53,20 @@ struct repoinfo *add_repo(const char *url)
|
|||||||
ret->path = NULL;
|
ret->path = NULL;
|
||||||
ret->desc = "[no description]";
|
ret->desc = "[no description]";
|
||||||
ret->owner = NULL;
|
ret->owner = NULL;
|
||||||
ret->group = cgit_repo_group;
|
ret->group = ctx.cfg.repo_group;
|
||||||
ret->defbranch = "master";
|
ret->defbranch = "master";
|
||||||
ret->snapshots = cgit_snapshots;
|
ret->snapshots = ctx.cfg.snapshots;
|
||||||
ret->enable_log_filecount = cgit_enable_log_filecount;
|
ret->enable_log_filecount = ctx.cfg.enable_log_filecount;
|
||||||
ret->enable_log_linecount = cgit_enable_log_linecount;
|
ret->enable_log_linecount = ctx.cfg.enable_log_linecount;
|
||||||
ret->module_link = cgit_module_link;
|
ret->module_link = ctx.cfg.module_link;
|
||||||
ret->readme = NULL;
|
ret->readme = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct repoinfo *cgit_get_repoinfo(const char *url)
|
struct cgit_repo *cgit_get_repoinfo(const char *url)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct repoinfo *repo;
|
struct cgit_repo *repo;
|
||||||
|
|
||||||
for (i=0; i<cgit_repolist.count; i++) {
|
for (i=0; i<cgit_repolist.count; i++) {
|
||||||
repo = &cgit_repolist.repos[i];
|
repo = &cgit_repolist.repos[i];
|
||||||
@ -143,131 +76,6 @@ struct repoinfo *cgit_get_repoinfo(const char *url)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cgit_global_config_cb(const char *name, const char *value)
|
|
||||||
{
|
|
||||||
if (!strcmp(name, "root-title"))
|
|
||||||
cgit_root_title = xstrdup(value);
|
|
||||||
else if (!strcmp(name, "css"))
|
|
||||||
cgit_css = xstrdup(value);
|
|
||||||
else if (!strcmp(name, "logo"))
|
|
||||||
cgit_logo = xstrdup(value);
|
|
||||||
else if (!strcmp(name, "index-header"))
|
|
||||||
cgit_index_header = xstrdup(value);
|
|
||||||
else if (!strcmp(name, "index-info"))
|
|
||||||
cgit_index_info = xstrdup(value);
|
|
||||||
else if (!strcmp(name, "logo-link"))
|
|
||||||
cgit_logo_link = xstrdup(value);
|
|
||||||
else if (!strcmp(name, "module-link"))
|
|
||||||
cgit_module_link = xstrdup(value);
|
|
||||||
else if (!strcmp(name, "virtual-root")) {
|
|
||||||
cgit_virtual_root = trim_end(value, '/');
|
|
||||||
if (!cgit_virtual_root && (!strcmp(value, "/")))
|
|
||||||
cgit_virtual_root = "";
|
|
||||||
} else if (!strcmp(name, "nocache"))
|
|
||||||
cgit_nocache = atoi(value);
|
|
||||||
else if (!strcmp(name, "snapshots"))
|
|
||||||
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"))
|
|
||||||
cgit_enable_log_linecount = atoi(value);
|
|
||||||
else if (!strcmp(name, "cache-root"))
|
|
||||||
cgit_cache_root = xstrdup(value);
|
|
||||||
else if (!strcmp(name, "cache-root-ttl"))
|
|
||||||
cgit_cache_root_ttl = atoi(value);
|
|
||||||
else if (!strcmp(name, "cache-repo-ttl"))
|
|
||||||
cgit_cache_repo_ttl = atoi(value);
|
|
||||||
else if (!strcmp(name, "cache-static-ttl"))
|
|
||||||
cgit_cache_static_ttl = atoi(value);
|
|
||||||
else if (!strcmp(name, "cache-dynamic-ttl"))
|
|
||||||
cgit_cache_dynamic_ttl = atoi(value);
|
|
||||||
else if (!strcmp(name, "max-message-length"))
|
|
||||||
cgit_max_msg_len = atoi(value);
|
|
||||||
else if (!strcmp(name, "max-repodesc-length"))
|
|
||||||
cgit_max_repodesc_len = atoi(value);
|
|
||||||
else if (!strcmp(name, "max-commit-count"))
|
|
||||||
cgit_max_commit_count = atoi(value);
|
|
||||||
else if (!strcmp(name, "summary-log"))
|
|
||||||
cgit_summary_log = atoi(value);
|
|
||||||
else if (!strcmp(name, "summary-branches"))
|
|
||||||
cgit_summary_branches = atoi(value);
|
|
||||||
else if (!strcmp(name, "summary-tags"))
|
|
||||||
cgit_summary_tags = atoi(value);
|
|
||||||
else if (!strcmp(name, "agefile"))
|
|
||||||
cgit_agefile = xstrdup(value);
|
|
||||||
else if (!strcmp(name, "renamelimit"))
|
|
||||||
cgit_renamelimit = atoi(value);
|
|
||||||
else if (!strcmp(name, "robots"))
|
|
||||||
cgit_robots = xstrdup(value);
|
|
||||||
else if (!strcmp(name, "clone-prefix"))
|
|
||||||
cgit_clone_prefix = xstrdup(value);
|
|
||||||
else if (!strcmp(name, "repo.group"))
|
|
||||||
cgit_repo_group = xstrdup(value);
|
|
||||||
else if (!strcmp(name, "repo.url"))
|
|
||||||
cgit_repo = add_repo(value);
|
|
||||||
else if (!strcmp(name, "repo.name"))
|
|
||||||
cgit_repo->name = xstrdup(value);
|
|
||||||
else if (cgit_repo && !strcmp(name, "repo.path"))
|
|
||||||
cgit_repo->path = trim_end(value, '/');
|
|
||||||
else if (cgit_repo && !strcmp(name, "repo.clone-url"))
|
|
||||||
cgit_repo->clone_url = xstrdup(value);
|
|
||||||
else if (cgit_repo && !strcmp(name, "repo.desc"))
|
|
||||||
cgit_repo->desc = xstrdup(value);
|
|
||||||
else if (cgit_repo && !strcmp(name, "repo.owner"))
|
|
||||||
cgit_repo->owner = xstrdup(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 & 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"))
|
|
||||||
cgit_repo->enable_log_linecount = cgit_enable_log_linecount * atoi(value);
|
|
||||||
else if (cgit_repo && !strcmp(name, "repo.module-link"))
|
|
||||||
cgit_repo->module_link= xstrdup(value);
|
|
||||||
else if (cgit_repo && !strcmp(name, "repo.readme") && value != NULL) {
|
|
||||||
if (*value == '/')
|
|
||||||
cgit_repo->readme = xstrdup(value);
|
|
||||||
else
|
|
||||||
cgit_repo->readme = xstrdup(fmt("%s/%s", cgit_repo->path, value));
|
|
||||||
} else if (!strcmp(name, "include"))
|
|
||||||
cgit_read_config(value, cgit_global_config_cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cgit_querystring_cb(const char *name, const char *value)
|
|
||||||
{
|
|
||||||
if (!strcmp(name,"r")) {
|
|
||||||
cgit_query_repo = xstrdup(value);
|
|
||||||
cgit_repo = cgit_get_repoinfo(value);
|
|
||||||
} else if (!strcmp(name, "p")) {
|
|
||||||
cgit_query_page = xstrdup(value);
|
|
||||||
cgit_cmd = cgit_get_cmd_index(value);
|
|
||||||
} else if (!strcmp(name, "url")) {
|
|
||||||
cgit_parse_url(value);
|
|
||||||
} else if (!strcmp(name, "qt")) {
|
|
||||||
cgit_query_grep = xstrdup(value);
|
|
||||||
} else if (!strcmp(name, "q")) {
|
|
||||||
cgit_query_search = xstrdup(value);
|
|
||||||
} else if (!strcmp(name, "h")) {
|
|
||||||
cgit_query_head = xstrdup(value);
|
|
||||||
cgit_query_has_symref = 1;
|
|
||||||
} else if (!strcmp(name, "id")) {
|
|
||||||
cgit_query_sha1 = xstrdup(value);
|
|
||||||
cgit_query_has_sha1 = 1;
|
|
||||||
} else if (!strcmp(name, "id2")) {
|
|
||||||
cgit_query_sha2 = xstrdup(value);
|
|
||||||
cgit_query_has_sha1 = 1;
|
|
||||||
} else if (!strcmp(name, "ofs")) {
|
|
||||||
cgit_query_ofs = atoi(value);
|
|
||||||
} else if (!strcmp(name, "path")) {
|
|
||||||
cgit_query_path = trim_end(value, '/');
|
|
||||||
} else if (!strcmp(name, "name")) {
|
|
||||||
cgit_query_name = xstrdup(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *cgit_free_commitinfo(struct commitinfo *info)
|
void *cgit_free_commitinfo(struct commitinfo *info)
|
||||||
{
|
{
|
||||||
free(info->author);
|
free(info->author);
|
||||||
@ -281,18 +89,6 @@ void *cgit_free_commitinfo(struct commitinfo *info)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hextoint(char c)
|
|
||||||
{
|
|
||||||
if (c >= 'a' && c <= 'f')
|
|
||||||
return 10 + c - 'a';
|
|
||||||
else if (c >= 'A' && c <= 'F')
|
|
||||||
return 10 + c - 'A';
|
|
||||||
else if (c >= '0' && c <= '9')
|
|
||||||
return c - '0';
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *trim_end(const char *str, char c)
|
char *trim_end(const char *str, char c)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
@ -491,7 +287,7 @@ void cgit_diff_tree(const unsigned char *old_sha1,
|
|||||||
diff_setup(&opt);
|
diff_setup(&opt);
|
||||||
opt.output_format = DIFF_FORMAT_CALLBACK;
|
opt.output_format = DIFF_FORMAT_CALLBACK;
|
||||||
opt.detect_rename = 1;
|
opt.detect_rename = 1;
|
||||||
opt.rename_limit = cgit_renamelimit;
|
opt.rename_limit = ctx.cfg.renamelimit;
|
||||||
DIFF_OPT_SET(&opt, RECURSIVE);
|
DIFF_OPT_SET(&opt, RECURSIVE);
|
||||||
opt.format_callback = cgit_diff_tree_cb;
|
opt.format_callback = cgit_diff_tree_cb;
|
||||||
opt.format_callback_data = fn;
|
opt.format_callback_data = fn;
|
||||||
@ -519,3 +315,30 @@ void cgit_diff_commit(struct commit *commit, filepair_fn fn)
|
|||||||
old_sha1 = commit->parents->item->object.sha1;
|
old_sha1 = commit->parents->item->object.sha1;
|
||||||
cgit_diff_tree(old_sha1, commit->object.sha1, fn, NULL);
|
cgit_diff_tree(old_sha1, commit->object.sha1, fn, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cgit_parse_snapshots_mask(const char *str)
|
||||||
|
{
|
||||||
|
const struct cgit_snapshot_format *f;
|
||||||
|
static const char *delim = " \t,:/|;";
|
||||||
|
int tl, sl, rv = 0;
|
||||||
|
|
||||||
|
/* favor legacy setting */
|
||||||
|
if(atoi(str))
|
||||||
|
return 1;
|
||||||
|
for(;;) {
|
||||||
|
str += strspn(str,delim);
|
||||||
|
tl = strcspn(str,delim);
|
||||||
|
if (!tl)
|
||||||
|
break;
|
||||||
|
for (f = cgit_snapshot_formats; f->suffix; f++) {
|
||||||
|
sl = strlen(f->suffix);
|
||||||
|
if((tl == sl && !strncmp(f->suffix, str, tl)) ||
|
||||||
|
(tl == sl-1 && !strncmp(f->suffix+1, str, tl-1))) {
|
||||||
|
rv |= f->bit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str += tl;
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
18
ui-blob.c
18
ui-blob.c
@ -1,6 +1,16 @@
|
|||||||
#include "cgit.h"
|
/* ui-blob.c: show blob content
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Lars Hjemli
|
||||||
|
*
|
||||||
|
* Licensed under GNU General Public License v2
|
||||||
|
* (see COPYING for full license text)
|
||||||
|
*/
|
||||||
|
|
||||||
void cgit_print_blob(struct cacheitem *item, const char *hex, char *path)
|
#include "cgit.h"
|
||||||
|
#include "html.h"
|
||||||
|
#include "ui-shared.h"
|
||||||
|
|
||||||
|
void cgit_print_blob(const char *hex, char *path)
|
||||||
{
|
{
|
||||||
|
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
@ -26,6 +36,8 @@ void cgit_print_blob(struct cacheitem *item, const char *hex, char *path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf[size] = '\0';
|
buf[size] = '\0';
|
||||||
cgit_print_snapshot_start("text/plain", path, item);
|
ctx.page.mimetype = "text/plain";
|
||||||
|
ctx.page.filename = path;
|
||||||
|
cgit_print_http_headers(&ctx);
|
||||||
write(htmlfd, buf, size);
|
write(htmlfd, buf, size);
|
||||||
}
|
}
|
||||||
|
6
ui-blob.h
Normal file
6
ui-blob.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef UI_BLOB_H
|
||||||
|
#define UI_BLOB_H
|
||||||
|
|
||||||
|
extern void cgit_print_blob(const char *hex, char *path);
|
||||||
|
|
||||||
|
#endif /* UI_BLOB_H */
|
26
ui-commit.c
26
ui-commit.c
@ -7,6 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
#include "html.h"
|
||||||
|
#include "ui-shared.h"
|
||||||
|
|
||||||
static int files, slots;
|
static int files, slots;
|
||||||
static int total_adds, total_rems, max_changes;
|
static int total_adds, total_rems, max_changes;
|
||||||
@ -62,20 +64,20 @@ void print_fileinfo(struct fileinfo *info)
|
|||||||
html("<tr>");
|
html("<tr>");
|
||||||
htmlf("<td class='mode'>");
|
htmlf("<td class='mode'>");
|
||||||
if (is_null_sha1(info->new_sha1)) {
|
if (is_null_sha1(info->new_sha1)) {
|
||||||
html_filemode(info->old_mode);
|
cgit_print_filemode(info->old_mode);
|
||||||
} else {
|
} else {
|
||||||
html_filemode(info->new_mode);
|
cgit_print_filemode(info->new_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->old_mode != info->new_mode &&
|
if (info->old_mode != info->new_mode &&
|
||||||
!is_null_sha1(info->old_sha1) &&
|
!is_null_sha1(info->old_sha1) &&
|
||||||
!is_null_sha1(info->new_sha1)) {
|
!is_null_sha1(info->new_sha1)) {
|
||||||
html("<span class='modechange'>[");
|
html("<span class='modechange'>[");
|
||||||
html_filemode(info->old_mode);
|
cgit_print_filemode(info->old_mode);
|
||||||
html("]</span>");
|
html("]</span>");
|
||||||
}
|
}
|
||||||
htmlf("</td><td class='%s'>", class);
|
htmlf("</td><td class='%s'>", class);
|
||||||
cgit_diff_link(info->new_path, NULL, NULL, cgit_query_head, curr_rev,
|
cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, curr_rev,
|
||||||
NULL, info->new_path);
|
NULL, info->new_path);
|
||||||
if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED)
|
if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED)
|
||||||
htmlf(" (%s from %s)",
|
htmlf(" (%s from %s)",
|
||||||
@ -143,7 +145,7 @@ void cgit_print_commit(char *hex)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!hex)
|
if (!hex)
|
||||||
hex = cgit_query_head;
|
hex = ctx.qry.head;
|
||||||
curr_rev = hex;
|
curr_rev = hex;
|
||||||
|
|
||||||
if (get_sha1(hex, sha1)) {
|
if (get_sha1(hex, sha1)) {
|
||||||
@ -175,7 +177,7 @@ void cgit_print_commit(char *hex)
|
|||||||
html("<tr><th>tree</th><td colspan='2' class='sha1'>");
|
html("<tr><th>tree</th><td colspan='2' class='sha1'>");
|
||||||
tmp = xstrdup(hex);
|
tmp = xstrdup(hex);
|
||||||
cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL,
|
cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL,
|
||||||
cgit_query_head, tmp, NULL);
|
ctx.qry.head, tmp, NULL);
|
||||||
html("</td></tr>\n");
|
html("</td></tr>\n");
|
||||||
for (p = commit->parents; p ; p = p->next) {
|
for (p = commit->parents; p ; p = p->next) {
|
||||||
parent = lookup_commit_reference(p->item->object.sha1);
|
parent = lookup_commit_reference(p->item->object.sha1);
|
||||||
@ -188,16 +190,16 @@ void cgit_print_commit(char *hex)
|
|||||||
html("<tr><th>parent</th>"
|
html("<tr><th>parent</th>"
|
||||||
"<td colspan='2' class='sha1'>");
|
"<td colspan='2' class='sha1'>");
|
||||||
cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL,
|
cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL,
|
||||||
cgit_query_head, sha1_to_hex(p->item->object.sha1));
|
ctx.qry.head, sha1_to_hex(p->item->object.sha1));
|
||||||
html(" (");
|
html(" (");
|
||||||
cgit_diff_link("diff", NULL, NULL, cgit_query_head, hex,
|
cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex,
|
||||||
sha1_to_hex(p->item->object.sha1), NULL);
|
sha1_to_hex(p->item->object.sha1), NULL);
|
||||||
html(")</td></tr>");
|
html(")</td></tr>");
|
||||||
}
|
}
|
||||||
if (cgit_repo->snapshots) {
|
if (ctx.repo->snapshots) {
|
||||||
html("<tr><th>download</th><td colspan='2' class='sha1'>");
|
html("<tr><th>download</th><td colspan='2' class='sha1'>");
|
||||||
cgit_print_snapshot_links(cgit_query_repo, cgit_query_head,
|
cgit_print_snapshot_links(ctx.qry.repo, ctx.qry.head,
|
||||||
hex, cgit_repo->snapshots);
|
hex, ctx.repo->snapshots);
|
||||||
html("</td></tr>");
|
html("</td></tr>");
|
||||||
}
|
}
|
||||||
html("</table>\n");
|
html("</table>\n");
|
||||||
@ -218,7 +220,7 @@ void cgit_print_commit(char *hex)
|
|||||||
html("<div class='diffstat-summary'>");
|
html("<div class='diffstat-summary'>");
|
||||||
htmlf("%d files changed, %d insertions, %d deletions (",
|
htmlf("%d files changed, %d insertions, %d deletions (",
|
||||||
files, total_adds, total_rems);
|
files, total_adds, total_rems);
|
||||||
cgit_diff_link("show diff", NULL, NULL, cgit_query_head, hex,
|
cgit_diff_link("show diff", NULL, NULL, ctx.qry.head, hex,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
html(")</div>");
|
html(")</div>");
|
||||||
}
|
}
|
||||||
|
6
ui-commit.h
Normal file
6
ui-commit.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef UI_COMMIT_H
|
||||||
|
#define UI_COMMIT_H
|
||||||
|
|
||||||
|
extern void cgit_print_commit(char *hex);
|
||||||
|
|
||||||
|
#endif /* UI_COMMIT_H */
|
@ -7,7 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
#include "html.h"
|
||||||
|
#include "ui-shared.h"
|
||||||
|
|
||||||
unsigned char old_rev_sha1[20];
|
unsigned char old_rev_sha1[20];
|
||||||
unsigned char new_rev_sha1[20];
|
unsigned char new_rev_sha1[20];
|
||||||
@ -71,13 +72,13 @@ static void header(unsigned char *sha1, char *path1, int mode1,
|
|||||||
}
|
}
|
||||||
html("<br/>--- a/");
|
html("<br/>--- a/");
|
||||||
if (mode1 != 0)
|
if (mode1 != 0)
|
||||||
cgit_tree_link(path1, NULL, NULL, cgit_query_head,
|
cgit_tree_link(path1, NULL, NULL, ctx.qry.head,
|
||||||
sha1_to_hex(old_rev_sha1), path1);
|
sha1_to_hex(old_rev_sha1), path1);
|
||||||
else
|
else
|
||||||
html_txt(path1);
|
html_txt(path1);
|
||||||
html("<br/>+++ b/");
|
html("<br/>+++ b/");
|
||||||
if (mode2 != 0)
|
if (mode2 != 0)
|
||||||
cgit_tree_link(path2, NULL, NULL, cgit_query_head,
|
cgit_tree_link(path2, NULL, NULL, ctx.qry.head,
|
||||||
sha1_to_hex(new_rev_sha1), path2);
|
sha1_to_hex(new_rev_sha1), path2);
|
||||||
else
|
else
|
||||||
html_txt(path2);
|
html_txt(path2);
|
||||||
@ -107,7 +108,7 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, const char *prefi
|
|||||||
struct commit *commit, *commit2;
|
struct commit *commit, *commit2;
|
||||||
|
|
||||||
if (!new_rev)
|
if (!new_rev)
|
||||||
new_rev = cgit_query_head;
|
new_rev = ctx.qry.head;
|
||||||
get_sha1(new_rev, new_rev_sha1);
|
get_sha1(new_rev, new_rev_sha1);
|
||||||
type = sha1_object_info(new_rev_sha1, &size);
|
type = sha1_object_info(new_rev_sha1, &size);
|
||||||
if (type == OBJ_BAD) {
|
if (type == OBJ_BAD) {
|
||||||
|
7
ui-diff.h
Normal file
7
ui-diff.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef UI_DIFF_H
|
||||||
|
#define UI_DIFF_H
|
||||||
|
|
||||||
|
extern void cgit_print_diff(const char *new_hex, const char *old_hex,
|
||||||
|
const char *prefix);
|
||||||
|
|
||||||
|
#endif /* UI_DIFF_H */
|
32
ui-log.c
32
ui-log.c
@ -7,6 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
#include "html.h"
|
||||||
|
#include "ui-shared.h"
|
||||||
|
|
||||||
int files, add_lines, rem_lines;
|
int files, add_lines, rem_lines;
|
||||||
|
|
||||||
@ -25,7 +27,7 @@ void count_lines(char *line, int size)
|
|||||||
void inspect_files(struct diff_filepair *pair)
|
void inspect_files(struct diff_filepair *pair)
|
||||||
{
|
{
|
||||||
files++;
|
files++;
|
||||||
if (cgit_repo->enable_log_linecount)
|
if (ctx.repo->enable_log_linecount)
|
||||||
cgit_diff_files(pair->one->sha1, pair->two->sha1, count_lines);
|
cgit_diff_files(pair->one->sha1, pair->two->sha1, count_lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,16 +39,16 @@ void print_commit(struct commit *commit)
|
|||||||
html("<tr><td>");
|
html("<tr><td>");
|
||||||
cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);
|
cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);
|
||||||
html("</td><td>");
|
html("</td><td>");
|
||||||
cgit_commit_link(info->subject, NULL, NULL, cgit_query_head,
|
cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head,
|
||||||
sha1_to_hex(commit->object.sha1));
|
sha1_to_hex(commit->object.sha1));
|
||||||
if (cgit_repo->enable_log_filecount) {
|
if (ctx.repo->enable_log_filecount) {
|
||||||
files = 0;
|
files = 0;
|
||||||
add_lines = 0;
|
add_lines = 0;
|
||||||
rem_lines = 0;
|
rem_lines = 0;
|
||||||
cgit_diff_commit(commit, inspect_files);
|
cgit_diff_commit(commit, inspect_files);
|
||||||
html("</td><td class='right'>");
|
html("</td><td class='right'>");
|
||||||
htmlf("%d", files);
|
htmlf("%d", files);
|
||||||
if (cgit_repo->enable_log_linecount) {
|
if (ctx.repo->enable_log_linecount) {
|
||||||
html("</td><td class='right'>");
|
html("</td><td class='right'>");
|
||||||
htmlf("-%d/+%d", rem_lines, add_lines);
|
htmlf("-%d/+%d", rem_lines, add_lines);
|
||||||
}
|
}
|
||||||
@ -67,7 +69,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!tip)
|
if (!tip)
|
||||||
argv[1] = cgit_query_head;
|
argv[1] = ctx.qry.head;
|
||||||
|
|
||||||
if (grep && pattern && (!strcmp(grep, "grep") ||
|
if (grep && pattern && (!strcmp(grep, "grep") ||
|
||||||
!strcmp(grep, "author") ||
|
!strcmp(grep, "author") ||
|
||||||
@ -94,9 +96,9 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern
|
|||||||
html("<tr class='nohover'><th class='left'>Age</th>"
|
html("<tr class='nohover'><th class='left'>Age</th>"
|
||||||
"<th class='left'>Message</th>");
|
"<th class='left'>Message</th>");
|
||||||
|
|
||||||
if (cgit_repo->enable_log_filecount) {
|
if (ctx.repo->enable_log_filecount) {
|
||||||
html("<th class='right'>Files</th>");
|
html("<th class='right'>Files</th>");
|
||||||
if (cgit_repo->enable_log_linecount)
|
if (ctx.repo->enable_log_linecount)
|
||||||
html("<th class='right'>Lines</th>");
|
html("<th class='right'>Lines</th>");
|
||||||
}
|
}
|
||||||
html("<th class='left'>Author</th></tr>\n");
|
html("<th class='left'>Author</th></tr>\n");
|
||||||
@ -123,17 +125,17 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern
|
|||||||
if (pager) {
|
if (pager) {
|
||||||
html("<div class='pager'>");
|
html("<div class='pager'>");
|
||||||
if (ofs > 0) {
|
if (ofs > 0) {
|
||||||
cgit_log_link("[prev]", NULL, NULL, cgit_query_head,
|
cgit_log_link("[prev]", NULL, NULL, ctx.qry.head,
|
||||||
cgit_query_sha1, cgit_query_path,
|
ctx.qry.sha1, ctx.qry.path,
|
||||||
ofs - cnt, cgit_query_grep,
|
ofs - cnt, ctx.qry.grep,
|
||||||
cgit_query_search);
|
ctx.qry.search);
|
||||||
html(" ");
|
html(" ");
|
||||||
}
|
}
|
||||||
if ((commit = get_revision(&rev)) != NULL) {
|
if ((commit = get_revision(&rev)) != NULL) {
|
||||||
cgit_log_link("[next]", NULL, NULL, cgit_query_head,
|
cgit_log_link("[next]", NULL, NULL, ctx.qry.head,
|
||||||
cgit_query_sha1, cgit_query_path,
|
ctx.qry.sha1, ctx.qry.path,
|
||||||
ofs + cnt, cgit_query_grep,
|
ofs + cnt, ctx.qry.grep,
|
||||||
cgit_query_search);
|
ctx.qry.search);
|
||||||
}
|
}
|
||||||
html("</div>");
|
html("</div>");
|
||||||
}
|
}
|
||||||
|
7
ui-log.h
Normal file
7
ui-log.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef UI_LOG_H
|
||||||
|
#define UI_LOG_H
|
||||||
|
|
||||||
|
extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep,
|
||||||
|
char *pattern, char *path, int pager);
|
||||||
|
|
||||||
|
#endif /* UI_LOG_H */
|
10
ui-patch.c
10
ui-patch.c
@ -7,6 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
#include "html.h"
|
||||||
|
#include "ui-shared.h"
|
||||||
|
|
||||||
static void print_line(char *line, int len)
|
static void print_line(char *line, int len)
|
||||||
{
|
{
|
||||||
@ -68,7 +70,7 @@ static void filepair_cb(struct diff_filepair *pair)
|
|||||||
html("Error running diff");
|
html("Error running diff");
|
||||||
}
|
}
|
||||||
|
|
||||||
void cgit_print_patch(char *hex, struct cacheitem *item)
|
void cgit_print_patch(char *hex)
|
||||||
{
|
{
|
||||||
struct commit *commit;
|
struct commit *commit;
|
||||||
struct commitinfo *info;
|
struct commitinfo *info;
|
||||||
@ -76,7 +78,7 @@ void cgit_print_patch(char *hex, struct cacheitem *item)
|
|||||||
char *patchname;
|
char *patchname;
|
||||||
|
|
||||||
if (!hex)
|
if (!hex)
|
||||||
hex = cgit_query_head;
|
hex = ctx.qry.head;
|
||||||
|
|
||||||
if (get_sha1(hex, sha1)) {
|
if (get_sha1(hex, sha1)) {
|
||||||
cgit_print_error(fmt("Bad object id: %s", hex));
|
cgit_print_error(fmt("Bad object id: %s", hex));
|
||||||
@ -95,7 +97,9 @@ void cgit_print_patch(char *hex, struct cacheitem *item)
|
|||||||
hashclr(old_sha1);
|
hashclr(old_sha1);
|
||||||
|
|
||||||
patchname = fmt("%s.patch", sha1_to_hex(sha1));
|
patchname = fmt("%s.patch", sha1_to_hex(sha1));
|
||||||
cgit_print_snapshot_start("text/plain", patchname, item);
|
ctx.page.mimetype = "text/plain";
|
||||||
|
ctx.page.filename = patchname;
|
||||||
|
cgit_print_http_headers(&ctx);
|
||||||
htmlf("From %s Mon Sep 17 00:00:00 2001\n", sha1_to_hex(sha1));
|
htmlf("From %s Mon Sep 17 00:00:00 2001\n", sha1_to_hex(sha1));
|
||||||
htmlf("From: %s%s\n", info->author, info->author_email);
|
htmlf("From: %s%s\n", info->author, info->author_email);
|
||||||
html("Date: ");
|
html("Date: ");
|
||||||
|
6
ui-patch.h
Normal file
6
ui-patch.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef UI_PATCH_H
|
||||||
|
#define UI_PATCH_H
|
||||||
|
|
||||||
|
extern void cgit_print_patch(char *hex);
|
||||||
|
|
||||||
|
#endif /* UI_PATCH_H */
|
175
ui-refs.c
175
ui-refs.c
@ -7,18 +7,189 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
#include "html.h"
|
||||||
|
#include "ui-shared.h"
|
||||||
|
|
||||||
|
static int header;
|
||||||
|
|
||||||
|
static int cmp_age(int age1, int age2)
|
||||||
|
{
|
||||||
|
if (age1 != 0 && age2 != 0)
|
||||||
|
return age2 - age1;
|
||||||
|
|
||||||
|
if (age1 == 0 && age2 == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (age1 == 0)
|
||||||
|
return +1;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_ref_name(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
struct refinfo *r1 = *(struct refinfo **)a;
|
||||||
|
struct refinfo *r2 = *(struct refinfo **)b;
|
||||||
|
|
||||||
|
return strcmp(r1->refname, r2->refname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_branch_age(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
struct refinfo *r1 = *(struct refinfo **)a;
|
||||||
|
struct refinfo *r2 = *(struct refinfo **)b;
|
||||||
|
|
||||||
|
return cmp_age(r1->commit->committer_date, r2->commit->committer_date);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_tag_age(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
struct refinfo *r1 = *(struct refinfo **)a;
|
||||||
|
struct refinfo *r2 = *(struct refinfo **)b;
|
||||||
|
|
||||||
|
return cmp_age(r1->tag->tagger_date, r2->tag->tagger_date);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int print_branch(struct refinfo *ref)
|
||||||
|
{
|
||||||
|
struct commitinfo *info = ref->commit;
|
||||||
|
char *name = (char *)ref->refname;
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return 1;
|
||||||
|
html("<tr><td>");
|
||||||
|
cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL);
|
||||||
|
html("</td><td>");
|
||||||
|
|
||||||
|
if (ref->object->type == OBJ_COMMIT) {
|
||||||
|
cgit_print_age(info->commit->date, -1, NULL);
|
||||||
|
html("</td><td>");
|
||||||
|
html_txt(info->author);
|
||||||
|
html("</td><td>");
|
||||||
|
cgit_commit_link(info->subject, NULL, NULL, name, NULL);
|
||||||
|
} else {
|
||||||
|
html("</td><td></td><td>");
|
||||||
|
cgit_object_link(ref->object);
|
||||||
|
}
|
||||||
|
html("</td></tr>\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 print_tag(struct refinfo *ref)
|
||||||
|
{
|
||||||
|
struct tag *tag;
|
||||||
|
struct taginfo *info;
|
||||||
|
char *url, *name = (char *)ref->refname;
|
||||||
|
|
||||||
|
if (ref->object->type == OBJ_TAG) {
|
||||||
|
tag = (struct tag *)ref->object;
|
||||||
|
info = ref->tag;
|
||||||
|
if (!tag || !info)
|
||||||
|
return 1;
|
||||||
|
html("<tr><td>");
|
||||||
|
url = cgit_pageurl(ctx.qry.repo, "tag",
|
||||||
|
fmt("id=%s", name));
|
||||||
|
html_link_open(url, NULL, NULL);
|
||||||
|
html_txt(name);
|
||||||
|
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_object_link(tag->tagged);
|
||||||
|
html("</td></tr>\n");
|
||||||
|
} else {
|
||||||
|
if (!header)
|
||||||
|
print_tag_header();
|
||||||
|
html("<tr><td>");
|
||||||
|
html_txt(name);
|
||||||
|
html("</td><td colspan='2'/><td>");
|
||||||
|
cgit_object_link(ref->object);
|
||||||
|
html("</td></tr>\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_refs_link(char *path)
|
||||||
|
{
|
||||||
|
html("<tr class='nohover'><td colspan='4'>");
|
||||||
|
cgit_refs_link("[...]", NULL, NULL, ctx.qry.head, NULL, path);
|
||||||
|
html("</td></tr>");
|
||||||
|
}
|
||||||
|
|
||||||
|
void cgit_print_branches(int maxcount)
|
||||||
|
{
|
||||||
|
struct reflist list;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
list.refs = NULL;
|
||||||
|
list.alloc = list.count = 0;
|
||||||
|
for_each_branch_ref(cgit_refs_cb, &list);
|
||||||
|
|
||||||
|
if (maxcount == 0 || maxcount > list.count)
|
||||||
|
maxcount = list.count;
|
||||||
|
|
||||||
|
if (maxcount < list.count) {
|
||||||
|
qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age);
|
||||||
|
qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0; i<maxcount; i++)
|
||||||
|
print_branch(list.refs[i]);
|
||||||
|
|
||||||
|
if (maxcount < list.count)
|
||||||
|
print_refs_link("heads");
|
||||||
|
}
|
||||||
|
|
||||||
|
void cgit_print_tags(int maxcount)
|
||||||
|
{
|
||||||
|
struct reflist list;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
header = 0;
|
||||||
|
list.refs = NULL;
|
||||||
|
list.alloc = list.count = 0;
|
||||||
|
for_each_tag_ref(cgit_refs_cb, &list);
|
||||||
|
if (list.count == 0)
|
||||||
|
return;
|
||||||
|
qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age);
|
||||||
|
if (!maxcount)
|
||||||
|
maxcount = list.count;
|
||||||
|
else if (maxcount > list.count)
|
||||||
|
maxcount = list.count;
|
||||||
|
print_tag_header();
|
||||||
|
for(i=0; i<maxcount; i++)
|
||||||
|
print_tag(list.refs[i]);
|
||||||
|
|
||||||
|
if (maxcount < list.count)
|
||||||
|
print_refs_link("tags");
|
||||||
|
}
|
||||||
|
|
||||||
void cgit_print_refs()
|
void cgit_print_refs()
|
||||||
{
|
{
|
||||||
|
|
||||||
html("<table class='list nowrap'>");
|
html("<table class='list nowrap'>");
|
||||||
|
|
||||||
if (cgit_query_path && !strncmp(cgit_query_path, "heads", 5))
|
if (ctx.qry.path && !strncmp(ctx.qry.path, "heads", 5))
|
||||||
cgit_print_branches(0);
|
cgit_print_branches(0);
|
||||||
else if (cgit_query_path && !strncmp(cgit_query_path, "tags", 4))
|
else if (ctx.qry.path && !strncmp(ctx.qry.path, "tags", 4))
|
||||||
cgit_print_tags(0);
|
cgit_print_tags(0);
|
||||||
else {
|
else {
|
||||||
cgit_print_branches(0);
|
cgit_print_branches(0);
|
||||||
|
8
ui-refs.h
Normal file
8
ui-refs.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef UI_REFS_H
|
||||||
|
#define UI_REFS_H
|
||||||
|
|
||||||
|
extern void cgit_print_branches(int maxcount);
|
||||||
|
extern void cgit_print_tags(int maxcount);
|
||||||
|
extern void cgit_print_refs();
|
||||||
|
|
||||||
|
#endif /* UI_REFS_H */
|
@ -6,9 +6,11 @@
|
|||||||
* (see COPYING for full license text)
|
* (see COPYING for full license text)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "cgit.h"
|
||||||
|
#include "html.h"
|
||||||
|
#include "ui-shared.h"
|
||||||
|
|
||||||
time_t read_agefile(char *path)
|
time_t read_agefile(char *path)
|
||||||
{
|
{
|
||||||
@ -25,12 +27,12 @@ time_t read_agefile(char *path)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_modtime(struct repoinfo *repo)
|
static void print_modtime(struct cgit_repo *repo)
|
||||||
{
|
{
|
||||||
char *path;
|
char *path;
|
||||||
struct stat s;
|
struct stat s;
|
||||||
|
|
||||||
path = fmt("%s/%s", repo->path, cgit_agefile);
|
path = fmt("%s/%s", repo->path, ctx.cfg.agefile);
|
||||||
if (stat(path, &s) == 0) {
|
if (stat(path, &s) == 0) {
|
||||||
cgit_print_age(read_agefile(path), -1, NULL);
|
cgit_print_age(read_agefile(path), -1, NULL);
|
||||||
return;
|
return;
|
||||||
@ -42,22 +44,24 @@ static void print_modtime(struct repoinfo *repo)
|
|||||||
cgit_print_age(s.st_mtime, -1, NULL);
|
cgit_print_age(s.st_mtime, -1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cgit_print_repolist(struct cacheitem *item)
|
void cgit_print_repolist()
|
||||||
{
|
{
|
||||||
int i, columns = 4;
|
int i, columns = 4;
|
||||||
char *last_group = NULL;
|
char *last_group = NULL;
|
||||||
|
|
||||||
if (cgit_enable_index_links)
|
if (ctx.cfg.enable_index_links)
|
||||||
columns++;
|
columns++;
|
||||||
|
|
||||||
cgit_print_docstart(cgit_root_title, item);
|
ctx.page.title = ctx.cfg.root_title;
|
||||||
cgit_print_pageheader(cgit_root_title, 0);
|
cgit_print_http_headers(&ctx);
|
||||||
|
cgit_print_docstart(&ctx);
|
||||||
|
cgit_print_pageheader(&ctx);
|
||||||
|
|
||||||
html("<table summary='repository list' class='list nowrap'>");
|
html("<table summary='repository list' class='list nowrap'>");
|
||||||
if (cgit_index_header) {
|
if (ctx.cfg.index_header) {
|
||||||
htmlf("<tr class='nohover'><td colspan='%d' class='include-block'>",
|
htmlf("<tr class='nohover'><td colspan='%d' class='include-block'>",
|
||||||
columns);
|
columns);
|
||||||
html_include(cgit_index_header);
|
html_include(ctx.cfg.index_header);
|
||||||
html("</td></tr>");
|
html("</td></tr>");
|
||||||
}
|
}
|
||||||
html("<tr class='nohover'>"
|
html("<tr class='nohover'>"
|
||||||
@ -65,37 +69,37 @@ void cgit_print_repolist(struct cacheitem *item)
|
|||||||
"<th class='left'>Description</th>"
|
"<th class='left'>Description</th>"
|
||||||
"<th class='left'>Owner</th>"
|
"<th class='left'>Owner</th>"
|
||||||
"<th class='left'>Idle</th>");
|
"<th class='left'>Idle</th>");
|
||||||
if (cgit_enable_index_links)
|
if (ctx.cfg.enable_index_links)
|
||||||
html("<th>Links</th>");
|
html("<th>Links</th>");
|
||||||
html("</tr>\n");
|
html("</tr>\n");
|
||||||
|
|
||||||
for (i=0; i<cgit_repolist.count; i++) {
|
for (i=0; i<cgit_repolist.count; i++) {
|
||||||
cgit_repo = &cgit_repolist.repos[i];
|
ctx.repo = &cgit_repolist.repos[i];
|
||||||
if ((last_group == NULL && cgit_repo->group != NULL) ||
|
if ((last_group == NULL && ctx.repo->group != NULL) ||
|
||||||
(last_group != NULL && cgit_repo->group == NULL) ||
|
(last_group != NULL && ctx.repo->group == NULL) ||
|
||||||
(last_group != NULL && cgit_repo->group != NULL &&
|
(last_group != NULL && ctx.repo->group != NULL &&
|
||||||
strcmp(cgit_repo->group, last_group))) {
|
strcmp(ctx.repo->group, last_group))) {
|
||||||
htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>",
|
htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>",
|
||||||
columns);
|
columns);
|
||||||
html_txt(cgit_repo->group);
|
html_txt(ctx.repo->group);
|
||||||
html("</td></tr>");
|
html("</td></tr>");
|
||||||
last_group = cgit_repo->group;
|
last_group = ctx.repo->group;
|
||||||
}
|
}
|
||||||
htmlf("<tr><td class='%s'>",
|
htmlf("<tr><td class='%s'>",
|
||||||
cgit_repo->group ? "sublevel-repo" : "toplevel-repo");
|
ctx.repo->group ? "sublevel-repo" : "toplevel-repo");
|
||||||
html_link_open(cgit_repourl(cgit_repo->url), NULL, NULL);
|
html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL);
|
||||||
html_txt(cgit_repo->name);
|
html_txt(ctx.repo->name);
|
||||||
html_link_close();
|
html_link_close();
|
||||||
html("</td><td>");
|
html("</td><td>");
|
||||||
html_ntxt(cgit_max_repodesc_len, cgit_repo->desc);
|
html_ntxt(ctx.cfg.max_repodesc_len, ctx.repo->desc);
|
||||||
html("</td><td>");
|
html("</td><td>");
|
||||||
html_txt(cgit_repo->owner);
|
html_txt(ctx.repo->owner);
|
||||||
html("</td><td>");
|
html("</td><td>");
|
||||||
print_modtime(cgit_repo);
|
print_modtime(ctx.repo);
|
||||||
html("</td>");
|
html("</td>");
|
||||||
if (cgit_enable_index_links) {
|
if (ctx.cfg.enable_index_links) {
|
||||||
html("<td>");
|
html("<td>");
|
||||||
html_link_open(cgit_repourl(cgit_repo->url),
|
html_link_open(cgit_repourl(ctx.repo->url),
|
||||||
NULL, "button");
|
NULL, "button");
|
||||||
html("summary</a>");
|
html("summary</a>");
|
||||||
cgit_log_link("log", NULL, "button", NULL, NULL, NULL,
|
cgit_log_link("log", NULL, "button", NULL, NULL, NULL,
|
||||||
|
6
ui-repolist.h
Normal file
6
ui-repolist.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef UI_REPOLIST_H
|
||||||
|
#define UI_REPOLIST_H
|
||||||
|
|
||||||
|
extern void cgit_print_repolist();
|
||||||
|
|
||||||
|
#endif /* UI_REPOLIST_H */
|
237
ui-shared.c
237
ui-shared.c
@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
#include "html.h"
|
||||||
|
|
||||||
const char cgit_doctype[] =
|
const char cgit_doctype[] =
|
||||||
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
|
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
|
||||||
@ -25,14 +26,6 @@ static char *http_date(time_t t)
|
|||||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long ttl_seconds(long ttl)
|
|
||||||
{
|
|
||||||
if (ttl<0)
|
|
||||||
return 60 * 60 * 24 * 365;
|
|
||||||
else
|
|
||||||
return ttl * 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cgit_print_error(char *msg)
|
void cgit_print_error(char *msg)
|
||||||
{
|
{
|
||||||
html("<div class='error'>");
|
html("<div class='error'>");
|
||||||
@ -42,16 +35,16 @@ void cgit_print_error(char *msg)
|
|||||||
|
|
||||||
char *cgit_rooturl()
|
char *cgit_rooturl()
|
||||||
{
|
{
|
||||||
if (cgit_virtual_root)
|
if (ctx.cfg.virtual_root)
|
||||||
return fmt("%s/", cgit_virtual_root);
|
return fmt("%s/", ctx.cfg.virtual_root);
|
||||||
else
|
else
|
||||||
return cgit_script_name;
|
return ctx.cfg.script_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *cgit_repourl(const char *reponame)
|
char *cgit_repourl(const char *reponame)
|
||||||
{
|
{
|
||||||
if (cgit_virtual_root) {
|
if (ctx.cfg.virtual_root) {
|
||||||
return fmt("%s/%s/", cgit_virtual_root, reponame);
|
return fmt("%s/%s/", ctx.cfg.virtual_root, reponame);
|
||||||
} else {
|
} else {
|
||||||
return fmt("?r=%s", reponame);
|
return fmt("?r=%s", reponame);
|
||||||
}
|
}
|
||||||
@ -63,8 +56,8 @@ char *cgit_fileurl(const char *reponame, const char *pagename,
|
|||||||
char *tmp;
|
char *tmp;
|
||||||
char *delim;
|
char *delim;
|
||||||
|
|
||||||
if (cgit_virtual_root) {
|
if (ctx.cfg.virtual_root) {
|
||||||
tmp = fmt("%s/%s/%s/%s", cgit_virtual_root, reponame,
|
tmp = fmt("%s/%s/%s/%s", ctx.cfg.virtual_root, reponame,
|
||||||
pagename, (filename ? filename:""));
|
pagename, (filename ? filename:""));
|
||||||
delim = "?";
|
delim = "?";
|
||||||
} else {
|
} else {
|
||||||
@ -110,14 +103,14 @@ const char *cgit_repobasename(const char *reponame)
|
|||||||
|
|
||||||
char *cgit_currurl()
|
char *cgit_currurl()
|
||||||
{
|
{
|
||||||
if (!cgit_virtual_root)
|
if (!ctx.cfg.virtual_root)
|
||||||
return cgit_script_name;
|
return ctx.cfg.script_name;
|
||||||
else if (cgit_query_page)
|
else if (ctx.qry.page)
|
||||||
return fmt("%s/%s/%s/", cgit_virtual_root, cgit_query_repo, cgit_query_page);
|
return fmt("%s/%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo, ctx.qry.page);
|
||||||
else if (cgit_query_repo)
|
else if (ctx.qry.repo)
|
||||||
return fmt("%s/%s/", cgit_virtual_root, cgit_query_repo);
|
return fmt("%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo);
|
||||||
else
|
else
|
||||||
return fmt("%s/", cgit_virtual_root);
|
return fmt("%s/", ctx.cfg.virtual_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *repolink(char *title, char *class, char *page, char *head,
|
static char *repolink(char *title, char *class, char *page, char *head,
|
||||||
@ -137,12 +130,12 @@ static char *repolink(char *title, char *class, char *page, char *head,
|
|||||||
html("'");
|
html("'");
|
||||||
}
|
}
|
||||||
html(" href='");
|
html(" href='");
|
||||||
if (cgit_virtual_root) {
|
if (ctx.cfg.virtual_root) {
|
||||||
html_attr(cgit_virtual_root);
|
html_attr(ctx.cfg.virtual_root);
|
||||||
if (cgit_virtual_root[strlen(cgit_virtual_root) - 1] != '/')
|
if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/')
|
||||||
html("/");
|
html("/");
|
||||||
html_attr(cgit_repo->url);
|
html_attr(ctx.repo->url);
|
||||||
if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/')
|
if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/')
|
||||||
html("/");
|
html("/");
|
||||||
if (page) {
|
if (page) {
|
||||||
html(page);
|
html(page);
|
||||||
@ -151,10 +144,10 @@ static char *repolink(char *title, char *class, char *page, char *head,
|
|||||||
html_attr(path);
|
html_attr(path);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
html(cgit_script_name);
|
html(ctx.cfg.script_name);
|
||||||
html("?url=");
|
html("?url=");
|
||||||
html_attr(cgit_repo->url);
|
html_attr(ctx.repo->url);
|
||||||
if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/')
|
if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/')
|
||||||
html("/");
|
html("/");
|
||||||
if (page) {
|
if (page) {
|
||||||
html(page);
|
html(page);
|
||||||
@ -164,7 +157,7 @@ static char *repolink(char *title, char *class, char *page, char *head,
|
|||||||
}
|
}
|
||||||
delim = "&";
|
delim = "&";
|
||||||
}
|
}
|
||||||
if (head && strcmp(head, cgit_repo->defbranch)) {
|
if (head && strcmp(head, ctx.repo->defbranch)) {
|
||||||
html(delim);
|
html(delim);
|
||||||
html("h=");
|
html("h=");
|
||||||
html_attr(head);
|
html_attr(head);
|
||||||
@ -179,7 +172,7 @@ static void reporevlink(char *page, char *name, char *title, char *class,
|
|||||||
char *delim;
|
char *delim;
|
||||||
|
|
||||||
delim = repolink(title, class, page, head, path);
|
delim = repolink(title, class, page, head, path);
|
||||||
if (rev && strcmp(rev, cgit_query_head)) {
|
if (rev && strcmp(rev, ctx.qry.head)) {
|
||||||
html(delim);
|
html(delim);
|
||||||
html("id=");
|
html("id=");
|
||||||
html_attr(rev);
|
html_attr(rev);
|
||||||
@ -201,7 +194,7 @@ void cgit_log_link(char *name, char *title, char *class, char *head,
|
|||||||
char *delim;
|
char *delim;
|
||||||
|
|
||||||
delim = repolink(title, class, "log", head, path);
|
delim = repolink(title, class, "log", head, path);
|
||||||
if (rev && strcmp(rev, cgit_query_head)) {
|
if (rev && strcmp(rev, ctx.qry.head)) {
|
||||||
html(delim);
|
html(delim);
|
||||||
html("id=");
|
html("id=");
|
||||||
html_attr(rev);
|
html_attr(rev);
|
||||||
@ -229,11 +222,11 @@ void cgit_log_link(char *name, char *title, char *class, char *head,
|
|||||||
void cgit_commit_link(char *name, char *title, char *class, char *head,
|
void cgit_commit_link(char *name, char *title, char *class, char *head,
|
||||||
char *rev)
|
char *rev)
|
||||||
{
|
{
|
||||||
if (strlen(name) > cgit_max_msg_len && cgit_max_msg_len >= 15) {
|
if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) {
|
||||||
name[cgit_max_msg_len] = '\0';
|
name[ctx.cfg.max_msg_len] = '\0';
|
||||||
name[cgit_max_msg_len - 1] = '.';
|
name[ctx.cfg.max_msg_len - 1] = '.';
|
||||||
name[cgit_max_msg_len - 2] = '.';
|
name[ctx.cfg.max_msg_len - 2] = '.';
|
||||||
name[cgit_max_msg_len - 3] = '.';
|
name[ctx.cfg.max_msg_len - 3] = '.';
|
||||||
}
|
}
|
||||||
reporevlink("commit", name, title, class, head, rev, NULL);
|
reporevlink("commit", name, title, class, head, rev, NULL);
|
||||||
}
|
}
|
||||||
@ -256,7 +249,7 @@ void cgit_diff_link(char *name, char *title, char *class, char *head,
|
|||||||
char *delim;
|
char *delim;
|
||||||
|
|
||||||
delim = repolink(title, class, "diff", head, path);
|
delim = repolink(title, class, "diff", head, path);
|
||||||
if (new_rev && strcmp(new_rev, cgit_query_head)) {
|
if (new_rev && strcmp(new_rev, ctx.qry.head)) {
|
||||||
html(delim);
|
html(delim);
|
||||||
html("id=");
|
html("id=");
|
||||||
html_attr(new_rev);
|
html_attr(new_rev);
|
||||||
@ -284,7 +277,7 @@ void cgit_object_link(struct object *obj)
|
|||||||
|
|
||||||
if (obj->type == OBJ_COMMIT) {
|
if (obj->type == OBJ_COMMIT) {
|
||||||
cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL,
|
cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL,
|
||||||
cgit_query_head, sha1_to_hex(obj->sha1));
|
ctx.qry.head, sha1_to_hex(obj->sha1));
|
||||||
return;
|
return;
|
||||||
} else if (obj->type == OBJ_TREE) {
|
} else if (obj->type == OBJ_TREE) {
|
||||||
page = "tree";
|
page = "tree";
|
||||||
@ -297,7 +290,7 @@ void cgit_object_link(struct object *obj)
|
|||||||
arg = "id";
|
arg = "id";
|
||||||
}
|
}
|
||||||
|
|
||||||
url = cgit_pageurl(cgit_query_repo, page,
|
url = cgit_pageurl(ctx.qry.repo, page,
|
||||||
fmt("%s=%s", arg, sha1_to_hex(obj->sha1)));
|
fmt("%s=%s", arg, sha1_to_hex(obj->sha1)));
|
||||||
html_link_open(url, NULL, NULL);
|
html_link_open(url, NULL, NULL);
|
||||||
htmlf("%s %s", typename(obj->type),
|
htmlf("%s %s", typename(obj->type),
|
||||||
@ -360,24 +353,34 @@ void cgit_print_age(time_t t, time_t max_relative, char *format)
|
|||||||
secs * 1.0 / TM_YEAR);
|
secs * 1.0 / TM_YEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cgit_print_docstart(char *title, struct cacheitem *item)
|
void cgit_print_http_headers(struct cgit_context *ctx)
|
||||||
{
|
{
|
||||||
html("Content-Type: text/html; charset=" PAGE_ENCODING "\n");
|
if (ctx->page.mimetype && ctx->page.charset)
|
||||||
htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime));
|
htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype,
|
||||||
htmlf("Expires: %s\n", http_date(item->st.st_mtime +
|
ctx->page.charset);
|
||||||
ttl_seconds(item->ttl)));
|
else if (ctx->page.mimetype)
|
||||||
|
htmlf("Content-Type: %s\n", ctx->page.mimetype);
|
||||||
|
if (ctx->page.filename)
|
||||||
|
htmlf("Content-Disposition: inline; filename=\"%s\"\n",
|
||||||
|
ctx->page.filename);
|
||||||
|
htmlf("Last-Modified: %s\n", http_date(ctx->page.modified));
|
||||||
|
htmlf("Expires: %s\n", http_date(ctx->page.expires));
|
||||||
html("\n");
|
html("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void cgit_print_docstart(struct cgit_context *ctx)
|
||||||
|
{
|
||||||
html(cgit_doctype);
|
html(cgit_doctype);
|
||||||
html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n");
|
html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n");
|
||||||
html("<head>\n");
|
html("<head>\n");
|
||||||
html("<title>");
|
html("<title>");
|
||||||
html_txt(title);
|
html_txt(ctx->page.title);
|
||||||
html("</title>\n");
|
html("</title>\n");
|
||||||
htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version);
|
htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version);
|
||||||
if (cgit_robots && *cgit_robots)
|
if (ctx->cfg.robots && *ctx->cfg.robots)
|
||||||
htmlf("<meta name='robots' content='%s'/>\n", cgit_robots);
|
htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots);
|
||||||
html("<link rel='stylesheet' type='text/css' href='");
|
html("<link rel='stylesheet' type='text/css' href='");
|
||||||
html_attr(cgit_css);
|
html_attr(ctx->cfg.css);
|
||||||
html("'/>\n");
|
html("'/>\n");
|
||||||
html("</head>\n");
|
html("</head>\n");
|
||||||
html("<body>\n");
|
html("<body>\n");
|
||||||
@ -392,7 +395,7 @@ int print_branch_option(const char *refname, const unsigned char *sha1,
|
|||||||
int flags, void *cb_data)
|
int flags, void *cb_data)
|
||||||
{
|
{
|
||||||
char *name = (char *)refname;
|
char *name = (char *)refname;
|
||||||
html_option(name, name, cgit_query_head);
|
html_option(name, name, ctx.qry.head);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,7 +429,7 @@ int print_archive_ref(const char *refname, const unsigned char *sha1,
|
|||||||
html("<h1>download</h1>\n");
|
html("<h1>download</h1>\n");
|
||||||
*header = 1;
|
*header = 1;
|
||||||
}
|
}
|
||||||
url = cgit_pageurl(cgit_query_repo, "blob",
|
url = cgit_pageurl(ctx.qry.repo, "blob",
|
||||||
fmt("id=%s&path=%s", sha1_to_hex(fileid),
|
fmt("id=%s&path=%s", sha1_to_hex(fileid),
|
||||||
buf));
|
buf));
|
||||||
html_link_open(url, NULL, "menu");
|
html_link_open(url, NULL, "menu");
|
||||||
@ -439,30 +442,30 @@ void add_hidden_formfields(int incl_head, int incl_search, char *page)
|
|||||||
{
|
{
|
||||||
char *url;
|
char *url;
|
||||||
|
|
||||||
if (!cgit_virtual_root) {
|
if (!ctx.cfg.virtual_root) {
|
||||||
url = fmt("%s/%s", cgit_query_repo, page);
|
url = fmt("%s/%s", ctx.qry.repo, page);
|
||||||
if (cgit_query_path)
|
if (ctx.qry.path)
|
||||||
url = fmt("%s/%s", url, cgit_query_path);
|
url = fmt("%s/%s", url, ctx.qry.path);
|
||||||
html_hidden("url", url);
|
html_hidden("url", url);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (incl_head && strcmp(cgit_query_head, cgit_repo->defbranch))
|
if (incl_head && strcmp(ctx.qry.head, ctx.repo->defbranch))
|
||||||
html_hidden("h", cgit_query_head);
|
html_hidden("h", ctx.qry.head);
|
||||||
|
|
||||||
if (cgit_query_sha1)
|
if (ctx.qry.sha1)
|
||||||
html_hidden("id", cgit_query_sha1);
|
html_hidden("id", ctx.qry.sha1);
|
||||||
if (cgit_query_sha2)
|
if (ctx.qry.sha2)
|
||||||
html_hidden("id2", cgit_query_sha2);
|
html_hidden("id2", ctx.qry.sha2);
|
||||||
|
|
||||||
if (incl_search) {
|
if (incl_search) {
|
||||||
if (cgit_query_grep)
|
if (ctx.qry.grep)
|
||||||
html_hidden("qt", cgit_query_grep);
|
html_hidden("qt", ctx.qry.grep);
|
||||||
if (cgit_query_search)
|
if (ctx.qry.search)
|
||||||
html_hidden("q", cgit_query_search);
|
html_hidden("q", ctx.qry.search);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cgit_print_pageheader(char *title, int show_search)
|
void cgit_print_pageheader(struct cgit_context *ctx)
|
||||||
{
|
{
|
||||||
static const char *default_info = "This is cgit, a fast webinterface for git repositories";
|
static const char *default_info = "This is cgit, a fast webinterface for git repositories";
|
||||||
int header = 0;
|
int header = 0;
|
||||||
@ -474,40 +477,40 @@ void cgit_print_pageheader(char *title, int show_search)
|
|||||||
html("<tr><td class='sidebar'>\n<a href='");
|
html("<tr><td class='sidebar'>\n<a href='");
|
||||||
html_attr(cgit_rooturl());
|
html_attr(cgit_rooturl());
|
||||||
htmlf("'><img src='%s' alt='cgit'/></a>\n",
|
htmlf("'><img src='%s' alt='cgit'/></a>\n",
|
||||||
cgit_logo);
|
ctx->cfg.logo);
|
||||||
html("</td></tr>\n<tr><td class='sidebar'>\n");
|
html("</td></tr>\n<tr><td class='sidebar'>\n");
|
||||||
if (cgit_query_repo) {
|
if (ctx->repo) {
|
||||||
html("<h1 class='first'>");
|
html("<h1 class='first'>");
|
||||||
html_txt(strrpart(cgit_repo->name, 20));
|
html_txt(strrpart(ctx->repo->name, 20));
|
||||||
html("</h1>\n");
|
html("</h1>\n");
|
||||||
html_txt(cgit_repo->desc);
|
html_txt(ctx->repo->desc);
|
||||||
if (cgit_repo->owner) {
|
if (ctx->repo->owner) {
|
||||||
html("<h1>owner</h1>\n");
|
html("<h1>owner</h1>\n");
|
||||||
html_txt(cgit_repo->owner);
|
html_txt(ctx->repo->owner);
|
||||||
}
|
}
|
||||||
html("<h1>navigate</h1>\n");
|
html("<h1>navigate</h1>\n");
|
||||||
reporevlink(NULL, "summary", NULL, "menu", cgit_query_head,
|
reporevlink(NULL, "summary", NULL, "menu", ctx->qry.head,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
cgit_log_link("log", NULL, "menu", cgit_query_head, NULL, NULL,
|
cgit_log_link("log", NULL, "menu", ctx->qry.head, NULL, NULL,
|
||||||
0, NULL, NULL);
|
0, NULL, NULL);
|
||||||
cgit_tree_link("tree", NULL, "menu", cgit_query_head,
|
cgit_tree_link("tree", NULL, "menu", ctx->qry.head,
|
||||||
cgit_query_sha1, NULL);
|
ctx->qry.sha1, NULL);
|
||||||
cgit_commit_link("commit", NULL, "menu", cgit_query_head,
|
cgit_commit_link("commit", NULL, "menu", ctx->qry.head,
|
||||||
cgit_query_sha1);
|
ctx->qry.sha1);
|
||||||
cgit_diff_link("diff", NULL, "menu", cgit_query_head,
|
cgit_diff_link("diff", NULL, "menu", ctx->qry.head,
|
||||||
cgit_query_sha1, cgit_query_sha2, NULL);
|
ctx->qry.sha1, ctx->qry.sha2, NULL);
|
||||||
cgit_patch_link("patch", NULL, "menu", cgit_query_head,
|
cgit_patch_link("patch", NULL, "menu", ctx->qry.head,
|
||||||
cgit_query_sha1);
|
ctx->qry.sha1);
|
||||||
|
|
||||||
for_each_ref(print_archive_ref, &header);
|
for_each_ref(print_archive_ref, &header);
|
||||||
|
|
||||||
if (cgit_repo->clone_url || cgit_clone_prefix) {
|
if (ctx->repo->clone_url || ctx->cfg.clone_prefix) {
|
||||||
html("<h1>clone</h1>\n");
|
html("<h1>clone</h1>\n");
|
||||||
if (cgit_repo->clone_url)
|
if (ctx->repo->clone_url)
|
||||||
url = cgit_repo->clone_url;
|
url = ctx->repo->clone_url;
|
||||||
else
|
else
|
||||||
url = fmt("%s%s", cgit_clone_prefix,
|
url = fmt("%s%s", ctx->cfg.clone_prefix,
|
||||||
cgit_repo->url);
|
ctx->repo->url);
|
||||||
html("<a class='menu' href='");
|
html("<a class='menu' href='");
|
||||||
html_attr(url);
|
html_attr(url);
|
||||||
html("' title='");
|
html("' title='");
|
||||||
@ -519,10 +522,10 @@ void cgit_print_pageheader(char *title, int show_search)
|
|||||||
|
|
||||||
html("<h1>branch</h1>\n");
|
html("<h1>branch</h1>\n");
|
||||||
html("<form method='get' action=''>\n");
|
html("<form method='get' action=''>\n");
|
||||||
add_hidden_formfields(0, 1, cgit_query_page);
|
add_hidden_formfields(0, 1, ctx->qry.page);
|
||||||
// html("<table summary='branch selector' class='grid'><tr><td id='branch-dropdown-cell'>");
|
// html("<table summary='branch selector' class='grid'><tr><td id='branch-dropdown-cell'>");
|
||||||
html("<select name='h' onchange='this.form.submit();'>\n");
|
html("<select name='h' onchange='this.form.submit();'>\n");
|
||||||
for_each_branch_ref(print_branch_option, cgit_query_head);
|
for_each_branch_ref(print_branch_option, ctx->qry.head);
|
||||||
html("</select>\n");
|
html("</select>\n");
|
||||||
// html("</td><td>");
|
// html("</td><td>");
|
||||||
html("<noscript><input type='submit' id='switch-btn' value='switch'/></noscript>\n");
|
html("<noscript><input type='submit' id='switch-btn' value='switch'/></noscript>\n");
|
||||||
@ -531,22 +534,22 @@ void cgit_print_pageheader(char *title, int show_search)
|
|||||||
|
|
||||||
html("<h1>search</h1>\n");
|
html("<h1>search</h1>\n");
|
||||||
html("<form method='get' action='");
|
html("<form method='get' action='");
|
||||||
if (cgit_virtual_root)
|
if (ctx->cfg.virtual_root)
|
||||||
html_attr(cgit_fileurl(cgit_query_repo, "log",
|
html_attr(cgit_fileurl(ctx->qry.repo, "log",
|
||||||
cgit_query_path, NULL));
|
ctx->qry.path, NULL));
|
||||||
html("'>\n");
|
html("'>\n");
|
||||||
add_hidden_formfields(1, 0, "log");
|
add_hidden_formfields(1, 0, "log");
|
||||||
html("<select name='qt'>\n");
|
html("<select name='qt'>\n");
|
||||||
html_option("grep", "log msg", cgit_query_grep);
|
html_option("grep", "log msg", ctx->qry.grep);
|
||||||
html_option("author", "author", cgit_query_grep);
|
html_option("author", "author", ctx->qry.grep);
|
||||||
html_option("committer", "committer", cgit_query_grep);
|
html_option("committer", "committer", ctx->qry.grep);
|
||||||
html("</select>\n");
|
html("</select>\n");
|
||||||
html("<input class='txt' type='text' name='q' value='");
|
html("<input class='txt' type='text' name='q' value='");
|
||||||
html_attr(cgit_query_search);
|
html_attr(ctx->qry.search);
|
||||||
html("'/>\n");
|
html("'/>\n");
|
||||||
html("</form>\n");
|
html("</form>\n");
|
||||||
} else {
|
} else {
|
||||||
if (!cgit_index_info || html_include(cgit_index_info))
|
if (!ctx->cfg.index_info || html_include(ctx->cfg.index_info))
|
||||||
html(default_info);
|
html(default_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,16 +558,34 @@ void cgit_print_pageheader(char *title, int show_search)
|
|||||||
html("<td id='content'>\n");
|
html("<td id='content'>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cgit_print_filemode(unsigned short mode)
|
||||||
void cgit_print_snapshot_start(const char *mimetype, const char *filename,
|
|
||||||
struct cacheitem *item)
|
|
||||||
{
|
{
|
||||||
htmlf("Content-Type: %s\n", mimetype);
|
if (S_ISDIR(mode))
|
||||||
htmlf("Content-Disposition: inline; filename=\"%s\"\n", filename);
|
html("d");
|
||||||
htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime));
|
else if (S_ISLNK(mode))
|
||||||
htmlf("Expires: %s\n", http_date(item->st.st_mtime +
|
html("l");
|
||||||
ttl_seconds(item->ttl)));
|
else if (S_ISGITLINK(mode))
|
||||||
html("\n");
|
html("m");
|
||||||
|
else
|
||||||
|
html("-");
|
||||||
|
html_fileperm(mode >> 6);
|
||||||
|
html_fileperm(mode >> 3);
|
||||||
|
html_fileperm(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vim:set sw=8: */
|
void cgit_print_snapshot_links(const char *repo, const char *head,
|
||||||
|
const char *hex, int snapshots)
|
||||||
|
{
|
||||||
|
const struct cgit_snapshot_format* f;
|
||||||
|
char *filename;
|
||||||
|
|
||||||
|
for (f = cgit_snapshot_formats; f->suffix; f++) {
|
||||||
|
if (!(snapshots & f->bit))
|
||||||
|
continue;
|
||||||
|
filename = fmt("%s-%s%s", cgit_repobasename(repo), hex,
|
||||||
|
f->suffix);
|
||||||
|
cgit_snapshot_link(filename, NULL, NULL, (char *)head,
|
||||||
|
(char *)hex, filename);
|
||||||
|
html("<br/>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
36
ui-shared.h
Normal file
36
ui-shared.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef UI_SHARED_H
|
||||||
|
#define UI_SHARED_H
|
||||||
|
|
||||||
|
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 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, char *grep,
|
||||||
|
char *pattern);
|
||||||
|
extern void cgit_commit_link(char *name, char *title, char *class, char *head,
|
||||||
|
char *rev);
|
||||||
|
extern void cgit_refs_link(char *name, char *title, char *class, char *head,
|
||||||
|
char *rev, char *path);
|
||||||
|
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);
|
||||||
|
extern void cgit_print_http_headers(struct cgit_context *ctx);
|
||||||
|
extern void cgit_print_docstart(struct cgit_context *ctx);
|
||||||
|
extern void cgit_print_docend();
|
||||||
|
extern void cgit_print_pageheader(struct cgit_context *ctx);
|
||||||
|
extern void cgit_print_filemode(unsigned short mode);
|
||||||
|
extern void cgit_print_snapshot_links(const char *repo, const char *head,
|
||||||
|
const char *hex, int snapshots);
|
||||||
|
|
||||||
|
#endif /* UI_SHARED_H */
|
125
ui-snapshot.c
125
ui-snapshot.c
@ -7,6 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
#include "html.h"
|
||||||
|
#include "ui-shared.h"
|
||||||
|
|
||||||
static int write_compressed_tar_archive(struct archiver_args *args,const char *filter)
|
static int write_compressed_tar_archive(struct archiver_args *args,const char *filter)
|
||||||
{
|
{
|
||||||
@ -54,104 +56,59 @@ static int write_tar_bzip2_archive(struct archiver_args *args)
|
|||||||
return write_compressed_tar_archive(args,"bzip2");
|
return write_compressed_tar_archive(args,"bzip2");
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct snapshot_archive_t {
|
const struct cgit_snapshot_format cgit_snapshot_formats[] = {
|
||||||
const char *suffix;
|
|
||||||
const char *mimetype;
|
|
||||||
write_archive_fn_t write_func;
|
|
||||||
int bit;
|
|
||||||
} snapshot_archives[] = {
|
|
||||||
{ ".zip", "application/x-zip", write_zip_archive, 0x1 },
|
{ ".zip", "application/x-zip", write_zip_archive, 0x1 },
|
||||||
{ ".tar.gz", "application/x-tar", write_tar_gzip_archive, 0x2 },
|
{ ".tar.gz", "application/x-tar", write_tar_gzip_archive, 0x2 },
|
||||||
{ ".tar.bz2", "application/x-tar", write_tar_bzip2_archive, 0x4 },
|
{ ".tar.bz2", "application/x-tar", write_tar_bzip2_archive, 0x4 },
|
||||||
{ ".tar", "application/x-tar", write_tar_archive, 0x8 }
|
{ ".tar", "application/x-tar", write_tar_archive, 0x8 },
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define snapshot_archives_len (sizeof(snapshot_archives) / sizeof(*snapshot_archives))
|
static int make_snapshot(const struct cgit_snapshot_format *format,
|
||||||
|
|
||||||
void cgit_print_snapshot(struct cacheitem *item, const char *head,
|
|
||||||
const char *hex, const char *prefix,
|
const char *hex, const char *prefix,
|
||||||
const char *filename, int snapshots)
|
const char *filename)
|
||||||
{
|
{
|
||||||
const struct snapshot_archive_t* sat;
|
|
||||||
struct archiver_args args;
|
struct archiver_args args;
|
||||||
struct commit *commit;
|
struct commit *commit;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
int f, sl, fnl = strlen(filename);
|
|
||||||
|
|
||||||
for(f=0; f<snapshot_archives_len; f++) {
|
if(get_sha1(hex, sha1)) {
|
||||||
sat = &snapshot_archives[f];
|
cgit_print_error(fmt("Bad object id: %s", hex));
|
||||||
if(!(snapshots & sat->bit))
|
return 1;
|
||||||
|
}
|
||||||
|
commit = lookup_commit_reference(sha1);
|
||||||
|
if(!commit) {
|
||||||
|
cgit_print_error(fmt("Not a commit reference: %s", hex));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
memset(&args, 0, sizeof(args));
|
||||||
|
args.base = fmt("%s/", prefix);
|
||||||
|
args.tree = commit->tree;
|
||||||
|
args.time = commit->date;
|
||||||
|
ctx.page.mimetype = xstrdup(format->mimetype);
|
||||||
|
ctx.page.filename = xstrdup(filename);
|
||||||
|
cgit_print_http_headers(&ctx);
|
||||||
|
format->write_func(&args);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cgit_print_snapshot(const char *head, const char *hex, const char *prefix,
|
||||||
|
const char *filename, int snapshots)
|
||||||
|
{
|
||||||
|
const struct cgit_snapshot_format* f;
|
||||||
|
int sl, fnl;
|
||||||
|
|
||||||
|
fnl = strlen(filename);
|
||||||
|
if (!hex)
|
||||||
|
hex = head;
|
||||||
|
for (f = cgit_snapshot_formats; f->suffix; f++) {
|
||||||
|
if (!(snapshots & f->bit))
|
||||||
continue;
|
continue;
|
||||||
sl = strlen(sat->suffix);
|
sl = strlen(f->suffix);
|
||||||
if(fnl<sl || strcmp(&filename[fnl-sl],sat->suffix))
|
if(fnl < sl || strcmp(&filename[fnl-sl], f->suffix))
|
||||||
continue;
|
continue;
|
||||||
if (!hex)
|
make_snapshot(f, hex, prefix, filename);
|
||||||
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;
|
|
||||||
args.time = commit->date;
|
|
||||||
cgit_print_snapshot_start(sat->mimetype, filename, item);
|
|
||||||
(*sat->write_func)(&args);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cgit_print_error(fmt("Unsupported snapshot format: %s", filename));
|
cgit_print_error(fmt("Unsupported snapshot format: %s", filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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/>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int cgit_parse_snapshots_mask(const char *str)
|
|
||||||
{
|
|
||||||
const struct snapshot_archive_t* sat;
|
|
||||||
static const char *delim = " \t,:/|;";
|
|
||||||
int f, tl, sl, 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];
|
|
||||||
sl = strlen(sat->suffix);
|
|
||||||
if((tl == sl && !strncmp(sat->suffix, str, tl)) ||
|
|
||||||
(tl == sl-1 && !strncmp(sat->suffix+1, str, tl-1))) {
|
|
||||||
rv |= sat->bit;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
str += tl;
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vim:set sw=8: */
|
|
||||||
|
8
ui-snapshot.h
Normal file
8
ui-snapshot.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef UI_SNAPSHOT_H
|
||||||
|
#define UI_SNAPSHOT_H
|
||||||
|
|
||||||
|
extern void cgit_print_snapshot(const char *head, const char *hex,
|
||||||
|
const char *prefix, const char *filename,
|
||||||
|
int snapshot);
|
||||||
|
|
||||||
|
#endif /* UI_SNAPSHOT_H */
|
189
ui-summary.c
189
ui-summary.c
@ -7,194 +7,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
#include "html.h"
|
||||||
static int header;
|
#include "ui-log.h"
|
||||||
|
#include "ui-refs.h"
|
||||||
static int cmp_age(int age1, int age2)
|
|
||||||
{
|
|
||||||
if (age1 != 0 && age2 != 0)
|
|
||||||
return age2 - age1;
|
|
||||||
|
|
||||||
if (age1 == 0 && age2 == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (age1 == 0)
|
|
||||||
return +1;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmp_ref_name(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
struct refinfo *r1 = *(struct refinfo **)a;
|
|
||||||
struct refinfo *r2 = *(struct refinfo **)b;
|
|
||||||
|
|
||||||
return strcmp(r1->refname, r2->refname);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmp_branch_age(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
struct refinfo *r1 = *(struct refinfo **)a;
|
|
||||||
struct refinfo *r2 = *(struct refinfo **)b;
|
|
||||||
|
|
||||||
return cmp_age(r1->commit->committer_date, r2->commit->committer_date);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmp_tag_age(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
struct refinfo *r1 = *(struct refinfo **)a;
|
|
||||||
struct refinfo *r2 = *(struct refinfo **)b;
|
|
||||||
|
|
||||||
return cmp_age(r1->tag->tagger_date, r2->tag->tagger_date);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int print_branch(struct refinfo *ref)
|
|
||||||
{
|
|
||||||
struct commitinfo *info = ref->commit;
|
|
||||||
char *name = (char *)ref->refname;
|
|
||||||
|
|
||||||
if (!info)
|
|
||||||
return 1;
|
|
||||||
html("<tr><td>");
|
|
||||||
cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL);
|
|
||||||
html("</td><td>");
|
|
||||||
|
|
||||||
if (ref->object->type == OBJ_COMMIT) {
|
|
||||||
cgit_print_age(info->commit->date, -1, NULL);
|
|
||||||
html("</td><td>");
|
|
||||||
html_txt(info->author);
|
|
||||||
html("</td><td>");
|
|
||||||
cgit_commit_link(info->subject, NULL, NULL, name, NULL);
|
|
||||||
} else {
|
|
||||||
html("</td><td></td><td>");
|
|
||||||
cgit_object_link(ref->object);
|
|
||||||
}
|
|
||||||
html("</td></tr>\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 print_tag(struct refinfo *ref)
|
|
||||||
{
|
|
||||||
struct tag *tag;
|
|
||||||
struct taginfo *info;
|
|
||||||
char *url, *name = (char *)ref->refname;
|
|
||||||
|
|
||||||
if (ref->object->type == OBJ_TAG) {
|
|
||||||
tag = (struct tag *)ref->object;
|
|
||||||
info = ref->tag;
|
|
||||||
if (!tag || !info)
|
|
||||||
return 1;
|
|
||||||
html("<tr><td>");
|
|
||||||
url = cgit_pageurl(cgit_query_repo, "tag",
|
|
||||||
fmt("id=%s", name));
|
|
||||||
html_link_open(url, NULL, NULL);
|
|
||||||
html_txt(name);
|
|
||||||
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_object_link(tag->tagged);
|
|
||||||
html("</td></tr>\n");
|
|
||||||
} else {
|
|
||||||
if (!header)
|
|
||||||
print_tag_header();
|
|
||||||
html("<tr><td>");
|
|
||||||
html_txt(name);
|
|
||||||
html("</td><td colspan='2'/><td>");
|
|
||||||
cgit_object_link(ref->object);
|
|
||||||
html("</td></tr>\n");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_refs_link(char *path)
|
|
||||||
{
|
|
||||||
html("<tr class='nohover'><td colspan='4'>");
|
|
||||||
cgit_refs_link("[...]", NULL, NULL, cgit_query_head, NULL, path);
|
|
||||||
html("</td></tr>");
|
|
||||||
}
|
|
||||||
|
|
||||||
void cgit_print_branches(int maxcount)
|
|
||||||
{
|
|
||||||
struct reflist list;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
list.refs = NULL;
|
|
||||||
list.alloc = list.count = 0;
|
|
||||||
for_each_branch_ref(cgit_refs_cb, &list);
|
|
||||||
|
|
||||||
if (maxcount == 0 || maxcount > list.count)
|
|
||||||
maxcount = list.count;
|
|
||||||
|
|
||||||
if (maxcount < list.count) {
|
|
||||||
qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age);
|
|
||||||
qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i=0; i<maxcount; i++)
|
|
||||||
print_branch(list.refs[i]);
|
|
||||||
|
|
||||||
if (maxcount < list.count)
|
|
||||||
print_refs_link("heads");
|
|
||||||
}
|
|
||||||
|
|
||||||
void cgit_print_tags(int maxcount)
|
|
||||||
{
|
|
||||||
struct reflist list;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
header = 0;
|
|
||||||
list.refs = NULL;
|
|
||||||
list.alloc = list.count = 0;
|
|
||||||
for_each_tag_ref(cgit_refs_cb, &list);
|
|
||||||
if (list.count == 0)
|
|
||||||
return;
|
|
||||||
qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age);
|
|
||||||
if (!maxcount)
|
|
||||||
maxcount = list.count;
|
|
||||||
else if (maxcount > list.count)
|
|
||||||
maxcount = list.count;
|
|
||||||
print_tag_header();
|
|
||||||
for(i=0; i<maxcount; i++)
|
|
||||||
print_tag(list.refs[i]);
|
|
||||||
|
|
||||||
if (maxcount < list.count)
|
|
||||||
print_refs_link("tags");
|
|
||||||
}
|
|
||||||
|
|
||||||
void cgit_print_summary()
|
void cgit_print_summary()
|
||||||
{
|
{
|
||||||
if (cgit_repo->readme) {
|
if (ctx.repo->readme) {
|
||||||
html("<div id='summary'>");
|
html("<div id='summary'>");
|
||||||
html_include(cgit_repo->readme);
|
html_include(ctx.repo->readme);
|
||||||
html("</div>");
|
html("</div>");
|
||||||
}
|
}
|
||||||
if (cgit_summary_log > 0)
|
if (ctx.cfg.summary_log > 0)
|
||||||
cgit_print_log(cgit_query_head, 0, cgit_summary_log, NULL,
|
cgit_print_log(ctx.qry.head, 0, ctx.cfg.summary_log, NULL,
|
||||||
NULL, NULL, 0);
|
NULL, NULL, 0);
|
||||||
html("<table summary='repository info' class='list nowrap'>");
|
html("<table summary='repository info' class='list nowrap'>");
|
||||||
if (cgit_summary_log > 0)
|
if (ctx.cfg.summary_log > 0)
|
||||||
html("<tr class='nohover'><td colspan='4'> </td></tr>");
|
html("<tr class='nohover'><td colspan='4'> </td></tr>");
|
||||||
cgit_print_branches(cgit_summary_branches);
|
cgit_print_branches(ctx.cfg.summary_branches);
|
||||||
html("<tr class='nohover'><td colspan='4'> </td></tr>");
|
html("<tr class='nohover'><td colspan='4'> </td></tr>");
|
||||||
cgit_print_tags(cgit_summary_tags);
|
cgit_print_tags(ctx.cfg.summary_tags);
|
||||||
html("</table>");
|
html("</table>");
|
||||||
}
|
}
|
||||||
|
6
ui-summary.h
Normal file
6
ui-summary.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef UI_SUMMARY_H
|
||||||
|
#define UI_SUMMARY_H
|
||||||
|
|
||||||
|
extern void cgit_print_summary();
|
||||||
|
|
||||||
|
#endif /* UI_SUMMARY_H */
|
3
ui-tag.c
3
ui-tag.c
@ -7,7 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
#include "html.h"
|
||||||
|
#include "ui-shared.h"
|
||||||
|
|
||||||
static void print_tag_content(char *buf)
|
static void print_tag_content(char *buf)
|
||||||
{
|
{
|
||||||
|
6
ui-tag.h
Normal file
6
ui-tag.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef UI_TAG_H
|
||||||
|
#define UI_TAG_H
|
||||||
|
|
||||||
|
extern void cgit_print_tag(char *revname);
|
||||||
|
|
||||||
|
#endif /* UI_TAG_H */
|
26
ui-tree.c
26
ui-tree.c
@ -7,6 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
#include "html.h"
|
||||||
|
#include "ui-shared.h"
|
||||||
|
|
||||||
char *curr_rev;
|
char *curr_rev;
|
||||||
char *match_path;
|
char *match_path;
|
||||||
@ -34,7 +36,7 @@ static void print_object(const unsigned char *sha1, char *path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
html(" blob: <a href='");
|
html(" blob: <a href='");
|
||||||
html_attr(cgit_pageurl(cgit_query_repo, "blob", fmt("id=%s", sha1_to_hex(sha1))));
|
html_attr(cgit_pageurl(ctx.qry.repo, "blob", fmt("id=%s", sha1_to_hex(sha1))));
|
||||||
htmlf("'>%s</a>",sha1_to_hex(sha1));
|
htmlf("'>%s</a>",sha1_to_hex(sha1));
|
||||||
|
|
||||||
html("<table summary='blob content' class='blob'>\n");
|
html("<table summary='blob content' class='blob'>\n");
|
||||||
@ -67,8 +69,8 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen,
|
|||||||
unsigned long size = 0;
|
unsigned long size = 0;
|
||||||
|
|
||||||
name = xstrdup(pathname);
|
name = xstrdup(pathname);
|
||||||
fullpath = fmt("%s%s%s", cgit_query_path ? cgit_query_path : "",
|
fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "",
|
||||||
cgit_query_path ? "/" : "", name);
|
ctx.qry.path ? "/" : "", name);
|
||||||
|
|
||||||
type = sha1_object_info(sha1, &size);
|
type = sha1_object_info(sha1, &size);
|
||||||
if (type == OBJ_BAD && !S_ISGITLINK(mode)) {
|
if (type == OBJ_BAD && !S_ISGITLINK(mode)) {
|
||||||
@ -79,27 +81,27 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
html("<tr><td class='ls-mode'>");
|
html("<tr><td class='ls-mode'>");
|
||||||
html_filemode(mode);
|
cgit_print_filemode(mode);
|
||||||
html("</td><td>");
|
html("</td><td>");
|
||||||
if (S_ISGITLINK(mode)) {
|
if (S_ISGITLINK(mode)) {
|
||||||
htmlf("<a class='ls-mod' href='");
|
htmlf("<a class='ls-mod' href='");
|
||||||
html_attr(fmt(cgit_repo->module_link,
|
html_attr(fmt(ctx.repo->module_link,
|
||||||
name,
|
name,
|
||||||
sha1_to_hex(sha1)));
|
sha1_to_hex(sha1)));
|
||||||
html("'>");
|
html("'>");
|
||||||
html_txt(name);
|
html_txt(name);
|
||||||
html("</a>");
|
html("</a>");
|
||||||
} else if (S_ISDIR(mode)) {
|
} else if (S_ISDIR(mode)) {
|
||||||
cgit_tree_link(name, NULL, "ls-dir", cgit_query_head,
|
cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head,
|
||||||
curr_rev, fullpath);
|
curr_rev, fullpath);
|
||||||
} else {
|
} else {
|
||||||
cgit_tree_link(name, NULL, "ls-blob", cgit_query_head,
|
cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head,
|
||||||
curr_rev, fullpath);
|
curr_rev, fullpath);
|
||||||
}
|
}
|
||||||
htmlf("</td><td class='ls-size'>%li</td>", size);
|
htmlf("</td><td class='ls-size'>%li</td>", size);
|
||||||
|
|
||||||
html("<td>");
|
html("<td>");
|
||||||
cgit_log_link("log", NULL, "button", cgit_query_head, curr_rev,
|
cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev,
|
||||||
fullpath, 0, NULL, NULL);
|
fullpath, 0, NULL, NULL);
|
||||||
html("</td></tr>\n");
|
html("</td></tr>\n");
|
||||||
free(name);
|
free(name);
|
||||||
@ -153,10 +155,10 @@ static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
|
|||||||
if (state == 0) {
|
if (state == 0) {
|
||||||
memcpy(buffer, base, baselen);
|
memcpy(buffer, base, baselen);
|
||||||
strcpy(buffer+baselen, pathname);
|
strcpy(buffer+baselen, pathname);
|
||||||
url = cgit_pageurl(cgit_query_repo, "tree",
|
url = cgit_pageurl(ctx.qry.repo, "tree",
|
||||||
fmt("h=%s&path=%s", curr_rev, buffer));
|
fmt("h=%s&path=%s", curr_rev, buffer));
|
||||||
html("/");
|
html("/");
|
||||||
cgit_tree_link(xstrdup(pathname), NULL, NULL, cgit_query_head,
|
cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head,
|
||||||
curr_rev, buffer);
|
curr_rev, buffer);
|
||||||
|
|
||||||
if (strcmp(match_path, buffer))
|
if (strcmp(match_path, buffer))
|
||||||
@ -188,7 +190,7 @@ void cgit_print_tree(const char *rev, char *path)
|
|||||||
const char *paths[] = {path, NULL};
|
const char *paths[] = {path, NULL};
|
||||||
|
|
||||||
if (!rev)
|
if (!rev)
|
||||||
rev = cgit_query_head;
|
rev = ctx.qry.head;
|
||||||
|
|
||||||
curr_rev = xstrdup(rev);
|
curr_rev = xstrdup(rev);
|
||||||
if (get_sha1(rev, sha1)) {
|
if (get_sha1(rev, sha1)) {
|
||||||
@ -202,7 +204,7 @@ void cgit_print_tree(const char *rev, char *path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
html("path: <a href='");
|
html("path: <a href='");
|
||||||
html_attr(cgit_pageurl(cgit_query_repo, "tree", fmt("h=%s", rev)));
|
html_attr(cgit_pageurl(ctx.qry.repo, "tree", fmt("h=%s", rev)));
|
||||||
html("'>root</a>");
|
html("'>root</a>");
|
||||||
|
|
||||||
if (path == NULL) {
|
if (path == NULL) {
|
||||||
|
Loading…
Reference in New Issue
Block a user