summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2008-03-24 00:09:39 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2008-03-24 00:43:48 (UTC)
commite0e4478e7b4812f822d60a13a33525f8e529e1e8 (patch) (unidiff)
tree577c3927deb9b122f940b69ca7db66afe2422814
parentb608e88adb6f77328288afb6dd0eddf674fc9b5b (diff)
downloadcgit-e0e4478e7b4812f822d60a13a33525f8e529e1e8.zip
cgit-e0e4478e7b4812f822d60a13a33525f8e529e1e8.tar.gz
cgit-e0e4478e7b4812f822d60a13a33525f8e529e1e8.tar.bz2
Add command dispatcher
This simplifies the code in cgit.c and makes it easier to extend cgit with new pages/commands. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--Makefile2
-rw-r--r--cgit.c130
-rw-r--r--cgit.h14
-rw-r--r--cmd.c101
-rw-r--r--cmd.h15
-rw-r--r--parsing.c4
-rw-r--r--shared.c13
7 files changed, 169 insertions, 110 deletions
diff --git a/Makefile b/Makefile
index 7102908..d9ff7d8 100644
--- a/Makefile
+++ b/Makefile
@@ -13,13 +13,13 @@ GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2
13-include cgit.conf 13-include cgit.conf
14 14
15 15
16EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lcrypto 16EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lcrypto
17OBJECTS = shared.o cache.o parsing.o html.o ui-shared.o ui-repolist.o \ 17OBJECTS = shared.o cache.o parsing.o html.o ui-shared.o ui-repolist.o \
18 ui-summary.o ui-log.o ui-tree.o ui-commit.o ui-diff.o \ 18 ui-summary.o ui-log.o ui-tree.o ui-commit.o ui-diff.o \
19 ui-snapshot.o ui-blob.o ui-tag.o ui-refs.o ui-patch.o 19 ui-snapshot.o ui-blob.o ui-tag.o ui-refs.o ui-patch.o cmd.o
20 20
21 21
22ifdef NEEDS_LIBICONV 22ifdef NEEDS_LIBICONV
23 EXTLIBS += -liconv 23 EXTLIBS += -liconv
24endif 24endif
25 25
diff --git a/cgit.c b/cgit.c
index a83f0be..79e0e43 100644
--- a/cgit.c
+++ b/cgit.c
@@ -78,117 +78,90 @@ char *find_default_branch(struct cgit_repo *repo)
78 if (info.match) 78 if (info.match)
79 return info.req_ref; 79 return info.req_ref;
80 else 80 else
81 return info.first_ref; 81 return info.first_ref;
82} 82}
83 83
84static void cgit_print_repo_page() 84static int prepare_repo_cmd(struct cgit_context *ctx)
85{ 85{
86 char *tmp; 86 char *tmp;
87 int show_search;
88 unsigned char sha1[20]; 87 unsigned char sha1[20];
89 int nongit = 0; 88 int nongit = 0;
90 89
91 setenv("GIT_DIR", ctx.repo->path, 1); 90 setenv("GIT_DIR", ctx->repo->path, 1);
92 setup_git_directory_gently(&nongit); 91 setup_git_directory_gently(&nongit);
93 if (nongit) { 92 if (nongit) {
94 ctx.page.title = fmt("%s - %s", ctx.cfg.root_title, 93 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title,
95 "config error"); 94 "config error");
96 tmp = fmt("Not a git repository: '%s'", ctx.repo->path); 95 tmp = fmt("Not a git repository: '%s'", ctx->repo->path);
97 ctx.repo = NULL; 96 ctx->repo = NULL;
98 cgit_print_http_headers(&ctx); 97 cgit_print_http_headers(ctx);
99 cgit_print_docstart(&ctx); 98 cgit_print_docstart(ctx);
100 cgit_print_pageheader(&ctx); 99 cgit_print_pageheader(ctx);
101 cgit_print_error(tmp); 100 cgit_print_error(tmp);
102 cgit_print_docend(); 101 cgit_print_docend();
103 return; 102 return 1;
104 } 103 }
104 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc);
105 105
106 ctx.page.title = fmt("%s - %s", ctx.repo->name, ctx.repo->desc); 106 if (!ctx->qry.head) {
107 show_search = 0; 107 ctx->qry.head = xstrdup(find_default_branch(ctx->repo));
108 108 ctx->repo->defbranch = ctx->qry.head;
109 if (!ctx.qry.head) {
110 ctx.qry.head = xstrdup(find_default_branch(ctx.repo));
111 ctx.repo->defbranch = ctx.qry.head;
112 } 109 }
113 110
114 if (!ctx.qry.head) { 111 if (!ctx->qry.head) {
115 cgit_print_http_headers(&ctx); 112 cgit_print_http_headers(ctx);
116 cgit_print_docstart(&ctx); 113 cgit_print_docstart(ctx);
117 cgit_print_pageheader(&ctx); 114 cgit_print_pageheader(ctx);
118 cgit_print_error("Repository seems to be empty"); 115 cgit_print_error("Repository seems to be empty");
119 cgit_print_docend(); 116 cgit_print_docend();
120 return; 117 return 1;
121 } 118 }
122 119
123 if (get_sha1(ctx.qry.head, sha1)) { 120 if (get_sha1(ctx->qry.head, sha1)) {
124 tmp = xstrdup(ctx.qry.head); 121 tmp = xstrdup(ctx->qry.head);
125 ctx.qry.head = ctx.repo->defbranch; 122 ctx->qry.head = ctx->repo->defbranch;
126 cgit_print_http_headers(&ctx); 123 cgit_print_http_headers(ctx);
127 cgit_print_docstart(&ctx); 124 cgit_print_docstart(ctx);
128 cgit_print_pageheader(&ctx); 125 cgit_print_pageheader(ctx);
129 cgit_print_error(fmt("Invalid branch: %s", tmp)); 126 cgit_print_error(fmt("Invalid branch: %s", tmp));
130 cgit_print_docend(); 127 cgit_print_docend();
131 return; 128 return 1;
132 } 129 }
130 return 0;
131}
133 132
134 if ((cgit_cmd == CMD_SNAPSHOT) && ctx.repo->snapshots) { 133static void process_request(struct cgit_context *ctx)
135 cgit_print_snapshot(ctx.qry.head, ctx.qry.sha1, 134{
136 cgit_repobasename(ctx.repo->url), 135 struct cgit_cmd *cmd;
137 ctx.qry.path, 136
138 ctx.repo->snapshots ); 137 cmd = cgit_get_cmd(ctx);
138 if (!cmd) {
139 ctx->page.title = "cgit error";
140 ctx->repo = NULL;
141 cgit_print_http_headers(ctx);
142 cgit_print_docstart(ctx);
143 cgit_print_pageheader(ctx);
144 cgit_print_error("Invalid request");
145 cgit_print_docend();
139 return; 146 return;
140 } 147 }
141 148
142 if (cgit_cmd == CMD_PATCH) { 149 if (cmd->want_repo && prepare_repo_cmd(ctx))
143 cgit_print_patch(ctx.qry.sha1);
144 return; 150 return;
145 }
146 151
147 if (cgit_cmd == CMD_BLOB) { 152 if (cmd->want_layout) {
148 cgit_print_blob(ctx.qry.sha1, ctx.qry.path); 153 cgit_print_http_headers(ctx);
149 return; 154 cgit_print_docstart(ctx);
155 cgit_print_pageheader(ctx);
150 } 156 }
151 157
152 show_search = (cgit_cmd == CMD_LOG); 158 cmd->fn(ctx);
153 cgit_print_http_headers(&ctx);
154 cgit_print_docstart(&ctx);
155 if (!cgit_cmd) {
156 cgit_print_pageheader(&ctx);
157 cgit_print_summary();
158 cgit_print_docend();
159 return;
160 }
161 159
162 cgit_print_pageheader(&ctx); 160 if (cmd->want_layout)
163 161 cgit_print_docend();
164 switch(cgit_cmd) {
165 case CMD_LOG:
166 cgit_print_log(ctx.qry.sha1, ctx.qry.ofs,
167 ctx.cfg.max_commit_count, ctx.qry.grep, ctx.qry.search,
168 ctx.qry.path, 1);
169 break;
170 case CMD_TREE:
171 cgit_print_tree(ctx.qry.sha1, ctx.qry.path);
172 break;
173 case CMD_COMMIT:
174 cgit_print_commit(ctx.qry.sha1);
175 break;
176 case CMD_REFS:
177 cgit_print_refs();
178 break;
179 case CMD_TAG:
180 cgit_print_tag(ctx.qry.sha1);
181 break;
182 case CMD_DIFF:
183 cgit_print_diff(ctx.qry.sha1, ctx.qry.sha2, ctx.qry.path);
184 break;
185 default:
186 cgit_print_error("Invalid request");
187 }
188 cgit_print_docend();
189} 162}
190 163
191static long ttl_seconds(long ttl) 164static long ttl_seconds(long ttl)
192{ 165{
193 if (ttl<0) 166 if (ttl<0)
194 return 60 * 60 * 24 * 365; 167 return 60 * 60 * 24 * 365;
@@ -206,16 +179,13 @@ static void cgit_fill_cache(struct cacheitem *item, int use_cache)
206 chk_zero(close(STDOUT_FILENO), "Closing STDOUT"); 179 chk_zero(close(STDOUT_FILENO), "Closing STDOUT");
207 chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)"); 180 chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)");
208 } 181 }
209 182
210 ctx.page.modified = time(NULL); 183 ctx.page.modified = time(NULL);
211 ctx.page.expires = ctx.page.modified + ttl_seconds(item->ttl); 184 ctx.page.expires = ctx.page.modified + ttl_seconds(item->ttl);
212 if (ctx.repo) 185 process_request(&ctx);
213 cgit_print_repo_page();
214 else
215 cgit_print_repolist();
216 186
217 if (use_cache) { 187 if (use_cache) {
218 chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT"); 188 chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT");
219 chk_positive(dup2(stdout2, STDOUT_FILENO), 189 chk_positive(dup2(stdout2, STDOUT_FILENO),
220 "Restoring original STDOUT"); 190 "Restoring original STDOUT");
221 chk_zero(close(stdout2), "Closing temporary STDOUT"); 191 chk_zero(close(stdout2), "Closing temporary STDOUT");
diff --git a/cgit.h b/cgit.h
index 40e2d40..295441b 100644
--- a/cgit.h
+++ b/cgit.h
@@ -17,25 +17,12 @@
17#include <archive.h> 17#include <archive.h>
18#include <xdiff/xdiff.h> 18#include <xdiff/xdiff.h>
19#include <utf8.h> 19#include <utf8.h>
20 20
21 21
22/* 22/*
23 * The valid cgit repo-commands
24 */
25#define CMD_LOG 1
26#define CMD_COMMIT 2
27#define CMD_DIFF 3
28#define CMD_TREE 4
29#define CMD_BLOB 5
30#define CMD_SNAPSHOT 6
31#define CMD_TAG 7
32#define CMD_REFS 8
33#define CMD_PATCH 9
34
35/*
36 * Dateformats used on misc. pages 23 * Dateformats used on misc. pages
37 */ 24 */
38#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S" 25#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S"
39#define FMT_SHORTDATE "%Y-%m-%d" 26#define FMT_SHORTDATE "%Y-%m-%d"
40 27
41 28
@@ -194,13 +181,12 @@ extern const char *cgit_version;
194 181
195extern struct cgit_repolist cgit_repolist; 182extern struct cgit_repolist cgit_repolist;
196extern struct cgit_context ctx; 183extern struct cgit_context ctx;
197extern int cgit_cmd; 184extern int cgit_cmd;
198 185
199extern void cgit_prepare_context(struct cgit_context *ctx); 186extern void cgit_prepare_context(struct cgit_context *ctx);
200extern int cgit_get_cmd_index(const char *cmd);
201extern struct cgit_repo *cgit_get_repoinfo(const char *url); 187extern struct cgit_repo *cgit_get_repoinfo(const char *url);
202extern void cgit_global_config_cb(const char *name, const char *value); 188extern void cgit_global_config_cb(const char *name, const char *value);
203extern void cgit_repo_config_cb(const char *name, const char *value); 189extern void cgit_repo_config_cb(const char *name, const char *value);
204extern void cgit_querystring_cb(const char *name, const char *value); 190extern void cgit_querystring_cb(const char *name, const char *value);
205 191
206extern int chk_zero(int result, char *msg); 192extern int chk_zero(int result, char *msg);
diff --git a/cmd.c b/cmd.c
new file mode 100644
index 0000000..489a11c
--- a/dev/null
+++ b/cmd.c
@@ -0,0 +1,101 @@
1/* cmd.c: the cgit command dispatcher
2 *
3 * Copyright (C) 2008 Lars Hjemli
4 *
5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text)
7 */
8
9#include "cgit.h"
10#include "cmd.h"
11
12static void blob_fn(struct cgit_context *ctx)
13{
14 cgit_print_blob(ctx->qry.sha1, ctx->qry.path);
15}
16
17static void commit_fn(struct cgit_context *ctx)
18{
19 cgit_print_commit(ctx->qry.sha1);
20}
21
22static void diff_fn(struct cgit_context *ctx)
23{
24 cgit_print_diff(ctx->qry.sha1, ctx->qry.sha2, ctx->qry.path);
25}
26
27static void repolist_fn(struct cgit_context *ctx)
28{
29 cgit_print_repolist();
30}
31
32static void log_fn(struct cgit_context *ctx)
33{
34 cgit_print_log(ctx->qry.sha1, ctx->qry.ofs, ctx->cfg.max_commit_count,
35 ctx->qry.grep, ctx->qry.search, ctx->qry.path, 1);
36}
37
38static void patch_fn(struct cgit_context *ctx)
39{
40 cgit_print_patch(ctx->qry.sha1);
41}
42
43static void refs_fn(struct cgit_context *ctx)
44{
45 cgit_print_refs();
46}
47
48static void snapshot_fn(struct cgit_context *ctx)
49{
50 cgit_print_snapshot(ctx->qry.head, ctx->qry.sha1,
51 cgit_repobasename(ctx->repo->url), ctx->qry.path,
52 ctx->repo->snapshots);
53}
54
55static void summary_fn(struct cgit_context *ctx)
56{
57 cgit_print_summary();
58}
59
60static void tag_fn(struct cgit_context *ctx)
61{
62 cgit_print_tag(ctx->qry.sha1);
63}
64
65static void tree_fn(struct cgit_context *ctx)
66{
67 cgit_print_tree(ctx->qry.sha1, ctx->qry.path);
68}
69
70#define def_cmd(name, want_repo, want_layout) \
71 {#name, name##_fn, want_repo, want_layout}
72
73struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx)
74{
75 static struct cgit_cmd cmds[] = {
76 def_cmd(blob, 1, 0),
77 def_cmd(commit, 1, 1),
78 def_cmd(diff, 1, 1),
79 def_cmd(log, 1, 1),
80 def_cmd(patch, 1, 0),
81 def_cmd(refs, 1, 1),
82 def_cmd(repolist, 0, 0),
83 def_cmd(snapshot, 1, 0),
84 def_cmd(summary, 1, 1),
85 def_cmd(tag, 1, 1),
86 def_cmd(tree, 1, 1),
87 };
88 int i;
89
90 if (ctx->qry.page == NULL) {
91 if (ctx->repo)
92 ctx->qry.page = "summary";
93 else
94 ctx->qry.page = "repolist";
95 }
96
97 for(i = 0; i < sizeof(cmds)/sizeof(*cmds); i++)
98 if (!strcmp(ctx->qry.page, cmds[i].name))
99 return &cmds[i];
100 return NULL;
101}
diff --git a/cmd.h b/cmd.h
new file mode 100644
index 0000000..ec9e691
--- a/dev/null
+++ b/cmd.h
@@ -0,0 +1,15 @@
1#ifndef CMD_H
2#define CMD_H
3
4typedef void (*cgit_cmd_fn)(struct cgit_context *ctx);
5
6struct cgit_cmd {
7 const char *name;
8 cgit_cmd_fn fn;
9 unsigned int want_repo:1,
10 want_layout:1;
11};
12
13extern struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx);
14
15#endif /* CMD_H */
diff --git a/parsing.c b/parsing.c
index 027f06b..8dce488 100644
--- a/parsing.c
+++ b/parsing.c
@@ -167,14 +167,14 @@ void cgit_parse_url(const char *url)
167 p = strchr(cmd + 1, '/'); 167 p = strchr(cmd + 1, '/');
168 if (p) { 168 if (p) {
169 p[0] = '\0'; 169 p[0] = '\0';
170 if (p[1]) 170 if (p[1])
171 ctx.qry.path = trim_end(p + 1, '/'); 171 ctx.qry.path = trim_end(p + 1, '/');
172 } 172 }
173 cgit_cmd = cgit_get_cmd_index(cmd + 1); 173 if (cmd[1])
174 ctx.qry.page = xstrdup(cmd + 1); 174 ctx.qry.page = xstrdup(cmd + 1);
175 return; 175 return;
176 } 176 }
177} 177}
178 178
179char *substr(const char *head, const char *tail) 179char *substr(const char *head, const char *tail)
180{ 180{
diff --git a/shared.c b/shared.c
index 539d533..67eb67b 100644
--- a/shared.c
+++ b/shared.c
@@ -37,24 +37,12 @@ void cgit_prepare_context(struct cgit_context *ctx)
37 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 37 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
38 ctx->page.mimetype = "text/html"; 38 ctx->page.mimetype = "text/html";
39 ctx->page.charset = PAGE_ENCODING; 39 ctx->page.charset = PAGE_ENCODING;
40 ctx->page.filename = NULL; 40 ctx->page.filename = NULL;
41} 41}
42 42
43int cgit_get_cmd_index(const char *cmd)
44{
45 static char *cmds[] = {"log", "commit", "diff", "tree", "blob",
46 "snapshot", "tag", "refs", "patch", NULL};
47 int i;
48
49 for(i = 0; cmds[i]; i++)
50 if (!strcmp(cmd, cmds[i]))
51 return i + 1;
52 return 0;
53}
54
55int chk_zero(int result, char *msg) 43int chk_zero(int result, char *msg)
56{ 44{
57 if (result != 0) 45 if (result != 0)
58 die("%s: %s", msg, strerror(errno)); 46 die("%s: %s", msg, strerror(errno));
59 return result; 47 return result;
60} 48}
@@ -213,13 +201,12 @@ void cgit_querystring_cb(const char *name, const char *value)
213{ 201{
214 if (!strcmp(name,"r")) { 202 if (!strcmp(name,"r")) {
215 ctx.qry.repo = xstrdup(value); 203 ctx.qry.repo = xstrdup(value);
216 ctx.repo = cgit_get_repoinfo(value); 204 ctx.repo = cgit_get_repoinfo(value);
217 } else if (!strcmp(name, "p")) { 205 } else if (!strcmp(name, "p")) {
218 ctx.qry.page = xstrdup(value); 206 ctx.qry.page = xstrdup(value);
219 cgit_cmd = cgit_get_cmd_index(value);
220 } else if (!strcmp(name, "url")) { 207 } else if (!strcmp(name, "url")) {
221 cgit_parse_url(value); 208 cgit_parse_url(value);
222 } else if (!strcmp(name, "qt")) { 209 } else if (!strcmp(name, "qt")) {
223 ctx.qry.grep = xstrdup(value); 210 ctx.qry.grep = xstrdup(value);
224 } else if (!strcmp(name, "q")) { 211 } else if (!strcmp(name, "q")) {
225 ctx.qry.search = xstrdup(value); 212 ctx.qry.search = xstrdup(value);