Esempio n. 1
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;
}
Esempio n. 2
0
static VALUE rb_git_commit_author_SET(VALUE self, VALUE rb_sig)
{
	git_commit *commit;
	RUGGED_OBJ_UNWRAP(self, git_commit, commit);

	git_commit_set_author(commit, rugged_signature_get(rb_sig));
	return Qnil;
}
Esempio n. 3
0
static VALUE rb_git_tag_tagger_SET(VALUE self, VALUE rb_sig)
{
	git_tag *tag;
	RUGGED_OBJ_UNWRAP(self, git_tag, tag);

	git_tag_set_tagger(tag, rugged_signature_get(rb_sig));
	return Qnil;
}
Esempio n. 4
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);
}
Esempio n. 5
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);
}
Esempio n. 6
0
/*
 *  call-seq:
 *    rebase.finish -> nil
 *
 *  Finish the rebase currently in progress once all patches have been
 *  applied.
 */
static VALUE rb_git_rebase_finish(VALUE self, VALUE rb_sig)
{
	git_rebase *rebase;
	git_signature *sig;
	int error;

	Data_Get_Struct(self, git_rebase, rebase);
	sig = rugged_signature_get(rb_sig, NULL);
	error = git_rebase_finish(rebase, sig);
	git_signature_free(sig);

	rugged_exception_check(error);

	return Qnil;
}
Esempio n. 7
0
/*
 *  call-seq:
 *    tags.create_annotation(name, target, annotation) -> annotation
 *
 *  Create a new annotated tag object with the specified +name+ on +target+ in
 *  +repo+.
 *
 *  Unlike the +create+ method, +create_annotation+ simply creates a tag
 *  object. It does not write a tag ref.
 *
 *  +annotation+ must have the following keys:
 *
 *  :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 an instance of Rugged::Tag::Annotation representing the newly
 *  created annotation.
 */
static VALUE rb_git_tag_collection_create_annotation(VALUE self, VALUE rb_name, VALUE rb_target, VALUE rb_annotation)
{
	git_oid tag_oid;
	git_repository *repo = NULL;
	git_object *target = NULL, *tag = NULL;
	git_signature *tagger = NULL;
	VALUE rb_message;
	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);

	target = rugged_object_get(repo, rb_target, GIT_OBJ_ANY);

	rb_message = rb_hash_aref(rb_annotation, CSTR2SYM("message"));
	Check_Type(rb_message, T_STRING);

	tagger = rugged_signature_get(
		rb_hash_aref(rb_annotation, CSTR2SYM("tagger")), repo
	);

	error = git_tag_annotation_create(
		&tag_oid,
		repo,
		StringValueCStr(rb_name),
		target,
		tagger,
		StringValueCStr(rb_message)
	);

	git_object_free(target);
	git_signature_free(tagger);

	rugged_exception_check(error);

	error = git_object_lookup(&tag, repo, &tag_oid, GIT_OBJ_TAG);
	rugged_exception_check(error);

	return rugged_object_new(rb_repo, tag);
}
Esempio n. 8
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.
 *
 *  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.
 *
 *  :message ::
 *    A single line log message to be appended to the reflog of each local remote-tracking
 *    branch that gets updated. Defaults to: "fetch".
 *
 *  :signature ::
 *    The signature to be used for populating the reflog entries.
 *
 *  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, rb_val;
	VALUE rb_repo = rugged_owner(self);
	VALUE rb_exception = Qnil, rb_result = rb_hash_new();

	git_repository *repo;
	git_remote *remote, *tmp_remote = NULL;
	git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
	git_push *push = NULL;
	git_signature *signature = NULL;

	int error = 0, i = 0;
	char *log_message = NULL;

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

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

	if (!NIL_P(rb_refspecs)) {
		Check_Type(rb_refspecs, T_ARRAY);
		for (i = 0; i < RARRAY_LEN(rb_refspecs); ++i) {
			VALUE rb_refspec = rb_ary_entry(rb_refspecs, i);
			Check_Type(rb_refspec, T_STRING);
		}
	}

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

	if (!NIL_P(rb_options)) {
		rugged_remote_init_callbacks_and_payload_from_options(rb_options, &callbacks, &payload);

		rb_val = rb_hash_aref(rb_options, CSTR2SYM("message"));
		if (!NIL_P(rb_val))
			log_message = StringValueCStr(rb_val);

		rb_val = rb_hash_aref(rb_options, CSTR2SYM("signature"));
		if (!NIL_P(rb_val))
			signature = rugged_signature_get(rb_val, repo);
	}

	// Create a temporary remote that we use for pushing
	if ((error = git_remote_dup(&tmp_remote, remote)) ||
	    (error = git_remote_set_callbacks(tmp_remote, &callbacks)))
	    goto cleanup;

	if (!NIL_P(rb_refspecs)) {
		git_remote_clear_refspecs(tmp_remote);

		for (i = 0; !error && i < RARRAY_LEN(rb_refspecs); ++i) {
			VALUE rb_refspec = rb_ary_entry(rb_refspecs, i);

			if ((error = git_remote_add_push(tmp_remote, StringValueCStr(rb_refspec))))
				goto cleanup;
		}
	}

	if ((error = git_push_new(&push, tmp_remote)))
		goto cleanup;

	// TODO: Get rid of this once git_remote_push lands in libgit2.
	{
		git_strarray push_refspecs;
		size_t i;

		if ((error = git_remote_get_push_refspecs(&push_refspecs, tmp_remote)))
			goto cleanup;

		if (push_refspecs.count == 0) {
			rb_exception = rb_exc_new2(rb_eRuggedError, "no pushspecs are configured for the given remote");
			goto cleanup;
		}

		for (i = 0; !error && i < push_refspecs.count; ++i) {
			error = git_push_add_refspec(push, push_refspecs.strings[i]);
		}

		git_strarray_free(&push_refspecs);
		if (error) goto cleanup;
	}

	if ((error = git_push_finish(push)))
		goto cleanup;

	if (!git_push_unpack_ok(push)) {
		rb_exception = rb_exc_new2(rb_eRuggedError, "the remote side did not unpack successfully");
		goto cleanup;
	}

	if ((error = git_push_status_foreach(push, &push_status_cb, (void *)rb_result)) ||
	    (error = git_push_update_tips(push, signature, log_message)))
	    goto cleanup;

