Skip to content

Commit f6add44

Browse files
author
Edward Thomson
committed
Teach Rugged::Blob.merge_files to look up by oid
Accept an optional `oid` parameter that `merge_files` will use to look up the file contents to merge.
1 parent 3e30f9e commit f6add44

File tree

2 files changed

+111
-32
lines changed

2 files changed

+111
-32
lines changed

ext/rugged/rugged_blob.c

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -551,55 +551,105 @@ static VALUE rb_git_blob_to_buffer(int argc, VALUE *argv, VALUE self)
551551
return rb_ret;
552552
}
553553

554-
static void rugged_parse_merge_file_input(git_merge_file_input *input, VALUE rb_input)
554+
#define RUGGED_MERGE_FILE_INPUT_INIT { GIT_MERGE_FILE_INPUT_INIT }
555+
556+
typedef struct {
557+
git_merge_file_input parent;
558+
int has_id;
559+
git_oid id;
560+
} rugged_merge_file_input;
561+
562+
static void rugged_parse_merge_file_input(rugged_merge_file_input *input, git_repository *repo, VALUE rb_input)
555563
{
556564
VALUE rb_value;
557565

558566
Check_Type(rb_input, T_HASH);
559567

560-
rb_value = rb_hash_aref(rb_input, CSTR2SYM("content"));
561-
if (NIL_P(rb_value))
562-
rb_raise(rb_eArgError, "File input must have `:content`.");
568+
if (!NIL_P(rb_value = rb_hash_aref(rb_input, CSTR2SYM("content")))) {
569+
input->parent.ptr = RSTRING_PTR(rb_value);
570+
input->parent.size = RSTRING_LEN(rb_value);
571+
} else if (!NIL_P(rb_value = rb_hash_aref(rb_input, CSTR2SYM("oid")))) {
572+
if (!repo)
573+
rb_raise(rb_eArgError, "Rugged repository is required when file input is `:oid`.");
563574

564-
input->ptr = RSTRING_PTR(rb_value);
565-
input->size = RSTRING_LEN(rb_value);
575+
rugged_exception_check(git_oid_fromstr(&input->id, RSTRING_PTR(rb_value)));
576+
input->has_id = 1;
577+
} else {
578+
rb_raise(rb_eArgError, "File input must have `:content` or `:oid`.");
579+
}
566580

567581
rb_value = rb_hash_aref(rb_input, CSTR2SYM("filemode"));
568582
if (!NIL_P(rb_value))
569-
input->mode = FIX2UINT(rb_value);
583+
input->parent.mode = FIX2UINT(rb_value);
570584

571585
rb_value = rb_hash_aref(rb_input, CSTR2SYM("path"));
572586
if (!NIL_P(rb_value)) {
573587
Check_Type(rb_value, T_STRING);
574-
input->path = RSTRING_PTR(rb_value);
588+
input->parent.path = RSTRING_PTR(rb_value);
575589
}
576590
}
577591

592+
static int rugged_load_merge_file_input(git_blob **out, git_repository *repo, rugged_merge_file_input *input)
593+
{
594+
int error;
595+
596+
if (!input->has_id)
597+
return 0;
598+
599+
if ((error = git_blob_lookup(out, repo, &input->id)) < 0)
600+
return error;
601+
602+
input->parent.ptr = git_blob_rawcontent(*out);
603+
input->parent.size = git_blob_rawsize(*out);
604+
605+
return 0;
606+
}
607+
578608
static VALUE rb_git_blob_merge_files(int argc, VALUE *argv, VALUE klass)
579609
{
580-
VALUE rb_ancestor, rb_ours, rb_theirs, rb_options, rb_result;
610+
VALUE rb_repo, rb_ancestor, rb_ours, rb_theirs, rb_options, rb_result;
581611

582-
git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT,
583-
ours = GIT_MERGE_FILE_INPUT_INIT,
584-
theirs = GIT_MERGE_FILE_INPUT_INIT;
612+
git_repository *repo = NULL;
613+
rugged_merge_file_input ancestor = RUGGED_MERGE_FILE_INPUT_INIT,
614+
ours = RUGGED_MERGE_FILE_INPUT_INIT,
615+
theirs = RUGGED_MERGE_FILE_INPUT_INIT;
616+
git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL;
585617
git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT;
586618
git_merge_file_result result = {0};
587619
int error;
588620

589-
rb_scan_args(argc, argv, "31", &rb_ancestor, &rb_ours, &rb_theirs, &rb_options);
621+
rb_scan_args(argc, argv, "41", &rb_repo, &rb_ancestor, &rb_ours, &rb_theirs, &rb_options);
590622

591-
rugged_parse_merge_file_input(&ancestor, rb_ancestor);
592-
rugged_parse_merge_file_input(&ours, rb_ours);
593-
rugged_parse_merge_file_input(&theirs, rb_theirs);
623+
if (!NIL_P(rb_repo)) {
624+
rugged_check_repo(rb_repo);
625+
Data_Get_Struct(rb_repo, git_repository, repo);
626+
}
594627

595628
if (!NIL_P(rb_options))
596629
rugged_parse_merge_file_options(&opts, rb_options);
597630

598-
rugged_exception_check(git_merge_file(&result, &ancestor, &ours, &theirs, &opts));
631+
if (!NIL_P(rb_ancestor))
632+
rugged_parse_merge_file_input(&ancestor, repo, rb_ancestor);
633+
if (!NIL_P(rb_ours))
634+
rugged_parse_merge_file_input(&ours, repo, rb_ours);
635+
if (!NIL_P(rb_theirs))
636+
rugged_parse_merge_file_input(&theirs, repo, rb_theirs);
637+
638+
if ((error = rugged_load_merge_file_input(&ancestor_blob, repo, &ancestor)) < 0 ||
639+
(error = rugged_load_merge_file_input(&our_blob, repo, &ours)) < 0 ||
640+
(error = rugged_load_merge_file_input(&their_blob, repo, &theirs)) < 0 ||
641+
(error = git_merge_file(&result, &ancestor.parent, &ours.parent, &theirs.parent, &opts)) < 0)
642+
goto done;
599643

600644
rb_result = rb_merge_file_result_fromC(&result);
645+
646+
done:
647+
git_blob_free(ancestor_blob);
648+
git_blob_free(our_blob);
649+
git_blob_free(their_blob);
601650
git_merge_file_result_free(&result);
602651

652+
rugged_exception_check(error);
603653
return rb_result;
604654
}
605655

