Example #1
0
/*
 *  call-seq:
 *    index.read_tree(tree)
 *
 *  Clear the current index and start the index again on top of +tree+
 *
 *  Further index operations (+add+, +update+, +remove+, etc) will
 *  be considered changes on top of +tree+.
 */
static VALUE rb_git_index_readtree(VALUE self, VALUE rb_tree)
{
	git_index *index;
	git_tree *tree;
	int error;

	Data_Get_Struct(self, git_index, index);
	Data_Get_Struct(rb_tree, git_tree, tree);

	if (!rb_obj_is_kind_of(rb_tree, rb_cRuggedTree)) {
		rb_raise(rb_eTypeError, "A Rugged::Tree instance is required");
	}

	error = git_index_read_tree(index, tree);
	rugged_exception_check(error);

	return Qnil;
}
Example #2
0
/*
 *  call-seq:
 *    Index.new([path])
 *
 *  Create a bare index object based on the index file at +path+.
 *
 *  Any index methods that rely on the ODB or a working directory (e.g. #add)
 *  will raise a Rugged::IndexError.
 */
static VALUE rb_git_index_new(int argc, VALUE *argv, VALUE klass)
{
	git_index *index;
	int error;

	VALUE rb_path;
	const char *path = NULL;

	if (rb_scan_args(argc, argv, "01", &rb_path) == 1) {
		Check_Type(rb_path, T_STRING);
		path = StringValueCStr(rb_path);
	}

	error = git_index_open(&index, path);
	rugged_exception_check(error);

	return rugged_index_new(klass, Qnil, index);
}
Example #3
0
/*
 *  call-seq:
 *    remote.push_url = url -> url
 *
 *  Sets the remote's url for pushing without persisting it in the config.
 *  Existing connections will not be updated.
 *
 *    remote.push_url = '[email protected]/libgit2/rugged.git' #=> "[email protected]/libgit2/rugged.git"
 */
static VALUE rb_git_remote_set_push_url(VALUE self, VALUE rb_url)
{
	VALUE rb_repo = rugged_owner(self);
	git_remote *remote;
	git_repository *repo;

	rugged_check_repo(rb_repo);
	Data_Get_Struct(rb_repo, git_repository, repo);

	Check_Type(rb_url, T_STRING);
	Data_Get_Struct(self, git_remote, remote);

	rugged_exception_check(
		git_remote_set_pushurl(repo, git_remote_name(remote), StringValueCStr(rb_url))
	);

	return rb_url;
}
static VALUE each_tag(int argc, VALUE *argv, VALUE self, int tag_names_only)
{
	git_repository *repo;
	git_strarray tags;
	size_t i;
	int error, exception = 0;
	VALUE rb_repo = rugged_owner(self), rb_pattern;
	const char *pattern = NULL;

	rb_scan_args(argc, argv, "01", &rb_pattern);

	if (!rb_block_given_p()) {
		VALUE symbol = tag_names_only ? CSTR2SYM("each_name") : CSTR2SYM("each");
		return rb_funcall(self, rb_intern("to_enum"), 2, symbol, rb_pattern);
	}

	if (!NIL_P(rb_pattern)) {
		Check_Type(rb_pattern, T_STRING);
		pattern = StringValueCStr(rb_pattern);
	}

	rugged_check_repo(rb_repo);
	Data_Get_Struct(rb_repo, git_repository, repo);

	error = git_tag_list_match(&tags, pattern ? pattern : "", repo);
	rugged_exception_check(error);

	if (tag_names_only) {
		for (i = 0; !exception && i < tags.count; ++i)
			rb_protect(rb_yield, rb_str_new_utf8(tags.strings[i]), &exception);
	} else {
		for (i = 0; !exception && i < tags.count; ++i) {
			rb_protect(rb_yield, rb_git_tag_collection_aref(self,
				rb_str_new_utf8(tags.strings[i])), &exception);
		}
	}

	git_strarray_free(&tags);

	if (exception)
		rb_jump_tag(exception);

	return Qnil;
}
Example #5
0
/*
 *  call-seq:
 *    rebase.commit(author: nil, committer: committer, message: nil) -> oid or nil
 *
 *  Commit the current patch. Any conflicts must have been resolved.
 *
 *  If +author+ is +nil+, the existing author for the commit will be
 *  used. If +message+ is +nil+, the existing message will be used.
 *
 *  Returns a string containing the oid of the newly created commit,
 *  or +nil+ if there are no changes to be committed.
 */