cleanup:
	git_push_free(push);
	git_remote_free(tmp_remote);
	git_signature_free(signature);

	if (!NIL_P(rb_exception))
		rb_exc_raise(rb_exception);

	rugged_exception_check(error);

	return rb_result;
}
Esempio n. 9
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 an alternative list of +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.
 *
 *  :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+.
 *
 *  :message ::
 *    The message to insert into the reflogs. Defaults to "fetch".
 *
 *  :signature ::
 *    The signature to be used for updating the reflogs.
 *
 *  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, *tmp_remote = NULL;
	git_repository *repo;
	git_signature *signature = NULL;
	git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
	struct rugged_remote_cb_payload payload = { Qnil, Qnil, Qnil, Qnil, Qnil, 0 };

	char *log_message = NULL;
	int error, i;

	VALUE rb_options, rb_refspecs, rb_result = Qnil, rb_repo = rugged_owner(self);

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

	if (!NIL_P(rb_refspecs)) {
		Check_Type(rb_refspecs, T_ARRAY);
		for (i = 0; i < RARRAY_LEN(rb_refspecs); ++i) {
			VALUE rb_refspec = rb_ary_entry(rb_refspecs, i);
			Check_Type(rb_refspec, T_STRING);
		}
	}

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

	if (!NIL_P(rb_options)) {
		VALUE rb_val = rb_hash_aref(rb_options, CSTR2SYM("signature"));
		if (!NIL_P(rb_val))
			signature = rugged_signature_get(rb_val, repo);

		rb_val = rb_hash_aref(rb_options, CSTR2SYM("message"));
		if (!NIL_P(rb_val))
			log_message = StringValueCStr(rb_val);

		rugged_remote_init_callbacks_and_payload_from_options(rb_options, &callbacks, &payload);
	}

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

	if (!NIL_P(rb_refspecs)) {
		git_remote_clear_refspecs(tmp_remote);
		for (i = 0; !error && i < RARRAY_LEN(rb_refspecs); ++i) {
			VALUE rb_refspec = rb_ary_entry(rb_refspecs, i);

			if ((error = git_remote_add_fetch(tmp_remote, StringValueCStr(rb_refspec))))
				goto cleanup;
		}
	}

	if ((error = git_remote_fetch(tmp_remote, signature, log_message)) == GIT_OK) {
		const git_transfer_progress *stats = git_remote_stats(tmp_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));
	}

	cleanup:

	git_signature_free(signature);
	git_remote_free(tmp_remote);

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

	rugged_exception_check(error);

	return rb_result;
}
Esempio n. 10
0
/*
 *  call-seq:
 *    obj.create_note(data = {}) -> oid
 *
 *  Write a new +note+ to +object+, with the given +data+
 *  arguments, passed as a +Hash+:
 *
 *  - +:message+: the content of the note to add to the object
 *  - +:committer+: a hash with the signature for the committer
 *  - +:author+: a hash with the signature for the author
 *  - +:ref+: (optional): cannonical name of the reference to use, defaults to "refs/notes/commits"
 *  - +:force+: (optional): overwrite existing note (disabled by default)
 *
 *  When the note is successfully written to disk, its +oid+ will be
 *  returned as a hex +String+.
 *
 *    author = {:email=>"*****@*****.**", :time=>Time.now, :name=>"Vicent Mart\303\255"}
 *
 *    obj.create_note(
 *      :author    => author,
 *      :committer => author,
 *      :message   => "Hello world\n\n",
 *      :ref       => 'refs/notes/builds'
 *    )
 */
