static VALUE rb_git_treebuilder_insert(VALUE self, VALUE rb_entry) { git_treebuilder *builder; VALUE rb_path, rb_oid, rb_attr; git_oid oid; int error; Data_Get_Struct(self, git_treebuilder, builder); Check_Type(rb_entry, T_HASH); rb_path = rb_hash_aref(rb_entry, CSTR2SYM("name")); Check_Type(rb_path, T_STRING); rb_oid = rb_hash_aref(rb_entry, CSTR2SYM("oid")); Check_Type(rb_oid, T_STRING); rugged_exception_check(git_oid_fromstr(&oid, StringValueCStr(rb_oid))); rb_attr = rb_hash_aref(rb_entry, CSTR2SYM("filemode")); Check_Type(rb_attr, T_FIXNUM); error = git_treebuilder_insert(NULL, builder, StringValueCStr(rb_path), &oid, FIX2INT(rb_attr)); rugged_exception_check(error); return Qnil; }
static void rndr_tablecell(struct buf *ob, const struct buf *text, int align, void *opaque) { VALUE rb_align; switch (align) { case MKD_TABLE_ALIGN_L: rb_align = CSTR2SYM("left"); break; case MKD_TABLE_ALIGN_R: rb_align = CSTR2SYM("right"); break; case MKD_TABLE_ALIGN_CENTER: rb_align = CSTR2SYM("center"); break; default: rb_align = Qnil; break; } BLOCK_CALLBACK("table_cell", 2, buf2str(text), rb_align); }
/* * call-seq: * index.conflict_add(conflict) -> nil * * Add or update index entries that represent a conflict. * * +conflict+ has to be a hash containing +:ancestor+, +:ours+ and * +:theirs+ key/value pairs. Any of those paris can be +nil+ (or left out) * to indicate that the file was not present in the respective tree during * the merge. */ static VALUE rb_git_conflict_add(VALUE self, VALUE rb_conflict) { VALUE rb_ancestor, rb_ours, rb_theirs; git_index *index; git_index_entry ancestor, ours, theirs; int error; Check_Type(rb_conflict, T_HASH); rb_ancestor = rb_hash_aref(rb_conflict, CSTR2SYM("ancestor")); rb_ours = rb_hash_aref(rb_conflict, CSTR2SYM("ours")); rb_theirs = rb_hash_aref(rb_conflict, CSTR2SYM("theirs")); if (!NIL_P(rb_ancestor)) rb_git_indexentry_toC(&ancestor, rb_ancestor); if (!NIL_P(rb_ours)) rb_git_indexentry_toC(&ours, rb_ours); if (!NIL_P(rb_theirs)) rb_git_indexentry_toC(&theirs, rb_theirs); Data_Get_Struct(self, git_index, index); error = git_index_conflict_add(index, NIL_P(rb_ancestor) ? NULL : &ancestor, NIL_P(rb_theirs) ? NULL : &ours, NIL_P(rb_ours) ? NULL : &theirs); rugged_exception_check(error); return Qnil; }
VALUE rugged_signature_new(const git_signature *sig, const char *encoding_name) { VALUE rb_sig, rb_time; rb_encoding *encoding = rb_utf8_encoding(); if (encoding_name != NULL) encoding = rb_enc_find(encoding_name); rb_sig = rb_hash_new(); /* Allocate the time with a the given timezone */ rb_time = rb_funcall( rb_time_new(sig->when.time, 0), rb_intern("getlocal"), 1, INT2FIX(sig->when.offset * 60) ); rb_hash_aset(rb_sig, CSTR2SYM("name"), rb_enc_str_new(sig->name, strlen(sig->name), encoding)); rb_hash_aset(rb_sig, CSTR2SYM("email"), rb_enc_str_new(sig->email, strlen(sig->email), encoding)); rb_hash_aset(rb_sig, CSTR2SYM("time"), rb_time); return rb_sig; }
/* * call-seq: * index.conflicts -> conflicts * * Return all conflicts in +index+. * * Each conflict is represented as a Hash with +:ancestor+, +:ours+ or * +:theirs+ key-value pairs, each containing index entry data. * * If the value of the +:ancestor+, +:ours+ or +:theirs+ key is +nil+, * that indicates that file in conflict did not exists in the respective tree. */ static VALUE rb_git_index_conflicts(VALUE self) { VALUE rb_conflicts = rb_ary_new(); git_index *index; git_index_conflict_iterator *iter; const git_index_entry *ancestor, *ours, *theirs; int error; Data_Get_Struct(self, git_index, index); error = git_index_conflict_iterator_new(&iter, index); rugged_exception_check(error); while ((error = git_index_conflict_next(&ancestor, &ours, &theirs, iter)) == GIT_OK) { VALUE rb_conflict = rb_hash_new(); rb_hash_aset(rb_conflict, CSTR2SYM("ancestor"), rb_git_indexentry_fromC(ancestor)); rb_hash_aset(rb_conflict, CSTR2SYM("ours"), rb_git_indexentry_fromC(ours)); rb_hash_aset(rb_conflict, CSTR2SYM("theirs"), rb_git_indexentry_fromC(theirs)); rb_ary_push(rb_conflicts, rb_conflict); } git_index_conflict_iterator_free(iter); if (error != GIT_ITEROVER) rugged_exception_check(error); return rb_conflicts; }
/* * call-seq: * Rebase.next() -> operation or nil * * Perform the next step in the rebase. The returned operation is a * Hash with its details or nil if there are no more operations to * perform. The Hash contains some of the following entries: * * :type :: * The type of operation being done. Can be one of +:pick+, * +:reword+, +:edit+, +:squash+, +:fixup+ or +:exec+. * * :id :: * The id of the commit being cherry-picked. Exists for all but * +:exec+ operations. * * :exec :: * If the operatin is +:exec+ this is what the user asked to be * executed. */ static VALUE rb_git_rebase_next(VALUE self) { int error; git_rebase *rebase; git_rebase_operation *operation; VALUE hash, val; Data_Get_Struct(self, git_rebase, rebase); error = git_rebase_next(&operation, rebase); if (error == GIT_ITEROVER) return Qnil; rugged_exception_check(error); /* Create the operation hash out of the relevant details */ hash = rb_hash_new(); val = rebase_operation_type(operation); rb_hash_aset(hash, CSTR2SYM("type"), val); if (operation->type != GIT_REBASE_OPERATION_EXEC) { val = rugged_create_oid(&operation->id); rb_hash_aset(hash, CSTR2SYM("id"), val); } if (operation->exec) { val = rb_str_new_utf8(operation->exec); rb_hash_aset(hash, CSTR2SYM("exec"), val); } return hash; }
static VALUE rb_git_delta_status_fromC(git_delta_t status) { switch(status) { case GIT_DELTA_UNMODIFIED: return CSTR2SYM("unmodified"); case GIT_DELTA_ADDED: return CSTR2SYM("added"); case GIT_DELTA_DELETED: return CSTR2SYM("deleted"); case GIT_DELTA_MODIFIED: return CSTR2SYM("modified"); case GIT_DELTA_RENAMED: return CSTR2SYM("renamed"); case GIT_DELTA_COPIED: return CSTR2SYM("copied"); case GIT_DELTA_IGNORED: return CSTR2SYM("ignored"); case GIT_DELTA_UNTRACKED: return CSTR2SYM("untracked"); case GIT_DELTA_TYPECHANGE: return CSTR2SYM("typechange"); default: return CSTR2SYM("unknown"); } }
git_signature *rugged_signature_get(VALUE rb_sig) { int error; VALUE rb_time, rb_unix_t, rb_offset, rb_name, rb_email; git_signature *sig; Check_Type(rb_sig, T_HASH); rb_name = rb_hash_aref(rb_sig, CSTR2SYM("name")); rb_email = rb_hash_aref(rb_sig, CSTR2SYM("email")); rb_time = rb_hash_aref(rb_sig, CSTR2SYM("time")); Check_Type(rb_name, T_STRING); Check_Type(rb_email, T_STRING); if (!rb_obj_is_kind_of(rb_time, rb_cTime)) rb_raise(rb_eTypeError, "expected Time object"); rb_unix_t = rb_funcall(rb_time, rb_intern("tv_sec"), 0); rb_offset = rb_funcall(rb_time, rb_intern("utc_offset"), 0); error = git_signature_new(&sig, StringValueCStr(rb_name), StringValueCStr(rb_email), NUM2LONG(rb_unix_t), FIX2INT(rb_offset) / 60); rugged_exception_check(error); return sig; }
static VALUE rb_redcarpet_htmltoc_init(int argc, VALUE *argv, VALUE self) { struct rb_redcarpet_rndr *rndr; unsigned int render_flags = HTML_TOC; VALUE hash, nesting_level = Qnil; Data_Get_Struct(self, struct rb_redcarpet_rndr, rndr); if (rb_scan_args(argc, argv, "01", &hash) == 1) { Check_Type(hash, T_HASH); /* escape_html */ if (rb_hash_aref(hash, CSTR2SYM("escape_html")) == Qtrue) render_flags |= HTML_ESCAPE; /* Nesting level */ nesting_level = rb_hash_aref(hash, CSTR2SYM("nesting_level")); } sdhtml_toc_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html, render_flags); rb_redcarpet__overload(self, rb_cRenderHTML_TOC); if (!(NIL_P(nesting_level))) rndr->options.html.toc_data.nesting_level = NUM2INT(nesting_level); else rndr->options.html.toc_data.nesting_level = 6; return Qnil; }
static VALUE reflog_entry_new(const git_reflog_entry *entry) { VALUE rb_entry = rb_hash_new(); const char *message; rb_hash_aset(rb_entry, CSTR2SYM("id_old"), rugged_create_oid(git_reflog_entry_id_old(entry)) ); rb_hash_aset(rb_entry, CSTR2SYM("id_new"), rugged_create_oid(git_reflog_entry_id_new(entry)) ); rb_hash_aset(rb_entry, CSTR2SYM("committer"), rugged_signature_new(git_reflog_entry_committer(entry), NULL) ); if ((message = git_reflog_entry_message(entry)) != NULL) { rb_hash_aset(rb_entry, CSTR2SYM("message"), rb_str_new_utf8(message)); } return rb_entry; }
/* * call-seq: * patch.bytesize(options = {}) -> int * * The following options can be passed in the +options+ Hash: * * :exclude_context :: * Boolean value specifying that context lines should be excluded when * counting the number of bytes in the patch. * * :exclude_hunk_headers :: * Boolean value specifying that hunk headers should be excluded when * counting the number of bytes in the patch. * * :exclude_file_headers :: * Boolean value specifying that file headers should be excluded when * counting the number of bytes in the patch. * * Returns the number of bytes in the patch, depending on which options are * specified. */ static VALUE rb_git_diff_patch_bytesize(int argc, VALUE *argv, VALUE self) { git_patch *patch; size_t bytesize; VALUE rb_options; int include_context, include_hunk_headers, include_file_headers; Data_Get_Struct(self, git_patch, patch); include_context = include_hunk_headers = include_file_headers = 1; rb_scan_args(argc, argv, "0:", &rb_options); if (!NIL_P(rb_options)) { if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_context")))) { include_context = 0; } if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_hunk_headers")))) { include_hunk_headers = 0; } if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_file_headers")))) { include_file_headers = 0; } } bytesize = git_patch_size(patch, include_context, include_hunk_headers, include_file_headers); return INT2FIX(bytesize); }
/* * call-seq: * commit.to_mbox(options = {}) -> str * * Returns +commit+'s contents formatted to resemble UNIX mailbox format. * * Does not (yet) support merge commits. * * The following options can be passed in the +options+ Hash: * * :patch_no :: * Number for this patch in the series. Defaults to +1+. * * :total_patches :: * Total number of patches in the series. Defaults to +1+. * * :exclude_subject_patch_marker :: * If set to true, no "[PATCH]" marker will be * added to the beginning of the subject line. * * Additionally, you can also pass the same options as for Rugged::Tree#diff. */ static VALUE rb_git_commit_to_mbox(int argc, VALUE *argv, VALUE self) { git_buf email_patch = { NULL }; git_repository *repo; git_commit *commit; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_format_email_flags_t flags = GIT_DIFF_FORMAT_EMAIL_NONE; VALUE rb_repo = rugged_owner(self), rb_email_patch = Qnil, rb_val, rb_options; int error; size_t patch_no = 1, total_patches = 1; rb_scan_args(argc, argv, ":", &rb_options); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); Data_Get_Struct(self, git_commit, commit); if (!NIL_P(rb_options)) { Check_Type(rb_options, T_HASH); rb_val = rb_hash_aref(rb_options, CSTR2SYM("patch_no")); if (!NIL_P(rb_val)) patch_no = NUM2INT(rb_val); rb_val = rb_hash_aref(rb_options, CSTR2SYM("total_patches")); if (!NIL_P(rb_val)) total_patches = NUM2INT(rb_val); if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_subject_patch_marker")))) flags |= GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER; rugged_parse_diff_options(&opts, rb_options); } error = git_diff_commit_as_email( &email_patch, repo, commit, patch_no, total_patches, flags, &opts); if (error) goto cleanup; rb_email_patch = rb_enc_str_new(email_patch.ptr, email_patch.size, rb_utf8_encoding()); cleanup: xfree(opts.pathspec.strings); git_buf_free(&email_patch); rugged_exception_check(error); return rb_email_patch; }
/* * call-seq: * tags.create(name, target[, force = false][, annotation = nil]) -> oid * * Create a new tag with the specified +name+ on +target+ in +repo+. * * If +annotation+ is not +nil+, it will cause the creation of an annotated tag object. * +annotation+ has to contain the following key value pairs: * * :tagger :: * An optional Hash containing a git signature. Defaults to the signature * from the configuration if only `:message` is given. Will cause the * creation of an annotated tag object if present. * * :message :: * An optional string containing the message for the new tag. * * Returns the OID of the newly created tag. */ static VALUE rb_git_tag_collection_create(int argc, VALUE *argv, VALUE self) { git_oid tag_oid; git_repository *repo = NULL; git_object *target = NULL; int error, force = 0; VALUE rb_repo = rugged_owner(self), rb_name, rb_target, rb_force, rb_annotation; rb_scan_args(argc, argv, "21:", &rb_name, &rb_target, &rb_force, &rb_annotation); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); Check_Type(rb_name, T_STRING); if (!NIL_P(rb_force)) force = rugged_parse_bool(rb_force); target = rugged_object_get(repo, rb_target, GIT_OBJ_ANY); if (NIL_P(rb_annotation)) { error = git_tag_create_lightweight( &tag_oid, repo, StringValueCStr(rb_name), target, force ); } else { git_signature *tagger = rugged_signature_get( rb_hash_aref(rb_annotation, CSTR2SYM("tagger")), repo ); VALUE rb_message = rb_hash_aref(rb_annotation, CSTR2SYM("message")); Check_Type(rb_message, T_STRING); error = git_tag_create( &tag_oid, repo, StringValueCStr(rb_name), target, tagger, StringValueCStr(rb_message), force ); git_signature_free(tagger); } git_object_free(target); rugged_exception_check(error); return rb_git_tag_collection_aref(self, rb_name); }
/* * call-seq: * obj.remove_note(data = {}) -> boolean * * Removes a +note+ from +object+, with the given +data+ * arguments, passed as a +Hash+: * * - +:committer+ (optional): a hash with the signature for the committer, * defaults to the signature from the configuration * - +:author+ (optional): a hash with the signature for the author, * defaults to the signature from the configuration * - +:ref+: (optional): canonical name of the reference to use, defaults to "refs/notes/commits" * * When the note is successfully removed +true+ will be * returned as a +Boolean+. * * author = {:email=>"*****@*****.**", :time=>Time.now, :name=>"Vicent Mart\303\255"} * * obj.remove_note( * :author => author, * :committer => author, * :ref => 'refs/notes/builds' * ) */ static VALUE rb_git_note_remove(int argc, VALUE *argv, VALUE self) { int error = 0; const char *notes_ref = NULL; git_repository *repo = NULL; git_signature *author, *committer; git_object *target = NULL; VALUE rb_data; VALUE rb_ref = Qnil; VALUE rb_author = Qnil; VALUE rb_committer = Qnil; VALUE owner; Data_Get_Struct(self, git_object, target); owner = rugged_owner(self); Data_Get_Struct(owner, git_repository, repo); rb_scan_args(argc, argv, "01", &rb_data); if (!NIL_P(rb_data)) { Check_Type(rb_data, T_HASH); rb_ref = rb_hash_aref(rb_data, CSTR2SYM("ref")); if (!NIL_P(rb_ref)) { Check_Type(rb_ref, T_STRING); notes_ref = StringValueCStr(rb_ref); } rb_committer = rb_hash_aref(rb_data, CSTR2SYM("committer")); rb_author = rb_hash_aref(rb_data, CSTR2SYM("author")); } committer = rugged_signature_get(rb_committer, repo); author = rugged_signature_get(rb_author, repo); error = git_note_remove( repo, notes_ref, author, committer, git_object_id(target)); git_signature_free(author); git_signature_free(committer); if (error == GIT_ENOTFOUND) return Qfalse; rugged_exception_check(error); return Qtrue; }
static VALUE rugged_rhead_new(const git_remote_head *head) { VALUE rb_head = rb_hash_new(); rb_hash_aset(rb_head, CSTR2SYM("local?"), head->local ? Qtrue : Qfalse); rb_hash_aset(rb_head, CSTR2SYM("oid"), rugged_create_oid(&head->oid)); rb_hash_aset(rb_head, CSTR2SYM("loid"), git_oid_iszero(&head->loid) ? Qnil : rugged_create_oid(&head->loid)); rb_hash_aset(rb_head, CSTR2SYM("name"), rb_str_new_utf8(head->name)); return rb_head; }
git_signature *rugged_signature_get(VALUE rb_sig, git_repository *repo) { int error; VALUE rb_time, rb_unix_t, rb_offset, rb_name, rb_email, rb_time_offset; git_signature *sig; if (NIL_P(rb_sig)) { rugged_exception_check( git_signature_default(&sig, repo) ); return sig; } Check_Type(rb_sig, T_HASH); rb_name = rb_hash_aref(rb_sig, CSTR2SYM("name")); rb_email = rb_hash_aref(rb_sig, CSTR2SYM("email")); rb_time = rb_hash_aref(rb_sig, CSTR2SYM("time")); rb_time_offset = rb_hash_aref(rb_sig, CSTR2SYM("time_offset")); Check_Type(rb_name, T_STRING); Check_Type(rb_email, T_STRING); if (NIL_P(rb_time)) { error = git_signature_now(&sig, StringValueCStr(rb_name), StringValueCStr(rb_email)); } else { if (!rb_obj_is_kind_of(rb_time, rb_cTime)) rb_raise(rb_eTypeError, "expected Time object"); rb_unix_t = rb_funcall(rb_time, rb_intern("tv_sec"), 0); if (NIL_P(rb_time_offset)) { rb_offset = rb_funcall(rb_time, rb_intern("utc_offset"), 0); } else { Check_Type(rb_time_offset, T_FIXNUM); rb_offset = rb_time_offset; } error = git_signature_new(&sig, StringValueCStr(rb_name), StringValueCStr(rb_email), NUM2LONG(rb_unix_t), FIX2INT(rb_offset) / 60); } rugged_exception_check(error); return sig; }
/* * call-seq: * blob.diff(other, options = {}) -> patch * * Directly generate a Rugged::Patch from the difference between +blob+ and +other+. * * +other+ can either be another Rugged::Blob instance, a string, * or nil (treated as an empty blob). * * The following options can be passed in the +options+ Hash: * * :max_size :: * An integer specifying the maximum byte size of a blob before a it will * be treated as binary. The default value is 512MB. * * :context_lines :: * The number of unchanged lines that define the boundary of a hunk (and * to display before and after the actual changes). The default is 3. * * :interhunk_lines :: * The maximum number of unchanged lines between hunk boundaries before the hunks * will be merged into a one. The default is 0. * * :reverse :: * If true, the sides of the diff will be reversed. * * :force_text :: * If true, all files will be treated as text, disabling binary attributes & detection. * * :ignore_whitespace :: * If true, all whitespace will be ignored. * * :ignore_whitespace_change :: * If true, changes in amount of whitespace will be ignored. * * :ignore_whitespace_eol :: * If true, whitespace at end of line will be ignored. * * :patience :: * If true, the "patience diff" algorithm will be used (currently unimplemented). * * :skip_binary_check :: * If true, diff deltas will be generated without spending time on binary * detection. This is useful to improve performance in cases where the actual * file content difference is not needed. * * :old_path :: * An optional string to treat +blob+ as if it had this filename. * * :new_path :: * An optional string to treat +other+ as if it had this filename. */ static VALUE rb_git_blob_diff(int argc, VALUE *argv, VALUE self) { git_blob *blob; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_patch *patch; const char *old_path = NULL, *new_path = NULL; VALUE rb_other, rb_options; int error; rb_scan_args(argc, argv, "10:", &rb_other, &rb_options); if (!NIL_P(rb_options)) { VALUE rb_value; rb_value = rb_hash_aref(rb_options, CSTR2SYM("old_path")); if (!NIL_P(rb_value)) { Check_Type(rb_value, T_STRING); old_path = StringValueCStr(rb_value); } rb_value = rb_hash_aref(rb_options, CSTR2SYM("new_path")); if (!NIL_P(rb_value)) { Check_Type(rb_value, T_STRING); new_path = StringValueCStr(rb_value); } rugged_parse_diff_options(&opts, rb_options); } Data_Get_Struct(self, git_blob, blob); if (NIL_P(rb_other)) { error = git_diff_patch_from_blobs(&patch, blob, old_path, NULL, new_path, &opts); } else if (rb_obj_is_kind_of(rb_other, rb_cRuggedBlob)) { git_blob *other_blob; Data_Get_Struct(rb_other, git_blob, other_blob); error = git_diff_patch_from_blobs(&patch, blob, old_path, other_blob, new_path, &opts); } else if (TYPE(rb_other) == T_STRING) { const char * buffer = StringValueCStr(rb_other); error = git_diff_patch_from_blob_and_buffer(&patch, blob, old_path, buffer, RSTRING_LEN(rb_other), new_path, &opts); } else { rb_raise(rb_eTypeError, "wrong argument type %s (expected Rugged::Blob, String, or nil)", rb_obj_classname(rb_other)); } rugged_exception_check(error); return rugged_diff_patch_new(self, patch); }
/* * call-seq: * remote.fetch(refspecs = nil, options = {}) -> hash * * Downloads new data from the remote for the given +refspecs+ and updates tips. * * You can optionally pass in a single or multiple alternative +refspecs+ to use instead of the fetch * refspecs already configured for +remote+. * * Returns a hash containing statistics for the fetch operation. * * The following options can be passed in the +options+ Hash: * * :credentials :: * The credentials to use for the fetch operation. Can be either an instance of one * of the Rugged::Credentials types, or a proc returning one of the former. * The proc will be called with the +url+, the +username+ from the url (if applicable) and * a list of applicable credential types. * * :headers :: * Extra HTTP headers to include with the request (only applies to http:// or https:// remotes) * * :progress :: * A callback that will be executed with the textual progress received from the remote. * This is the text send over the progress side-band (ie. the "counting objects" output). * * :transfer_progress :: * A callback that will be executed to report clone progress information. It will be passed * the amount of +total_objects+, +indexed_objects+, +received_objects+, +local_objects+, * +total_deltas+, +indexed_deltas+ and +received_bytes+. * * :update_tips :: * A callback that will be executed each time a reference is updated locally. It will be * passed the +refname+, +old_oid+ and +new_oid+. * * :certificate_check :: * A callback that will be executed each time we validate a certificate using https. It * will be passed the +valid+, +host_name+ and the callback should return a true/false to * indicate if the certificate has been validated. * * :message :: * The message to insert into the reflogs. Defaults to "fetch". * * :prune :: * Specifies the prune mode for the fetch. +true+ remove any remote-tracking references that * no longer exist, +false+ do not prune, +nil+ use configured settings Defaults to "nil". * * Example: * * remote = Rugged::Remote.lookup(@repo, 'origin') * remote.fetch({ * transfer_progress: lambda { |total_objects, indexed_objects, received_objects, local_objects, total_deltas, indexed_deltas, received_bytes| * # ... * } * }) */ static VALUE rb_git_remote_fetch(int argc, VALUE *argv, VALUE self) { git_remote *remote; git_strarray refspecs; git_fetch_options opts = GIT_FETCH_OPTIONS_INIT; const git_transfer_progress *stats; struct rugged_remote_cb_payload payload = { Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, 0 }; char *log_message = NULL; int error; VALUE rb_options, rb_refspecs, rb_result = Qnil; rb_scan_args(argc, argv, "01:", &rb_refspecs, &rb_options); rugged_rb_ary_to_strarray(rb_refspecs, &refspecs); Data_Get_Struct(self, git_remote, remote); rugged_remote_init_callbacks_and_payload_from_options(rb_options, &opts.callbacks, &payload); init_custom_headers(rb_options, &opts.custom_headers); if (!NIL_P(rb_options)) { VALUE rb_prune_type; VALUE rb_val = rb_hash_aref(rb_options, CSTR2SYM("message")); if (!NIL_P(rb_val)) log_message = StringValueCStr(rb_val); rb_prune_type = rb_hash_aref(rb_options, CSTR2SYM("prune")); opts.prune = parse_prune_type(rb_prune_type); } error = git_remote_fetch(remote, &refspecs, &opts, log_message); xfree(refspecs.strings); git_strarray_free(&opts.custom_headers); if (payload.exception) rb_jump_tag(payload.exception); rugged_exception_check(error); stats = git_remote_stats(remote); rb_result = rb_hash_new(); rb_hash_aset(rb_result, CSTR2SYM("total_objects"), UINT2NUM(stats->total_objects)); rb_hash_aset(rb_result, CSTR2SYM("indexed_objects"), UINT2NUM(stats->indexed_objects)); rb_hash_aset(rb_result, CSTR2SYM("received_objects"), UINT2NUM(stats->received_objects)); rb_hash_aset(rb_result, CSTR2SYM("local_objects"), UINT2NUM(stats->local_objects)); rb_hash_aset(rb_result, CSTR2SYM("total_deltas"), UINT2NUM(stats->total_deltas)); rb_hash_aset(rb_result, CSTR2SYM("indexed_deltas"), UINT2NUM(stats->indexed_deltas)); rb_hash_aset(rb_result, CSTR2SYM("received_bytes"), INT2FIX(stats->received_bytes)); return rb_result; }
static VALUE allowed_types_to_rb_ary(int allowed_types) { VALUE rb_allowed_types = rb_ary_new(); if (allowed_types & GIT_CREDTYPE_USERPASS_PLAINTEXT) rb_ary_push(rb_allowed_types, CSTR2SYM("plaintext")); if (allowed_types & GIT_CREDTYPE_SSH_KEY) rb_ary_push(rb_allowed_types, CSTR2SYM("ssh_key")); if (allowed_types & GIT_CREDTYPE_DEFAULT) rb_ary_push(rb_allowed_types, CSTR2SYM("default")); return rb_allowed_types; }
static VALUE rb_git_merge_file(int argc, VALUE *argv, VALUE self) { VALUE rb_path, rb_options; VALUE rb_result = rb_hash_new(); VALUE rb_repo = rugged_owner(self); git_repository *repo; git_index *index; const git_index_entry *ancestor, *ours, *theirs; git_merge_file_result merge_file_result = {0}; git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT; int error; rb_scan_args(argc, argv, "1:", &rb_path, &rb_options); if (!NIL_P(rb_options)) { Check_Type(rb_options, T_HASH); rugged_parse_merge_file_options(&opts, rb_options); } Check_Type(rb_path, T_STRING); Data_Get_Struct(self, git_index, index); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); error = git_index_conflict_get(&ancestor, &ours, &theirs, index, StringValueCStr(rb_path)); if (error == GIT_ENOTFOUND) return Qnil; else rugged_exception_check(error); if (ours == NULL) rb_raise(rb_eRuntimeError, "The conflict does not have a stage 2 entry"); else if (theirs == NULL) rb_raise(rb_eRuntimeError, "The conflict does not have a stage 3 entry"); error = git_merge_file_from_index(&merge_file_result, repo, ancestor, ours, theirs, &opts); rugged_exception_check(error); rb_hash_aset(rb_result, CSTR2SYM("automergeable"), merge_file_result.automergeable ? Qtrue : Qfalse); rb_hash_aset(rb_result, CSTR2SYM("path"), rb_path); rb_hash_aset(rb_result, CSTR2SYM("filemode"), INT2FIX(merge_file_result.mode)); rb_hash_aset(rb_result, CSTR2SYM("data"), rb_str_new(merge_file_result.ptr, merge_file_result.len)); git_merge_file_result_free(&merge_file_result); return rb_result; }
/* * call-seq: * Rugged.capabilities -> capabilities * * Returns an array representing the 'capabilities' that libgit2 was compiled * with — this includes GIT_CAP_THREADS (thread support) and GIT_CAP_HTTPS (https). * This is implemented in libgit2 with simple bitwise ops; we offer Rubyland an array * of symbols representing the capabilities. * * The possible capabilities are "threads" and "https". * * Rugged.capabilities #=> [:threads, :https] */ static VALUE rb_git_capabilities(VALUE self) { VALUE ret_arr = rb_ary_new(); int caps = git_libgit2_capabilities(); if (caps & GIT_CAP_THREADS) rb_ary_push(ret_arr, CSTR2SYM("threads")); if (caps & GIT_CAP_HTTPS) rb_ary_push(ret_arr, CSTR2SYM("https")); return ret_arr; }
/* * call-seq: * reference.type -> :symbolic or :direct * * Return whether the reference is +:symbolic+ or +:direct+ */ static VALUE rb_git_ref_type(VALUE self) { git_reference *ref; Data_Get_Struct(self, git_reference, ref); switch (git_reference_type(ref)) { case GIT_REF_OID: return CSTR2SYM("direct"); case GIT_REF_SYMBOLIC: return CSTR2SYM("symbolic"); default: return Qnil; } }
/* * call-seq: * tree.walk(mode) { |root, entry| block } * tree.walk(mode) -> Iterator * * Walk +tree+ with the given mode (either +:preorder+ or +:postorder+) and yield * to +block+ every entry in +tree+ and all its subtrees, as a +Hash+. The +block+ * also takes a +root+, the relative path in the traversal, starting from the root * of the original tree. * * If no +block+ is given, an +Iterator+ is returned instead. * * tree.walk(:postorder) { |root, entry| puts "#{root}#{entry[:name]} [#{entry[:oid]}]" } * * generates: * * USAGE.rb [02bae86c91f96b5fdb6b1cf06f5aa3612139e318] * ext [23f135b3c576b6ac4785821888991d7089f35db1] * ext/rugged [25c88faa9302e34e16664eb9c990deb2bcf77849] * ext/rugged/extconf.rb [40c1aa8a8cec8ca444ed5758e3f00ecff093070a] * ... */ static VALUE rb_git_tree_walk(VALUE self, VALUE rb_mode) { git_tree *tree; int error, mode = 0; ID id_mode; Data_Get_Struct(self, git_tree, tree); if (!rb_block_given_p()) return rb_funcall(self, rb_intern("to_enum"), 2, CSTR2SYM("walk"), rb_mode); Check_Type(rb_mode, T_SYMBOL); id_mode = SYM2ID(rb_mode); if (id_mode == rb_intern("preorder")) mode = GIT_TREEWALK_PRE; else if (id_mode == rb_intern("postorder")) mode = GIT_TREEWALK_POST; else rb_raise(rb_eTypeError, "Invalid iteration mode. Expected `:preorder` or `:postorder`"); error = git_tree_walk(tree, &rugged__treewalk_cb, mode, (void *)rb_block_proc()); rugged_exception_check(error); return Qnil; }
/* * call-seq: * repo.each_note(notes_ref = "refs/notes/commits") { |note_blob, annotated_object| block } * repo.each_note(notes_ref = "refs/notes/commits") -> an_enumerator * * Call the given block once for each note_blob/annotated_object pair in +repository+ * - +notes_ref+: (optional): cannonical name of the reference to use defaults to "refs/notes/commits" * * If no block is given, an +Enumerator+ is returned. * * @repo.each_note do |note_blob, annotated_object| * puts "#{note_blob.oid} => #{annotated_object.oid}" * end */ static VALUE rb_git_note_each(int argc, VALUE *argv, VALUE self) { git_repository *repo; const char *notes_ref = NULL; int error; struct rugged_cb_payload payload = { self, 0 }; VALUE rb_notes_ref; rb_scan_args(argc, argv, "01", &rb_notes_ref); if (!rb_block_given_p()) { return rb_funcall(self, rb_intern("to_enum"), 3, CSTR2SYM("each_note"), self, rb_notes_ref); } if (!NIL_P(rb_notes_ref)) { Check_Type(rb_notes_ref, T_STRING); notes_ref = StringValueCStr(rb_notes_ref); } Data_Get_Struct(self, git_repository, repo); error = git_note_foreach(repo, notes_ref, &cb_note__each, &payload); if (payload.exception) rb_jump_tag(payload.exception); rugged_exception_check(error); return Qnil; }
/* * call-seq: * branches.create(name, target, options = {}) -> branch * * Create a new branch with the given +name+, pointing to the +target+. * * +name+ needs to be a branch name, not an absolute reference path * (e.g. +development+ instead of +refs/heads/development+). * * +target+ needs to be an existing commit in the given repository. * * The following options can be passed in the +options+ Hash: * * :force :: * Overwrites the branch with the given +name+, if it already exists, * instead of raising an exception. * * If a branch with the given +name+ already exists and +:force+ is not +true+, * an exception will be raised. * * Returns a Rugged::Branch for the newly created branch. */ static VALUE rb_git_branch_collection_create(int argc, VALUE *argv, VALUE self) { VALUE rb_repo = rugged_owner(self), rb_name, rb_target, rb_options; git_repository *repo; git_reference *branch; git_commit *target; int error, force = 0; rb_scan_args(argc, argv, "20:", &rb_name, &rb_target, &rb_options); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); Check_Type(rb_name, T_STRING); Check_Type(rb_target, T_STRING); if (!NIL_P(rb_options)) { force = RTEST(rb_hash_aref(rb_options, CSTR2SYM("force"))); } target = (git_commit *)rugged_object_get(repo, rb_target, GIT_OBJ_COMMIT); error = git_branch_create(&branch, repo, StringValueCStr(rb_name), target, force); git_commit_free(target); rugged_exception_check(error); return rugged_branch_new(rb_repo, branch); }
/* * call-seq: * branch.move(old_name, new_name, options = {}) -> new_branch * branch.move(branch, new_name, options = {}) -> new_branch * branch.rename(old_name, new_name, options = {}) -> new_branch * branch.rename(branch, new_name, options = {}) -> new_branch * * Rename a branch to +new_name+. * * +new_name+ needs to be a branch name, not an absolute reference path * (e.g. +development+ instead of +refs/heads/development+). * * The following options can be passed in the +options+ Hash: * * :force :: * Overwrites the branch with the given +name+, if it already exists, * instead of raising an exception. * * If a branch with the given +new_name+ already exists and +:force+ is not +true+, * an exception will be raised. * * A new Rugged::Branch object for the renamed branch will be returned. * */ static VALUE rb_git_branch_collection_move(int argc, VALUE *argv, VALUE self) { VALUE rb_repo = rugged_owner(self), rb_name_or_branch, rb_new_branch_name, rb_options; git_reference *old_branch = NULL, *new_branch = NULL; git_repository *repo; int error, force = 0; rb_scan_args(argc, argv, "20:", &rb_name_or_branch, &rb_new_branch_name, &rb_options); Check_Type(rb_new_branch_name, T_STRING); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); error = rugged_branch_lookup(&old_branch, repo, rb_name_or_branch); rugged_exception_check(error); if (!NIL_P(rb_options)) { force = RTEST(rb_hash_aref(rb_options, CSTR2SYM("force"))); } error = git_branch_move(&new_branch, old_branch, StringValueCStr(rb_new_branch_name), force); git_reference_free(old_branch); rugged_exception_check(error); return rugged_branch_new(rugged_owner(self), new_branch); }
/* * call-seq: * hunk.each_line { |line| } -> self * hunk.each_line -> Enumerator * * If given a block, yields each line that is part of the current hunk. * * If no block is given, an enumerator is returned instead. */ static VALUE rb_git_diff_hunk_each_line(VALUE self) { git_patch *patch; int error = 0, l, lines_count, hunk_idx; if (!rb_block_given_p()) { return rb_funcall(self, rb_intern("to_enum"), 1, CSTR2SYM("each_line"), self); } Data_Get_Struct(rugged_owner(self), git_patch, patch); lines_count = FIX2INT(rb_iv_get(self, "@line_count")); hunk_idx = FIX2INT(rb_iv_get(self, "@hunk_index")); for (l = 0; l < lines_count; ++l) { const git_diff_line *line; error = git_patch_get_line_in_hunk(&line, patch, hunk_idx, l); if (error) break; rb_yield(rugged_diff_line_new(line)); } rugged_exception_check(error); return self; }
/* * call-seq: * patch.each_hunk { |hunk| } -> self * patch.each_hunk -> enumerator * * If given a block, yields each hunk that is part of the patch. * * If no block is given, an enumerator is returned instead. */ static VALUE rb_git_diff_patch_each_hunk(VALUE self) { git_patch *patch; const git_diff_hunk *hunk; size_t lines_in_hunk; int error = 0; size_t hunks_count, h; if (!rb_block_given_p()) { return rb_funcall(self, rb_intern("to_enum"), 1, CSTR2SYM("each_hunk"), self); } Data_Get_Struct(self, git_patch, patch); hunks_count = git_patch_num_hunks(patch); for (h = 0; h < hunks_count; ++h) { error = git_patch_get_hunk(&hunk, &lines_in_hunk, patch, h); if (error) break; rb_yield(rugged_diff_hunk_new(self, h, hunk, lines_in_hunk)); } rugged_exception_check(error); return self; }
/* * call-seq: * submodules.setup_add(url, path[, options]) -> submodule * * Setup a new +submodule+ for checkout in +repository+. * * This does <tt>"git submodule add"</tt> up to the fetch and checkout of the * submodule contents. It prepares a new submodule, creates an entry in * +.gitmodules+ and creates an empty initialized repository either at the * given +path+ in the working directory or in +.git/modules+ with a gitlink * from the working directory to the new repository. * * To fully emulate <tt>"git submodule add"</tt> call this function, then open * the submodule repository and perform the clone step as needed. * Lastly, call Submodule#finalize_add to wrap up adding the new submodule and * +.gitmodules+ to the index to be ready to commit. * * - +url+: URL for the submodule's remote * - +path+: path at which the submodule should be created * * The following options can be passed in the +options+ Hash: * :gitlink :: * (defaults to +true+) should workdir contain a * gitlink to the repository in +.git/modules+ vs. repository * directly in workdir. * * Returns the newly created +submodule+ */ static VALUE rb_git_submodule_setup_add(int argc, VALUE *argv, VALUE self) { git_submodule *submodule; git_repository *repo; int error; int use_gitlink = 1; VALUE rb_repo, rb_url, rb_path, rb_options; rb_scan_args(argc, argv, "20:", &rb_url, &rb_path, &rb_options); Check_Type(rb_url, T_STRING); Check_Type(rb_path, T_STRING); rb_repo = rugged_owner(self); Data_Get_Struct(rb_repo, git_repository, repo); if (!NIL_P(rb_options)) { VALUE rb_val; rb_val = rb_hash_aref(rb_options, CSTR2SYM("gitlink")); use_gitlink = (rb_val != Qfalse); } error = git_submodule_add_setup( &submodule, repo, StringValueCStr(rb_url), StringValueCStr(rb_path), use_gitlink ); rugged_exception_check(error); return rugged_submodule_new(rb_repo, submodule); }
static VALUE each_branch(int argc, VALUE *argv, VALUE self, int branch_names_only) { VALUE rb_repo = rugged_owner(self), rb_filter; git_repository *repo; git_branch_iterator *iter; int error, exception = 0; git_branch_t filter = (GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE), branch_type; rb_scan_args(argc, argv, "01", &rb_filter); if (!rb_block_given_p()) { VALUE symbol = branch_names_only ? CSTR2SYM("each_name") : CSTR2SYM("each"); return rb_funcall(self, rb_intern("to_enum"), 2, symbol, rb_filter); } rugged_check_repo(rb_repo); if (!NIL_P(rb_filter)) filter = parse_branch_type(rb_filter); Data_Get_Struct(rb_repo, git_repository, repo); error = git_branch_iterator_new(&iter, repo, filter); rugged_exception_check(error); if (branch_names_only) { git_reference *branch; while (!exception && (error = git_branch_next(&branch, &branch_type, iter)) == GIT_OK) { rb_protect(rb_yield, rb_str_new_utf8(git_reference_shorthand(branch)), &exception); } } else { git_reference *branch; while (!exception && (error = git_branch_next(&branch, &branch_type, iter)) == GIT_OK) { rb_protect(rb_yield, rugged_branch_new(rb_repo, branch), &exception); } } git_branch_iterator_free(iter); if (exception) rb_jump_tag(exception); if (error != GIT_ITEROVER) rugged_exception_check(error); return Qnil; }