test/blob_test.rb

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -122,28 +122,57 @@ def test_blob_text_set_encoding
122122
blob = @repo.lookup(oid)
123123
assert_equal Encoding::ASCII_8BIT, blob.text(0, Encoding::ASCII_8BIT).encoding
124124
end
125+
end
126+
127+
class BlobMergeTest < Rugged::TestCase
128+
def setup
129+
@source_repo = FixtureRepo.from_rugged("testrepo.git")
130+
@repo = FixtureRepo.clone(@source_repo)
131+
132+
@ancestor_content = "Common ancestor"
133+
@our_content = "Ours side"
134+
@their_content = "Theirs side"
135+
136+
@expected_data = "<<<<<<< OURS\nOurs side\n" +
137+
"||||||| ANCESTOR\nCommon ancestor\n" +
138+
"=======\n" +
139+
"Theirs side\n>>>>>>> THEIRS\n"
140+
141+
@opts = {
142+
:ancestor_label => "ANCESTOR",
143+
:our_label => "OURS",
144+
:their_label => "THEIRS",
145+
:style => :diff3 }
146+
end
125147

126148
def test_blob_merge_files
127-
ancestor = { :content => "Common ancestor", :path => "file.txt", :filemode => 0100644 }
128-
ours = { :content => "Ours side", :path => "newfile.txt", :filemode => 0100644 }
129-
theirs = { :content => "Theirs side", :path => "file.txt", :filemode => 0100755 }
149+
ancestor = { :content => @ancestor_content, :path => "file.txt", :filemode => 0100644 }
150+
ours = { :content => @our_content, :path => "newfile.txt", :filemode => 0100644 }
151+
theirs = { :content => @their_content, :path => "file.txt", :filemode => 0100755 }
130152

131-
result = Rugged::Blob.merge_files(ancestor, ours, theirs,
132-
{ :ancestor_label => "ANCESTOR",
133-
:our_label => "OURS",
134-
:their_label => "THEIRS",
135-
:style => :diff3 })
153+
result = Rugged::Blob.merge_files(nil, ancestor, ours, theirs, @opts)
136154

137155
assert_equal false, result[:automergeable]
138156
assert_equal "newfile.txt", result[:path]
139157
assert_equal 0100755, result[:filemode]
140-
assert_equal "<<<<<<< OURS\n" +
141-
"Ours side\n" +
142-
"||||||| ANCESTOR\n" +
143-
"Common ancestor\n" +
144-
"=======\n" +
145-
"Theirs side\n" +
146-
">>>>>>> THEIRS\n", result[:data]
158+
assert_equal @expected_data, result[:data]
159+
end
160+
161+
def test_blob_merge_files_by_oid
162+
ancestor_oid = Rugged::Blob.from_buffer(@repo, @ancestor_content)
163+
our_oid = Rugged::Blob.from_buffer(@repo, @our_content)
164+
their_oid = Rugged::Blob.from_buffer(@repo, @their_content)
165+
166+
ancestor = { :oid => ancestor_oid, :path => "file.txt", :filemode => 0100644 }
167+
ours = { :oid => our_oid, :path => "newfile.txt", :filemode => 0100644 }
168+
theirs = { :oid => their_oid, :path => "file.txt", :filemode => 0100755 }
169+
170+
result = Rugged::Blob.merge_files(@repo, ancestor, ours, theirs, @opts)
171+
172+
assert_equal false, result[:automergeable]
173+
assert_equal "newfile.txt", result[:path]
174+
assert_equal 0100755, result[:filemode]
175+
assert_equal @expected_data, result[:data]
147176
end
148177
end
149178

0 commit comments

Comments
 (0)