shortlog: split builtin from common code
[git] / ruby.c
1 #include "cache.h"
2 #include "exec_cmd.h"
3 #include "refs.h"
4 #include "object.h"
5 #include "commit.h"
6 #include "remote.h"
7 #include "transport.h"
8
9 #undef NORETURN
10 #undef PATH_SEP
11
12 #include <ruby.h>
13
14 static VALUE git_rb_object;
15 static VALUE git_rb_commit;
16 static VALUE git_rb_commit_list;
17 static VALUE git_rb_remote;
18 static VALUE git_rb_transport;
19 static VALUE git_rb_ref;
20
21 static inline VALUE sha1_to_str(const unsigned char *sha1)
22 {
23         return rb_str_new((const char *)sha1, 20);
24 }
25
26 static inline VALUE cstr_to_str(const char *str)
27 {
28         if (str == NULL)
29                 return Qnil;
30         return rb_str_new2(str);
31 }
32
33 static inline char *str_to_cstr(VALUE str)
34 {
35         if (str == Qnil)
36                 return NULL;
37         return RSTRING_PTR(str);
38 }
39
40 static inline unsigned char *str_to_sha1(VALUE str)
41 {
42         return (unsigned char *)str_to_cstr(str);
43 }
44
45 static VALUE git_rb_setup_git_directory(VALUE self)
46 {
47         int nongit_ok;
48         const char *prefix;
49         prefix = setup_git_directory_gently(&nongit_ok);
50         return rb_ary_new3(2, cstr_to_str(prefix), INT2FIX(nongit_ok));
51 }
52
53 static int for_each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
54 {
55         VALUE r;
56         r = rb_yield_values(3, rb_str_new2(refname), sha1_to_str(sha1), INT2FIX(flags));
57         return r == Qfalse;
58 }
59
60 static VALUE git_rb_for_each_ref(void)
61 {
62         int r;
63         r = for_each_ref(for_each_ref_fn, NULL);
64         return INT2FIX(r);
65 }
66
67 static VALUE git_rb_dwim_ref(VALUE self, VALUE name)
68 {
69         unsigned char buf[20];
70         char *ref;
71         int r;
72
73         r = dwim_ref(RSTRING_PTR(name), RSTRING_LEN(name), buf, &ref);
74         return rb_ary_new3(3, sha1_to_str(buf), INT2NUM(r), cstr_to_str(ref));
75 }
76
77 static int git_config_fn(const char *var, const char *value, void *cb_data)
78 {
79         VALUE r;
80         r = rb_yield_values(2, rb_str_new2(var), rb_str_new2(value));
81         return r == Qfalse;
82 }
83
84 static VALUE git_rb_git_config(VALUE self)
85 {
86         int r;
87         r = git_config(git_config_fn, NULL);
88         return INT2FIX(r);
89 }
90
91 static VALUE git_rb_read_ref(VALUE self, VALUE refname)
92 {
93         unsigned char sha1[20];
94         if (read_ref(RSTRING_PTR(refname), sha1))
95                 return Qnil;
96         return sha1_to_str(sha1);
97 }
98
99 static VALUE git_rb_peel_ref(VALUE self, VALUE refname)
100 {
101         unsigned char sha1[20];
102         if (peel_ref(RSTRING_PTR(refname), sha1))
103                 return Qnil;
104         return sha1_to_str(sha1);
105 }
106
107 static VALUE git_rb_get_sha1(VALUE self, VALUE name)
108 {
109         unsigned char buf[20];
110         int r;
111         r = get_sha1(RSTRING_PTR(name), buf);
112         if (r)
113                 return Qnil;
114         return sha1_to_str(buf);
115 }
116
117 static VALUE git_rb_object_get(VALUE class, VALUE id)
118 {
119         struct object *object;
120         object = parse_object(str_to_sha1(id));
121         return Data_Wrap_Struct(git_rb_object, NULL, NULL, object);
122 }
123
124 static VALUE git_rb_commit_get(VALUE class, VALUE id)
125 {
126         struct object *object;
127         object = parse_object(str_to_sha1(id));
128         if (!object || object->type != OBJ_COMMIT)
129                 return Qnil;
130         return Data_Wrap_Struct(git_rb_commit, NULL, NULL, object);
131 }
132
133 static VALUE git_rb_object_sha1(VALUE self)
134 {
135         struct object *object;
136         Data_Get_Struct(self, struct object, object);
137         return sha1_to_str(object->sha1);
138 }
139
140 static VALUE git_rb_object_type(VALUE self)
141 {
142         struct object *object;
143         Data_Get_Struct(self, struct object, object);
144         return INT2FIX(object->type);
145 }
146
147 static VALUE git_rb_object_to_s(VALUE self)
148 {
149         struct object *object;
150         Data_Get_Struct(self, struct object, object);
151         return rb_str_new2(sha1_to_hex(object->sha1));
152 }
153
154 static VALUE git_rb_commit_buffer(VALUE self)
155 {
156         struct commit *commit;
157         Data_Get_Struct(self, struct commit, commit);
158         return cstr_to_str(commit->buffer);
159 }
160
161 static VALUE git_rb_commit_list_each(VALUE self)
162 {
163         struct commit_list *e, *list;
164         Data_Get_Struct(self, struct commit_list, list);
165
166         for (e = list; e; e = e->next) {
167                 VALUE c;
168                 c = Data_Wrap_Struct(git_rb_commit, NULL, NULL, e->item);
169                 rb_yield(c);
170         }
171
172         return self;
173 }
174
175 static VALUE git_rb_get_merge_bases(VALUE self, VALUE commits, VALUE cleanup)
176 {
177         struct commit *g_commits[RARRAY_LEN(commits)];
178         struct commit_list *result;
179         int i;
180
181         for (i = 0; i < RARRAY_LEN(commits); i++) {
182                 VALUE commit = RARRAY_PTR(commits)[i];
183                 Data_Get_Struct(commit, struct commit, g_commits[i]);
184         }
185         result = get_merge_bases_many(g_commits[0], RARRAY_LEN(commits) - 1, g_commits + 1, NUM2INT(cleanup));
186         if (!result)
187                 return Qnil;
188         return Data_Wrap_Struct(git_rb_commit_list, NULL, NULL, result);
189 }
190
191 static VALUE git_rb_remote_get(VALUE self, VALUE name)
192 {
193         struct remote *remote;
194         remote = remote_get(RSTRING_PTR(name));
195         if (!remote)
196                 return Qnil;
197         return Data_Wrap_Struct(git_rb_remote, NULL, NULL, remote);
198 }
199
200 static VALUE git_rb_remote_url(VALUE self)
201 {
202         struct remote *remote;
203         VALUE url;
204         int i;
205
206         Data_Get_Struct(self, struct remote, remote);
207         url = rb_ary_new2(remote->url_nr);
208         for (i = 0; i < remote->url_nr; i++)
209                 rb_ary_store(url, i, rb_str_new2(remote->url[i]));
210         return url;
211 }
212
213 static VALUE git_rb_transport_get(VALUE self, VALUE remote, VALUE url)
214 {
215         struct transport *transport;
216         struct remote *g_remote;
217         Data_Get_Struct(remote, struct remote, g_remote);
218         transport = transport_get(g_remote, str_to_cstr(url));
219         if (!transport)
220                 return Qnil;
221         return Data_Wrap_Struct(git_rb_transport, NULL, transport_disconnect, transport);
222 }
223
224 static VALUE git_rb_transport_get_remote_refs(VALUE self)
225 {
226         struct transport *transport;
227         const struct ref *ref;
228         Data_Get_Struct(self, struct transport, transport);
229         ref = transport_get_remote_refs(transport);
230         return Data_Wrap_Struct(git_rb_ref, NULL, NULL, (void *)ref);
231 }
232
233 static VALUE git_rb_ref_each(VALUE self)
234 {
235         struct ref *e, *ref;
236         Data_Get_Struct(self, struct ref, ref);
237
238         for (e = ref; e; e = e->next) {
239                 VALUE c;
240                 c = Data_Wrap_Struct(git_rb_ref, NULL, NULL, e);
241                 rb_yield(c);
242         }
243
244         return self;
245 }
246
247 static VALUE git_rb_ref_name(VALUE self)
248 {
249         struct ref *ref;
250         Data_Get_Struct(self, struct ref, ref);
251         return rb_str_new2(ref->name);
252 }
253
254 static VALUE git_rb_ref_old_sha1(VALUE self)
255 {
256         struct ref *ref;
257         Data_Get_Struct(self, struct ref, ref);
258         return sha1_to_str(ref->old_sha1);
259 }
260
261 static VALUE git_rb_find_unique_abbrev(VALUE self, VALUE sha1, VALUE len)
262 {
263         const char *abbrev;
264         abbrev = find_unique_abbrev(str_to_sha1(sha1), NUM2INT(len));
265         return rb_str_new2(abbrev);
266 }
267
268 static VALUE git_rb_read_sha1_file(VALUE self, VALUE sha1, VALUE type)
269 {
270         enum object_type g_type;
271         void *buffer;
272         unsigned long size;
273
274         buffer = read_sha1_file(str_to_sha1(sha1), &g_type, &size);
275         if (!buffer)
276                 return Qnil;
277         return rb_ary_new3(2, rb_str_new(buffer, size), INT2FIX(g_type));
278 }
279
280 static void git_ruby_init(void)
281 {
282         VALUE mod;
283
284         mod = rb_define_module("Git");
285
286         rb_define_global_const("OBJ_BAD", INT2FIX(OBJ_BAD));
287         rb_define_global_const("OBJ_NONE", INT2FIX(OBJ_NONE));
288         rb_define_global_const("OBJ_COMMIT", INT2FIX(OBJ_COMMIT));
289         rb_define_global_const("OBJ_TREE", INT2FIX(OBJ_TREE));
290         rb_define_global_const("OBJ_BLOB", INT2FIX(OBJ_BLOB));
291         rb_define_global_const("OBJ_TAG", INT2FIX(OBJ_TAG));
292         rb_define_global_const("OBJ_OFS_DELTA", INT2FIX(OBJ_OFS_DELTA));
293         rb_define_global_const("OBJ_REF_DELTA", INT2FIX(OBJ_REF_DELTA));
294         rb_define_global_const("OBJ_ANY", INT2FIX(OBJ_ANY));
295         rb_define_global_const("OBJ_MAX", INT2FIX(OBJ_MAX));
296
297         rb_define_global_const("DEFAULT_ABBREV", INT2FIX(DEFAULT_ABBREV));
298
299         rb_define_global_function("setup_git_directory", git_rb_setup_git_directory, 0);
300         rb_define_global_function("for_each_ref", git_rb_for_each_ref, 0);
301         rb_define_global_function("dwim_ref", git_rb_dwim_ref, 1);
302         rb_define_global_function("git_config", git_rb_git_config, 0);
303         rb_define_global_function("read_ref", git_rb_read_ref, 1);
304         rb_define_global_function("peel_ref", git_rb_peel_ref, 1);
305         rb_define_global_function("get_sha1", git_rb_get_sha1, 1);
306         rb_define_global_function("get_merge_bases", git_rb_get_merge_bases, 2);
307         rb_define_global_function("remote_get", git_rb_remote_get, 1);
308         rb_define_global_function("transport_get", git_rb_transport_get, 2);
309         rb_define_global_function("find_unique_abbrev", git_rb_find_unique_abbrev, 2);
310         rb_define_global_function("read_sha1_file", git_rb_read_sha1_file, 1);
311
312         git_rb_object = rb_define_class_under(mod, "Object", rb_cData);
313         rb_define_singleton_method(git_rb_object, "get", git_rb_object_get, 1);
314         rb_define_method(git_rb_object, "sha1", git_rb_object_sha1, 0);
315         rb_define_method(git_rb_object, "type", git_rb_object_type, 0);
316         rb_define_method(git_rb_object, "to_s", git_rb_object_to_s, 0);
317
318         git_rb_commit = rb_define_class_under(mod, "Commit", git_rb_object);
319         rb_define_singleton_method(git_rb_commit, "get", git_rb_commit_get, 1);
320         rb_define_method(git_rb_commit, "buffer", git_rb_commit_buffer, 0);
321
322         git_rb_commit_list = rb_define_class_under(mod, "CommitList", rb_cData);
323         rb_include_module(git_rb_commit_list, rb_mEnumerable);
324         rb_define_method(git_rb_commit_list, "each", git_rb_commit_list_each, 0);
325
326         git_rb_remote = rb_define_class_under(mod, "Remote", rb_cData);
327         rb_define_method(git_rb_remote, "url", git_rb_remote_url, 0);
328
329         git_rb_transport = rb_define_class_under(mod, "Transport", rb_cData);
330         rb_define_method(git_rb_transport, "get_remote_refs", git_rb_transport_get_remote_refs, 0);
331
332         git_rb_ref = rb_define_class_under(mod, "Ref", rb_cData);
333         rb_include_module(git_rb_ref, rb_mEnumerable);
334         rb_define_method(git_rb_ref, "each", git_rb_ref_each, 0);
335         rb_define_method(git_rb_ref, "name", git_rb_ref_name, 0);
336         rb_define_method(git_rb_ref, "old_sha1", git_rb_ref_old_sha1, 0);
337 }
338
339 static int run_ruby_command(const char *cmd, int argc, const char **argv)
340 {
341         static char buf[PATH_MAX + 1];
342         void *node;
343         struct stat st;
344
345         ruby_init();
346         git_ruby_init();
347
348         node = ruby_options(argc, (char **)argv);
349
350         ruby_script(cmd);
351         snprintf(buf, PATH_MAX, "%s/%s", git_exec_path(), "git-rb-setup.rb");
352         if (!stat(buf, &st))
353                 rb_load(rb_str_new2(buf), 0);
354
355         return ruby_run_node(node);
356 }
357
358 int main(int argc, const char **argv)
359 {
360         if (!strcmp(argv[0], "git-ruby")) {
361                 return run_ruby_command(argv[1], argc, argv);
362         } else {
363                 const char *cmd = argv[0];
364                 static char buf[PATH_MAX + 1];
365                 const char *args[argc + 1];
366                 int i;
367
368                 snprintf(buf, PATH_MAX, "%s/%s.rb",
369                                 git_exec_path(), basename((char *)cmd));
370
371                 args[0] = "git";
372                 args[1] = buf;
373                 for (i = 0; i < argc - 1; i++)
374                         args[i + 2] = (char *)argv[i + 1];
375
376                 return run_ruby_command(cmd, argc + 1, args);
377         }
378 }