summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/simplewiki_main.c67
1 files changed, 47 insertions, 20 deletions
diff --git a/src/simplewiki_main.c b/src/simplewiki_main.c
index 5c04467..089d129 100644
--- a/src/simplewiki_main.c
+++ b/src/simplewiki_main.c
@@ -6,12 +6,15 @@
// #include <assert.h>
#include <errno.h> // errno, EEXIST
#include <git2.h> // git_*
+#include <unistd.h> // link
#include <stdbool.h> // false
#include <stdio.h>
#include <stdlib.h> // EXIT_SUCCESS
#include <sys/stat.h> // mkdir
#include <sys/types.h> // mode_t
+#define REF "refs/heads/master"
+
void xmkdir(const char *path, mode_t mode, bool exist_ok) {
if (mkdir(path, mode) < 0) {
if (exist_ok && errno == EEXIST) {
@@ -22,6 +25,13 @@ void xmkdir(const char *path, mode_t mode, bool exist_ok) {
}
}
+void xsymlink(const char *source_path, const char *target_path)
+{
+ if (symlink(source_path, target_path) < 0) {
+ die_errno("failed to link '%s' => '%s'", target_path, source_path);
+ }
+}
+
void process_other_file(const char *path, const char *source, size_t source_len) {
FILE *out = fopen(path, "w");
printf("Copying: %s\n", path);
@@ -138,30 +148,47 @@ int main(int argc, char *argv[])
die_git("open repository");
}
- // Find HEAD.
- struct git_object *head;
- const struct git_oid *head_id;
- if (git_revparse_single(&head, repo, "HEAD") < 0) {
- die_git("parse HEAD");
- }
- head_id = git_object_id(head);
- git_object_free(head);
-
- // Get a handle to the tree at head.
- struct git_commit *commit;
- if (git_commit_lookup(&commit, repo, head_id) < 0) {
- die_git("look up head commit");
- }
- struct git_tree *tree;
- if (git_commit_tree(&tree, commit) < 0) {
- die_git("get tree for commit %s", git_oid_tostr_s(git_commit_id(commit)));
- }
+ // Create a revision walker to iterate commits on the main branch.
+ git_revwalk *walker = NULL;
+ git_revwalk_new(&walker, repo);
+ git_revwalk_push_ref(walker, REF);
// Create the initial output directory.
xmkdir(out_path, 0755, true);
- struct arena a = arena_create(1024);
- list_tree(&a, repo, tree, out_path);
+ struct arena a = arena_create(2048);
+ git_oid commit_oid;
+ while (git_revwalk_next(&commit_oid, walker) == 0) {
+ const char *commit_sha = git_oid_tostr_s(&commit_oid);
+
+ git_commit *commit = NULL;
+ if (git_commit_lookup(&commit, repo, &commit_oid) < 0) {
+ die_git("find commit %s", commit_sha);
+ }
+
+ struct git_tree *tree;
+ if (git_commit_tree(&tree, commit) < 0) {
+ die_git("get tree for commit %s", commit_sha);
+ }
+
+ const char *prefix = joinpath(&a, out_path, commit_sha);
+ xmkdir(prefix, 0755, true);
+ list_tree(&a, repo, tree, prefix);
+
+ a.used = 0; // reset arena after each iteration
+ git_commit_free(commit);
+ git_tree_free(tree);
+ }
+
+ // Create a symbolic link to the latest commit.
+ git_oid latest_commit;
+ if (git_reference_name_to_id(&latest_commit, repo, REF) < 0) {
+ die_git("Failed to resolve " REF " to commit");
+ }
+ const char *source = git_oid_tostr_s(&latest_commit);
+ const char *target = joinpath(&a, out_path, "latest");
+ xsymlink(source, target);
+
#ifndef NDEBUG
arena_destroy(&a);
#endif