static VALUE rb_git_rebase_commit(int argc, VALUE *argv, VALUE self)
{
	int error;
	git_oid id;
	git_rebase *rebase;
	git_signature *author = NULL, *committer;
	const char *message = NULL;
	VALUE rb_options, rb_author, rb_committer, rb_message;

	Data_Get_Struct(self, git_rebase, rebase);
	rb_scan_args(argc, argv, ":", &rb_options);

	Check_Type(rb_options, T_HASH);

	rb_author = rb_hash_aref(rb_options, CSTR2SYM("author"));
	rb_committer = rb_hash_aref(rb_options, CSTR2SYM("committer"));
	rb_message = rb_hash_aref(rb_options, CSTR2SYM("message"));

	if (!NIL_P(rb_message)) {
		Check_Type(rb_message, T_STRING);
		message = StringValueCStr(rb_message);
	}

	if (NIL_P(rb_committer))
		rb_raise(rb_eArgError, "Expected non-nil committer");
	else
		committer = rugged_signature_get(rb_committer, NULL);

	if (!NIL_P(rb_author))
		author = rugged_signature_get(rb_author, NULL);

	error = git_rebase_commit(&id, rebase, author, committer, NULL, message);
	git_signature_free(author);
	git_signature_free(committer);

	if (error == GIT_EAPPLIED) {
		giterr_clear();
		return Qnil;
	}

	rugged_exception_check(error);

	return rugged_create_oid(&id);
}
Example #6
0
/*
 *  call-seq:
 *    branch.upstream -> branch
 *
 *  Returns the remote tracking branch, or +nil+ if the branch is
 *  remote or has no tracking branch.
 */
static VALUE rb_git_branch_upstream(VALUE self)
{
	git_reference *branch, *upstream_branch;
	int error;

	Data_Get_Struct(self, git_reference, branch);

	if (git_reference_is_remote(branch))
		return Qnil;

	error = git_branch_upstream(&upstream_branch, branch);

	if (error == GIT_ENOTFOUND)
		return Qnil;

	rugged_exception_check(error);

	return rugged_branch_new(rugged_owner(self), upstream_branch);
}
Example #7
0
/*
 *  call-seq:
 *    commit.header_field(field_name) -> str
 *
 *  Returns +commit+'s header field value.
 */
static VALUE rb_git_commit_header_field(VALUE self, VALUE rb_field) {
	git_buf header_field = { 0 };
	VALUE rb_result;
	git_commit *commit;

	Check_Type(rb_field, T_STRING);

	Data_Get_Struct(self, git_commit, commit);

	rugged_exception_check(
		git_commit_header_field(&header_field, commit, StringValueCStr(rb_field))
	);

	rb_result = rb_enc_str_new(header_field.ptr, header_field.size, rb_utf8_encoding());

	git_buf_free(&header_field);

	return rb_result;
}
Example #8
0
/*
 *  call-seq:
 *    remote.ls(options = {}) -> an_enumerator
 *    remote.ls(options = {}) { |remote_head_hash| block }
 *
 *  Connects +remote+ to list all references available along with their
 *  associated commit ids.
 *
 *  The given block is called once for each remote head with a Hash containing the
 *  following keys:
 *
 *  :local? ::
 *    +true+ if the remote head is available locally, +false+ otherwise.
 *
 *  :oid ::
 *    The id of the object the remote head is currently pointing to.
 *
 *  :loid ::
 *    The id of the object the local copy of the remote head is currently
 *    pointing to. Set to +nil+ if there is no local copy of the remote head.
 *
 *  :name ::
 *    The fully qualified reference name of the remote head.
 *
 *  If no block is given, an enumerator will be returned.
 *
 *  The following options can be passed in the +options+ Hash:
 *
 *  :credentials ::
 *    The credentials to use for the ls 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)
 */
