author | Lars Hjemli <hjemli@gmail.com> | 2008-08-05 23:20:24 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2008-08-06 09:21:09 (UTC) |
commit | 02a545e63454530c1639014d3239c14ced2022c6 (patch) (side-by-side diff) | |
tree | da4c89a94b117d936f2eeb486c9dedf192e6746e | |
parent | 0f0ab148c6d444316af10e6b4c7a60630fed45d3 (diff) | |
download | cgit-02a545e63454530c1639014d3239c14ced2022c6.zip cgit-02a545e63454530c1639014d3239c14ced2022c6.tar.gz cgit-02a545e63454530c1639014d3239c14ced2022c6.tar.bz2 |
Add support for cloning over http
This patch implements basic support for cloning over http, based on the
work on git-http-backend by Shawn O. Pearce.
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | cmd.c | 19 | ||||
-rw-r--r-- | html.c | 7 | ||||
-rw-r--r-- | html.h | 1 | ||||
-rw-r--r-- | ui-clone.c | 104 | ||||
-rw-r--r-- | ui-clone.h | 8 |
6 files changed, 140 insertions, 0 deletions
@@ -53,12 +53,13 @@ OBJECTS += cgit.o OBJECTS += cmd.o OBJECTS += configfile.o OBJECTS += html.o OBJECTS += parsing.o OBJECTS += shared.o OBJECTS += ui-blob.o +OBJECTS += ui-clone.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 @@ -8,23 +8,29 @@ #include "cgit.h" #include "cmd.h" #include "cache.h" #include "ui-shared.h" #include "ui-blob.h" +#include "ui-clone.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 HEAD_fn(struct cgit_context *ctx) +{ + cgit_clone_head(ctx); +} + static void about_fn(struct cgit_context *ctx) { if (ctx->repo) cgit_print_repo_readme(); else cgit_print_site_readme(); @@ -42,12 +48,17 @@ static void commit_fn(struct cgit_context *ctx) static void diff_fn(struct cgit_context *ctx) { cgit_print_diff(ctx->qry.sha1, ctx->qry.sha2, ctx->qry.path); } +static void info_fn(struct cgit_context *ctx) +{ + cgit_clone_info(ctx); +} + 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); } @@ -56,12 +67,17 @@ static void ls_cache_fn(struct cgit_context *ctx) ctx->page.mimetype = "text/plain"; ctx->page.filename = "ls-cache.txt"; cgit_print_http_headers(ctx); cache_ls(ctx->cfg.cache_root); } +static void objects_fn(struct cgit_context *ctx) +{ + cgit_clone_objects(ctx); +} + static void repolist_fn(struct cgit_context *ctx) { cgit_print_repolist(); } static void patch_fn(struct cgit_context *ctx) @@ -99,18 +115,21 @@ static void tree_fn(struct cgit_context *ctx) #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(HEAD, 1, 0), def_cmd(about, 0, 1), def_cmd(blob, 1, 0), def_cmd(commit, 1, 1), def_cmd(diff, 1, 1), + def_cmd(info, 1, 0), def_cmd(log, 1, 1), def_cmd(ls_cache, 0, 0), + def_cmd(objects, 1, 0), 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), @@ -48,12 +48,19 @@ void htmlf(const char *format, ...) va_start(args, format); vsnprintf(buf, sizeof(buf), format, args); va_end(args); html(buf); } +void html_status(int code, int more_headers) +{ + htmlf("Status: %d\n", code); + if (!more_headers) + html("\n"); +} + void html_txt(char *txt) { char *t = txt; while(t && *t){ int c = *t; if (c=='<' || c=='>' || c=='&') { @@ -2,12 +2,13 @@ #define HTML_H extern int htmlfd; extern void html(const char *txt); extern void htmlf(const char *format,...); +extern void html_status(int code, int more_headers); 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); diff --git a/ui-clone.c b/ui-clone.c new file mode 100644 index 0000000..3a037ad --- a/dev/null +++ b/ui-clone.c @@ -0,0 +1,104 @@ +/* ui-clone.c: functions for http cloning, based on + * git's http-backend.c by Shawn O. Pearce + * + * Copyright (C) 2008 Lars Hjemli + * + * Licensed under GNU General Public License v2 + * (see COPYING for full license text) + */ + +#include "cgit.h" +#include "html.h" +#include "ui-shared.h" + +static int print_ref_info(const char *refname, const unsigned char *sha1, + int flags, void *cb_data) +{ + struct object *obj; + + if (!(obj = parse_object(sha1))) + return 0; + + if (!strcmp(refname, "HEAD") || !prefixcmp(refname, "refs/heads/")) + htmlf("%s\t%s\n", sha1_to_hex(sha1), refname); + else if (!prefixcmp(refname, "refs/tags") && obj->type == OBJ_TAG) { + if (!(obj = deref_tag(obj, refname, 0))) + return 0; + htmlf("%s\t%s\n", sha1_to_hex(sha1), refname); + htmlf("%s\t%s^{}\n", sha1_to_hex(obj->sha1), refname); + } + return 0; +} + +static void print_pack_info(struct cgit_context *ctx) +{ + struct packed_git *pack; + int ofs; + + ctx->page.mimetype = "text/plain"; + ctx->page.filename = "objects/info/packs"; + cgit_print_http_headers(ctx); + ofs = strlen(ctx->repo->path) + strlen("/objects/pack/"); + prepare_packed_git(); + for (pack = packed_git; pack; pack = pack->next) + if (pack->pack_local) + htmlf("P %s\n", pack->pack_name + ofs); +} + +static void send_file(struct cgit_context *ctx, char *path) +{ + struct stat st; + int err; + + if (stat(path, &st)) { + switch (errno) { + case ENOENT: + err = 404; + break; + case EACCES: + err = 403; + break; + default: + err = 400; + } + html_status(err, 0); + return; + } + ctx->page.mimetype = "application/octet-stream"; + ctx->page.filename = path; + if (prefixcmp(ctx->repo->path, path)) + ctx->page.filename += strlen(ctx->repo->path) + 1; + cgit_print_http_headers(ctx); + html_include(path); +} + +void cgit_clone_info(struct cgit_context *ctx) +{ + if (!ctx->qry.path || strcmp(ctx->qry.path, "refs")) + return; + + ctx->page.mimetype = "text/plain"; + ctx->page.filename = "info/refs"; + cgit_print_http_headers(ctx); + for_each_ref(print_ref_info, ctx); +} + +void cgit_clone_objects(struct cgit_context *ctx) +{ + if (!ctx->qry.path) { + html_status(400, 0); + return; + } + + if (!strcmp(ctx->qry.path, "info/packs")) { + print_pack_info(ctx); + return; + } + + send_file(ctx, git_path("objects/%s", ctx->qry.path)); +} + +void cgit_clone_head(struct cgit_context *ctx) +{ + send_file(ctx, git_path("%s", "HEAD")); +} diff --git a/ui-clone.h b/ui-clone.h new file mode 100644 index 0000000..89cd4f1 --- a/dev/null +++ b/ui-clone.h @@ -0,0 +1,8 @@ +#ifndef UI_CLONE_H +#define UI_CLONE_H + +void cgit_clone_info(struct cgit_context *ctx); +void cgit_clone_objects(struct cgit_context *ctx); +void cgit_clone_head(struct cgit_context *ctx); + +#endif /* UI_CLONE_H */ |