so://phie

soso

My pretty neat website
git clone git://soophie.de/soso

blob: 060847774c3d57ed7e55b8936a715b90e1454b82 (9286 bytes)[raw]

1#include <git2.h>

2#include <git2/types.h>

3#include "git_repo.h"

4

5#include "../templ/duc_git_repo.h"

6

7static orb_rc_t init(orb_module_t *self) {

8 duc_git_repo_t *data = self->data;

9 git_repo_param_list_t *param_list = self->param_list;

10 if (param_list) {

11 data->repo = (git_repo_t) {

12 .path = param_list->repo_path,

13 .meta = {0},

14 .handle = NULL,

15 .flag_ref_oid = param_list->flag_ref_oid,

16 .flag_oid = param_list->flag_oid,

17 .flag_path = param_list->flag_path,

18 .ref_head = NULL,

19 .ref = NULL,

20 .ref_list = NULL,

21 .ref_list_len = 0,

22 };

23 data->repo.meta.name = param_list->repo_name;

24 data->tab_mode = param_list->tab_mode;

25 }

26 return ORB_OK;

27}

28

29static int _fetch_read_text_file(char *filename, char **content) {

30 FILE *fd = fopen(filename, "r");

31 if (fd == NULL) return 1;

32 fseek(fd, 0, SEEK_END);

33 size_t len = ftell(fd);

34 fseek(fd, 0, SEEK_SET);

35 *content = calloc(1, sizeof(char) * (len + 1));

36 fread(*content, sizeof(char), len, fd);

37 (*content)[len] = '\0';

38 fclose(fd);

39 return 0;

40}

41

42static int _fetch_read_git_file(char *repo_path, char *filename, char **content) {

43 size_t file_path_len = strlen(repo_path) + strlen(filename) + 2;

44 char file_path[file_path_len];

45 snprintf(file_path, file_path_len, "%s/%s", repo_path, filename);

46 return _fetch_read_text_file(file_path, content);

47}

48

49static bool _fetch_git_file_exists(char *repo_path, char *filename) {

50 size_t file_path_len = strlen(repo_path) + strlen(filename) + 2;

51 char file_path[file_path_len];

52 snprintf(file_path, file_path_len, "%s/%s", repo_path, filename);

53 FILE *fp = fopen(file_path, "r");

54 if (!fp) return false;

55 fclose(fp);

56 return true;

57}

58

59static char *_fetch_git_file_oid(git_repository *repo, char *ref_name, char *filename) {

60 size_t spec_len = strlen(ref_name) + strlen(filename) + 2;

61 char spec[spec_len];

62 snprintf(spec, spec_len, "%s:%s", ref_name, filename);

63 git_object *obj_handle = NULL;

64 if (git_revparse_single(&obj_handle, repo, spec) != 0) return NULL;

65 char oid_str[GIT_OID_HEXSZ + 1];

66 git_oid_tostr(oid_str, sizeof(oid_str), git_object_id(obj_handle));

67 git_object_free(obj_handle);

68 return strdup(oid_str);

69}

70

