Beispiel #1
0
static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fetchhead)
{
	git_remote *remote;
	git_buf fetchhead_buf = GIT_BUF_INIT;
	int equals = 0;

	cl_git_pass(git_remote_load(&remote, g_repo, "origin"));
	git_remote_set_autotag(remote, GIT_REMOTE_DOWNLOAD_TAGS_AUTO);

	if(fetchspec != NULL) {
		git_remote_clear_refspecs(remote);
		git_remote_add_fetch(remote, fetchspec);
	}

	cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH));
	cl_git_pass(git_remote_download(remote));
	cl_git_pass(git_remote_update_tips(remote, NULL, NULL));
	git_remote_disconnect(remote);
	git_remote_free(remote);

	cl_git_pass(git_futils_readbuffer(&fetchhead_buf, "./foo/.git/FETCH_HEAD"));

	equals = (strcmp(fetchhead_buf.ptr, expected_fetchhead) == 0);

	git_buf_free(&fetchhead_buf);

	cl_assert(equals);
}
Beispiel #2
0
static int remote_mirror_cb(git_remote **out, git_repository *repo,
                            const char *name, const char *url, void *payload)
{
    int error;
    git_remote *remote;
    git_remote_callbacks *callbacks = (git_remote_callbacks *) payload;


    if ((error = git_remote_create(&remote, repo, name, url)) < 0)
        return error;

    if ((error = git_remote_set_callbacks(remote, callbacks)) < 0) {
        git_remote_free(remote);
        return error;
    }

    git_remote_clear_refspecs(remote);

    if ((error = git_remote_add_fetch(remote, "+refs/*:refs/*")) < 0) {
        git_remote_free(remote);
        return error;
    }

    *out = remote;
    return 0;
}
Beispiel #3
0
void test_network_fetchlocal__clone_into_mirror(void)
{
	git_buf path = GIT_BUF_INIT;
	git_repository *repo;
	git_remote *remote;
	git_reference *head;

	cl_git_pass(git_repository_init(&repo, "./foo.git", true));
	cl_git_pass(git_remote_create(&remote, repo, "origin", cl_git_fixture_url("testrepo.git")));

	git_remote_clear_refspecs(remote);
	cl_git_pass(git_remote_add_fetch(remote, "+refs/*:refs/*"));

	cl_git_pass(git_clone_into(repo, remote, NULL, NULL, NULL));

	cl_git_pass(git_reference_lookup(&head, repo, "HEAD"));
	cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head));
	cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head));

	git_remote_free(remote);
	git_reference_free(head);
	git_repository_free(repo);
	git_buf_free(&path);
	cl_fixture_cleanup("./foo.git");
}
Beispiel #4
0
void test_online_clone__clone_mirror(void)
{
	git_buf path = GIT_BUF_INIT;
	git_remote *remote;
	git_reference *head;
	git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;

	bool fetch_progress_cb_was_called = false;

	cl_git_pass(git_repository_init(&g_repo, "./foo.git", true));
	cl_git_pass(git_remote_create(&remote, g_repo, "origin", LIVE_REPO_URL));

	callbacks.transfer_progress = &fetch_progress;
	callbacks.payload = &fetch_progress_cb_was_called;
	git_remote_set_callbacks(remote, &callbacks);

	git_remote_clear_refspecs(remote);
	cl_git_pass(git_remote_add_fetch(remote, "+refs/*:refs/*"));

	cl_git_pass(git_clone_into(g_repo, remote, NULL, NULL, NULL));

	cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD"));
	cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head));
	cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head));

	cl_assert_equal_i(true, fetch_progress_cb_was_called);

	git_remote_free(remote);
	git_reference_free(head);
	git_buf_free(&path);
	git_repository_free(g_repo);
	g_repo = NULL;

	cl_fixture_cleanup("./foo.git");
}
Beispiel #5
0
/*
 *  call-seq:
 *    remote.clear_refspecs -> nil
 *
 *  Remove all configured fetch and push refspecs from the remote.
 */
static VALUE rb_git_remote_clear_refspecs(VALUE self)
{
	git_remote *remote;

	Data_Get_Struct(self, git_remote, remote);

	git_remote_clear_refspecs(remote);

	return Qnil;
}
Beispiel #6
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;
}
Beispiel #7
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;
}