static VALUE rb_git_note_create(VALUE self, VALUE rb_data)
{
	VALUE rb_ref, rb_message, rb_force;
	git_repository *repo = NULL;
	const char *notes_ref = NULL;

	VALUE owner;

	git_signature *author, *committer;
	git_oid note_oid;

	git_object *target = NULL;
	int error = 0;
	int force = 0;

	Check_Type(rb_data, T_HASH);

	Data_Get_Struct(self, git_object, target);

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

	rb_ref = rb_hash_aref(rb_data, CSTR2SYM("ref"));

	rb_force = rb_hash_aref(rb_data, CSTR2SYM("force"));
	if (!NIL_P(rb_force))
		force = rugged_parse_bool(rb_force);

	if (!NIL_P(rb_ref)) {
		Check_Type(rb_ref, T_STRING);
		notes_ref = StringValueCStr(rb_ref);
	}

	rb_message = rb_hash_aref(rb_data, CSTR2SYM("message"));
	Check_Type(rb_message, T_STRING);

	committer = rugged_signature_get(
		rb_hash_aref(rb_data, CSTR2SYM("committer"))
	);

	author = rugged_signature_get(
		rb_hash_aref(rb_data, CSTR2SYM("author"))
	);

	error = git_note_create(
			&note_oid,
			repo,
			author,
			committer,
			notes_ref,
			git_object_id(target),
			StringValueCStr(rb_message),
			force);


	git_signature_free(author);
	git_signature_free(committer);

	rugged_exception_check(error);

	return rugged_create_oid(&note_oid);
}
Esempio n. 11
0
/*
 *  call-seq:
 *    Commit.create(repository, data = {}) -> oid
 *
 *  Write a new +Commit+ object to +repository+, 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+.
 *  - +:update_ref+ (optional): a +String+ with the name of a reference in the
 *    repository which should be updated to point to this commit (e.g. "HEAD")
 *
 *  When the commit is successfully written to disk, its +oid+ will be
 *  returned as a hex +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) #=> "f148106ca58764adc93ad4e2d6b1d168422b9796"
 */