static VALUE rb_git_remote_ls(int argc, VALUE *argv, VALUE self)
{
	git_remote *remote;
	git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
	git_strarray custom_headers = {0};
	const git_remote_head **heads;

	struct rugged_remote_cb_payload payload = { Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, 0 };

	VALUE rb_options;

	int error;
	size_t heads_len, i;

	Data_Get_Struct(self, git_remote, remote);

	rb_scan_args(argc, argv, ":", &rb_options);

	if (!rb_block_given_p())
		return rb_funcall(self, rb_intern("to_enum"), 2, CSTR2SYM("ls"), rb_options);

	rugged_remote_init_callbacks_and_payload_from_options(rb_options, &callbacks, &payload);
	init_custom_headers(rb_options, &custom_headers);

	if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks, NULL, &custom_headers)) ||
	    (error = git_remote_ls(&heads, &heads_len, remote)))
		goto cleanup;

	for (i = 0; i < heads_len && !payload.exception; i++)
		rb_protect(rb_yield, rugged_rhead_new(heads[i]), &payload.exception);

	cleanup:

	git_remote_disconnect(remote);
	git_strarray_free(&custom_headers);

	if (payload.exception)
		rb_jump_tag(payload.exception);

	rugged_exception_check(error);

	return Qnil;
}
/*
 *  call-seq:
 *    branches[name] -> branch
 *
 *  Return the branch with the given +name+.
 *
 *  Branches can be looked up by their relative (+development+) or absolute
 *  (+refs/heads/development+) branch name.
 *
 *  If a local branch and a remote branch both share the same short name
 *  (e.g. +refs/heads/origin/master+ and +refs/remotes/origin/master+),
 *  passing +origin/master+ as the +name+ will return the local branch.
 *  You can explicitly request the local branch by passing
 *  +heads/origin/master+, or the remote branch through +remotes/origin/master+.
 *
 *  Returns the looked up branch, or +nil+ if the branch doesn't exist.
 */
static VALUE rb_git_branch_collection_aref(VALUE self, VALUE rb_name) {
	git_reference *branch;
	git_repository *repo;

	VALUE rb_repo = rugged_owner(self);
	int error;

	rugged_check_repo(rb_repo);
	Data_Get_Struct(rb_repo, git_repository, repo);

	Check_Type(rb_name, T_STRING);

	error = rugged_branch_lookup(&branch, repo, rb_name);
	if (error == GIT_ENOTFOUND)
		return Qnil;

	rugged_exception_check(error);
	return rugged_branch_new(rb_repo, branch);
}
Example #10
0
/*
 *  call-seq:
 *    Remote.lookup(repository, name) -> remote or nil
 *
 *  Return an existing remote with +name+ in +repository+:
 *  - +name+: a valid remote name
 *
 *  Returns a new Rugged::Remote object or +nil+ if the
 *  remote doesn't exist
 *
 *    Rugged::Remote.lookup(@repo, 'origin') #=> #<Rugged::Remote:0x00000001fbfa80>
 */
static VALUE rb_git_remote_lookup(VALUE klass, VALUE rb_repo, VALUE rb_name)
{
	git_remote *remote;
	git_repository *repo;
	int error;

	Check_Type(rb_name, T_STRING);
	rugged_check_repo(rb_repo);
	Data_Get_Struct(rb_repo, git_repository, repo);

	error = git_remote_load(&remote, repo, StringValueCStr(rb_name));

	if (error == GIT_ENOTFOUND)
		return Qnil;

	rugged_exception_check(error);

	return rugged_remote_new(klass, rb_repo, remote);
}
/*
 *  call-seq:
 *    branches.exist?(name) -> true or false
 *    branches.exists?(name) -> true or false
 *
 *  Check if a branch exists with the given +name+.
 */
static VALUE rb_git_branch_collection_exist_p(VALUE self, VALUE rb_name)
{
	VALUE rb_repo = rugged_owner(self);
	git_repository *repo;
	git_reference *branch;
	int error;

	Check_Type(rb_name, T_STRING);
	Data_Get_Struct(rb_repo, git_repository, repo);

	error = rugged_branch_lookup(&branch, repo, rb_name);
	git_reference_free(branch);

	if (error == GIT_ENOTFOUND)
		return Qfalse;
	else
		rugged_exception_check(error);

	return Qtrue;
}
/*
 *  call-seq:
 *    remotes.delete(remote) -> nil
 *    remotes.delete(name) -> nil
 *
 *  Delete the specified remote.
 *
 *    repo.remotes.delete("origin")
 *    # Remote no longer exists in the configuration.
 */
static VALUE rb_git_remote_collection_delete(VALUE self, VALUE rb_name_or_remote)
{
	VALUE rb_repo = rugged_owner(self);
	git_repository *repo;
	int error;

	if (rb_obj_is_kind_of(rb_name_or_remote, rb_cRuggedRemote))
		rb_name_or_remote = rb_funcall(rb_name_or_remote, rb_intern("name"), 0);

	if (TYPE(rb_name_or_remote) != T_STRING)
		rb_raise(rb_eTypeError, "Expecting a String or Rugged::Remote instance");

	rugged_check_repo(rb_repo);
	Data_Get_Struct(rb_repo, git_repository, repo);

	error = git_remote_delete(repo, StringValueCStr(rb_name_or_remote));
	rugged_exception_check(error);

	return Qnil;
}
Example #13
0
/*
 *  call-seq:
 *    Rugged.prettify_message(message, strip_comments) -> clean_message
 *
 *  Process a commit or tag message into standard form, by stripping trailing spaces and
 *  comments, and making sure that the message has a proper header line.
 */
