log.c (2959B)
1 #include "writer/gemini/log.h" 2 3 #include <assert.h> 4 #include <err.h> 5 #include <stdint.h> 6 #include <stdlib.h> 7 8 #include "format.h" 9 #include "utils.h" 10 #include "writer/cache/cache.h" 11 #include "writer/gemini/page.h" 12 13 #include <sys/stat.h> 14 #include <unistd.h> 15 16 struct GeminiLog { 17 const GitRepo* repo; 18 const FileSystem* fs; 19 FILE* out; 20 Cache* cache; 21 GeminiPage* page; 22 size_t remaining_commits; 23 size_t unlogged_commits; 24 }; 25 26 static void write_commit_row(FILE* out, const GitCommit* commit); 27 28 GeminiLog* gemini_log_create(const GitRepo* repo, const FileSystem* fs) { 29 assert(repo != NULL); 30 assert(fs != NULL); 31 GeminiLog* log = ecalloc(1, sizeof(GeminiLog)); 32 log->repo = repo; 33 log->fs = fs; 34 log->out = fs->fopen("log.gmi", "w"); 35 if (!log->out) { 36 err(1, "fopen: log.gmi"); 37 } 38 log->page = gemini_page_create(log->out, repo, fs, "Log", ""); 39 log->remaining_commits = SIZE_MAX; 40 log->unlogged_commits = 0; 41 return log; 42 } 43 44 void gemini_log_free(GeminiLog* log) { 45 if (!log) { 46 return; 47 } 48 log->fs->fclose(log->out); 49 log->out = NULL; 50 cache_free(log->cache); 51 log->cache = NULL; 52 gemini_page_free(log->page); 53 log->page = NULL; 54 free(log); 55 } 56 57 void gemini_log_set_cachefile(GeminiLog* log, const char* cachefile) { 58 assert(log != NULL); 59 assert(cachefile != NULL); 60 log->cache = cache_open(log->fs, cachefile, write_commit_row); 61 } 62 63 void gemini_log_set_commit_limit(GeminiLog* log, size_t count) { 64 assert(log != NULL); 65 log->remaining_commits = count; 66 } 67 68 bool gemini_log_can_add_commits(const GeminiLog* log) { 69 assert(log != NULL); 70 return !log->cache || cache_can_add_commits(log->cache); 71 } 72 73 void gemini_log_begin(GeminiLog* log) { 74 assert(log != NULL); 75 gemini_page_begin(log->page); 76 } 77 78 void gemini_log_add_commit(GeminiLog* log, const GitCommit* commit) { 79 assert(log != NULL); 80 assert(commit != NULL); 81 if (log->cache) { 82 cache_add_commit_row(log->cache, commit); 83 } else if (log->remaining_commits > 0) { 84 write_commit_row(log->out, commit); 85 log->remaining_commits--; 86 } else { 87 log->unlogged_commits++; 88 } 89 } 90 91 void gemini_log_end(GeminiLog* log) { 92 assert(log != NULL); 93 if (log->cache) { 94 cache_close_and_replace(log->cache, log->out); 95 } else if (log->unlogged_commits > 0) { 96 size_t count = log->unlogged_commits; 97 fprintf(log->out, "\n%zu more commits remaining, fetch the repository\n", 98 count); 99 } 100 fprintf(log->out, "\n=> atom.xml Atom feed\n"); 101 fprintf(log->out, "=> tags.xml Atom feed (tags)\n"); 102 gemini_page_end(log->page); 103 } 104 105 static void write_commit_row(FILE* out, const GitCommit* commit) { 106 assert(out != NULL); 107 assert(commit != NULL); 108 fprintf(out, "=> commit/"); 109 print_percent_encoded(out, commit->oid); 110 fprintf(out, ".gmi "); 111 print_time_short(out, commit->author_time); 112 fprintf(out, " "); 113 const char* summary = commit->summary; 114 if (summary) { 115 fprintf(out, "%s", summary); 116 } 117 fprintf(out, " [%s]\n", commit->author_name); 118 }