Lindenii Project Forge
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; }