static VALUE rb_git_prettify_message(VALUE self, VALUE rb_message, VALUE rb_strip_comments)
{
    char *message;
    int strip_comments, message_len;
    VALUE result;

    Check_Type(rb_message, T_STRING);
    strip_comments = rugged_parse_bool(rb_strip_comments);

    message_len = (int)RSTRING_LEN(rb_message) + 2;
    message = xmalloc(message_len);

    message_len = git_message_prettify(message, message_len, StringValueCStr(rb_message), strip_comments);
    rugged_exception_check(message_len);

    result = rb_enc_str_new(message, message_len - 1, rb_utf8_encoding());
    xfree(message);

    return result;
}
Example #14
0
static VALUE rb_git_remote_refspecs(VALUE self, git_direction direction)
{
	git_remote *remote;
	int error = 0;
	git_strarray refspecs;
	VALUE rb_refspec_array;

	Data_Get_Struct(self, git_remote, remote);

	if (direction == GIT_DIRECTION_FETCH)
		error = git_remote_get_fetch_refspecs(&refspecs, remote);
	else
		error = git_remote_get_push_refspecs(&refspecs, remote);

	rugged_exception_check(error);

	rb_refspec_array = rugged_strarray_to_rb_ary(&refspecs);
	git_strarray_free(&refspecs);
	return rb_refspec_array;
}
Example #15
0
static VALUE rb_git_treebuilder_init(int argc, VALUE *argv, VALUE self)
{
	git_treebuilder *builder;
	git_tree *tree = NULL;
	VALUE rb_object;
	int error;

	if (rb_scan_args(argc, argv, "01", &rb_object) == 1) {
		if (!rb_obj_is_kind_of(rb_object, rb_cRuggedTree))
			rb_raise(rb_eTypeError, "A Rugged::Tree instance is required");

		Data_Get_Struct(rb_object, git_tree, tree);
	}

	error = git_treebuilder_create(&builder, tree);
	rugged_exception_check(error);

	DATA_PTR(self) = builder;
	return Qnil;
}
Example #16
0
/*
 *  call-seq:
 *    Rugged.prettify_message(message, strip_comments = '#') -> clean_message
 *
 *  Process a commit or tag message into standard form, by stripping trailing spaces and
 *  comments, and making sure that the message has a proper header line.
 */
static VALUE rb_git_prettify_message(int argc, VALUE *argv, VALUE self)
{
	char comment_char = '#';
	int strip_comments = 1;

	git_buf message = { NULL };
	VALUE rb_message, rb_strip;
	int error;
	VALUE result = Qnil;

	rb_scan_args(argc, argv, "11", &rb_message, &rb_strip);

	Check_Type(rb_message, T_STRING);

	switch (TYPE(rb_strip)) {
	case T_FALSE:
		strip_comments = 0;
		break;

	case T_STRING:
		if (RSTRING_LEN(rb_strip) > 0)
			comment_char = RSTRING_PTR(rb_strip)[0];
		break;

	case T_TRUE:
	case T_NIL:
	default:
		break;
	}

	error = git_message_prettify(&message,
				StringValueCStr(rb_message), strip_comments, comment_char);

	if (!error)
		result = rb_enc_str_new(message.ptr, message.size, rb_utf8_encoding());

	git_buf_free(&message);
	rugged_exception_check(error);

	return result;
}
Example #17
0
/*
 *  call-seq:
 *    Remote.new(repository, url) -> remote
 *
 *  Return a new remote with +url+ in +repository+ , the remote is not persisted:
 *  - +url+: a valid remote url
 *
 *  Returns a new Rugged::Remote object
 *
 *    Rugged::Remote.new(@repo, 'git://github.com/libgit2/libgit2.git') #=> #<Rugged::Remote:0x00000001fbfa80>
 */
static VALUE rb_git_remote_new(VALUE klass, VALUE rb_repo, VALUE rb_url)
{
	git_remote *remote;
	git_repository *repo;
	int error;

	rugged_check_repo(rb_repo);
	rugged_validate_remote_url(rb_url);

	Data_Get_Struct(rb_repo, git_repository, repo);

	error = git_remote_create_anonymous(
			&remote,
			repo,
			StringValueCStr(rb_url),
			NULL);

	rugged_exception_check(error);

	return rugged_remote_new(klass, rb_repo, remote);
}
Example #18
0
/*
 *  call-seq:
 *    index.remove_dir(dir[, stage = 0]) -> nil
 *
 *  Removes all entries under the given +dir+ with the given +stage+
 *  from the index.
 */
