My pretty neat website
git clone git://soophie.de/soso
diff --git a/src/duc_macro.h b/src/duc_macro.h
index 5a0f426..491af84 100644
--- a/src/duc_macro.h
+++ b/src/duc_macro.h
1
@@ -6,7 +6,9 @@3
#define DUC_OUT ((orb_ctx_t *) out)4
#define DUC_WRITE(str) { buf_write(DUC_OUT->out, str); }5
+#define DUC_CLEAR() { buf_free(DUC_OUT->out); }7
+#define BINARY(bytes, len) { buf_write_len(DUC_OUT->out, bytes, len); }8
#define HTML(str) DUC_WRITE(str ? str : "")9
#define STRING(str) { \10
buf_t buf = BUF_NULL; \
diff --git a/src/main.c b/src/main.c
index cc34490..a603864 100644
--- a/src/main.c
+++ b/src/main.c
1
@@ -66,7 +66,7 @@ TPEE_GET("/git/*", git_repo_page) {2
if (!tab_mode) {3
tab_mode = strdup("log");4
}5
- const char *tab_mode_list[] = { "log", "tree", "refs", "commit", "blob" };6
+ const char *tab_mode_list[] = { "log", "tree", "refs", "commit", "blob", "raw" };7
size_t tab_mode_list_len = sizeof(tab_mode_list) / sizeof(tab_mode_list[0]);8
bool is_tab_mode_valid = false;9
for (size_t i = 0; i < tab_mode_list_len; i++) {10
@@ -89,14 +89,19 @@ TPEE_GET("/git/*", git_repo_page) {11
.repo_name = repo_name,12
.repo_path = repo_path,13
.tab_mode = tab_mode,14
- .ref = tpee_pairs_get(&query_list, "ref"),15
- .oid = tpee_pairs_get(&query_list, "oid"),16
+ .flag_ref_oid = tpee_pairs_get(&query_list, "ref"),17
+ .flag_oid = tpee_pairs_get(&query_list, "oid"),18
+ .flag_path = tpee_pairs_get(&query_list, "path"),19
}));20
orb_module_t page_module = orb_module_create(&PAGE_TYPE, &((page_param_list_t) {21
.title = repo_name,22
.module = &git_repo_module,23
}));24
- orb_module_run(&page_module, &ctx);25
+ orb_module_t *module = &page_module;26
+ if (strcmp(tab_mode, "raw") == 0) {27
+ module = &git_repo_module;28
+ }29
+ orb_module_run(module, &ctx);30
tpee_pairs_free(&query_list);31
if (tab_mode) {32
free(tab_mode);
diff --git a/src/module/git_repo.c b/src/module/git_repo.c
index 6db8d8b..e728bd8 100644
--- a/src/module/git_repo.c
+++ b/src/module/git_repo.c
1
@@ -12,8 +12,9 @@ static orb_rc_t init(orb_module_t *self) {2
.path = param_list->repo_path,3
.meta = {0},4
.handle = NULL,5
- .ref_oid = param_list->ref,6
- .oid = param_list->oid,7
+ .flag_ref_oid = param_list->flag_ref_oid,8
+ .flag_oid = param_list->flag_oid,9
+ .flag_path = param_list->flag_path,10
.ref_head = NULL,11
.ref = NULL,12
.ref_list = NULL,13
@@ -142,9 +143,9 @@ static orb_rc_t fetch(orb_module_t *self) {14
}15
git_reference_iterator_free(iter);16
}17
- if (data->repo.ref_head && data->repo.ref_oid && strcmp(data->repo.ref_head->oid, data->repo.ref_oid) != 0) {18
+ if (data->repo.ref_head && data->repo.flag_ref_oid && strcmp(data->repo.ref_head->oid, data->repo.flag_ref_oid) != 0) {19
git_oid ref_oid;20
- if (git_oid_fromstr(&ref_oid, data->repo.ref_oid) == 0) {21
+ if (git_oid_fromstr(&ref_oid, data->repo.flag_ref_oid) == 0) {22
git_reference_iterator *iter = NULL;23
git_reference *ref_handle = NULL;24
git_reference_iterator_new(&iter, data->repo.handle);25
@@ -153,7 +154,7 @@ static orb_rc_t fetch(orb_module_t *self) {26
if (oid && git_oid_equal(oid, &ref_oid)) {27
data->repo.ref = calloc(1, sizeof(git_repo_ref_t));28
git_repo_ref_t *ref = data->repo.ref;29
- ref->oid = strdup(data->repo.ref_oid);30
+ ref->oid = strdup(data->repo.flag_ref_oid);31
const char *ref_name = git_reference_name(ref_handle);32
if (git_reference_is_branch(ref_handle)) {33
ref->name = strdup(ref_name + strlen("refs/heads/"));
diff --git a/src/module/git_repo.h b/src/module/git_repo.h
index 99c9b27..a8b3eee 100644
--- a/src/module/git_repo.h
+++ b/src/module/git_repo.h
1
@@ -8,8 +8,9 @@2
typedef struct {3
char *repo_name;4
char *repo_path;5
- char *ref;6
- char *oid;7
+ char *flag_ref_oid;8
+ char *flag_oid;9
+ char *flag_path;10
const char *tab_mode;11
} git_repo_param_list_t;13
@@ -34,6 +35,7 @@ typedef struct {14
char *name;15
char *content;16
size_t size;17
+ bool is_binary;18
} git_repo_blob_t;20
typedef struct {21
@@ -47,8 +49,9 @@ typedef struct {22
char *path;23
git_repo_meta_t meta;24
git_repository *handle;25
- char *ref_oid;26
- char *oid;27
+ char *flag_ref_oid;28
+ char *flag_oid;29
+ char *flag_path;30
git_repo_ref_t *ref_head;31
git_repo_ref_t *ref;32
git_repo_ref_t *ref_list;
diff --git a/src/module/git_repo_blob.c b/src/module/git_repo_blob.c
index d3be875..58a3acb 100644
--- a/src/module/git_repo_blob.c
+++ b/src/module/git_repo_blob.c
1
@@ -7,25 +7,68 @@ static orb_rc_t init(orb_module_t *self) {2
duc_git_repo_blob_t *data = self->data;3
git_repo_blob_param_list_t *param_list = self->param_list;4
if (param_list) {5
+ data->repo = param_list->repo;6
data->is_markdown = param_list->is_markdown;7
+ data->is_raw = param_list->is_raw;8
}9
return ORB_OK;10
}12
+static int _fetch_tree_cb(const char *root, const git_tree_entry *entry_handle, void *data) {13
+ git_repo_blob_tree_cb_t *handle = data;14
+ const char *name = git_tree_entry_name(entry_handle);15
+ git_filemode_t mode_handle = git_tree_entry_filemode(entry_handle);16
+ if (mode_handle != GIT_FILEMODE_TREE) {17
+ const git_oid *oid = git_tree_entry_id(entry_handle);18
+ size_t file_path_len = strlen(root) + strlen(name);19
+ char file_path[file_path_len + 1];20
+ snprintf(file_path, sizeof(file_path), "%s%s", root, name);21
+ if (strcmp(handle->file_path, file_path) == 0) {22
+ git_oid_cpy(handle->blob_oid, oid);23
+ return -1;24
+ }25
+ }26
+ return 0;27
+}28
+29
static orb_rc_t fetch(orb_module_t *self) {30
duc_git_repo_blob_t *data = self->data;31
- git_repo_blob_param_list_t *param_list = self->param_list;32
- if (!param_list) return ORB_FATAL(1);33
- if (!param_list->repo) return ORB_FATAL(2);34
- if (!param_list->repo->oid) return ORB_FATAL(3);35
- data->repo = param_list->repo;36
+ if (!data->repo) return ORB_FATAL(1);37
git_oid blob_oid;38
- if (git_oid_fromstr(&blob_oid, data->repo->oid) != 0) return ORB_FATAL(4);39
+ if (data->repo->flag_oid) {40
+ if (git_oid_fromstr(&blob_oid, data->repo->flag_oid) != 0) return ORB_FATAL(2);41
+ }42
+ if (data->repo->flag_path) {43
+ char *ref_oid = NULL;44
+ if (data->repo->ref_head) ref_oid = data->repo->ref_head->oid;45
+ if (data->repo->ref) ref_oid = data->repo->ref->oid;46
+ if (!ref_oid) return ORB_ERR(2);47
+ const char *spec_suffix = "^{commit}";48
+ size_t spec_len = strlen(ref_oid) + strlen(spec_suffix) + 1;49
+ char spec[spec_len];50
+ snprintf(spec, spec_len, "%s%s", ref_oid, spec_suffix);51
+ git_object *obj = NULL;52
+ if (git_revparse_single(&obj, data->repo->handle, spec) == 0) {53
+ git_commit *commit_handle = (git_commit *) obj;54
+ git_tree *tree_handle = NULL;55
+ if (git_commit_tree(&tree_handle, commit_handle) == 0) {56
+ git_tree_walk(tree_handle, GIT_TREEWALK_PRE, _fetch_tree_cb, &((git_repo_blob_tree_cb_t) {57
+ .blob_oid = &blob_oid,58
+ .file_path = data->repo->flag_path,59
+ }));60
+ git_tree_free(tree_handle);61
+ }62
+ git_object_free(obj);63
+ }64
+ if (git_oid_is_zero(&blob_oid)) return ORB_FATAL(3);65
+ }66
git_blob *blob_handle = NULL;67
- if (git_blob_lookup(&blob_handle, data->repo->handle, &blob_oid) != 0) return ORB_FATAL(5);68
+ if (git_blob_lookup(&blob_handle, data->repo->handle, &blob_oid) != 0) return ORB_FATAL(4);69
data->blob = calloc(1, sizeof(git_repo_blob_t));70
git_repo_blob_t *blob = data->blob;71
- blob->oid = strdup(data->repo->oid);72
+ char oid_str[GIT_OID_HEXSZ + 1];73
+ git_oid_tostr(oid_str, sizeof(oid_str), &blob_oid);74
+ blob->oid = strdup(oid_str);75
blob->name = NULL;76
size_t size = (size_t) git_blob_rawsize(blob_handle);77
const char *content = git_blob_rawcontent(blob_handle);78
@@ -35,6 +78,7 @@ static orb_rc_t fetch(orb_module_t *self) {79
blob->content[size] = '\0';80
blob->size = size;81
}82
+ blob->is_binary = git_blob_is_binary(blob_handle);83
git_blob_free(blob_handle);84
return ORB_OK;85
}
diff --git a/src/module/git_repo_blob.h b/src/module/git_repo_blob.h
index 023d81b..054080d 100644
--- a/src/module/git_repo_blob.h
+++ b/src/module/git_repo_blob.h
1
@@ -6,6 +6,12 @@2
typedef struct {3
git_repo_t *repo;4
bool is_markdown;5
+ bool is_raw;6
} git_repo_blob_param_list_t;8
+typedef struct {9
+ git_oid *blob_oid;10
+ const char *file_path;11
+} git_repo_blob_tree_cb_t;12
+13
extern const orb_module_type_t GIT_REPO_BLOB_TYPE;
diff --git a/src/module/git_repo_commit.c b/src/module/git_repo_commit.c
index fd85e7b..0829870 100644
--- a/src/module/git_repo_commit.c
+++ b/src/module/git_repo_commit.c
1
@@ -10,16 +10,16 @@ static orb_rc_t fetch(orb_module_t *self) {2
git_repo_commit_param_list_t *param_list = self->param_list;3
if (!param_list) return ORB_FATAL(1);4
if (!param_list->repo) return ORB_FATAL(2);5
- if (!param_list->repo->oid) return ORB_FATAL(3);6
+ if (!param_list->repo->flag_oid) return ORB_FATAL(3);7
data->repo = param_list->repo;8
git_oid commit_oid;9
- if (git_oid_fromstr(&commit_oid, data->repo->oid) != 0) return ORB_FATAL(4);10
+ if (git_oid_fromstr(&commit_oid, data->repo->flag_oid) != 0) return ORB_FATAL(4);11
git_commit *commit_handle = NULL;12
git_commit *parent_commit_handle = NULL;13
git_commit_lookup(&commit_handle, data->repo->handle, &commit_oid);14
data->commit = calloc(1, sizeof(git_repo_commit_t));15
git_repo_commit_t *commit = data->commit;16
- commit->oid = strdup(data->repo->oid);17
+ commit->oid = strdup(data->repo->flag_oid);18
commit->message = strdup(git_commit_message(commit_handle));19
commit->summary = strdup(git_commit_summary(commit_handle));20
const char *body = git_commit_body(commit_handle);
diff --git a/src/module/git_repo_tree.c b/src/module/git_repo_tree.c
index 2ec8d50..f20159b 100644
--- a/src/module/git_repo_tree.c
+++ b/src/module/git_repo_tree.c
1
@@ -4,6 +4,15 @@3
#include "../templ/duc_git_repo_tree.h"5
+static orb_rc_t init(orb_module_t *self) {6
+ duc_git_repo_tree_t *data = self->data;7
+ git_repo_tree_param_list_t *param_list = self->param_list;8
+ if (param_list) {9
+ data->repo = param_list->repo;10
+ }11
+ return ORB_OK;12
+}13
+14
static int _fetch_tree_cb(const char *root, const git_tree_entry *entry_handle, void *data) {15
git_repo_tree_cb_t *handle = data;16
const char *name = git_tree_entry_name(entry_handle);17
@@ -36,30 +45,22 @@ static int _fetch_tree_cb(const char *root, const git_tree_entry *entry_handle,19
static orb_rc_t fetch(orb_module_t *self) {20
duc_git_repo_tree_t *data = self->data;21
- git_repo_tree_param_list_t *param_list = self->param_list;22
- if (!param_list) return ORB_ERR(1);23
- if (!param_list->repo) return ORB_ERR(2);24
- data->repo = param_list->repo;25
- git_object *obj = NULL;26
- git_commit *commit_handle = NULL;27
+ if (!data->repo) return ORB_ERR(1);28
char *ref_oid = NULL;29
- if (param_list->repo->ref_head) {30
- ref_oid = param_list->repo->ref_head->oid;31
- }32
- if (param_list->repo->ref) {33
- ref_oid = param_list->repo->ref->oid;34
- }35
- if (!ref_oid) return ORB_ERR(3);36
+ if (data->repo->ref_head) ref_oid = data->repo->ref_head->oid;37
+ if (data->repo->ref) ref_oid = data->repo->ref->oid;38
+ if (!ref_oid) return ORB_ERR(2);39
const char *spec_suffix = "^{commit}";40
size_t spec_len = strlen(ref_oid) + strlen(spec_suffix) + 1;41
char spec[spec_len];42
snprintf(spec, spec_len, "%s%s", ref_oid, spec_suffix);43
- if (git_revparse_single(&obj, param_list->repo->handle, spec) == 0) {44
- commit_handle = (git_commit *) obj;45
+ git_object *obj = NULL;46
+ if (git_revparse_single(&obj, data->repo->handle, spec) == 0) {47
+ git_commit *commit_handle = (git_commit *) obj;48
git_tree *tree_handle = NULL;49
if (git_commit_tree(&tree_handle, commit_handle) == 0) {50
git_tree_walk(tree_handle, GIT_TREEWALK_PRE, _fetch_tree_cb, &((git_repo_tree_cb_t) {51
- .repo_handle = param_list->repo->handle,52
+ .repo_handle = data->repo->handle,53
.entry_list = &data->entry_list,54
.entry_list_len = &data->entry_list_len,55
}));56
@@ -91,6 +92,7 @@ static void cleanup(orb_module_t *self) {58
const orb_module_type_t GIT_REPO_TREE_TYPE = {59
.size = sizeof(duc_git_repo_tree_t),60
+ .init = init,61
.fetch = fetch,62
.render = render,63
.cleanup = cleanup,
diff --git a/templ/git_repo.html b/templ/git_repo.html
index b3fad4c..63524fb 100644
--- a/templ/git_repo.html
+++ b/templ/git_repo.html
1
@@ -11,17 +11,23 @@2
git_repo_t repo;3
const char *tab_mode;4
) %5
-6
+% if (ctx->tab_mode && strcmp(ctx->tab_mode, "raw") == 0) {7
+ ORB_MODULE_DEF(GIT_REPO_BLOB_TYPE, &((git_repo_blob_param_list_t) {8
+ .repo = &ctx->repo,9
+ .is_raw = true,10
+ }))11
+ return;12
+} %13
<div class="git--repo">14
<h2>% STRING(ctx->repo.meta.name) %</h2>15
<p>16
- % if (ctx->repo.meta.description) { % <span>% STRING(ctx->repo.meta.description) %</span><br/> % } %17
- git clone <a href="git://soophie.de/% STRING(ctx->repo.meta.name) %">git://soophie.de/% STRING(ctx->repo.meta.name) %</a>18
+ % if (ctx->repo.meta.description) { % <span class="repo--description">% STRING(ctx->repo.meta.description) %</span><br/> % } %19
+ <span class="repo--clone">git clone <a href="git://soophie.de/% STRING(ctx->repo.meta.name) %">git://soophie.de/% STRING(ctx->repo.meta.name) %</a></span>20
</p>21
<ul class="link-list">22
<li class="link % if (strcmp(ctx->tab_mode, "log") == 0 || strcmp(ctx->tab_mode, "commit") == 0) { %link--active% } %"><a href="/git/% STRING(ctx->repo.meta.name) if (ctx->repo.ref) { %?ref=% STRING(ctx->repo.ref->oid) } %">log</a></li>23
- % bool is_readme = ctx->repo.oid && ctx->repo.readme_oid && strcmp(ctx->repo.oid, ctx->repo.readme_oid) == 0; %24
- % bool is_license = ctx->repo.oid && ctx->repo.license_oid && strcmp(ctx->repo.oid, ctx->repo.license_oid) == 0; %25
+ % bool is_readme = ctx->repo.flag_oid && ctx->repo.readme_oid && strcmp(ctx->repo.flag_oid, ctx->repo.readme_oid) == 0; %26
+ % bool is_license = ctx->repo.flag_oid && ctx->repo.license_oid && strcmp(ctx->repo.flag_oid, ctx->repo.license_oid) == 0; %27
<li class="link % if (strcmp(ctx->tab_mode, "tree") == 0 || (strcmp(ctx->tab_mode, "blob") == 0 && !is_readme && !is_license)) { %link--active% } %"><a href="/git/% STRING(ctx->repo.meta.name) %/tree% if (ctx->repo.ref) { %?ref=% STRING(ctx->repo.ref->oid) } %">tree</a></li>28
<li class="link % if (strcmp(ctx->tab_mode, "refs") == 0) { %link--active% } %"><a href="/git/% STRING(ctx->repo.meta.name) %/refs% if (ctx->repo.ref) { %?ref=% STRING(ctx->repo.ref->oid) } %">refs</a></li>29
% if (ctx->repo.readme_oid) { %30
@@ -41,9 +47,9 @@31
if (strcmp(ctx->tab_mode, "refs") == 0) tab = "refs";32
}33
bool is_branch_select = true;34
- if (ctx->repo.oid) {35
- if (ctx->repo.readme_oid && strcmp(ctx->repo.oid, ctx->repo.readme_oid) == 0) is_branch_select = false;36
- if (ctx->repo.license_oid && strcmp(ctx->repo.oid, ctx->repo.license_oid) == 0) is_branch_select = false;37
+ if (ctx->repo.flag_oid) {38
+ if (ctx->repo.readme_oid && strcmp(ctx->repo.flag_oid, ctx->repo.readme_oid) == 0) is_branch_select = false;39
+ if (ctx->repo.license_oid && strcmp(ctx->repo.flag_oid, ctx->repo.license_oid) == 0) is_branch_select = false;40
}41
%42
% if (is_branch_select) { %43
@@ -83,8 +89,8 @@44
} %45
% if (ctx->tab_mode && strcmp(ctx->tab_mode, "blob") == 0) {46
bool is_markdown = false;47
- if (ctx->repo.oid) {48
- if (ctx->repo.readme_oid && strcmp(ctx->repo.oid, ctx->repo.readme_oid) == 0) is_markdown = true;49
+ if (ctx->repo.flag_oid) {50
+ if (ctx->repo.readme_oid && strcmp(ctx->repo.flag_oid, ctx->repo.readme_oid) == 0) is_markdown = true;51
}52
ORB_MODULE_DEF(GIT_REPO_BLOB_TYPE, &((git_repo_blob_param_list_t) {53
.repo = &ctx->repo,
diff --git a/templ/git_repo_blob.html b/templ/git_repo_blob.html
index 2a0c059..3f0b9ad 100644
--- a/templ/git_repo_blob.html
+++ b/templ/git_repo_blob.html
1
@@ -1,22 +1,84 @@2
% #include "src/duc_macro.h" %3
% #include "src/module/git_repo.h" %4
% #include "src/module/git_repo_blob.h" %5
+% #include <math.h> %7
% DUC_TEMPLDEF(8
duc_git_repo_blob,9
git_repo_t *repo;10
git_repo_blob_t *blob;11
bool is_markdown;12
+ bool is_raw;13
) %15
% if (ctx->is_markdown) { %16
<div class="blob--markdown">% MARKDOWN(ctx->blob->content) %</div>17
-% } else { %18
- <p>19
- <span>blob: % STRING(ctx->blob->oid) %</span><br/>20
- <span>size: % NUMBER(ctx->blob->size) %</span>21
- </p>22
- <pre class="blob--code">% STRING(ctx->blob->content) %</pre>23
+% } else if (ctx->is_raw) {24
+ DUC_CLEAR()25
+ BINARY(ctx->blob->content, ctx->blob->size)26
+ return;27
+} else { %28
+ <div class="blob">29
+ <pre class="blob--meta"><span>blob: % STRING(ctx->blob->oid) % (% NUMBER(ctx->blob->size) % bytes)</span><a class="link--raw" href="/git/% STRING(ctx->repo->meta.name) %/raw?oid=% STRING(ctx->repo->flag_oid) %">[raw]</a></pre>30
+ % if (ctx->blob->is_binary) { %31
+ <pre class="blob--code"><span class="blob--binary">Binary file: <a href="/git/% STRING(ctx->repo->meta.name) %/raw?oid=% STRING(ctx->repo->flag_oid) %">[view raw]</p></span></pre>32
+ % } else { %33
+ <pre class="blob--code">%34
+35
+ size_t len = strlen(ctx->blob->content);36
+ size_t i = 0;37
+ size_t ln = 0;38
+ size_t sol = 0;39
+ while (i < len) {40
+ char c = ctx->blob->content[i];41
+ if (c == '\n') {42
+ ln++;43
+ }44
+ i++;45
+ }46
+ size_t pad = floor(log10(ln + 1)) + 1;47
+ i = 0;48
+ ln = 0;49
+ sol = 0;50
+ size_t df = 0;51
+ bool is_meta = false;52
+ while (i < len) {53
+ char c = ctx->blob->content[i];54
+ if (c == '\n') {55
+ size_t ln_len = i - sol;56
+ char line[ln_len + 1];57
+ memcpy(line, ctx->blob->content + sol, ln_len);58
+ line[ln_len] = '\0';59
+ sol = i + 1;60
+ bool is_diff = strncmp(line, "diff --git", 10) == 0;61
+ bool is_hunk = strncmp(line, "@@ ", 3) == 0;62
+ if (is_diff) {63
+ is_meta = true;64
+ }65
+ if (is_diff && ln != 0) {66
+ df++;67
+ %</pre>%68
+ %<pre class="diff--meta">%69
+ }70
+ if (is_hunk && is_meta) {71
+ is_meta = false;72
+ ln = 0;73
+ %</pre>%74
+ %<pre class="diff--code">%75
+ }76
+ if (is_meta) {77
+ %<p>%STRING(line)%</p>%78
+ }79
+ else {80
+ %<p id="% NUMBER(ln + 1) %" class="% if (is_hunk) { %is-hunk% } % % if (strncmp(line, "+", 1) == 0 && strncmp(line, "+++", 3) != 0) { %is-add% } % % if (strncmp(line, "-", 1) == 0 && strncmp(line, "---", 3) != 0) { %is-rem% } %"><span class="ln"><a href="#% NUMBER(ln + 1) %">% PRINTF("%%*ld", pad, ln + 1) %</a></span><span class="line"><code>% STRING(line) %</code></span></p>%81
+ }82
+ ln++;83
+ }84
+ i++;85
+ }86
+ %</pre>87
+ % } %88
+ </div>89
% } %91
% DUC_ENDTEMPL %