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;
27 static inline VALUE sha1_to_str(const unsigned char *sha1)
29 return rb_str_new((const char *)sha1, 20);
32 static inline VALUE cstr_to_str(const char *str)
36 return rb_str_new2(str);
39 static inline char *str_to_cstr(VALUE str)
43 return RSTRING_PTR(str);
46 static inline unsigned char *str_to_sha1(VALUE str)
48 return (unsigned char *)str_to_cstr(str);
51 static VALUE git_rb_setup_git_directory(VALUE self)
55 prefix = setup_git_directory_gently(&nongit_ok);
56 return rb_ary_new3(2, cstr_to_str(prefix), INT2FIX(nongit_ok));
59 static int for_each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
62 r = rb_yield_values(3, rb_str_new2(refname), sha1_to_str(sha1), INT2FIX(flags));
66 static VALUE git_rb_for_each_ref(void)
69 r = for_each_ref(for_each_ref_fn, NULL);
73 static VALUE git_rb_dwim_ref(VALUE self, VALUE name)
75 unsigned char buf[20];
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));
83 static int git_config_fn(const char *var, const char *value, void *cb_data)
86 r = rb_yield_values(2, rb_str_new2(var), rb_str_new2(value));
90 static VALUE git_rb_git_config(VALUE self)
93 r = git_config(git_config_fn, NULL);
97 static VALUE git_rb_read_ref(VALUE self, VALUE refname)
99 unsigned char sha1[20];
100 if (read_ref(RSTRING_PTR(refname), sha1))
102 return sha1_to_str(sha1);
105 static VALUE git_rb_peel_ref(VALUE self, VALUE refname)
107 unsigned char sha1[20];
108 if (peel_ref(RSTRING_PTR(refname), sha1))
110 return sha1_to_str(sha1);
113 static VALUE git_rb_get_sha1(VALUE self, VALUE name)
115 unsigned char buf[20];
117 r = get_sha1(RSTRING_PTR(name), buf);
120 return sha1_to_str(buf);
123 static VALUE git_rb_object_get(VALUE class, VALUE id)
125 struct object *object;
126 object = parse_object(str_to_sha1(id));
127 return Data_Wrap_Struct(git_rb_object, NULL, NULL, object);
130 static VALUE git_rb_commit_get(VALUE class, VALUE id)
132 struct object *object;
133 object = parse_object(str_to_sha1(id));
134 if (!object || object->type != OBJ_COMMIT)
136 return Data_Wrap_Struct(git_rb_commit, NULL, NULL, object);
139 static VALUE git_rb_object_sha1(VALUE self)
141 struct object *object;
142 Data_Get_Struct(self, struct object, object);
143 return sha1_to_str(object->sha1);
146 static VALUE git_rb_object_type(VALUE self)
148 struct object *object;
149 Data_Get_Struct(self, struct object, object);
150 return INT2FIX(object->type);
153 static VALUE git_rb_object_to_s(VALUE self)
155 struct object *object;
156 Data_Get_Struct(self, struct object, object);
157 return rb_str_new2(sha1_to_hex(object->sha1));
160 static VALUE git_rb_commit_buffer(VALUE self)
162 struct commit *commit;
163 Data_Get_Struct(self, struct commit, commit);
164 return cstr_to_str(commit->buffer);
167 static VALUE git_rb_commit_list_each(VALUE self)
169 struct commit_list *e, *list;
170 Data_Get_Struct(self, struct commit_list, list);
172 for (e = list; e; e = e->next) {
174 c = Data_Wrap_Struct(git_rb_commit, NULL, NULL, e->item);
181 static VALUE git_rb_get_merge_bases(VALUE self, VALUE commits, VALUE cleanup)
183 struct commit *g_commits[RARRAY_LEN(commits)];
184 struct commit_list *result;
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]);
191 result = get_merge_bases_many(g_commits[0], RARRAY_LEN(commits) - 1, g_commits + 1, NUM2INT(cleanup));
194 return Data_Wrap_Struct(git_rb_commit_list, NULL, NULL, result);
197 static VALUE git_rb_remote_get(VALUE self, VALUE name)
199 struct remote *remote;
200 remote = remote_get(RSTRING_PTR(name));
203 return Data_Wrap_Struct(git_rb_remote, NULL, NULL, remote);
206 static VALUE git_rb_remote_url(VALUE self)
208 struct remote *remote;
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]));
219 static VALUE git_rb_transport_get(VALUE self, VALUE remote, VALUE url)
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));
227 return Data_Wrap_Struct(git_rb_transport, NULL, transport_disconnect, transport);
230 static VALUE git_rb_transport_get_remote_refs(VALUE self)
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);
239 static VALUE git_rb_ref_each(VALUE self)
242 Data_Get_Struct(self, struct ref, ref);
244 for (e = ref; e; e = e->next) {
246 c = Data_Wrap_Struct(git_rb_ref, NULL, NULL, e);
253 static VALUE git_rb_ref_name(VALUE self)
256 Data_Get_Struct(self, struct ref, ref);
257 return rb_str_new2(ref->name);
260 static VALUE git_rb_ref_old_sha1(VALUE self)
263 Data_Get_Struct(self, struct ref, ref);
264 return sha1_to_str(ref->old_sha1);
267 static VALUE git_rb_find_unique_abbrev(VALUE self, VALUE sha1, VALUE len)
270 abbrev = find_unique_abbrev(str_to_sha1(sha1), NUM2INT(len));
271 return rb_str_new2(abbrev);
274 static VALUE git_rb_read_sha1_file(VALUE self, VALUE sha1, VALUE type)
276 enum object_type g_type;
280 buffer = read_sha1_file(str_to_sha1(sha1), &g_type, &size);
283 return rb_ary_new3(2, rb_str_new(buffer, size), INT2FIX(g_type));
286 static VALUE git_rb_rev_info_alloc(VALUE class)
288 struct rev_info *revs;
289 return Data_Make_Struct(class, struct rev_info, NULL, free, revs);
292 static VALUE git_rb_rev_info_init(VALUE self, VALUE prefix)
294 struct rev_info *revs;
295 Data_Get_Struct(self, struct rev_info, revs);
296 init_revisions(revs, str_to_cstr(prefix));
300 static VALUE git_rb_rev_info_setup(VALUE self, VALUE args, VALUE opts)
302 struct rev_info *revs;
303 const char *argv[RARRAY_LEN(args) + 2];
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]);
311 r = setup_revisions(RARRAY_LEN(args) + 1, argv, revs, NULL);
312 return INT2FIX(r - 1);
315 static VALUE git_rb_rev_info_single_setup(VALUE class, VALUE prefix, VALUE args, VALUE opts)
317 struct rev_info *revs;
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);
325 static VALUE git_rb_rev_info_each_revision(VALUE self, VALUE args, VALUE opts)
327 struct commit *commit;
328 struct rev_info *revs;
330 Data_Get_Struct(self, struct rev_info, revs);
331 if (prepare_revision_walk(revs))
333 while ((commit = get_revision(revs))) {
335 c = Data_Wrap_Struct(git_rb_commit, NULL, NULL, commit);
341 static VALUE git_rb_rev_info_diffopt(VALUE self)
343 struct rev_info *revs;
345 Data_Get_Struct(self, struct rev_info, revs);
346 return Data_Wrap_Struct(git_rb_diff_opt, NULL, NULL, &revs->diffopt);
349 static VALUE git_rb_shortlog(VALUE self, VALUE commits)
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);
360 shortlog_output(&log);
364 static VALUE git_rb_diff_tree_sha1(VALUE self, VALUE old, VALUE new, VALUE base, VALUE opt)
366 struct diff_options *g_opt;
369 Data_Get_Struct(opt, struct diff_options, g_opt);
371 r = diff_tree_sha1(str_to_sha1(old), str_to_sha1(new), str_to_cstr(base), g_opt);
375 static VALUE git_rb_log_tree_diff_flush(VALUE self, VALUE revs)
377 struct rev_info *g_revs;
380 Data_Get_Struct(revs, struct rev_info, g_revs);
381 r = log_tree_diff_flush(g_revs);
385 static VALUE git_rb_diff_opt_new(VALUE class)
387 struct diff_options *opt;
389 self = Data_Make_Struct(class, struct diff_options, NULL, free, opt);
396 static VALUE git_rb_diff_opt_method_missing(int argc, VALUE *argv, VALUE self)
398 struct diff_options *opt;
401 id = rb_to_id(argv[0]);
402 Data_Get_Struct(self, struct diff_options, opt);
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);
419 return rb_call_super(argc, argv);
423 static void git_ruby_init(void)
427 mod = rb_define_module("Git");
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));
440 rb_define_global_const("DEFAULT_ABBREV", INT2FIX(DEFAULT_ABBREV));
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));
455 rb_define_global_const("DIFF_DETECT_RENAME", INT2FIX(DIFF_DETECT_RENAME));
456 rb_define_global_const("DIFF_DETECT_COPY", INT2FIX(DIFF_DETECT_COPY));
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));
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);
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);
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);
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);
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);
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);
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);
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);
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);
545 static int run_ruby_command(const char *cmd, int argc, const char **argv)
547 static char buf[PATH_MAX + 1];
554 node = ruby_options(argc, (char **)argv);
557 snprintf(buf, PATH_MAX, "%s/%s", git_exec_path(), "git-rb-setup.rb");
559 rb_load(rb_str_new2(buf), 0);
561 return ruby_run_node(node);
564 int main(int argc, const char **argv)
566 if (!strcmp(argv[0], "git-ruby")) {
567 return run_ruby_command(argv[1], argc, argv);
569 const char *cmd = argv[0];
570 static char buf[PATH_MAX + 1];
571 const char *args[argc + 1];
574 snprintf(buf, PATH_MAX, "%s/%s.rb",
575 git_exec_path(), basename((char *)cmd));
579 for (i = 0; i < argc - 1; i++)
580 args[i + 2] = (char *)argv[i + 1];
582 return run_ruby_command(cmd, argc + 1, args);