static VALUE rb_git_index_remove_directory(int argc, VALUE *argv, VALUE self)
{
	git_index *index;
	int error, stage = 0;

	VALUE rb_dir, rb_stage;

	Data_Get_Struct(self, git_index, index);

	if (rb_scan_args(argc, argv, "11", &rb_dir, &rb_stage) > 1) {
		Check_Type(rb_stage, T_FIXNUM);
		stage = FIX2INT(rb_stage);
	}

	Check_Type(rb_dir, T_STRING);

	error = git_index_remove_directory(index, StringValueCStr(rb_dir), stage);
	rugged_exception_check(error);

	return Qnil;
}
/*
 *  call-seq:
 *    remotes[name] -> remote or nil
 *
 *  Lookup a remote in the collection with the given +name+.
 *
 *  Returns a new Rugged::Remote object or +nil+ if the
 *  remote doesn't exist.
 *
 *    @repo.remotes["origin"] #=> #<Rugged::Remote:0x00000001fbfa80>
 */
static VALUE rb_git_remote_collection_aref(VALUE self, VALUE rb_name)
{
	git_remote *remote;
	git_repository *repo;
	int error;

	VALUE rb_repo = rugged_owner(self);
	rugged_check_repo(rb_repo);
	Data_Get_Struct(rb_repo, git_repository, repo);

	Check_Type(rb_name, T_STRING);

	error = git_remote_lookup(&remote, repo, StringValueCStr(rb_name));

	if (error == GIT_ENOTFOUND)
		return Qnil;

	rugged_exception_check(error);

	return rugged_remote_new(rb_repo, remote);
}
Example #20
0
/*
 *  call-seq:
 *    Rebase.new(repo, branch, upstream[, onto][, options]) -> Rebase
 *
 *  Initialize a new rebase operation. This will put +repo+ in a
 *  rebase state.
 *
 *  +branch+ is the branch to be rebased, and +upstream+ is the branch
 *  which is to be the new base. If +onto+ is specified, this will be
 *  the one base, and +upstream+ is used to determine which commits
 *  from +branch+ to use for the rebase.
 *
 *  You can pass merge and checkout options for the options hash, plus
 *  a few rebase-specific ones:
 *
 *  :quiet ::
 *    If true, a flag will be set to ask tools to activate quiet
 *    mode. This does not do anything for libgit2/rugged but can be
 *    used to interact with other implementations.
 *
 *  :inmemory ::
 *    Do not put the repository in a rebase state but perform all the
 *    operations in-memory. In case of conflicts, the RebaseOperation
 *    returned by #next will contain the index which can be used to
 *    resolve conflicts.
 *
 *  :rewrite_notes_ref ::
 *    Name of the notes reference used to rewrite notes for rebased
 *    commits when finishing the rebase. If +nil+, it will be taken
 *    from the configuration.
 */
static VALUE rb_git_rebase_new(int argc, VALUE* argv, VALUE klass)
{
	int error = 0, exception = 0;
	git_rebase *rebase = NULL;
	git_repository *repo;
	git_annotated_commit *branch = NULL, *upstream = NULL, *onto = NULL;
	VALUE rb_repo, rb_branch, rb_upstream, rb_onto, rb_options;
	git_rebase_options options = GIT_REBASE_OPTIONS_INIT;

	rb_scan_args(argc, argv, "31:", &rb_repo, &rb_branch, &rb_upstream, &rb_onto, &rb_options);
	Data_Get_Struct(rb_repo, git_repository, repo);

	if ((exception = rugged_get_annotated_commit(&branch, rb_repo, rb_branch)))
		goto cleanup;

	if ((exception = rugged_get_annotated_commit(&upstream, rb_repo, rb_upstream)))
		goto cleanup;

	if (!NIL_P(rb_onto)) {
		if ((exception = rugged_get_annotated_commit(&onto, rb_repo, rb_onto)))
			goto cleanup;
	}

	parse_rebase_options(&options, rb_options);

	error = git_rebase_init(&rebase, repo, branch, upstream, onto, &options);

cleanup:
	git_annotated_commit_free(branch);
	git_annotated_commit_free(upstream);
	git_annotated_commit_free(onto);

	if (error) {
		rugged_exception_check(error);
	} else if (exception) {
		rb_jump_tag(exception);
	}

	return rugged_rebase_new(klass, rb_repo, rebase);
}
Example #21
0
/*
 *  call-seq:
 *    remote.push(refspecs = nil, options = {}) -> hash
 *
 *  Pushes the given +refspecs+ to the given +remote+. Returns a hash that contains
 *  key-value pairs that reflect pushed refs and error messages, if applicable.
 *
 *  You can optionally pass in an alternative list of +refspecs+ to use instead of the push
 *  refspecs already configured for +remote+.
 *
 *  The following options can be passed in the +options+ Hash:
 *
 *  :credentials ::
 *    The credentials to use for the push 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.
 *
 *  :update_tips ::
 *    A callback that will be executed each time a reference is updated remotely. It will be
 *    passed the +refname+, +old_oid+ and +new_oid+.
 *
 *  Example:
 *
 *    remote = Rugged::Remote.lookup(@repo, 'origin')
 *    remote.push(["refs/heads/master", ":refs/heads/to_be_deleted"])
 */
