示例#1
0
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;
}
示例#2
0
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);
}
示例#3
0
/*
 *  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;
}
示例#4
0
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;
}
示例#5
0
/*
 *  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;
}
示例#6
0
/*
 *  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;
}
示例#7
0
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");
	}
}
示例#8
0
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;
}
示例#9
0
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;
}
示例#10
0
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;
}
示例#11
0
/*
 *  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);
}
示例#12
0
/*
 *  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;
}
示例#13
0
/*
 *  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);
}
示例#14
0
/*
 *  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;
}
示例#15
0
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;
}
示例#16
0
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;
}
示例#17
0
/*
 *  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);
}
示例#18
0
/*
 *  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;
}
示例#19
0
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;
}
示例#20
0
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;
}
示例#21
0
/*
 *  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;
}
示例#22
0
/*
 *  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;
	}
}
示例#23
0
/*
 *	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;
}
示例#24
0
/*
 *  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);
}
示例#27
0
/*
 *  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;
}
示例#28
0
/*
 *  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;
}