gout.c (4607B)
1 #include "gout.h" 2 3 #include <assert.h> 4 #include <errno.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <unistd.h> 8 9 #include "git/commit.h" 10 #include "git/file.h" 11 #include "git/git.h" 12 #include "git/reference.h" 13 #include "security.h" 14 #include "utils.h" 15 #include "writer/repo_writer.h" 16 17 static void repo_callback(Git* git, void* user_data); 18 static void commit_callback(const GitCommit* commit, void* user_data); 19 static void reference_callback(const GitReference* ref, void* user_data); 20 static void file_callback(const GitFile* file, void* user_data); 21 22 GoutOptions* gout_options_create(int argc, const char* argv[]) { 23 assert(argv != NULL); 24 GoutOptions options = { 25 .repodir = NULL, 26 .log_commit_limit = -1, 27 .cachefile_path = NULL, 28 .baseurl = "", 29 .writer_type = kRepoWriterTypeHtml, 30 }; 31 32 int ch; 33 optind = 1; 34 opterr = 0; 35 while ((ch = getopt(argc, (char* const*)argv, "c:l:u:HGM")) != -1) { 36 switch (ch) { 37 case 'c': 38 // Mutually exclusive with -l. 39 if (options.log_commit_limit > 0) { 40 return NULL; 41 } 42 options.cachefile_path = optarg; 43 break; 44 case 'l': 45 // Mutually exclusive with -c. 46 if (options.cachefile_path) { 47 return NULL; 48 } 49 errno = 0; 50 char* p; 51 options.log_commit_limit = strtoll(optarg, &p, 10); 52 if (!optarg[0] || *p || options.log_commit_limit <= 0 || errno) { 53 return NULL; 54 } 55 break; 56 case 'u': 57 options.baseurl = optarg; 58 break; 59 case 'H': 60 options.writer_type = kRepoWriterTypeHtml; 61 break; 62 case 'G': 63 options.writer_type = kRepoWriterTypeGopher; 64 break; 65 case 'M': 66 options.writer_type = kRepoWriterTypeGemini; 67 break; 68 default: 69 return NULL; 70 } 71 } 72 argc -= optind; 73 argv += optind; 74 75 // Must specify exactly one repo directory. 76 if (argc != 1) { 77 return NULL; 78 } 79 options.repodir = argv[0]; 80 81 GoutOptions* options_out = ecalloc(1, sizeof(GoutOptions)); 82 *options_out = options; 83 return options_out; 84 } 85 86 void gout_options_free(GoutOptions* options) { 87 if (!options) { 88 return; 89 } 90 options->repodir = NULL; 91 options->log_commit_limit = -1; 92 options->cachefile_path = NULL; 93 options->baseurl = NULL; 94 free(options); 95 } 96 97 void gout_init(const GoutOptions* options, Git* git) { 98 assert(options != NULL); 99 assert(git != NULL); 100 101 const char* readonly_paths[] = {options->repodir}; 102 size_t readonly_paths_count = 1; 103 const char* readwrite_paths[2] = {".", NULL}; 104 size_t readwrite_paths_count = 1; 105 if (options->cachefile_path) { 106 readwrite_paths[1] = options->cachefile_path; 107 readwrite_paths_count = 2; 108 } 109 restrict_filesystem_access(readonly_paths, readonly_paths_count, 110 readwrite_paths, readwrite_paths_count); 111 restrict_system_operations( 112 options->cachefile_path != NULL ? kGoutWithCachefile : kGout); 113 114 git->initialize(git); 115 } 116 117 void gout_run(const GoutOptions* options, Git* git) { 118 assert(options != NULL); 119 assert(git != NULL); 120 git->for_repo(git, options->repodir, repo_callback, (void*)options); 121 } 122 123 static void repo_callback(Git* git, void* user_data) { 124 assert(git != NULL); 125 assert(user_data != NULL); 126 const GoutOptions* options = (const GoutOptions*)user_data; 127 RepoWriter* writer = 128 repowriter_create(options->writer_type, git->repo, git->fs); 129 if (options->log_commit_limit >= 0) { 130 repowriter_set_log_commit_limit(writer, options->log_commit_limit); 131 } 132 if (options->cachefile_path) { 133 repowriter_set_log_cachefile(writer, options->cachefile_path); 134 } 135 if (options->baseurl) { 136 repowriter_set_baseurl(writer, options->baseurl); 137 } 138 139 repowriter_begin(writer); 140 git->for_each_commit(git, commit_callback, writer); 141 git->for_each_reference(git, reference_callback, writer); 142 git->for_each_file(git, file_callback, writer); 143 repowriter_end(writer); 144 145 repowriter_free(writer); 146 } 147 148 static void commit_callback(const GitCommit* ci, void* user_data) { 149 assert(ci != NULL); 150 assert(user_data != NULL); 151 RepoWriter* writer = (RepoWriter*)user_data; 152 repowriter_add_commit(writer, ci); 153 } 154 155 static void reference_callback(const GitReference* ref, void* user_data) { 156 assert(ref != NULL); 157 assert(user_data != NULL); 158 RepoWriter* writer = (RepoWriter*)user_data; 159 repowriter_add_reference(writer, ref); 160 } 161 162 static void file_callback(const GitFile* file, void* user_data) { 163 assert(file != NULL); 164 assert(user_data != NULL); 165 RepoWriter* writer = (RepoWriter*)user_data; 166 repowriter_add_file(writer, file); 167 }