repo_writer.c (5112B)
1 #include "writer/gemini/repo_writer.h" 2 3 #include <assert.h> 4 #include <err.h> 5 #include <limits.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <sys/stat.h> 9 #include <sys/types.h> 10 11 #include "git/commit.h" 12 #include "git/file.h" 13 #include "git/reference.h" 14 #include "utils.h" 15 #include "writer/atom/atom.h" 16 #include "writer/gemini/commit.h" 17 #include "writer/gemini/fileblob.h" 18 #include "writer/gemini/files.h" 19 #include "writer/gemini/log.h" 20 #include "writer/gemini/refs.h" 21 22 struct GeminiRepoWriter { 23 const GitRepo* repo; 24 const FileSystem* fs; 25 GeminiRefs* refs; 26 GeminiLog* log; 27 Atom* atom; 28 FILE* atom_out; 29 Atom* tags; 30 FILE* tags_out; 31 GeminiFiles* files; 32 }; 33 34 GeminiRepoWriter* gemini_repowriter_create(const GitRepo* repo, 35 const FileSystem* fs) { 36 assert(repo != NULL); 37 assert(fs != NULL); 38 GeminiRepoWriter* writer = ecalloc(1, sizeof(GeminiRepoWriter)); 39 writer->repo = repo; 40 writer->fs = fs; 41 writer->refs = gemini_refs_create(repo, fs); 42 writer->log = gemini_log_create(repo, fs); 43 writer->atom_out = fs->fopen("atom.xml", "w"); 44 if (!writer->atom_out) { 45 err(1, "fopen: atom.xml"); 46 } 47 writer->atom = atom_create(repo, writer->atom_out); 48 writer->tags_out = fs->fopen("tags.xml", "w"); 49 if (!writer->tags_out) { 50 err(1, "fopen: tags.xml"); 51 } 52 writer->tags = atom_create(repo, writer->tags_out); 53 writer->files = gemini_files_create(repo, fs); 54 return writer; 55 } 56 57 void gemini_repowriter_free(GeminiRepoWriter* writer) { 58 if (!writer) { 59 return; 60 } 61 gemini_refs_free(writer->refs); 62 gemini_log_free(writer->log); 63 atom_free(writer->atom); 64 if (writer->atom_out) { 65 writer->fs->fclose(writer->atom_out); 66 } 67 atom_free(writer->tags); 68 if (writer->tags_out) { 69 writer->fs->fclose(writer->tags_out); 70 } 71 gemini_files_free(writer->files); 72 free(writer); 73 } 74 75 void gemini_repowriter_set_log_cachefile(GeminiRepoWriter* writer, 76 const char* cachefile) { 77 assert(writer != NULL); 78 assert(cachefile != NULL); 79 gemini_log_set_cachefile(writer->log, cachefile); 80 } 81 82 void gemini_repowriter_set_log_commit_limit(GeminiRepoWriter* writer, 83 size_t count) { 84 assert(writer != NULL); 85 gemini_log_set_commit_limit(writer->log, count); 86 } 87 88 void gemini_repowriter_set_baseurl(GeminiRepoWriter* writer, 89 const char* baseurl) { 90 assert(writer != NULL); 91 assert(baseurl != NULL); 92 atom_set_baseurl(writer->atom, baseurl); 93 atom_set_baseurl(writer->tags, baseurl); 94 } 95 96 void gemini_repowriter_begin(GeminiRepoWriter* writer) { 97 assert(writer != NULL); 98 writer->fs->mkdir("commit", S_IRWXU | S_IRWXG | S_IRWXO); 99 writer->fs->mkdir("file", S_IRWXU | S_IRWXG | S_IRWXO); 100 101 gemini_refs_begin(writer->refs); 102 gemini_log_begin(writer->log); 103 atom_begin(writer->atom); 104 atom_begin(writer->tags); 105 gemini_files_begin(writer->files); 106 } 107 108 void gemini_repowriter_add_commit(GeminiRepoWriter* writer, 109 const GitCommit* git_commit) { 110 assert(writer != NULL); 111 assert(git_commit != NULL); 112 char filename[PATH_MAX]; 113 int r = snprintf(filename, sizeof(filename), "%s.gmi", git_commit->oid); 114 if (r < 0 || (size_t)r >= sizeof(filename)) { 115 errx(1, "snprintf: filename truncated or error"); 116 } 117 char* path = path_concat("commit", filename); 118 atom_add_commit(writer->atom, git_commit, path, "", ""); 119 free(path); 120 121 if (gemini_log_can_add_commits(writer->log)) { 122 gemini_log_add_commit(writer->log, git_commit); 123 GeminiCommit* commit = gemini_commit_create( 124 writer->repo, writer->fs, git_commit->oid, git_commit->summary); 125 gemini_commit_begin(commit); 126 gemini_commit_add_commit(commit, git_commit); 127 gemini_commit_end(commit); 128 gemini_commit_free(commit); 129 } 130 } 131 132 void gemini_repowriter_add_reference(GeminiRepoWriter* writer, 133 const GitReference* ref) { 134 assert(writer != NULL); 135 assert(ref != NULL); 136 gemini_refs_add_ref(writer->refs, ref); 137 if (ref->type == kReftypeTag) { 138 GitCommit* commit = ref->commit; 139 char filename[PATH_MAX]; 140 int r = snprintf(filename, sizeof(filename), "%s.gmi", commit->oid); 141 if (r < 0 || (size_t)r >= sizeof(filename)) { 142 errx(1, "snprintf: filename truncated or error"); 143 } 144 char* path = path_concat("commit", filename); 145 atom_add_commit(writer->tags, commit, path, "", ref->shorthand); 146 free(path); 147 } 148 } 149 150 void gemini_repowriter_add_file(GeminiRepoWriter* writer, const GitFile* file) { 151 assert(writer != NULL); 152 assert(file != NULL); 153 gemini_files_add_file(writer->files, file); 154 155 GeminiFileBlob* blob = 156 gemini_fileblob_create(writer->repo, writer->fs, file->repo_path); 157 gemini_fileblob_begin(blob); 158 gemini_fileblob_add_file(blob, file); 159 gemini_fileblob_end(blob); 160 gemini_fileblob_free(blob); 161 } 162 163 void gemini_repowriter_end(GeminiRepoWriter* writer) { 164 assert(writer != NULL); 165 gemini_refs_end(writer->refs); 166 gemini_log_end(writer->log); 167 atom_end(writer->atom); 168 atom_end(writer->tags); 169 gemini_files_end(writer->files); 170 }