static VALUE rb_git_remote_push(int argc, VALUE *argv, VALUE self)
{
	VALUE rb_refspecs, rb_options;
	VALUE rb_repo = rugged_owner(self);

	git_repository *repo;
	git_remote *remote;
	git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
	git_strarray refspecs;
	git_push_options opts = GIT_PUSH_OPTIONS_INIT;

	int error = 0;

	struct rugged_remote_cb_payload payload = { Qnil, Qnil, Qnil, Qnil, Qnil, rb_hash_new(), 0 };

	rb_scan_args(argc, argv, "01:", &rb_refspecs, &rb_options);

	rugged_rb_ary_to_strarray(rb_refspecs, &refspecs);

	rugged_check_repo(rb_repo);
	Data_Get_Struct(rb_repo, git_repository, repo);
	Data_Get_Struct(self, git_remote, remote);

	rugged_remote_init_callbacks_and_payload_from_options(rb_options, &callbacks, &payload);

	if ((error = git_remote_set_callbacks(remote, &callbacks)))
	    goto cleanup;

	error = git_remote_push(remote, &refspecs, &opts);

cleanup:
	xfree(refspecs.strings);

	if (payload.exception)
		rb_jump_tag(payload.exception);

	rugged_exception_check(error);

	return payload.result;
}
Example #22
0
static VALUE rb_git_index_add(VALUE self, VALUE rb_entry)
{
	git_index *index;
	git_index_entry *entry;
	int error;

	Data_Get_Struct(self, git_index, index);

	if (rb_obj_is_kind_of(rb_entry, rb_cRuggedIndexEntry)) {
		Data_Get_Struct(rb_entry, git_index_entry, entry);
		error = git_index_insert(index, entry);
	} else if (TYPE(rb_entry) == T_STRING) {
		error = git_index_add(index, RSTRING_PTR(rb_entry), 0);
	} else {
		rb_raise(rb_eTypeError, 
			"index_entry must be an existing IndexEntry object or a path to a file in the repository");
	}

	rugged_exception_check(error);

	return Qnil;
}
Example #23
0
/*
 *  call-seq:
 *    branch.remote_name -> string
 *
 *  Get the name of the remote the branch belongs to.
 *
 *  If +branch+ is a remote branch, the name of the remote it belongs to is
 *  returned. If +branch+ is a tracking branch, the name of the remote
 *  of the tracked branch is returned.
 *
 *  Otherwise, +nil+ is returned.
 */
static VALUE rb_git_branch_remote_name(VALUE self)
{
	git_reference *branch, *remote_ref;
	int error = 0;

	Data_Get_Struct(self, git_reference, branch);

	if (git_reference_is_remote(branch)) {
		remote_ref = branch;
	} else {
		error = git_branch_upstream(&remote_ref, branch);

		if (error == GIT_ENOTFOUND)
			return Qnil;

		rugged_exception_check(error);
	}

	return rb_git_branch__remote_name(
			rugged_owner(self),
			git_reference_name(remote_ref));
}
Example #24
0
/*
 *  call-seq:
 *     Remote.add(repository, name, url) -> remote
 *
 *  Add a new remote with +name+ and +url+ to +repository+
 *  - +url+: a valid remote url
 *  - +name+: a valid remote name
 *
 *  Returns a new Rugged::Remote object
 *
 *    Rugged::Remote.add(@repo, 'origin', 'git://github.com/libgit2/rugged.git') #=> #<Rugged::Remote:0x00000001fbfa80>
 */
