Hi… I am well aware that this diff view is very suboptimal. It will be fixed when the refactored server comes along!
git2c: Some perror
// SPDX-License-Identifier: AGPL-3.0-only
// SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>
// TODO: Make the C part report detailed error messages too
package git2c
import "errors"
var (
Success error
ErrUnknown = errors.New("git2c: unknown error")
ErrPath = errors.New("git2c: get tree entry by path failed")
ErrRevparse = errors.New("git2c: revparse failed")
ErrReadme = errors.New("git2c: no readme")
ErrBlobExpected = errors.New("git2c: blob expected")
ErrEntryToObject = errors.New("git2c: tree entry to object conversion failed")
ErrBlobRawContent = errors.New("git2c: get blob raw content failed")
ErrRevwalk = errors.New("git2c: revwalk failed")
ErrRevwalkPushHead = errors.New("git2c: revwalk push head failed")
ErrBareProto = errors.New("git2c: bare protocol error")
)
func Perror(errno uint) error {
switch errno {
case 0:
return Success
case 3:
return ErrPath
case 4:
return ErrRevparse
case 5:
return ErrReadme
case 6:
return ErrBlobExpected
case 7:
return ErrEntryToObject
case 8:
return ErrBlobRawContent
case 9:
return ErrRevwalk
case 10:
return ErrRevwalkPushHead
case 11:
return ErrBareProto
}
return ErrUnknown
}
/*-
* SPDX-License-Identifier: AGPL-3.0-only
* SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>
*/
#include "x.h"
int
cmd_index(git_repository *repo, struct bare_writer *writer)
{
/* HEAD tree */
git_object *obj = NULL;
int err = git_revparse_single(&obj, repo, "HEAD^{tree}");
if (err != 0) {
bare_put_uint(writer, 4);
return -1;
}
git_tree *tree = (git_tree *) obj;
/* README */
git_tree_entry *entry = NULL;
err = git_tree_entry_bypath(&entry, tree, "README.md");
if (err != 0) {
bare_put_uint(writer, 5);
git_tree_free(tree);
return -1;
}
git_otype objtype = git_tree_entry_type(entry);
if (objtype != GIT_OBJECT_BLOB) {
bare_put_uint(writer, 6);
git_tree_entry_free(entry);
git_tree_free(tree);
return -1;
}
git_object *obj2 = NULL;
err = git_tree_entry_to_object(&obj2, repo, entry);
if (err != 0) {
bare_put_uint(writer, 7);
git_tree_entry_free(entry);
git_tree_free(tree);
return -1;
}
git_blob *blob = (git_blob *) obj2;
const void *content = git_blob_rawcontent(blob);
if (content == NULL) {
bare_put_uint(writer, 8);
git_blob_free(blob);
git_tree_entry_free(entry);
git_tree_free(tree);
return -1;
}
bare_put_uint(writer, 0);
bare_put_data(writer, content, git_blob_rawsize(blob));
/* Commits */
/* TODO BUG: This might be a different commit from the displayed README due to races */
git_revwalk *walker = NULL;
if (git_revwalk_new(&walker, repo) != 0) {
bare_put_uint(writer, 9);
git_blob_free(blob);
git_tree_entry_free(entry);
git_tree_free(tree);
return -1;
}
if (git_revwalk_push_head(walker) != 0) {
bare_put_uint(writer, 9);
git_revwalk_free(walker);
git_blob_free(blob);
git_tree_entry_free(entry);
git_tree_free(tree);
return -1;
}
int count = 0;
git_oid oid;
while (count < 3 && git_revwalk_next(&oid, walker) == 0) {
git_commit *commit = NULL;
if (git_commit_lookup(&commit, repo, &oid) != 0)
break;
const char *msg = git_commit_summary(commit);
const git_signature *author = git_commit_author(commit);
/* ID */
bare_put_data(writer, oid.id, GIT_OID_RAWSZ);
/* Title */
size_t msg_len = msg ? strlen(msg) : 0;
bare_put_data(writer, (const uint8_t *)(msg ? msg : ""), msg_len);
/* Author's name */
const char *author_name = author ? author->name : "";
bare_put_data(writer, (const uint8_t *)author_name, strlen(author_name));
/* Author's email */
const char *author_email = author ? author->email : "";
bare_put_data(writer, (const uint8_t *)author_email, strlen(author_email));
/* Author's date */
/* TODO: Pass the integer instead of a string */
time_t time = git_commit_time(commit);
char timebuf[64];
struct tm *tm = localtime(&time);
if (tm)
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm);
else
strcpy(timebuf, "unknown");
bare_put_data(writer, (const uint8_t *)timebuf, strlen(timebuf));
git_commit_free(commit);
count++;
}
git_revwalk_free(walker);
git_blob_free(blob);
git_tree_entry_free(entry);
git_tree_free(tree);
return 0;
}
/*-
* SPDX-License-Identifier: AGPL-3.0-only
* SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>
*/
#include "x.h"
int
cmd_treeraw(git_repository *repo, struct bare_reader *reader, struct bare_writer *writer)
{
/* Path */
char path[4096] = {0};
int err = bare_get_data(reader, (uint8_t *)path, sizeof(path) - 1);
if (err != BARE_ERROR_NONE) {
bare_put_uint(writer, 10);
bare_put_uint(writer, 11);
return -1;
}
path[sizeof(path) - 1] = '\0';
/* HEAD^{tree} */
git_object *head_obj = NULL;
err = git_revparse_single(&head_obj, repo, "HEAD^{tree}");
if (err != 0) {
bare_put_uint(writer, 11);
bare_put_uint(writer, 4);
return -1;
}
git_tree *tree = (git_tree *)head_obj;
/* Path in tree */
git_tree_entry *entry = NULL;
git_otype objtype;
if (strlen(path) == 0) {
entry = NULL;
objtype = GIT_OBJECT_TREE;
} else {
err = git_tree_entry_bypath(&entry, tree, path);
if (err != 0) {
bare_put_uint(writer, 3);
git_tree_free(tree);
return 0;
}
objtype = git_tree_entry_type(entry);
}
if (objtype == GIT_OBJECT_TREE) {
/* Tree */
git_object *tree_obj = NULL;
if (entry == NULL) {
tree_obj = (git_object *)tree;
} else {
err = git_tree_entry_to_object(&tree_obj, repo, entry);
if (err != 0) {
bare_put_uint(writer, 3);
bare_put_uint(writer, 7);
goto cleanup;
}
}
git_tree *subtree = (git_tree *)tree_obj;
size_t count = git_tree_entrycount(subtree);
bare_put_uint(writer, 0);
bare_put_uint(writer, 1);
bare_put_uint(writer, count);
for (size_t i = 0; i < count; i++) {
const git_tree_entry *subentry = git_tree_entry_byindex(subtree, i);
const char *name = git_tree_entry_name(subentry);
git_otype type = git_tree_entry_type(subentry);
uint32_t mode = git_tree_entry_filemode(subentry);
uint8_t entry_type = 0;
uint64_t size = 0;
if (type == GIT_OBJECT_TREE) {
entry_type = 1;
} else if (type == GIT_OBJECT_BLOB) {
entry_type = 2;
git_object *subobj = NULL;
if (git_tree_entry_to_object(&subobj, repo, subentry) == 0) {
git_blob *b = (git_blob *)subobj;
size = git_blob_rawsize(b);
git_blob_free(b);
}
}
bare_put_uint(writer, entry_type);
bare_put_uint(writer, mode);
bare_put_uint(writer, size);
bare_put_data(writer, (const uint8_t *)name, strlen(name));
}
if (entry != NULL) {
git_tree_free(subtree);
}
} else if (objtype == GIT_OBJECT_BLOB) {
/* Blob */
git_object *blob_obj = NULL;
err = git_tree_entry_to_object(&blob_obj, repo, entry);
if (err != 0) {
bare_put_uint(writer, 3);
bare_put_uint(writer, 7);
goto cleanup;
}
git_blob *blob = (git_blob *)blob_obj;
const void *content = git_blob_rawcontent(blob);
if (content == NULL) {
bare_put_uint(writer, 3);
bare_put_uint(writer, 8);
git_blob_free(blob);
goto cleanup;
}
bare_put_uint(writer, 0);
bare_put_uint(writer, 2);
bare_put_data(writer, content, git_blob_rawsize(blob));
git_blob_free(blob);
} else {
/* Unknown */
bare_put_uint(writer, 3);
bare_put_uint(writer, -1);
} cleanup: if (entry != NULL) git_tree_entry_free(entry); git_tree_free(tree); return 0; }