71static orb_rc_t fetch(orb_module_t *self) {

72 duc_git_repo_t *data = self->data;

73 git_repo_param_list_t *param_list = self->param_list;

74 if (!param_list->repo_path) return ORB_FATAL(1);

75 bool is_public = _fetch_git_file_exists(param_list->repo_path, "git-daemon-export-ok");

76 if (!is_public) return ORB_FATAL(2);

77 git_repository *repo_handle = NULL;

78 int code = git_repository_open(&repo_handle, param_list->repo_path);

79 if (code < 0 || repo_handle == NULL) return ORB_FATAL(code);

80 data->repo.handle = repo_handle;

81 _fetch_read_git_file(data->repo.path, "description", &data->repo.meta.description);

82 _fetch_read_git_file(data->repo.path, "owner", &data->repo.meta.owner);

83 data->repo.meta.is_public = is_public;

84 data->repo.meta.is_archive = _fetch_git_file_exists(data->repo.path, ".archive");

85 data->repo.meta.is_fork = _fetch_git_file_exists(data->repo.path, ".fork");

86 git_reference *ref_head_handle = NULL;

87 git_repository_head(&ref_head_handle, data->repo.handle);

88 if (ref_head_handle) {

89 data->repo.ref_head = calloc(1, sizeof(git_repo_ref_t));

90 git_repo_ref_t *ref = data->repo.ref_head;

91 const git_oid *oid = git_reference_target(ref_head_handle);

92 char oid_str[GIT_OID_HEXSZ + 1];

93 git_oid_tostr(oid_str, sizeof(oid_str), oid);

94 ref->oid = strdup(oid_str);

95 const char *ref_name = git_reference_name(ref_head_handle);

96 if (git_reference_is_branch(ref_head_handle)) {

97 ref->name = strdup(ref_name + strlen("refs/heads/"));

98 ref->type = "branch";

99 }

100 if (git_reference_is_tag(ref_head_handle)) {

101 ref->name = strdup(ref_name + strlen("refs/tags/"));

102 ref->type = "tag";

103 }

104 if (git_reference_is_remote(ref_head_handle)) {

105 ref->name = strdup(ref_name + strlen("refs/remotes/"));

106 ref->type = "remote";

107 }

108 if (!ref->name) {

109 ref->name = strdup(ref_name);

110 }

111 git_reference_free(ref_head_handle);

112 data->repo.readme_oid = _fetch_git_file_oid(repo_handle, ref->name, "README.md");

113 data->repo.license_oid = _fetch_git_file_oid(repo_handle, ref->name, "LICENSE");

114 git_reference_iterator *iter = NULL;

115 git_reference *ref_handle = NULL;

116 git_reference_iterator_new(&iter, data->repo.handle);

117 while (git_reference_next(&ref_handle, iter) == 0) {

118 data->repo.ref_list = realloc(data->repo.ref_list, sizeof(git_repo_ref_t) * (data->repo.ref_list_len + 1));

119 git_repo_ref_t *ref = &data->repo.ref_list[data->repo.ref_list_len];

120 memset(ref, 0, sizeof(git_repo_ref_t));

121 const git_oid *oid = git_reference_target(ref_handle);

122 char oid_str[GIT_OID_HEXSZ + 1];

123 git_oid_tostr(oid_str, sizeof(oid_str), oid);

124 ref->oid = strdup(oid_str);

125 const char *ref_name = git_reference_name(ref_handle);

126 if (git_reference_is_branch(ref_handle)) {

127 ref->name = strdup(ref_name + strlen("refs/heads/"));

128 ref->type = "branch";

129 }

130 if (git_reference_is_tag(ref_handle)) {

131 ref->name = strdup(ref_name + strlen("refs/tags/"));

132 ref->type = "tag";

133 }

134 if (git_reference_is_remote(ref_handle)) {

135 ref->name = strdup(ref_name + strlen("refs/remotes/"));

136 ref->type = "remote";

137 }

138 if (!ref->name) {

139 ref->name = strdup(ref_name);

140 }

141 git_reference_free(ref_handle);

142 data->repo.ref_list_len++;

143 }

144 git_reference_iterator_free(iter);

145 }

146 if (data->repo.ref_head && data->repo.flag_ref_oid && strcmp(data->repo.ref_head->oid, data->repo.flag_ref_oid) != 0) {

147 git_oid ref_oid;

148 if (git_oid_fromstr(&ref_oid, data->repo.flag_ref_oid) == 0) {

149 git_reference_iterator *iter = NULL;

150 git_reference *ref_handle = NULL;

151 git_reference_iterator_new(&iter, data->repo.handle);

152 while (git_reference_next(&ref_handle, iter) == 0) {

153 const git_oid *oid = git_reference_target(ref_handle);

154 if (oid && git_oid_equal(oid, &ref_oid)) {

155 data->repo.ref = calloc(1, sizeof(git_repo_ref_t));

156 git_repo_ref_t *ref = data->repo.ref;

157 ref->oid = strdup(data->repo.flag_ref_oid);

158 const char *ref_name = git_reference_name(ref_handle);

159 if (git_reference_is_branch(ref_handle)) {

160 ref->name = strdup(ref_name + strlen("refs/heads/"));

161 ref->type = "branch";

162 }

163 if (git_reference_is_tag(ref_handle)) {

164 ref->name = strdup(ref_name + strlen("refs/tags/"));

165 ref->type = "tag";

166 }

167 if (git_reference_is_remote(ref_handle)) {

168 ref->name = strdup(ref_name + strlen("refs/remotes/"));

169 ref->type = "remote";

170 }

171 if (!ref->name) {

172 ref->name = strdup(ref_name);

173 }

174 }

175 git_reference_free(ref_handle);

176 }

177 git_reference_iterator_free(iter);

178 if (!data->repo.ref) {

179 git_object *obj_handle = NULL;

180 if (git_object_lookup(&obj_handle, data->repo.handle, &ref_oid, GIT_OBJECT_COMMIT) == 0) {

181 git_object_free(obj_handle);

182 data->repo.ref_list = realloc(data->repo.ref_list, sizeof(git_repo_ref_t) * (data->repo.ref_list_len + 1));

183 git_repo_ref_t *ref = &data->repo.ref_list[data->repo.ref_list_len];

184 memset(ref, 0, sizeof(git_repo_ref_t));

185 ref->oid = strdup(data->repo.flag_ref_oid);

186 ref->name = strdup(data->repo.flag_ref_oid);

187 ref->type = "commit";

188 data->repo.ref_list_len++;

189 data->repo.ref = calloc(1, sizeof(git_repo_ref_t));

190 ref = data->repo.ref;

191 ref->oid = strdup(data->repo.flag_ref_oid);

192 ref->name = strdup(data->repo.flag_ref_oid);

193 ref->type = "commit";

194 }

195 }

196 }

197 }

198 return ORB_OK;

199}

