repo_writer.c (5285B)
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 writer->refs = NULL; 63 gemini_log_free(writer->log); 64 writer->log = NULL; 65 atom_free(writer->atom); 66 writer->atom = NULL; 67 if (writer->atom_out) { 68 writer->fs->fclose(writer->atom_out); 69 writer->atom_out = NULL; 70 } 71 atom_free(writer->tags); 72 writer->tags = NULL; 73 if (writer->tags_out) { 74 writer->fs->fclose(writer->tags_out); 75 writer->tags_out = NULL; 76 } 77 gemini_files_free(writer->files); 78 writer->files = NULL; 79 free(writer); 80 } 81 82 void gemini_repowriter_set_log_cachefile(GeminiRepoWriter* writer, 83 const char* cachefile) { 84 assert(writer != NULL); 85 assert(cachefile != NULL); 86 gemini_log_set_cachefile(writer->log, cachefile); 87 } 88 89 void gemini_repowriter_set_log_commit_limit(GeminiRepoWriter* writer, 90 size_t count) { 91 assert(writer != NULL); 92 gemini_log_set_commit_limit(writer->log, count); 93 } 94 95 void gemini_repowriter_set_baseurl(GeminiRepoWriter* writer, 96 const char* baseurl) { 97 assert(writer != NULL); 98 assert(baseurl != NULL); 99 atom_set_baseurl(writer->atom, baseurl); 100 atom_set_baseurl(writer->tags, baseurl); 101 } 102 103 void gemini_repowriter_begin(GeminiRepoWriter* writer) { 104 assert(writer != NULL); 105 writer->fs->mkdir("commit", S_IRWXU | S_IRWXG | S_IRWXO); 106 writer->fs->mkdir("file", S_IRWXU | S_IRWXG | S_IRWXO); 107 108 gemini_refs_begin(writer->refs); 109 gemini_log_begin(writer->log); 110 atom_begin(writer->atom); 111 atom_begin(writer->tags); 112 gemini_files_begin(writer->files); 113 } 114 115 void gemini_repowriter_add_commit(GeminiRepoWriter* writer, 116 const GitCommit* git_commit) { 117 assert(writer != NULL); 118 assert(git_commit != NULL); 119 char filename[PATH_MAX]; 120 int r = snprintf(filename, sizeof(filename), "%s.gmi", git_commit->oid); 121 if (r < 0 || (size_t)r >= sizeof(filename)) { 122 errx(1, "snprintf: filename truncated or error"); 123 } 124 char* path = path_concat("commit", filename); 125 atom_add_commit(writer->atom, git_commit, path, "", ""); 126 free(path); 127 128 if (gemini_log_can_add_commits(writer->log)) { 129 gemini_log_add_commit(writer->log, git_commit); 130 GeminiCommit* commit = gemini_commit_create( 131 writer->repo, writer->fs, git_commit->oid, git_commit->summary); 132 gemini_commit_begin(commit); 133 gemini_commit_add_commit(commit, git_commit); 134 gemini_commit_end(commit); 135 gemini_commit_free(commit); 136 } 137 } 138 139 void gemini_repowriter_add_reference(GeminiRepoWriter* writer, 140 const GitReference* ref) { 141 assert(writer != NULL); 142 assert(ref != NULL); 143 gemini_refs_add_ref(writer->refs, ref); 144 if (ref->type == kReftypeTag) { 145 GitCommit* commit = ref->commit; 146 char filename[PATH_MAX]; 147 int r = snprintf(filename, sizeof(filename), "%s.gmi", commit->oid); 148 if (r < 0 || (size_t)r >= sizeof(filename)) { 149 errx(1, "snprintf: filename truncated or error"); 150 } 151 char* path = path_concat("commit", filename); 152 atom_add_commit(writer->tags, commit, path, "", ref->shorthand); 153 free(path); 154 } 155 } 156 157 void gemini_repowriter_add_file(GeminiRepoWriter* writer, const GitFile* file) { 158 assert(writer != NULL); 159 assert(file != NULL); 160 gemini_files_add_file(writer->files, file); 161 162 GeminiFileBlob* blob = 163 gemini_fileblob_create(writer->repo, writer->fs, file->repo_path); 164 gemini_fileblob_begin(blob); 165 gemini_fileblob_add_file(blob, file); 166 gemini_fileblob_end(blob); 167 gemini_fileblob_free(blob); 168 } 169 170 void gemini_repowriter_end(GeminiRepoWriter* writer) { 171 assert(writer != NULL); 172 gemini_refs_end(writer->refs); 173 gemini_log_end(writer->log); 174 atom_end(writer->atom); 175 atom_end(writer->tags); 176 gemini_files_end(writer->files); 177 }