static VALUE rb_git_remote_add(VALUE klass, VALUE rb_repo,VALUE rb_name, VALUE rb_url)
{
	git_remote *remote;
	git_repository *repo;
	int error;

	Check_Type(rb_name, T_STRING);
	rugged_validate_remote_url(rb_url);
	rugged_check_repo(rb_repo);

	Data_Get_Struct(rb_repo, git_repository, repo);

	error = git_remote_create(
			&remote,
			repo,
			StringValueCStr(rb_name),
			StringValueCStr(rb_url));

	rugged_exception_check(error);

	return rugged_remote_new(klass, rb_repo, remote);
}
Example #25
0
/*
 *  call-seq:
 *    Patch.from_strings(old_content = nil, new_content = nil, options = {}) -> patch
 *
 *  Directly generate a Rugged::Patch from the difference between the content of
 *  the two strings `old_content` and `new_content`.
 *
 *  The following options can be passed in the +options+ Hash:
 *
 *  :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.
 *
 *  Additionally, `options` can also contain all other valid diff options
 *  (see Rugged::Tree#diff for a complete list).
 */
VALUE rb_git_patch_from_strings(int argc, VALUE *argv, VALUE self)
{
    git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
    git_patch *patch;
    char * old_path = NULL, * new_path = NULL;
    VALUE rb_old_buffer, rb_new_buffer, rb_options;

    rb_scan_args(argc, argv, "02:", &rb_old_buffer, &rb_new_buffer, &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);
    }

    rugged_exception_check(git_patch_from_buffers(&patch,
                           NIL_P(rb_old_buffer) ? NULL : StringValuePtr(rb_old_buffer),
                           NIL_P(rb_old_buffer) ? 0 : RSTRING_LEN(rb_old_buffer),
                           old_path,
                           NIL_P(rb_new_buffer) ? NULL : StringValuePtr(rb_new_buffer),
                           NIL_P(rb_new_buffer) ? 0 : RSTRING_LEN(rb_new_buffer),
                           new_path,
                           &opts
                                                 ));

    return rugged_patch_new(self, patch);
}
Example #26
0
/*
 *  call-seq:
 *    index.write_tree([repo]) -> oid
 *
 *  Write the index to a tree, either in the index's repository, or in
 *  the given +repo+.
 *
 *  If the index contains any files in conflict, writing the tree will fail.
 *
 *  Returns the OID string of the written tree object.
 */
static VALUE rb_git_index_writetree(int argc, VALUE *argv, VALUE self)
{
	git_index *index;
	git_oid tree_oid;
	int error;
	VALUE rb_repo;

	Data_Get_Struct(self, git_index, index);

	if (rb_scan_args(argc, argv, "01", &rb_repo) == 1) {
		git_repository *repo = NULL;
		rugged_check_repo(rb_repo);
		Data_Get_Struct(rb_repo, git_repository, repo);
		error = git_index_write_tree_to(&tree_oid, index, repo);
	}
	else {
		error = git_index_write_tree(&tree_oid, index);
	}

	rugged_exception_check(error);
	return rugged_create_oid(&tree_oid);
}
Example #27
0
static VALUE rb_git_diff_index_to_workdir(VALUE self, VALUE rb_options)
{
	git_index *index;
	git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
	git_repository *repo;
	git_diff *diff = NULL;
	VALUE owner;
	int error;

	rugged_parse_diff_options(&opts, rb_options);

	Data_Get_Struct(self, git_index, index);
	owner = rugged_owner(self);
	Data_Get_Struct(owner, git_repository, repo);

	error = git_diff_index_to_workdir(&diff, repo, index, &opts);

	xfree(opts.pathspec.strings);
	rugged_exception_check(error);

	return rugged_diff_new(rb_cRuggedDiff, owner, diff);
}
Example #28
0
/*
 *  call-seq:
 *    commit.parents -> [commit, ...]
 *
 *  Return the parent(s) of this commit as an array of +Rugged::Commit+
 *  objects. An array is always returned even when the commit has only
 *  one or zero parents.
 *
 *    commit.parents #=> => [#<Rugged::Commit:0x108828918>]
 *    root.parents #=> []
 */