static VALUE rb_git_commit_create(VALUE self, VALUE rb_repo, VALUE rb_data)
{
	VALUE rb_message, rb_tree, rb_parents, rb_ref;
	VALUE rb_err_obj = Qnil;
	int parent_count, i, error = 0;
	const git_commit **parents = NULL;
	git_commit **free_list = NULL;
	git_tree *tree;
	git_signature *author, *committer;
	git_oid commit_oid;
	git_repository *repo;
	const char *update_ref = NULL;

	Check_Type(rb_data, T_HASH);

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

	rb_ref = rb_hash_aref(rb_data, CSTR2SYM("update_ref"));
	if (!NIL_P(rb_ref)) {
		Check_Type(rb_ref, T_STRING);
		update_ref = StringValueCStr(rb_ref);
	}

	rb_message = rb_hash_aref(rb_data, CSTR2SYM("message"));
	Check_Type(rb_message, T_STRING);

	committer = rugged_signature_get(
		rb_hash_aref(rb_data, CSTR2SYM("committer")), repo
	);

	author = rugged_signature_get(
		rb_hash_aref(rb_data, CSTR2SYM("author")), repo
	);

	rb_parents = rb_hash_aref(rb_data, CSTR2SYM("parents"));
	Check_Type(rb_parents, T_ARRAY);

	rb_tree = rb_hash_aref(rb_data, CSTR2SYM("tree"));
	tree = (git_tree *)rugged_object_get(repo, rb_tree, GIT_OBJ_TREE);

	parents = alloca(RARRAY_LEN(rb_parents) * sizeof(void *));
	free_list = alloca(RARRAY_LEN(rb_parents) * sizeof(void *));
	parent_count = 0;

	for (i = 0; i < (int)RARRAY_LEN(rb_parents); ++i) {
		VALUE p = rb_ary_entry(rb_parents, i);
		git_commit *parent = NULL;
		git_commit *free_ptr = NULL;

		if (NIL_P(p))
			continue;

		if (TYPE(p) == T_STRING) {
			git_oid oid;

			error = git_oid_fromstr(&oid, StringValueCStr(p));
			if (error < GIT_OK)
				goto cleanup;

			error = git_commit_lookup(&parent, repo, &oid);
			if (error < GIT_OK)
				goto cleanup;

			free_ptr = parent;

		} else if (rb_obj_is_kind_of(p, rb_cRuggedCommit)) {
			Data_Get_Struct(p, git_commit, parent);
		} else {
			rb_err_obj = rb_exc_new2(rb_eTypeError, "Invalid type for parent object");
			goto cleanup;
		}

		parents[parent_count] = parent;
		free_list[parent_count] = free_ptr;
		parent_count++;
	}

	error = git_commit_create(
		&commit_oid,
		repo,
		update_ref,
		author,
		committer,
		NULL,
		StringValueCStr(rb_message),
		tree,
		parent_count,
		parents);

cleanup:
	git_signature_free(author);
	git_signature_free(committer);

	git_object_free((git_object *)tree);

	for (i = 0; i < parent_count; ++i)
		git_object_free((git_object *)free_list[i]);

	if (!NIL_P(rb_err_obj))
		rb_exc_raise(rb_err_obj);

	rugged_exception_check(error);

	return rugged_create_oid(&commit_oid);
}
Esempio n. 12
0
/*
 *  call-seq:
 *    commit.amend(data = {}) -> oid
 *
 *  Amend a commit object, 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
 *  - +:tree+: the tree for this amended commit, represented as a <tt>Rugged::Tree</tt>
 *    instance or an OID +String+.
 *  - +:update_ref+ (optional): a +String+ with the name of a reference in the
 *  repository which should be updated to point to this amended commit (e.g. "HEAD")
 *
 *  When the amended commit is successfully written to disk, its +oid+ will be
 *  returned as a hex +String+.
 *
 *    author = {:email=>"*****@*****.**", :time=>Time.now, :name=>"Vicent Mart\303\255"}
 *
 *    commit.amend(
 *      :author => author,
 *      :message => "Updated Hello world\n\n",
 *      :committer => author,
 *      :tree => some_tree) #=> "f148106ca58764adc93ad4e2d6b1d168422b9796"
 */
