Git v1.9.1+fc2
[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 #include "revision.h"
9 #include "diff.h"
10 #include "shortlog.h"
11 #include "log-tree.h"
12
13 #undef NORETURN
14 #undef PATH_SEP
15
16 #include <ruby.h>
17
18 static VALUE git_rb_object;
19 static VALUE git_rb_commit;
20 static VALUE git_rb_commit_list;
21 static VALUE git_rb_remote;
22 static VALUE git_rb_transport;
23 static VALUE git_rb_ref;
24 static VALUE git_rb_rev_info;
25 static VALUE git_rb_diff_opt;
26
27 static inline VALUE sha1_to_str(const unsigned char *sha1)
28 {
29         return rb_str_new((const char *)sha1, 20);
30 }
31
32 static inline VALUE cstr_to_str(const char *str)
33 {
34         if (str == NULL)
35                 return Qnil;
36         return rb_str_new2(str);
37 }
38
39 static inline char *str_to_cstr(VALUE str)
40 {
41         if (str == Qnil)
42                 return NULL;
43         return RSTRING_PTR(str);
44 }
45
46 static inline unsigned char *str_to_sha1(VALUE str)
47 {
48         return (unsigned char *)str_to_cstr(str);
49 }
50
51 static VALUE git_rb_setup_git_directory(VALUE self)
52 {
53         int nongit_ok;
54         const char *prefix;
55         prefix = setup_git_directory_gently(&nongit_ok);
56         return rb_ary_new3(2, cstr_to_str(prefix), INT2FIX(nongit_ok));
57 }
58
59 static int for_each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
60 {
61         VALUE r;
62         r = rb_yield_values(3, rb_str_new2(refname), sha1_to_str(sha1), INT2FIX(flags));
63         return r == Qfalse;
64 }
65
66 static VALUE git_rb_for_each_ref(void)
67 {
68         int r;
69         r = for_each_ref(for_each_ref_fn, NULL);
70         return INT2FIX(r);
71 }
72
73 static VALUE git_rb_dwim_ref(VALUE self, VALUE name)
74 {
75         unsigned char buf[20];
76         char *ref;
77         int r;
78
79         r = dwim_ref(RSTRING_PTR(name), RSTRING_LEN(name), buf, &ref);
80         return rb_ary_new3(3, sha1_to_str(buf), INT2NUM(r), cstr_to_str(ref));
81 }
82
83 static int git_config_fn(const char *var, const char *value, void *cb_data)
84 {
85         VALUE r;
86         r = rb_yield_values(2, rb_str_new2(var), rb_str_new2(value));
87         return r == Qfalse;
88 }
89
90 static VALUE git_rb_git_config(VALUE self)
91 {
92         int r;
93         r = git_config(git_config_fn, NULL);
94         return INT2FIX(r);
95 }
96
97 static VALUE git_rb_read_ref(VALUE self, VALUE refname)
98 {
99         unsigned char sha1[20];
100         if (read_ref(RSTRING_PTR(refname), sha1))
101                 return Qnil;
102         return sha1_to_str(sha1);
103 }
104
105 static VALUE git_rb_peel_ref(VALUE self, VALUE refname)
106 {
107         unsigned char sha1[20];
108         if (peel_ref(RSTRING_PTR(refname), sha1))
109                 return Qnil;
110         return sha1_to_str(sha1);
111 }
112
113 static VALUE git_rb_get_sha1(VALUE self, VALUE name)
114 {
115         unsigned char buf[20];
116         int r;
117         r = get_sha1(RSTRING_PTR(name), buf);
118         if (r)
119                 return Qnil;
120         return sha1_to_str(buf);
121 }
122
123 static VALUE git_rb_object_get(VALUE class, VALUE id)
124 {
125         struct object *object;
126         object = parse_object(str_to_sha1(id));
127         return Data_Wrap_Struct(git_rb_object, NULL, NULL, object);
128 }
129
130 static VALUE git_rb_commit_get(VALUE class, VALUE id)
131 {
132         struct object *object;
133         object = parse_object(str_to_sha1(id));
134         if (!object || object->type != OBJ_COMMIT)
135                 return Qnil;
136         return Data_Wrap_Struct(git_rb_commit, NULL, NULL, object);
137 }
138
139 static VALUE git_rb_object_sha1(VALUE self)
140 {
141         struct object *object;
142         Data_Get_Struct(self, struct object, object);
143         return sha1_to_str(object->sha1);
144 }
145
146 static VALUE git_rb_object_type(VALUE self)
147 {
148         struct object *object;
149         Data_Get_Struct(self, struct object, object);
150         return INT2FIX(object->type);
151 }
152
153 static VALUE git_rb_object_to_s(VALUE self)
154 {
155         struct object *object;
156         Data_Get_Struct(self, struct object, object);
157         return rb_str_new2(sha1_to_hex(object->sha1));
158 }
159
160 static VALUE git_rb_commit_buffer(VALUE self)
161 {
162         struct commit *commit;
163         Data_Get_Struct(self, struct commit, commit);
164         return cstr_to_str(commit->buffer);
165 }
166
167 static VALUE git_rb_commit_list_each(VALUE self)
168 {
169         struct commit_list *e, *list;
170         Data_Get_Struct(self, struct commit_list, list);
171
172         for (e = list; e; e = e->next) {
173                 VALUE c;
174                 c = Data_Wrap_Struct(git_rb_commit, NULL, NULL, e->item);
175                 rb_yield(c);
176         }
177
178         return self;
179 }
180
181 static VALUE git_rb_get_merge_bases(VALUE self, VALUE commits, VALUE cleanup)
182 {
183         struct commit *g_commits[RARRAY_LEN(commits)];
184         struct commit_list *result;
185         int i;
186
187         for (i = 0; i < RARRAY_LEN(commits); i++) {
188                 VALUE commit = RARRAY_PTR(commits)[i];
189                 Data_Get_Struct(commit, struct commit, g_commits[i]);
190         }
191         result = get_merge_bases_many(g_commits[0], RARRAY_LEN(commits) - 1, g_commits + 1, NUM2INT(cleanup));
192         if (!result)
193                 return Qnil;
194         return Data_Wrap_Struct(git_rb_commit_list, NULL, NULL, result);
195 }
196
197 static VALUE git_rb_remote_get(VALUE self, VALUE name)
198 {
199         struct remote *remote;
200         remote = remote_get(RSTRING_PTR(name));
201         if (!remote)
202                 return Qnil;
203         return Data_Wrap_Struct(git_rb_remote, NULL, NULL, remote);
204 }
205
206 static VALUE git_rb_remote_url(VALUE self)
207 {
208         struct remote *remote;
209         VALUE url;
210         int i;
211
212         Data_Get_Struct(self, struct remote, remote);
213         url = rb_ary_new2(remote->url_nr);
214         for (i = 0; i < remote->url_nr; i++)
215                 rb_ary_store(url, i, rb_str_new2(remote->url[i]));
216         return url;
217 }
218
219 static VALUE git_rb_transport_get(VALUE self, VALUE remote, VALUE url)
220 {
221         struct transport *transport;
222         struct remote *g_remote;
223         Data_Get_Struct(remote, struct remote, g_remote);
224         transport = transport_get(g_remote, str_to_cstr(url));
225         if (!transport)
226                 return Qnil;
227         return Data_Wrap_Struct(git_rb_transport, NULL, transport_disconnect, transport);
228 }
229
230 static VALUE git_rb_transport_get_remote_refs(VALUE self)
231 {
232         struct transport *transport;
233         const struct ref *ref;
234         Data_Get_Struct(self, struct transport, transport);
235         ref = transport_get_remote_refs(transport);
236         return Data_Wrap_Struct(git_rb_ref, NULL, NULL, (void *)ref);
237 }
238
239 static VALUE git_rb_ref_each(VALUE self)
240 {
241         struct ref *e, *ref;
242         Data_Get_Struct(self, struct ref, ref);
243
244         for (e = ref; e; e = e->next) {
245                 VALUE c;
246                 c = Data_Wrap_Struct(git_rb_ref, NULL, NULL, e);
247                 rb_yield(c);
248         }
249
250         return self;
251 }
252
253 static VALUE git_rb_ref_name(VALUE self)
254 {
255         struct ref *ref;
256         Data_Get_Struct(self, struct ref, ref);
257         return rb_str_new2(ref->name);
258 }
259
260 static VALUE git_rb_ref_old_sha1(VALUE self)
261 {
262         struct ref *ref;
263         Data_Get_Struct(self, struct ref, ref);
264         return sha1_to_str(ref->old_sha1);
265 }
266
267 static VALUE git_rb_find_unique_abbrev(VALUE self, VALUE sha1, VALUE len)
268 {
269         const char *abbrev;
270         abbrev = find_unique_abbrev(str_to_sha1(sha1), NUM2INT(len));
271         return rb_str_new2(abbrev);
272 }
273
274 static VALUE git_rb_read_sha1_file(VALUE self, VALUE sha1, VALUE type)
275 {
276         enum object_type g_type;
277         void *buffer;
278         unsigned long size;
279
280         buffer = read_sha1_file(str_to_sha1(sha1), &g_type, &size);
281         if (!buffer)
282                 return Qnil;
283         return rb_ary_new3(2, rb_str_new(buffer, size), INT2FIX(g_type));
284 }
285
286 static VALUE git_rb_rev_info_alloc(VALUE class)
287 {
288         struct rev_info *revs;
289         return Data_Make_Struct(class, struct rev_info, NULL, free, revs);
290 }
291
292 static VALUE git_rb_rev_info_init(VALUE self, VALUE prefix)
293 {
294         struct rev_info *revs;
295         Data_Get_Struct(self, struct rev_info, revs);
296         init_revisions(revs, str_to_cstr(prefix));
297         return self;
298 }
299
300 static VALUE git_rb_rev_info_setup(VALUE self, VALUE args, VALUE opts)
301 {
302         struct rev_info *revs;
303         const char *argv[RARRAY_LEN(args) + 2];
304         int i, r;
305
306         argv[0] = "";
307         Data_Get_Struct(self, struct rev_info, revs);
308         for (i = 0; i < RARRAY_LEN(args); i++)
309                 argv[i + 1] = RSTRING_PTR(RARRAY_PTR(args)[i]);
310         argv[i + 1] = NULL;
311         r = setup_revisions(RARRAY_LEN(args) + 1, argv, revs, NULL);
312         return INT2FIX(r - 1);
313 }
314
315 static VALUE git_rb_rev_info_single_setup(VALUE class, VALUE prefix, VALUE args, VALUE opts)
316 {
317         struct rev_info *revs;
318         VALUE self;
319         self = Data_Make_Struct(class, struct rev_info, NULL, free, revs);
320         init_revisions(revs, str_to_cstr(prefix));
321         git_rb_rev_info_setup(self, args, opts);
322         return self;
323 }
324
325 static VALUE git_rb_rev_info_each_revision(VALUE self, VALUE args, VALUE opts)
326 {
327         struct commit *commit;
328         struct rev_info *revs;
329
330         Data_Get_Struct(self, struct rev_info, revs);
331         if (prepare_revision_walk(revs))
332                 return Qnil;
333         while ((commit = get_revision(revs))) {
334                 VALUE c;
335                 c = Data_Wrap_Struct(git_rb_commit, NULL, NULL, commit);
336                 rb_yield(c);
337         }
338         return Qnil;
339 }
340
341 static VALUE git_rb_rev_info_diffopt(VALUE self)
342 {
343         struct rev_info *revs;
344
345         Data_Get_Struct(self, struct rev_info, revs);
346         return Data_Wrap_Struct(git_rb_diff_opt, NULL, NULL, &revs->diffopt);
347 }
348
349 static VALUE git_rb_shortlog(VALUE self, VALUE commits)
350 {
351         struct shortlog log;
352         int i;
353
354         shortlog_init(&log);
355         for (i = 0; i < RARRAY_LEN(commits); i++) {
356                 struct commit *commit;
357                 Data_Get_Struct(rb_ary_entry(commits, i), struct commit, commit);
358                 shortlog_add_commit(&log, commit);
359         }
360         shortlog_output(&log);
361         return Qnil;
362 }
363
364 static VALUE git_rb_diff_tree_sha1(VALUE self, VALUE old, VALUE new, VALUE base, VALUE opt)
365 {
366         struct diff_options *g_opt;
367         int r;
368
369         Data_Get_Struct(opt, struct diff_options, g_opt);
370
371         r = diff_tree_sha1(str_to_sha1(old), str_to_sha1(new), str_to_cstr(base), g_opt);
372         return INT2FIX(r);
373 }
374
375 static VALUE git_rb_log_tree_diff_flush(VALUE self, VALUE revs)
376 {
377         struct rev_info *g_revs;
378         int r;
379
380         Data_Get_Struct(revs, struct rev_info, g_revs);
381         r = log_tree_diff_flush(g_revs);
382         return INT2FIX(r);
383 }
384
385 static VALUE git_rb_diff_opt_new(VALUE class)
386 {
387         struct diff_options *opt;
388         VALUE self;
389         self = Data_Make_Struct(class, struct diff_options, NULL, free, opt);
390
391         diff_setup(opt);
392
393         return self;
394 }
395
396 static VALUE git_rb_diff_opt_method_missing(int argc, VALUE *argv, VALUE self)
397 {
398         struct diff_options *opt;
399         ID id;
400
401         id = rb_to_id(argv[0]);
402         Data_Get_Struct(self, struct diff_options, opt);
403
404         if (id == rb_intern("stat_width="))
405                 opt->stat_width = NUM2INT(argv[1]);
406         else if (id == rb_intern("stat_graph_width="))
407                 opt->stat_graph_width = NUM2INT(argv[1]);
408         else if (id == rb_intern("output_format="))
409                 opt->output_format = NUM2INT(argv[1]);
410         else if (id == rb_intern("detect_rename="))
411                 opt->detect_rename = NUM2INT(argv[1]);
412         else if (id == rb_intern("flags="))
413                 opt->flags = NUM2INT(argv[1]);
414         else if (id == rb_intern("output_format"))
415                 return INT2FIX(opt->output_format);
416         else if (id == rb_intern("flags"))
417                 return INT2FIX(opt->flags);
418         else
419                 return rb_call_super(argc, argv);
420         return Qnil;
421 }
422
423 static void git_ruby_init(void)
424 {
425         VALUE mod;
426
427         mod = rb_define_module("Git");
428
429         rb_define_global_const("OBJ_BAD", INT2FIX(OBJ_BAD));
430         rb_define_global_const("OBJ_NONE", INT2FIX(OBJ_NONE));
431         rb_define_global_const("OBJ_COMMIT", INT2FIX(OBJ_COMMIT));
432         rb_define_global_const("OBJ_TREE", INT2FIX(OBJ_TREE));
433         rb_define_global_const("OBJ_BLOB", INT2FIX(OBJ_BLOB));
434         rb_define_global_const("OBJ_TAG", INT2FIX(OBJ_TAG));
435         rb_define_global_const("OBJ_OFS_DELTA", INT2FIX(OBJ_OFS_DELTA));
436         rb_define_global_const("OBJ_REF_DELTA", INT2FIX(OBJ_REF_DELTA));
437         rb_define_global_const("OBJ_ANY", INT2FIX(OBJ_ANY));
438         rb_define_global_const("OBJ_MAX", INT2FIX(OBJ_MAX));
439
440         rb_define_global_const("DEFAULT_ABBREV", INT2FIX(DEFAULT_ABBREV));
441
442         rb_define_global_const("DIFF_FORMAT_RAW", INT2FIX(DIFF_FORMAT_RAW));
443         rb_define_global_const("DIFF_FORMAT_DIFFSTAT", INT2FIX(DIFF_FORMAT_DIFFSTAT));
444         rb_define_global_const("DIFF_FORMAT_NUMSTAT", INT2FIX(DIFF_FORMAT_NUMSTAT));
445         rb_define_global_const("DIFF_FORMAT_SUMMARY", INT2FIX(DIFF_FORMAT_SUMMARY));
446         rb_define_global_const("DIFF_FORMAT_PATCH", INT2FIX(DIFF_FORMAT_PATCH));
447         rb_define_global_const("DIFF_FORMAT_SHORTSTAT", INT2FIX(DIFF_FORMAT_SHORTSTAT));
448         rb_define_global_const("DIFF_FORMAT_DIRSTAT", INT2FIX(DIFF_FORMAT_DIRSTAT));
449         rb_define_global_const("DIFF_FORMAT_NAME", INT2FIX(DIFF_FORMAT_NAME));
450         rb_define_global_const("DIFF_FORMAT_NAME_STATUS", INT2FIX(DIFF_FORMAT_NAME_STATUS));
451         rb_define_global_const("DIFF_FORMAT_CHECKDIFF", INT2FIX(DIFF_FORMAT_CHECKDIFF));
452         rb_define_global_const("DIFF_FORMAT_NO_OUTPUT", INT2FIX(DIFF_FORMAT_NO_OUTPUT));
453         rb_define_global_const("DIFF_FORMAT_CALLBACK", INT2FIX(DIFF_FORMAT_CALLBACK));
454
455         rb_define_global_const("DIFF_DETECT_RENAME", INT2FIX(DIFF_DETECT_RENAME));
456         rb_define_global_const("DIFF_DETECT_COPY", INT2FIX(DIFF_DETECT_COPY));
457
458         rb_define_global_const("DIFF_OPT_RECURSIVE", INT2FIX(DIFF_OPT_RECURSIVE));
459         rb_define_global_const("DIFF_OPT_TREE_IN_RECURSIVE", INT2FIX(DIFF_OPT_TREE_IN_RECURSIVE));
460         rb_define_global_const("DIFF_OPT_BINARY", INT2FIX(DIFF_OPT_BINARY));
461         rb_define_global_const("DIFF_OPT_TEXT", INT2FIX(DIFF_OPT_TEXT));
462         rb_define_global_const("DIFF_OPT_FULL_INDEX", INT2FIX(DIFF_OPT_FULL_INDEX));
463         rb_define_global_const("DIFF_OPT_SILENT_ON_REMOVE", INT2FIX(DIFF_OPT_SILENT_ON_REMOVE));
464         rb_define_global_const("DIFF_OPT_FIND_COPIES_HARDER", INT2FIX(DIFF_OPT_FIND_COPIES_HARDER));
465         rb_define_global_const("DIFF_OPT_FOLLOW_RENAMES", INT2FIX(DIFF_OPT_FOLLOW_RENAMES));
466         rb_define_global_const("DIFF_OPT_RENAME_EMPTY", INT2FIX(DIFF_OPT_RENAME_EMPTY));
467         rb_define_global_const("DIFF_OPT_HAS_CHANGES", INT2FIX(DIFF_OPT_HAS_CHANGES));
468         rb_define_global_const("DIFF_OPT_QUICK", INT2FIX(DIFF_OPT_QUICK));
469         rb_define_global_const("DIFF_OPT_NO_INDEX", INT2FIX(DIFF_OPT_NO_INDEX));
470         rb_define_global_const("DIFF_OPT_ALLOW_EXTERNAL", INT2FIX(DIFF_OPT_ALLOW_EXTERNAL));
471         rb_define_global_const("DIFF_OPT_EXIT_WITH_STATUS", INT2FIX(DIFF_OPT_EXIT_WITH_STATUS));
472         rb_define_global_const("DIFF_OPT_REVERSE_DIFF", INT2FIX(DIFF_OPT_REVERSE_DIFF));
473         rb_define_global_const("DIFF_OPT_CHECK_FAILED", INT2FIX(DIFF_OPT_CHECK_FAILED));
474         rb_define_global_const("DIFF_OPT_RELATIVE_NAME", INT2FIX(DIFF_OPT_RELATIVE_NAME));
475         rb_define_global_const("DIFF_OPT_IGNORE_SUBMODULES", INT2FIX(DIFF_OPT_IGNORE_SUBMODULES));
476         rb_define_global_const("DIFF_OPT_DIRSTAT_CUMULATIVE", INT2FIX(DIFF_OPT_DIRSTAT_CUMULATIVE));
477         rb_define_global_const("DIFF_OPT_DIRSTAT_BY_FILE", INT2FIX(DIFF_OPT_DIRSTAT_BY_FILE));
478         rb_define_global_const("DIFF_OPT_ALLOW_TEXTCONV", INT2FIX(DIFF_OPT_ALLOW_TEXTCONV));
479         rb_define_global_const("DIFF_OPT_DIFF_FROM_CONTENTS", INT2FIX(DIFF_OPT_DIFF_FROM_CONTENTS));
480         rb_define_global_const("DIFF_OPT_SUBMODULE_LOG", INT2FIX(DIFF_OPT_SUBMODULE_LOG));
481         rb_define_global_const("DIFF_OPT_DIRTY_SUBMODULES", INT2FIX(DIFF_OPT_DIRTY_SUBMODULES));
482         rb_define_global_const("DIFF_OPT_IGNORE_UNTRACKED_IN_SUBMODULES", INT2FIX(DIFF_OPT_IGNORE_UNTRACKED_IN_SUBMODULES));
483         rb_define_global_const("DIFF_OPT_IGNORE_DIRTY_SUBMODULES", INT2FIX(DIFF_OPT_IGNORE_DIRTY_SUBMODULES));
484         rb_define_global_const("DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG", INT2FIX(DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG));
485         rb_define_global_const("DIFF_OPT_DIRSTAT_BY_LINE", INT2FIX(DIFF_OPT_DIRSTAT_BY_LINE));
486         rb_define_global_const("DIFF_OPT_FUNCCONTEXT", INT2FIX(DIFF_OPT_FUNCCONTEXT));
487         rb_define_global_const("DIFF_OPT_PICKAXE_IGNORE_CASE", INT2FIX(DIFF_OPT_PICKAXE_IGNORE_CASE));
488
489         rb_define_global_function("setup_git_directory", git_rb_setup_git_directory, 0);
490         rb_define_global_function("for_each_ref", git_rb_for_each_ref, 0);
491         rb_define_global_function("dwim_ref", git_rb_dwim_ref, 1);
492         rb_define_global_function("git_config", git_rb_git_config, 0);
493         rb_define_global_function("read_ref", git_rb_read_ref, 1);
494         rb_define_global_function("peel_ref", git_rb_peel_ref, 1);
495         rb_define_global_function("get_sha1", git_rb_get_sha1, 1);
496         rb_define_global_function("get_merge_bases", git_rb_get_merge_bases, 2);
497         rb_define_global_function("remote_get", git_rb_remote_get, 1);
498         rb_define_global_function("transport_get", git_rb_transport_get, 2);
499         rb_define_global_function("find_unique_abbrev", git_rb_find_unique_abbrev, 2);
500         rb_define_global_function("read_sha1_file", git_rb_read_sha1_file, 1);
501         rb_define_global_function("shortlog", git_rb_shortlog, 1);
502         rb_define_global_function("diff_tree_sha1", git_rb_diff_tree_sha1, 4);
503         rb_define_global_function("log_tree_diff_flush", git_rb_log_tree_diff_flush, 1);
504
505         git_rb_object = rb_define_class_under(mod, "Object", rb_cData);
506         rb_define_singleton_method(git_rb_object, "get", git_rb_object_get, 1);
507         rb_define_method(git_rb_object, "sha1", git_rb_object_sha1, 0);
508         rb_define_method(git_rb_object, "type", git_rb_object_type, 0);
509         rb_define_method(git_rb_object, "to_s", git_rb_object_to_s, 0);
510
511         git_rb_commit = rb_define_class_under(mod, "Commit", git_rb_object);
512         rb_define_singleton_method(git_rb_commit, "get", git_rb_commit_get, 1);
513         rb_define_method(git_rb_commit, "buffer", git_rb_commit_buffer, 0);
514
515         git_rb_commit_list = rb_define_class_under(mod, "CommitList", rb_cData);
516         rb_include_module(git_rb_commit_list, rb_mEnumerable);
517         rb_define_method(git_rb_commit_list, "each", git_rb_commit_list_each, 0);
518
519         git_rb_remote = rb_define_class_under(mod, "Remote", rb_cData);
520         rb_define_method(git_rb_remote, "url", git_rb_remote_url, 0);
521
522         git_rb_transport = rb_define_class_under(mod, "Transport", rb_cData);
523         rb_define_method(git_rb_transport, "get_remote_refs", git_rb_transport_get_remote_refs, 0);
524
525         git_rb_ref = rb_define_class_under(mod, "Ref", rb_cData);
526         rb_include_module(git_rb_ref, rb_mEnumerable);
527         rb_define_method(git_rb_ref, "each", git_rb_ref_each, 0);
528         rb_define_method(git_rb_ref, "name", git_rb_ref_name, 0);
529         rb_define_method(git_rb_ref, "old_sha1", git_rb_ref_old_sha1, 0);
530
531         git_rb_rev_info = rb_define_class_under(mod, "RevInfo", rb_cData);
532         rb_include_module(git_rb_rev_info, rb_mEnumerable);
533         rb_define_alloc_func(git_rb_rev_info, git_rb_rev_info_alloc);
534         rb_define_method(git_rb_rev_info, "initialize", git_rb_rev_info_init, 1);
535         rb_define_singleton_method(git_rb_rev_info, "setup", git_rb_rev_info_single_setup, 3);
536         rb_define_method(git_rb_rev_info, "setup", git_rb_rev_info_setup, 2);
537         rb_define_method(git_rb_rev_info, "each", git_rb_rev_info_each_revision, 0);
538         rb_define_method(git_rb_rev_info, "diffopt", git_rb_rev_info_diffopt, 0);
539
540         git_rb_diff_opt = rb_define_class_under(mod, "DiffOptions", rb_cData);
541         rb_define_singleton_method(git_rb_diff_opt, "new", git_rb_diff_opt_new, 0);
542         rb_define_method(git_rb_diff_opt, "method_missing", git_rb_diff_opt_method_missing, -1);
543 }
544
545 static int run_ruby_command(const char *cmd, int argc, const char **argv)
546 {
547         static char buf[PATH_MAX + 1];
548         void *node;
549         struct stat st;
550
551         ruby_init();
552         git_ruby_init();
553
554         node = ruby_options(argc, (char **)argv);
555
556         ruby_script(cmd);
557         snprintf(buf, PATH_MAX, "%s/%s", git_exec_path(), "git-rb-setup.rb");
558         if (!stat(buf, &st))
559                 rb_load(rb_str_new2(buf), 0);
560
561         return ruby_run_node(node);
562 }
563
564 int main(int argc, const char **argv)
565 {
566         if (!strcmp(argv[0], "git-ruby")) {
567                 return run_ruby_command(argv[1], argc, argv);
568         } else {
569                 const char *cmd = argv[0];
570                 static char buf[PATH_MAX + 1];
571                 const char *args[argc + 1];
572                 int i;
573
574                 snprintf(buf, PATH_MAX, "%s/%s.rb",
575                                 git_exec_path(), basename((char *)cmd));
576
577                 args[0] = "git";
578                 args[1] = buf;
579                 for (i = 0; i < argc - 1; i++)
580                         args[i + 2] = (char *)argv[i + 1];
581
582                 return run_ruby_command(cmd, argc + 1, args);
583         }
584 }