Skip to content

Commit 7fea733

Browse files
committed
commit: extract the option parsing into its own function
1 parent 884f367 commit 7fea733

File tree

1 file changed

+109
-78
lines changed

1 file changed

+109
-78
lines changed

ext/rugged/rugged_commit.c

Lines changed: 109 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -338,86 +338,60 @@ static VALUE rb_git_commit_amend(VALUE self, VALUE rb_data)
338338
return rugged_create_oid(&commit_oid);
339339
}
340340

341-
/*
342-
* call-seq:
343-
* Commit.create(repository, data = {}) -> oid
344-
*
345-
* Write a new +Commit+ object to +repository+, with the given +data+
346-
* arguments, passed as a +Hash+:
347-
*
348-
* - +:message+: a string with the full text for the commit's message
349-
* - +:committer+ (optional): a hash with the signature for the committer,
350-
* defaults to the signature from the configuration
351-
* - +:author+ (optional): a hash with the signature for the author,
352-
* defaults to the signature from the configuration
353-
* - +:parents+: an +Array+ with zero or more parents for this commit,
354-
* represented as <tt>Rugged::Commit</tt> instances, or OID +String+.
355-
* - +:tree+: the tree for this commit, represented as a <tt>Rugged::Tree</tt>
356-
* instance or an OID +String+.
357-
* - +:update_ref+ (optional): a +String+ with the name of a reference in the
358-
* repository which should be updated to point to this commit (e.g. "HEAD")
359-
*
360-
* When the commit is successfully written to disk, its +oid+ will be
361-
* returned as a hex +String+.
362-
*
363-
* author = {:email=>"[email protected]", :time=>Time.now, :name=>"Vicent Mart\303\255"}
341+
struct commit_data {
342+
VALUE rb_err_obj;
343+
344+
const char *update_ref;
345+
const char *message;
346+
git_tree *tree;
347+
git_signature *author;
348+
git_signature *committer;
349+
int parent_count;
350+
const git_commit **parents;
351+
};
352+
353+
/**
354+
* Parse the commit options into something we can re-use
364355
*
365-
* Rugged::Commit.create(r,
366-
* :author => author,
367-
* :message => "Hello world\n\n",
368-
* :committer => author,
369-
* :parents => ["2cb831a8aea28b2c1b9c63385585b864e4d3bad1"],
370-
* :tree => some_tree) #=> "f148106ca58764adc93ad4e2d6b1d168422b9796"
356+
* Note that parents may be set even when the function errors, so make
357+
* sure to free this data.
371358
*/
372-
static VALUE rb_git_commit_create(VALUE self, VALUE rb_repo, VALUE rb_data)
359+
static VALUE parse_commit_options(struct commit_data *out, git_repository *repo, VALUE rb_data)
373360
{
374361
VALUE rb_message, rb_tree, rb_parents, rb_ref;
375-
VALUE rb_err_obj = Qnil;
376-
int parent_count, i, error = 0;
377-
const git_commit **parents = NULL;
378-
git_commit **free_list = NULL;
379-
git_tree *tree;
380-
git_signature *author, *committer;
381-
git_oid commit_oid;
382-
git_repository *repo;
383-
const char *update_ref = NULL;
384-
385-
Check_Type(rb_data, T_HASH);
386-
387-
rugged_check_repo(rb_repo);
388-
Data_Get_Struct(rb_repo, git_repository, repo);
362+
int error = 0, parent_count, i;
389363

390364
rb_ref = rb_hash_aref(rb_data, CSTR2SYM("update_ref"));
391365
if (!NIL_P(rb_ref)) {
392366
Check_Type(rb_ref, T_STRING);
393-
update_ref = StringValueCStr(rb_ref);
367+
out->update_ref = StringValueCStr(rb_ref);
394368
}
395369

396370
rb_message = rb_hash_aref(rb_data, CSTR2SYM("message"));
397371
Check_Type(rb_message, T_STRING);
372+
out->message = StringValueCStr(rb_message);
398373

399-
committer = rugged_signature_get(
374+
out->committer = rugged_signature_get(
400375
rb_hash_aref(rb_data, CSTR2SYM("committer")), repo
401376
);
402377

403-
author = rugged_signature_get(
378+
out->author = rugged_signature_get(
404379
rb_hash_aref(rb_data, CSTR2SYM("author")), repo
405380
);
406381

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

410385
rb_tree = rb_hash_aref(rb_data, CSTR2SYM("tree"));
411-
tree = (git_tree *)rugged_object_get(repo, rb_tree, GIT_OBJ_TREE);
386+
out->tree = (git_tree *)rugged_object_get(repo, rb_tree, GIT_OBJ_TREE);
412387

413-
parents = alloca(RARRAY_LEN(rb_parents) * sizeof(void *));
414-
free_list = alloca(RARRAY_LEN(rb_parents) * sizeof(void *));
388+
out->parents = xcalloc(RARRAY_LEN(rb_parents), sizeof(void *));
415389
parent_count = 0;
416390

417391
for (i = 0; i < (int)RARRAY_LEN(rb_parents); ++i) {
418392
VALUE p = rb_ary_entry(rb_parents, i);
419393
git_commit *parent = NULL;
420-
git_commit *free_ptr = NULL;
394+
git_commit *tmp = NULL;
421395

422396
if (NIL_P(p))
423397
continue;
@@ -427,49 +401,106 @@ static VALUE rb_git_commit_create(VALUE self, VALUE rb_repo, VALUE rb_data)
427401

428402
error = git_oid_fromstr(&oid, StringValueCStr(p));
429403
if (error < GIT_OK)
430-
goto cleanup;
404+
goto out;
431405

432406
error = git_commit_lookup(&parent, repo, &oid);
433407
if (error < GIT_OK)
434-
goto cleanup;
435-
436-
free_ptr = parent;
437-
408+
goto out;
438409
} else if (rb_obj_is_kind_of(p, rb_cRuggedCommit)) {
439-
Data_Get_Struct(p, git_commit, parent);
410+
Data_Get_Struct(p, git_commit, tmp);
411+
if ((error = git_object_dup((git_object **) &parent, (git_object *) tmp)) < 0)
412+
goto out;
440413
} else {
441-
rb_err_obj = rb_exc_new2(rb_eTypeError, "Invalid type for parent object");
442-
goto cleanup;
414+
out->rb_err_obj = rb_exc_new2(rb_eTypeError, "Invalid type for parent object");
415+
error = -1;
416+
goto out;
443417
}
444418

445-
parents[parent_count] = parent;
446-
free_list[parent_count] = free_ptr;
419+
out->parents[parent_count] = parent;
447420
parent_count++;
448421
}
449422

423+
out:
424+
out->parent_count = parent_count;
425+
return error;
426+
}
427+
428+
static void free_commit_options(struct commit_data *commit_data)
429+
{
430+
int i;
431+
432+
git_signature_free(commit_data->author);
433+
git_signature_free(commit_data->committer);
434+
435+
git_object_free((git_object *)commit_data->tree);
436+
437+
for (i = 0; i < commit_data->parent_count; ++i)
438+
git_object_free((git_object *) commit_data->parents[i]);
439+
xfree(commit_data->parents);
440+
}
441+
442+
/*
443+
* call-seq:
444+
* Commit.create(repository, data = {}) -> oid
445+
*
446+
* Write a new +Commit+ object to +repository+, with the given +data+
447+
* arguments, passed as a +Hash+:
448+
*
449+
* - +:message+: a string with the full text for the commit's message
450+
* - +:committer+ (optional): a hash with the signature for the committer,
451+
* defaults to the signature from the configuration
452+
* - +:author+ (optional): a hash with the signature for the author,
453+
* defaults to the signature from the configuration
454+
* - +:parents+: an +Array+ with zero or more parents for this commit,
455+
* represented as <tt>Rugged::Commit</tt> instances, or OID +String+.
456+
* - +:tree+: the tree for this commit, represented as a <tt>Rugged::Tree</tt>
457+
* instance or an OID +String+.
458+
* - +:update_ref+ (optional): a +String+ with the name of a reference in the
459+
* repository which should be updated to point to this commit (e.g. "HEAD")
460+
*
461+
* When the commit is successfully written to disk, its +oid+ will be
462+
* returned as a hex +String+.
463+
*
464+
* author = {:email=>"[email protected]", :time=>Time.now, :name=>"Vicent Mart\303\255"}
465+
*
466+
* Rugged::Commit.create(r,
467+
* :author => author,
468+
* :message => "Hello world\n\n",
469+
* :committer => author,
470+
* :parents => ["2cb831a8aea28b2c1b9c63385585b864e4d3bad1"],
471+
* :tree => some_tree) #=> "f148106ca58764adc93ad4e2d6b1d168422b9796"
472+
*/
473+
static VALUE rb_git_commit_create(VALUE self, VALUE rb_repo, VALUE rb_data)
474+
{
475+
int error = 0;
476+
struct commit_data commit_data = { Qnil };
477+
git_oid commit_oid;
478+
git_repository *repo;
479+
480+
Check_Type(rb_data, T_HASH);
481+
482+
rugged_check_repo(rb_repo);
483+
Data_Get_Struct(rb_repo, git_repository, repo);
484+
485+
if ((error = parse_commit_options(&commit_data, repo, rb_data)) < 0)
486+
goto cleanup;
487+
450488
error = git_commit_create(
451489
&commit_oid,
452490
repo,
453-
update_ref,
454-
author,
455-
committer,
491+
commit_data.update_ref,
492+
commit_data.author,
493+
commit_data.committer,
456494
NULL,
457-
StringValueCStr(rb_message),
458-
tree,
459-
parent_count,
460-
parents);
495+
commit_data.message,
496+
commit_data.tree,
497+
commit_data.parent_count,
498+
commit_data.parents);
461499

462500
cleanup:
463-
git_signature_free(author);
464-
git_signature_free(committer);
465-
466-
git_object_free((git_object *)tree);
467-
468-
for (i = 0; i < parent_count; ++i)
469-
git_object_free((git_object *)free_list[i]);
470-
471-
if (!NIL_P(rb_err_obj))
472-
rb_exc_raise(rb_err_obj);
501+
free_commit_options(&commit_data);
502+
if (!NIL_P(commit_data.rb_err_obj))
503+
rb_exc_raise(commit_data.rb_err_obj);
473504

474505
rugged_exception_check(error);
475506

0 commit comments

Comments
 (0)