Example #1
0
PyObject *
Remote_push(Remote *self, PyObject *args)
{
    git_push *push = NULL;
    const char *refspec = NULL;
    const char *msg = NULL;
    int err;

    if (!PyArg_ParseTuple(args, "s", &refspec))
        return NULL;

    err = git_push_new(&push, self->remote);
    if (err < 0)
        return Error_set(err);

    err = git_push_add_refspec(push, refspec);
    if (err < 0)
        goto error;

    err = git_push_finish(push);
    if (err < 0)
        goto error;

    if (!git_push_unpack_ok(push)) {
        git_push_free(push);
        PyErr_SetString(GitError, "Remote failed to unpack objects");
        return NULL;
    }

    err = git_push_status_foreach(push, push_status_foreach_callback, &msg);
    if (err < 0)
        goto error;
    if (msg != NULL) {
        git_push_free(push);
        PyErr_SetString(GitError, msg);
        return NULL;
    }

    err = git_push_update_tips(push);
    if (err < 0)
        goto error;

    git_push_free(push);
    Py_RETURN_NONE;

error:
    git_push_free(push);
    return Error_set(err);
}
Example #2
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;
}
Example #3
0
void Gitarre::onPushAction ()
{
	Repository *repo = Repos[RepoView->currentIndex().row()];
	 // TODO: Add remote selection

	git_remote *remote = repo->GetRemote(0);
	struct git_remote_callbacks cb = { 1,
										Gitarre::sRProgressCb,
										Gitarre::sRCompletionCb,
										Gitarre::sRCredentialsCb,
										Gitarre::sRTransferProgressCb,
										Gitarre::sRUpdateTipsCb,
										(void *)this
	};
	git_remote_set_callbacks (remote, &cb);

	// fix git protocol address
	const char *url = git_remote_url (remote);
	if (!strncmp (url, "git@", 4))
	{
		int len = strlen (url) - 4;
		char *_url = (char *) malloc (len + 9);
		strcpy (_url, "https://");
		strncpy (_url + 8, url + 4, len);
		_url [len + 8] = 0;
		char *sc = strrchr (_url, ':');
		if (sc)
			*sc = '/';
		git_remote_set_url (remote, _url);
	}

	StatusLabel->show();
	StatusLabel->setText ("Connecting to remote...");
	StatusProgress->show();
	StatusProgress->setRange (0,0);
	git_remote_connect (remote, GIT_DIRECTION_PUSH);
	if (git_remote_connected (remote))
	{
		git_push *push;
		git_push_new (&push, remote);
		git_push_add_refspec (push, "refs/heads/master:refs/heads/master");

		git_push_set_callbacks (push,
								Gitarre::sPPackbuilderProgressCb,
								(void *)this,
								Gitarre::sPTransferProgressCb,
								(void *)this);
		git_push_finish (push);
		if (git_push_unpack_ok (push))
		{
			git_push_status_foreach (push, Gitarre::sPStatusForeachCb, (void *)this);
			git_push_update_tips (push);
		}
		git_push_free (push);
		git_remote_disconnect (remote);
		git_remote_free (remote);
	}
	else
	{
		const git_error *error = giterr_last ();
		if (error->message)
			QMessageBox::warning(this, "Connect to remote", QString ("Failed to connect to ") + git_remote_url (remote) + " :\n" + error->message);
		else
			QMessageBox::warning(this, "Connect to remote", QString ("Failed to connect to ") + git_remote_url (remote));
	}
	StatusLabel->hide();
	StatusProgress->hide();
}