200

201static orb_rc_t render(orb_module_t *self, void *out) {

202 return ORB_ERR(duc_git_repo_render(out, (duc_git_repo_t *) self->data));

203}

204

205static void cleanup(orb_module_t *self) {

206 duc_git_repo_t *data = self->data;

207 if (data->repo.handle) {

208 git_repository_free(data->repo.handle);

209 data->repo.handle = NULL;

210 }

211 if (data->repo.meta.description) free(data->repo.meta.description);

212 if (data->repo.meta.owner) free(data->repo.meta.owner);

213 if (data->repo.ref_head) {

214 free(data->repo.ref_head->oid);

215 free(data->repo.ref_head->name);

216 free(data->repo.ref_head);

217 data->repo.ref_head = NULL;

218 }

219 if (data->repo.ref) {

220 free(data->repo.ref->oid);

221 free(data->repo.ref->name);

222 free(data->repo.ref);

223 data->repo.ref = NULL;

224 }

225 if (data->repo.readme_oid) free(data->repo.readme_oid);

226 if (data->repo.license_oid) free(data->repo.license_oid);

227 if (data->repo.ref_list && data->repo.ref_list_len > 0) {

228 for (size_t i = 0; i < data->repo.ref_list_len; i++) {

229 git_repo_ref_t *ref = &data->repo.ref_list[i];

230 free(ref->oid);

231 free(ref->name);

232 }

233 free(data->repo.ref_list);

234 data->repo.ref_list = NULL;

235 data->repo.ref_list_len = 0;

236 }

237}

238

239const orb_module_type_t GIT_REPO_TYPE = {

240 .size = sizeof(duc_git_repo_t),

241 .init = init,

242 .fetch = fetch,

243 .render = render,

244 .cleanup = cleanup,

245};