diff --git a/ext/rugged/rugged_repo.c b/ext/rugged/rugged_repo.c index 1f3aab3fd..2be7d7b1f 100644 --- a/ext/rugged/rugged_repo.c +++ b/ext/rugged/rugged_repo.c @@ -315,12 +315,42 @@ struct rugged_remote_cb_payload static int rugged__remote_transfer_progress_cb(const git_transfer_progress *stats, void *payload) { struct rugged_remote_cb_payload *remote_payload = payload; - VALUE args = rb_ary_new2(4); + VALUE args = rb_ary_new2(5); + rb_ary_push(args, remote_payload->transfer_progress); rb_ary_push(args, UINT2NUM(stats->total_objects)); rb_ary_push(args, UINT2NUM(stats->indexed_objects)); rb_ary_push(args, UINT2NUM(stats->received_objects)); rb_ary_push(args, INT2FIX(stats->received_bytes)); + + rb_protect(rugged__block_yield_splat, args, &remote_payload->exception); + + return remote_payload->exception ? GIT_ERROR : GIT_OK; +} + +static int rugged__remote_progress_cb(const char *str, int len, void *payload) +{ + struct rugged_remote_cb_payload *remote_payload = payload; + VALUE args = rb_ary_new2(2); + + rb_ary_push(args, remote_payload->progress); + rb_ary_push(args, rb_str_new(str, len)); + + rb_protect(rugged__block_yield_splat, args, &remote_payload->exception); + + return remote_payload->exception ? GIT_ERROR : GIT_OK; +} + +static int rugged__remote_update_tips_cb(const char *refname, const git_oid *a, const git_oid *b, void *payload) +{ + struct rugged_remote_cb_payload *remote_payload = payload; + VALUE args = rb_ary_new2(4); + + rb_ary_push(args, remote_payload->update_tips); + rb_ary_push(args, rb_str_new2(refname)); + rb_ary_push(args, rugged_create_oid(a)); + rb_ary_push(args, rugged_create_oid(b)); + rb_protect(rugged__block_yield_splat, args, &remote_payload->exception); return remote_payload->exception ? GIT_ERROR : GIT_OK; @@ -340,6 +370,15 @@ static void parse_clone_options(git_clone_options *ret, VALUE rb_options_hash, s git_remote_callbacks remote_callbacks = GIT_REMOTE_CALLBACKS_INIT; VALUE cb; + cb = rb_hash_aref(val, CSTR2SYM("progress")); + if (RTEST(cb)) { + if (!rb_respond_to(cb, rb_intern("call"))) { + rb_raise(rb_eArgError, "Expected a Proc or an object that responds to call (:progress)."); + } + remote_payload->progress = cb; + remote_callbacks.progress = rugged__remote_progress_cb; + } + cb = rb_hash_aref(val, CSTR2SYM("transfer_progress")); if (RTEST(cb)) { if (!rb_respond_to(cb, rb_intern("call"))) { @@ -350,6 +389,16 @@ static void parse_clone_options(git_clone_options *ret, VALUE rb_options_hash, s remote_callbacks.transfer_progress = rugged__remote_transfer_progress_cb; } + cb = rb_hash_aref(val, CSTR2SYM("update_tips")); + if (RTEST(cb)) { + if (!rb_respond_to(cb, rb_intern("call"))) { + rb_raise(rb_eArgError, "Expected a Proc or an object that responds to call (:update_tips)."); + } + + remote_payload->update_tips = cb; + remote_callbacks.update_tips = rugged__remote_update_tips_cb; + } + remote_callbacks.payload = remote_payload; ret->remote_callbacks = remote_callbacks; @@ -383,20 +432,15 @@ static void parse_clone_options(git_clone_options *ret, VALUE rb_options_hash, s * the clone operation. Possible callbacks are: * * :progress :: - * Not yet implemented. - * - * :completion :: - * Not yet implemented. - * - * :credentials :: - * Not yet implemented. + * A callback that will be executed with the textual progress from the remote. * * :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+ and +received_bytes+. * * :update_tips :: - * Not yet implemented. + * A callback that is called each time a reference is updated locally. It is passed the fully + * qualified +refname+, the previous +oid+, and the new oid. * * Example: * diff --git a/test/repo_test.rb b/test/repo_test.rb index 6a5628391..9a2343de2 100644 --- a/test/repo_test.rb +++ b/test/repo_test.rb @@ -397,7 +397,7 @@ def test_clone_bare end end - def test_clone_with_progress + def test_clone_with_transfer_progress_callback total_objects = indexed_objects = received_objects = received_bytes = nil callsback = 0 repo = Rugged::Repository.clone_at(@source_path, @tmppath,{ @@ -416,6 +416,29 @@ def test_clone_with_progress assert_equal 1563, received_bytes end + def test_clone_with_update_tips_callback + calls = 0 + updated_tips = {} + + repo = Rugged::Repository.clone_at(@source_path, @tmppath, { + callbacks: { + update_tips: lambda { |refname, a, b| + calls += 1 + updated_tips[refname] = [a, b] + } + } + }) + repo.close + + assert_equal 4, calls + assert_equal({ + "refs/remotes/origin/master" => ["0000000000000000000000000000000000000000", "36060c58702ed4c2a40832c51758d5344201d89a"], + "refs/remotes/origin/packed" => ["0000000000000000000000000000000000000000", "41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9"], + "refs/tags/v0.9" => ["0000000000000000000000000000000000000000", "5b5b025afb0b4c913b4c338a42934a3863bf3644"], + "refs/tags/v1.0" => ["0000000000000000000000000000000000000000", "0c37a5391bbff43c37f0d0371823a5509eed5b1d"], + }, updated_tips) + end + def test_clone_quits_on_error begin Rugged::Repository.clone_at(@source_path, @tmppath, :callbacks => {