static VALUE rb_git_commit_amend(VALUE self, VALUE rb_data)
{
	VALUE rb_message, rb_tree, rb_ref, owner;
	int error = 0;
	git_commit *commit_to_amend;
	char *message = NULL;
	git_tree *tree = NULL;
	git_signature *author = NULL, *committer = NULL;
	git_oid commit_oid;
	git_repository *repo;
	const char *update_ref = NULL;

	Check_Type(rb_data, T_HASH);

	Data_Get_Struct(self, git_commit, commit_to_amend);

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

	rb_ref = rb_hash_aref(rb_data, CSTR2SYM("update_ref"));
	if (!NIL_P(rb_ref)) {
		Check_Type(rb_ref, T_STRING);
		update_ref = StringValueCStr(rb_ref);
	}

	rb_message = rb_hash_aref(rb_data, CSTR2SYM("message"));
	if (!NIL_P(rb_message)) {
		Check_Type(rb_message, T_STRING);
		message = StringValueCStr(rb_message);
	}

	rb_tree = rb_hash_aref(rb_data, CSTR2SYM("tree"));
	if (!NIL_P(rb_tree))
		tree = (git_tree *)rugged_object_get(repo, rb_tree, GIT_OBJ_TREE);

	if (!NIL_P(rb_hash_aref(rb_data, CSTR2SYM("committer")))) {
		committer = rugged_signature_get(
			rb_hash_aref(rb_data, CSTR2SYM("committer")), repo
		);
	}

	if (!NIL_P(rb_hash_aref(rb_data, CSTR2SYM("author")))) {
		author = rugged_signature_get(
			rb_hash_aref(rb_data, CSTR2SYM("author")), repo
		);
	}

	error = git_commit_amend(
		&commit_oid,
		commit_to_amend,
		update_ref,
		author,
		committer,
		NULL,
		message,
		tree);

	git_signature_free(author);
	git_signature_free(committer);

	git_object_free((git_object *)tree);

	rugged_exception_check(error);

	return rugged_create_oid(&commit_oid);
}
Esempio n. 13
0
/**
 * Parse the commit options into something we can re-use
 *
 * Note that parents may be set even when the function errors, so make
 * sure to free this data.
 */
static VALUE parse_commit_options(struct commit_data *out, git_repository *repo, VALUE rb_data)
{
	VALUE rb_message, rb_tree, rb_parents, rb_ref;
	int error = 0, parent_count, i;

	rb_ref = rb_hash_aref(rb_data, CSTR2SYM("update_ref"));
	if (!NIL_P(rb_ref)) {
		Check_Type(rb_ref, T_STRING);
		out->update_ref = StringValueCStr(rb_ref);
	}

	rb_message = rb_hash_aref(rb_data, CSTR2SYM("message"));
	Check_Type(rb_message, T_STRING);
	out->message = StringValueCStr(rb_message);

	out->committer = rugged_signature_get(
		rb_hash_aref(rb_data, CSTR2SYM("committer")), repo
	);

	out->author = rugged_signature_get(
		rb_hash_aref(rb_data, CSTR2SYM("author")), repo
	);

	rb_parents = rb_hash_aref(rb_data, CSTR2SYM("parents"));
	Check_Type(rb_parents, T_ARRAY);

	rb_tree = rb_hash_aref(rb_data, CSTR2SYM("tree"));
	out->tree = (git_tree *)rugged_object_get(repo, rb_tree, GIT_OBJ_TREE);

	out->parents = xcalloc(RARRAY_LEN(rb_parents), sizeof(void *));
	parent_count = 0;

	for (i = 0; i < (int)RARRAY_LEN(rb_parents); ++i) {
		VALUE p = rb_ary_entry(rb_parents, i);
		git_commit *parent = NULL;
		git_commit *tmp = NULL;

		if (NIL_P(p))
			continue;

		if (TYPE(p) == T_STRING) {
			git_oid oid;

			error = git_oid_fromstr(&oid, StringValueCStr(p));
			if (error < GIT_OK)
				goto out;

			error = git_commit_lookup(&parent, repo, &oid);
			if (error < GIT_OK)
				goto out;
		} else if (rb_obj_is_kind_of(p, rb_cRuggedCommit)) {
			Data_Get_Struct(p, git_commit, tmp);
			if ((error = git_object_dup((git_object **) &parent, (git_object *) tmp)) < 0)
				goto out;
		} else {
			out->rb_err_obj = rb_exc_new2(rb_eTypeError, "Invalid type for parent object");
			error = -1;
			goto out;
		}

		out->parents[parent_count] = parent;
		parent_count++;
	}

out:
	out->parent_count = parent_count;
	return error;
}