static VALUE rb_git_commit_parents_GET(VALUE self)
{
	git_commit *commit;
	git_commit *parent;
	unsigned int n, parent_count;
	VALUE ret_arr, owner;
	int error;

	Data_Get_Struct(self, git_commit, commit);
	owner = rugged_owner(self);

	parent_count = git_commit_parentcount(commit);
	ret_arr = rb_ary_new2((long)parent_count);

	for (n = 0; n < parent_count; n++) {
		error = git_commit_parent(&parent, commit, n);
		rugged_exception_check(error);
		rb_ary_push(ret_arr, rugged_object_new(owner, (git_object *)parent));
	}

	return ret_arr;
}
Example #29
0
/*
 *  call-seq:
 *    remote.check_connection(direction, options = {}) -> boolean
 *
 *  Try to connect to the +remote+. Useful to simulate
 *  <tt>git fetch --dry-run</tt> and <tt>git push --dry-run</tt>.
 *
 *  Returns +true+ if connection is successful, +false+ otherwise.
 *
 *  +direction+ must be either +:fetch+ or +:push+.
 *
 *  The following options can be passed in the +options+ Hash:
 *
 *  +credentials+ ::
 *    The credentials to use for the connection. 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.
 *
 *  Example:
 *
 *    remote = repo.remotes["origin"]
 *    success = remote.check_connection(:fetch)
 *    raise Error("Unable to pull without credentials") unless success
 */
static VALUE rb_git_remote_check_connection(int argc, VALUE *argv, VALUE self)
{
	git_remote *remote;
	git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
	struct rugged_remote_cb_payload payload = { Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, 0 };
	VALUE rb_direction, rb_options;
	ID id_direction;
	int error, direction;

	Data_Get_Struct(self, git_remote, remote);
	rb_scan_args(argc, argv, "01:", &rb_direction, &rb_options);

	Check_Type(rb_direction, T_SYMBOL);
	id_direction = SYM2ID(rb_direction);
	if (id_direction == rb_intern("fetch"))
		direction = GIT_DIRECTION_FETCH;
	else if (id_direction == rb_intern("push"))
		direction = GIT_DIRECTION_PUSH;
	else
		rb_raise(rb_eTypeError, "Invalid direction. Expected :fetch or :push");

	rugged_remote_init_callbacks_and_payload_from_options(rb_options, &callbacks, &payload);

	if ((error = git_remote_set_callbacks(remote, &callbacks)) < 0)
		goto cleanup;

	if (git_remote_connect(remote, direction))
		return Qfalse;
	else {
		git_remote_disconnect(remote);
		return Qtrue;
	}

cleanup:
	if (payload.exception)
		rb_jump_tag(payload.exception);
	rugged_exception_check(error);
	return Qfalse;
}
Example #30
0
/*
 *  call-seq:
 *    Commit.create_to_s(repository, data = {}) -> str
 *
 *  Create a string with the contents of the commit, created with the
 *  given +data+ arguments, passed as a +Hash+:
 *
 *  - +:message+: a string with the full text for the commit's message
 *  - +: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
 *  - +:parents+: an +Array+ with zero or more parents for this commit,
 *    represented as <tt>Rugged::Commit</tt> instances, or OID +String+.
 *  - +:tree+: the tree for this commit, represented as a <tt>Rugged::Tree</tt>
 *    instance or an OID +String+.
 *
 *    author = {:email=>"*****@*****.**", :time=>Time.now, :name=>"Vicent Mart\303\255"}
 *
 *    Rugged::Commit.create(r,
 *      :author => author,
 *      :message => "Hello world\n\n",
 *      :committer => author,
 *      :parents => ["2cb831a8aea28b2c1b9c63385585b864e4d3bad1"],
 *      :tree => some_tree) #=> "tree some_tree\nparent 2cb831...."
 */
static VALUE rb_git_commit_create_to_s(VALUE self, VALUE rb_repo, VALUE rb_data)
{
	int error = 0;
	struct commit_data commit_data = { Qnil };
	git_repository *repo;
	git_buf buf = { 0 };
	VALUE ret;

	Check_Type(rb_data, T_HASH);

	rugged_check_repo(rb_repo);
	Data_Get_Struct(rb_repo, git_repository, repo);

	if ((error = parse_commit_options(&commit_data, repo, rb_data)) < 0)
		goto cleanup;

	error = git_commit_create_buffer(
		&buf,
		repo,
		commit_data.author,
		commit_data.committer,
		NULL,
		commit_data.message,
		commit_data.tree,
		commit_data.parent_count,
		commit_data.parents);

cleanup:
	free_commit_options(&commit_data);
	if (!NIL_P(commit_data.rb_err_obj))
		rb_exc_raise(commit_data.rb_err_obj);

	rugged_exception_check(error);

	ret = rb_str_new_utf8(buf.ptr);
	git_buf_free(&buf);

	return ret;
}