예제 #1
0
/**
 * Default notes reference
 *
 * Get the default notes reference for a repository
 * @param repo S4 class git_repository
 * @return Character vector of length one with name of default
 * reference
 */
SEXP git2r_note_default_ref(SEXP repo)
{
    int err;
    SEXP result = R_NilValue;
    const char *ref;
    git_repository *repository = NULL;

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    err = git_note_default_ref(&ref, repository);
    if (GIT_OK != err)
        goto cleanup;

    PROTECT(result = allocVector(STRSXP, 1));
    SET_STRING_ELT(result, 0, mkChar(ref));

cleanup:
    if (repository)
        git_repository_free(repository);

    if (R_NilValue != result)
        UNPROTECT(1);

    if (GIT_OK != err)
        git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    return result;
}
예제 #2
0
/**
 * Fetch new data and update tips
 *
 * @param repo S4 class git_repository
 * @param name The name of the remote to fetch from
 * @param credentials The credentials for remote repository access.
 * @param msg The one line long message to be appended to the reflog
 * @return R_NilValue
 */
SEXP git2r_remote_fetch(
    SEXP repo,
    SEXP name,
    SEXP credentials,
    SEXP msg)
{
    int err;
    SEXP result = R_NilValue;
    const git_transfer_progress *stats;
    git_remote *remote = NULL;
    git_repository *repository = NULL;
    git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;

    if (git2r_arg_check_string(name))
        git2r_error(git2r_err_string_arg, __func__, "name");
    if (git2r_arg_check_credentials(credentials))
        git2r_error(git2r_err_credentials_arg, __func__, "credentials");
    if (git2r_arg_check_string(msg))
        git2r_error(git2r_err_string_arg, __func__, "msg");

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    err = git_remote_lookup(&remote, repository, CHAR(STRING_ELT(name, 0)));
    if (GIT_OK != err)
        goto cleanup;

    callbacks.credentials = &git2r_cred_acquire_cb;
    callbacks.payload = credentials;
    err = git_remote_set_callbacks(remote, &callbacks);
    if (GIT_OK != err)
        goto cleanup;

    err = git_remote_fetch(remote, NULL,  CHAR(STRING_ELT(msg, 0)));
    if (GIT_OK != err)
        goto cleanup;

    stats = git_remote_stats(remote);
    PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_transfer_progress")));
    git2r_transfer_progress_init(stats, result);

cleanup:
    if (remote) {
        if (git_remote_connected(remote))
            git_remote_disconnect(remote);
        git_remote_free(remote);
    }

    if (repository)
        git_repository_free(repository);

    if (R_NilValue != result)
        UNPROTECT(1);

    if (GIT_OK != err)
        git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    return result;
}
예제 #3
0
/**
 * Add a remote with the default fetch refspec to the repository's
 * configuration.
 *
 * @param repo S4 class git_repository
 * @param name The name of the remote
 * @param url The url of the remote
 * @return R_NilValue
 */
SEXP git2r_remote_add(SEXP repo, SEXP name, SEXP url)
{
    int err;
    git_repository *repository = NULL;
    git_remote *remote = NULL;

    if (git2r_arg_check_string(name))
        git2r_error(__func__, NULL, "'name'", git2r_err_string_arg);
    if (git2r_arg_check_string(url))
        git2r_error(__func__, NULL, "'url'", git2r_err_string_arg);

    if (!git_remote_is_valid_name(CHAR(STRING_ELT(name, 0))))
	git2r_error(__func__, NULL, git2r_err_invalid_remote, NULL);

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    err = git_remote_create(
        &remote,
        repository,
        CHAR(STRING_ELT(name, 0)),
        CHAR(STRING_ELT(url, 0)));

    if (remote)
	git_remote_free(remote);

    if (repository)
	git_repository_free(repository);

    if (err)
	git2r_error(__func__, giterr_last(), NULL, NULL);

    return R_NilValue;
}
예제 #4
0
/**
 * Give the remote a new name
 *
 * @param repo S4 class git_repository
 * @param oldname The old name of the remote
 * @param newname The new name of the remote
 * @return R_NilValue
 */
SEXP git2r_remote_rename(SEXP repo, SEXP oldname, SEXP newname)
{
    int err;
    git_strarray problems = {0};
    git_repository *repository = NULL;

    if (git2r_arg_check_string(oldname))
        git2r_error(git2r_err_string_arg, __func__, "oldname");
    if (git2r_arg_check_string(newname))
        git2r_error(git2r_err_string_arg, __func__, "newname");

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    err = git_remote_rename(
        &problems,
        repository,
        CHAR(STRING_ELT(oldname, 0)),
        CHAR(STRING_ELT(newname, 0)));
    if (GIT_OK != err)
	goto cleanup;

    git_strarray_free(&problems);

cleanup:
    if (repository)
	git_repository_free(repository);

    if (GIT_OK != err)
	git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    return R_NilValue;
}
예제 #5
0
/**
 * List stashes in a repository
 *
 * @param repo S3 class git_repository
 * @return VECXSP with S3 objects of class git_stash
 */
SEXP git2r_stash_list(SEXP repo)
{
    SEXP list = R_NilValue;
    int error, nprotect = 0;
    git2r_stash_list_cb_data cb_data = {0, R_NilValue, R_NilValue, NULL};
    git_repository *repository = NULL;

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    /* Count number of stashes before creating the list */
    error = git_stash_foreach(repository, &git2r_stash_list_cb, &cb_data);
    if (error)
        goto cleanup;

    PROTECT(list = Rf_allocVector(VECSXP, cb_data.n));
    nprotect++;
    cb_data.n = 0;
    cb_data.list = list;
    cb_data.repo = repo;
    cb_data.repository = repository;
    error = git_stash_foreach(repository, &git2r_stash_list_cb, &cb_data);

cleanup:
    git_repository_free(repository);

    if (nprotect)
        UNPROTECT(nprotect);

    if (error)
        git2r_error(__func__, GIT2R_ERROR_LAST(), NULL, NULL);

    return list;
}
예제 #6
0
/**
 * Add a remote with the default fetch refspec to the repository's
 * configuration.
 *
 * @param repo S4 class git_repository
 * @param name The name of the remote
 * @param url The url of the remote
 * @return R_NilValue
 */
SEXP git2r_remote_add(SEXP repo, SEXP name, SEXP url)
{
    int err;
    git_repository *repository = NULL;
    git_remote *remote = NULL;

    if (git2r_arg_check_string(name))
        git2r_error(git2r_err_string_arg, __func__, "name");
    if (git2r_arg_check_string(url))
        git2r_error(git2r_err_string_arg, __func__, "url");

    if (!git_remote_is_valid_name(CHAR(STRING_ELT(name, 0))))
	git2r_error("Error in '%s': Invalid remote name", __func__, NULL);

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    err = git_remote_create(&remote,
			    repository,
			    CHAR(STRING_ELT(name, 0)),
			    CHAR(STRING_ELT(url, 0)));

    if (remote)
	git_remote_free(remote);

    if (repository)
	git_repository_free(repository);

    if (GIT_OK != err)
	git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    return R_NilValue;
}
예제 #7
0
/**
 * Get the configured remotes for a repo
 *
 * @param repo S4 class git_repository
 * @return Character vector with name of the remotes
 */
SEXP git2r_remote_list(SEXP repo)
{
    int err;
    size_t i;
    git_strarray rem_list;
    SEXP list = R_NilValue;
    git_repository *repository;

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    err = git_remote_list(&rem_list, repository);
    if (err)
        goto cleanup;

    PROTECT(list = allocVector(STRSXP, rem_list.count));
    for (i = 0; i < rem_list.count; i++)
        SET_STRING_ELT(list, i, mkChar(rem_list.strings[i]));

cleanup:
    git_strarray_free(&rem_list);

    if (repository)
        git_repository_free(repository);

    if (R_NilValue != list)
        UNPROTECT(1);

    if (err)
        git2r_error(__func__, giterr_last(), NULL, NULL);

    return list;
}
예제 #8
0
/**
 * Give the remote a new name
 *
 * @param repo S4 class git_repository
 * @param oldname The old name of the remote
 * @param newname The new name of the remote
 * @return R_NilValue
 */
SEXP git2r_remote_rename(SEXP repo, SEXP oldname, SEXP newname)
{
    int err;
    git_strarray problems = {0};
    git_repository *repository = NULL;

    if (git2r_arg_check_string(oldname))
        git2r_error(__func__, NULL, "'oldname'", git2r_err_string_arg);
    if (git2r_arg_check_string(newname))
        git2r_error(__func__, NULL, "'newname'", git2r_err_string_arg);

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    err = git_remote_rename(
        &problems,
        repository,
        CHAR(STRING_ELT(oldname, 0)),
        CHAR(STRING_ELT(newname, 0)));
    if (err)
	goto cleanup;

    git_strarray_free(&problems);

cleanup:
    if (repository)
	git_repository_free(repository);

    if (err)
	git2r_error(__func__, giterr_last(), NULL, NULL);

    return R_NilValue;
}
예제 #9
0
/**
 * Remove the note for an object
 *
 * @param note S4 class git_note
 * @param author Signature of the notes commit author
 * @param committer Signature of the notes commit committer
 * @return R_NilValue
 */
SEXP git2r_note_remove(SEXP note, SEXP author, SEXP committer)
{
    int err;
    SEXP repo;
    SEXP annotated;
    git_oid note_oid;
    git_signature *sig_author = NULL;
    git_signature *sig_committer = NULL;
    git_repository *repository = NULL;

    if (git2r_arg_check_note(note))
        git2r_error(git2r_err_note_arg, __func__, "note");
    if (git2r_arg_check_signature(author))
        git2r_error(git2r_err_signature_arg, __func__, "author");
    if (git2r_arg_check_signature(committer))
        git2r_error(git2r_err_signature_arg, __func__, "committer");

    repo = GET_SLOT(note, Rf_install("repo"));
    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    err = git2r_signature_from_arg(&sig_author, author);
    if (GIT_OK != err)
        goto cleanup;

    err = git2r_signature_from_arg(&sig_committer, committer);
    if (GIT_OK != err)
        goto cleanup;

    annotated = GET_SLOT(note, Rf_install("annotated"));
    err = git_oid_fromstr(&note_oid, CHAR(STRING_ELT(annotated, 0)));
    if (GIT_OK != err)
        goto cleanup;

    err = git_note_remove(
              repository,
              CHAR(STRING_ELT(GET_SLOT(note, Rf_install("refname")), 0)),
              sig_author,
              sig_committer,
              &note_oid);

cleanup:
    if (sig_author)
        git_signature_free(sig_author);

    if (sig_committer)
        git_signature_free(sig_committer);

    if (repository)
        git_repository_free(repository);

    if (GIT_OK != err)
        git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    return R_NilValue;
}
예제 #10
0
/**
 * List all the notes within a specified namespace.
 *
 * @param repo S4 class git_repository
 * @param ref Optional reference to read from.
 * @return VECXSP with S4 objects of class git_note
 */
SEXP git2r_notes(SEXP repo, SEXP ref)
{
    int err;
    SEXP result = R_NilValue;
    const char *notes_ref = NULL;
    git2r_note_foreach_cb_data cb_data = {0, R_NilValue, R_NilValue, NULL, NULL};
    git_repository *repository = NULL;

    if (R_NilValue != ref) {
        if (git2r_arg_check_string(ref))
            git2r_error(git2r_err_string_arg, __func__, "ref");
        notes_ref = CHAR(STRING_ELT(ref, 0));
    }

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    if (NULL == notes_ref) {
        err = git_note_default_ref(&notes_ref, repository);
        if (GIT_OK != err)
            goto cleanup;
    }

    /* Count number of notes before creating the list */
    err = git_note_foreach(repository, notes_ref, &git2r_note_foreach_cb, &cb_data);
    if (GIT_OK != err) {
        if (GIT_ENOTFOUND == err) {
            err = GIT_OK;
            PROTECT(result = allocVector(VECSXP, 0));
        }

        goto cleanup;
    }

    PROTECT(result = allocVector(VECSXP, cb_data.n));
    cb_data.n = 0;
    cb_data.list = result;
    cb_data.repo = repo;
    cb_data.repository = repository;
    cb_data.notes_ref = notes_ref;
    err = git_note_foreach(repository, notes_ref, &git2r_note_foreach_cb, &cb_data);

cleanup:
    if (repository)
        git_repository_free(repository);

    if (R_NilValue != result)
        UNPROTECT(1);

    if (GIT_OK != err)
        git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    return result;
}
예제 #11
0
/**
 * Get head of repository
 *
 * @param repo S4 class git_repository
 * @return R_NilValue if unborn branch or not found. S4 class
 * git_branch if not a detached head. S4 class git_commit if detached
 * head
 */
SEXP git2r_repository_head(SEXP repo)
{
    int err;
    SEXP result = R_NilValue;
    git_commit *commit = NULL;
    git_reference *reference = NULL;
    git_repository *repository = NULL;

    repository= git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    err = git_repository_head(&reference, repository);
    if (GIT_OK != err) {
        if (GIT_EUNBORNBRANCH == err || GIT_ENOTFOUND == err)
            err = GIT_OK;
        goto cleanup;
    }

    if (git_reference_is_branch(reference)) {
        git_branch_t type = GIT_BRANCH_LOCAL;
        if (git_reference_is_remote(reference))
            type = GIT_BRANCH_REMOTE;
        PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_branch")));
        err = git2r_branch_init(reference, type, repo, result);
    } else {
        err = git_commit_lookup(
            &commit,
            repository,
            git_reference_target(reference));
        if (GIT_OK != err)
            goto cleanup;
        PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_commit")));
        git2r_commit_init(commit, repo, result);
    }

cleanup:
    if (commit)
        git_commit_free(commit);

    if (reference)
        git_reference_free(reference);

    if (repository)
        git_repository_free(repository);

    if (R_NilValue != result)
        UNPROTECT(1);

    if (GIT_OK != err)
        git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    return result;
}
예제 #12
0
/**
 * Parents of a commit
 *
 * @param commit S4 class git_commit
 * @return list of S4 class git_commit objects
 */
SEXP git2r_commit_parent_list(SEXP commit)
{
    int err;
    size_t i, n;
    SEXP repo;
    SEXP list = R_NilValue;
    git_commit *commit_obj = NULL;
    git_repository *repository = NULL;

    if (git2r_arg_check_commit(commit))
        git2r_error(git2r_err_commit_arg, __func__, "commit");

    repo = GET_SLOT(commit, Rf_install("repo"));
    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    err = git2r_commit_lookup(&commit_obj, repository, commit);
    if (GIT_OK != err)
        goto cleanup;

    n = git_commit_parentcount(commit_obj);
    PROTECT(list = allocVector(VECSXP, n));

    for (i = 0; i < n; i++) {
        git_commit *parent = NULL;
        SEXP item;

        err = git_commit_parent(&parent, commit_obj, i);
        if (GIT_OK != err)
            goto cleanup;

        SET_VECTOR_ELT(list, i, item = NEW_OBJECT(MAKE_CLASS("git_commit")));
        git2r_commit_init(parent, repo, item);
        git_commit_free(parent);
    }

cleanup:
    if (commit_obj)
        git_commit_free(commit_obj);

    if (repository)
        git_repository_free(repository);

    if (R_NilValue != list)
        UNPROTECT(1);

    if (GIT_OK != err)
        git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    return list;
}
예제 #13
0
파일: git2r_reflog.c 프로젝트: krlmlr/git2r
/**
 * List the reflog within a specified reference.
 *
 * @param repo S4 class git_repository
 * @param ref Reference to read from.
 * @return VECXSP with S4 objects of class git_reflog
 */
SEXP git2r_reflog_list(SEXP repo, SEXP ref)
{
    int err;
    size_t i, n;
    SEXP result = R_NilValue;
    git_reflog *reflog = NULL;
    git_repository *repository = NULL;

    if (git2r_arg_check_string(ref))
        git2r_error(__func__, NULL, "'ref'", git2r_err_string_arg);

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    err = git_reflog_read(&reflog, repository, CHAR(STRING_ELT(ref, 0)));
    if (err)
        goto cleanup;

    n = git_reflog_entrycount(reflog);
    PROTECT(result = allocVector(VECSXP, n));
    for (i = 0; i < n; i++) {
        const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, i);

        if (entry) {
            SEXP item;

            SET_VECTOR_ELT(result,
                           i,
                           item = NEW_OBJECT(MAKE_CLASS("git_reflog_entry")));
            git2r_reflog_entry_init(entry, i, repo, ref, item);
        }
    }

cleanup:
    if (reflog)
        git_reflog_free(reflog);

    if (repository)
        git_repository_free(repository);

    if (R_NilValue != result)
        UNPROTECT(1);

    if (err)
        git2r_error(__func__, giterr_last(), NULL, NULL);

    return result;
}
예제 #14
0
파일: git2r_graph.c 프로젝트: krlmlr/git2r
/**
 * Count the number of unique commits between two commit objects
 *
 * @param local The commit for local
 * @param upstream The commit for upstream
 * @return Integer vector of length two with the values ahead and
 * behind.
 */
SEXP git2r_graph_ahead_behind(SEXP local, SEXP upstream)
{
    size_t ahead, behind;
    int err;
    SEXP result = R_NilValue;
    SEXP slot;
    git_oid local_oid;
    git_oid upstream_oid;
    git_repository *repository = NULL;

    if (git2r_arg_check_commit(local))
        git2r_error(__func__, NULL, "'local'", git2r_err_commit_arg);
    if (git2r_arg_check_commit(upstream))
        git2r_error(__func__, NULL, "'upstream'", git2r_err_commit_arg);

    slot = GET_SLOT(local, Rf_install("repo"));
    repository = git2r_repository_open(slot);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    slot = GET_SLOT(local, Rf_install("sha"));
    git2r_oid_from_sha_sexp(slot, &local_oid);

    slot = GET_SLOT(upstream, Rf_install("sha"));
    git2r_oid_from_sha_sexp(slot, &upstream_oid);

    err = git_graph_ahead_behind(&ahead, &behind, repository, &local_oid,
                                 &upstream_oid);
    if (err)
        goto cleanup;

    PROTECT(result = allocVector(INTSXP, 2));
    INTEGER(result)[0] = ahead;
    INTEGER(result)[1] = behind;

cleanup:
    if (repository)
        git_repository_free(repository);

    if (R_NilValue != result)
        UNPROTECT(1);

    if (err)
        git2r_error(__func__, giterr_last(), NULL, NULL);

    return result;
}
예제 #15
0
/**
 * Get the remote's url
 *
 * @param repo S4 class git_repository
 * @param remote Character vector with name of remote. NA values are
 * ok and give NA values as result at corresponding index in url
 * vector
 * @return Character vector with url for each remote
 */
SEXP git2r_remote_url(SEXP repo, SEXP remote)
{
    int err = GIT_OK;
    SEXP url;
    size_t len;
    size_t i = 0;
    git_remote *tmp_remote;
    git_repository *repository = NULL;

    if (git2r_arg_check_string_vec(remote))
        git2r_error(__func__, NULL, "'remote'", git2r_err_string_vec_arg);

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    len = LENGTH(remote);
    PROTECT(url = allocVector(STRSXP, len));

    for (; i < len; i++) {
        if (NA_STRING == STRING_ELT(remote, i)) {
            SET_STRING_ELT(url, i, NA_STRING);
        } else {
            err = git_remote_lookup(
                &tmp_remote,
                repository,
                CHAR(STRING_ELT(remote, i)));
            if (err)
                goto cleanup;

            SET_STRING_ELT(url, i, mkChar(git_remote_url(tmp_remote)));
            git_remote_free(tmp_remote);
        }
    }

cleanup:
    if (repository)
        git_repository_free(repository);

    UNPROTECT(1);

    if (err)
        git2r_error(__func__, giterr_last(), NULL, NULL);

    return url;
}
예제 #16
0
/**
 * Get the tree pointed to by a commit
 *
 * @param commit S4 class git_commit or git_stash
 * @return S4 class git_tree
 */
SEXP git2r_commit_tree(SEXP commit)
{
    int err;
    SEXP result = R_NilValue;
    SEXP repo;
    git_commit *commit_obj = NULL;
    git_repository *repository = NULL;
    git_tree *tree = NULL;

    if (git2r_arg_check_commit(commit))
        git2r_error(git2r_err_commit_arg, __func__, "commit");

    repo = GET_SLOT(commit, Rf_install("repo"));
    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    err = git2r_commit_lookup(&commit_obj, repository, commit);
    if (GIT_OK != err)
        goto cleanup;

    err = git_commit_tree(&tree, commit_obj);
    if (GIT_OK != err)
        goto cleanup;

    PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_tree")));
    git2r_tree_init((git_tree*)tree, repo, result);

cleanup:
    if (commit_obj)
        git_commit_free(commit_obj);

    if (tree)
        git_tree_free(tree);

    if (repository)
        git_repository_free(repository);

    if (R_NilValue != result)
        UNPROTECT(1);

    if (GIT_OK != err)
        git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    return result;
}
예제 #17
0
/**
 * Get all tags that can be found in a repository.
 *
 * @param repo S4 class git_repository
 * @return VECXSP with S4 objects of class git_tag
 */
SEXP git2r_tag_list(SEXP repo)
{
    int err;
    SEXP result = R_NilValue;
    git2r_tag_foreach_cb_data cb_data = {0, NULL, R_NilValue, R_NilValue};
    git_repository *repository;

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    /* Count number of tags before creating the list */
    err = git_tag_foreach(repository, &git2r_tag_foreach_cb, &cb_data);
    if (err) {
        if (GIT_ENOTFOUND == err) {
            err = 0;
            PROTECT(result = allocVector(VECSXP, 0));
            setAttrib(result, R_NamesSymbol, allocVector(STRSXP, 0));
        }

        goto cleanup;
    }

    PROTECT(result = allocVector(VECSXP, cb_data.n));
    setAttrib(result, R_NamesSymbol, allocVector(STRSXP, cb_data.n));

    cb_data.n = 0;
    cb_data.tags = result;
    cb_data.repo = repo;
    cb_data.repository = repository;

    err = git_tag_foreach(repository, &git2r_tag_foreach_cb, &cb_data);

cleanup:
    if (repository)
        git_repository_free(repository);

    if (R_NilValue != result)
        UNPROTECT(1);

    if (err)
        git2r_error(__func__, giterr_last(), NULL, NULL);

    return result;
}
예제 #18
0
파일: git2r_graph.c 프로젝트: krlmlr/git2r
/**
 * Determine if a commit is the descendant of another commit.
 *
 * @param commit A commit.
 * @param ancestor A potential ancestor commit.
 * @return TRUE or FALSE
 */
SEXP git2r_graph_descendant_of(SEXP commit, SEXP ancestor)
{
    int err;
    SEXP slot;
    SEXP result = R_NilValue;
    git_oid commit_oid;
    git_oid ancestor_oid;
    git_repository *repository = NULL;

    if (git2r_arg_check_commit(commit))
        git2r_error(__func__, NULL, "'commit'", git2r_err_commit_arg);
    if (git2r_arg_check_commit(ancestor))
        git2r_error(__func__, NULL, "'ancestor'", git2r_err_commit_arg);

    slot = GET_SLOT(commit, Rf_install("repo"));
    repository = git2r_repository_open(slot);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    slot = GET_SLOT(commit, Rf_install("sha"));
    git2r_oid_from_sha_sexp(slot, &commit_oid);

    slot = GET_SLOT(ancestor, Rf_install("sha"));
    git2r_oid_from_sha_sexp(slot, &ancestor_oid);

    err = git_graph_descendant_of(repository, &commit_oid, &ancestor_oid);
    if (0 > err || 1 < err)
        goto cleanup;

    PROTECT(result = allocVector(LGLSXP, 1));
    LOGICAL(result)[0] = err;
    err = GIT_OK;

cleanup:
    if (repository)
        git_repository_free(repository);

    if (R_NilValue != result)
        UNPROTECT(1);

    if (err)
        git2r_error(__func__, giterr_last(), NULL, NULL);

    return result;
}
예제 #19
0
/**
 * Get entries in FETCH_HEAD file
 *
 * @param repo S4 class git_repository
 * @return list with the S4 class git_fetch_head entries. R_NilValue
 * if there is no FETCH_HEAD file.
 */
SEXP git2r_repository_fetch_heads(SEXP repo)
{
    int err;
    SEXP result = R_NilValue;
    git2r_fetch_head_cb_data cb_data = {0, R_NilValue, R_NilValue};
    git_repository *repository = NULL;

    repository= git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    /* Count number of fetch heads before creating the list */
    err = git_repository_fetchhead_foreach(
        repository,
        git2r_repository_fetchhead_foreach_cb,
        &cb_data);

    if (GIT_OK != err) {
        if (GIT_ENOTFOUND == err)
            err = GIT_OK;
        goto cleanup;
    }

    PROTECT(result = allocVector(VECSXP, cb_data.n));
    cb_data.n = 0;
    cb_data.list = result;
    cb_data.repo = repo;
    err = git_repository_fetchhead_foreach(
        repository,
        git2r_repository_fetchhead_foreach_cb,
        &cb_data);

cleanup:
    if (repository)
        git_repository_free(repository);

    if (R_NilValue != result)
        UNPROTECT(1);

    if (GIT_OK != err)
        git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    return result;
}
예제 #20
0
/**
 * Remove a stash from the stash list
 *
 * @param repo S3 class git_repository that contains the stash
 * @param index The index to the stash. 0 is the most recent stash.
 * @return R_NilValue
 */
SEXP git2r_stash_drop(SEXP repo, SEXP index)
{
    int error;
    git_repository *repository = NULL;

    if (git2r_arg_check_integer_gte_zero(index))
        git2r_error(__func__, NULL, "'index'", git2r_err_integer_gte_zero_arg);

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    error = git_stash_drop(repository, INTEGER(index)[0]);
    git_repository_free(repository);
    if (error)
        git2r_error(__func__, GIT2R_ERROR_LAST(), NULL, NULL);

    return R_NilValue;
}
예제 #21
0
/**
 * Get workdir of repository.
 *
 * @param repo S4 class git_repository
 * @return R_NilValue if bare repository, else character vector
 * of length one with path.
 */
SEXP git2r_repository_workdir(SEXP repo)
{
    SEXP result = R_NilValue;
    git_repository *repository;

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    if (!git_repository_is_bare(repository)) {
        const char *wd = git_repository_workdir(repository);
        PROTECT(result = allocVector(STRSXP, 1));
        SET_STRING_ELT(result, 0, mkChar(wd));
        UNPROTECT(1);
    }

    git_repository_free(repository);

    return result;
}
예제 #22
0
/**
 * Make the repository HEAD directly point to the commit.
 *
 * @param commit S4 class git_commit
 * @return R_NilValue
 */
SEXP git2r_repository_set_head_detached(SEXP commit)
{
    int err;
    SEXP sha;
    git_oid oid;
    git_commit *treeish = NULL;
    git_repository *repository = NULL;

    if (git2r_arg_check_commit(commit))
        git2r_error(git2r_err_commit_arg, __func__, "commit");

    repository = git2r_repository_open(GET_SLOT(commit, Rf_install("repo")));
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    sha = GET_SLOT(commit, Rf_install("sha"));
    err = git_oid_fromstr(&oid, CHAR(STRING_ELT(sha, 0)));
    if (GIT_OK != err)
        goto cleanup;

    err = git_commit_lookup(&treeish, repository, &oid);
    if (GIT_OK != err)
        goto cleanup;

    err = git_repository_set_head_detached(
        repository,
        git_commit_id(treeish));

cleanup:
    if (treeish)
        git_commit_free(treeish);

    if (repository)
        git_repository_free(repository);

    if (GIT_OK != err)
        git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    return R_NilValue;
}
예제 #23
0
/**
 * Updates some entries in the index from the HEAD commit tree.
 *
 * @param repo S3 class git_repository
 * @param path The paths to reset
 * @return R_NilValue
 */
SEXP git2r_reset_default(SEXP repo, SEXP path)
{
    int error = 0;
    git_strarray pathspec = {0};
    git_reference *head = NULL;
    git_object *head_commit = NULL;
    git_repository *repository = NULL;

    if (git2r_arg_check_string_vec(path))
        git2r_error(__func__, NULL, "'path'", git2r_err_string_vec_arg);

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    error = git2r_copy_string_vec(&pathspec, path);
    if (error || !pathspec.count)
        goto cleanup;

    error = git_repository_head(&head, repository);
    if (error)
        goto cleanup;

    error = git_reference_peel(&head_commit, head, GIT2R_OBJECT_COMMIT);
    if (error)
        goto cleanup;

    error = git_reset_default(repository, head_commit, &pathspec);

cleanup:
    git_reference_free(head);
    git_object_free(head_commit);
    free(pathspec.strings);
    git_repository_free(repository);

    if (error)
        git2r_error(__func__, GIT2R_ERROR_LAST(), NULL, NULL);

    return R_NilValue;
}
예제 #24
0
/**
 * Check if repository is bare.
 *
 * @param repo S4 class git_repository
 * @return TRUE if bare else FALSE
 */
SEXP git2r_repository_is_bare(SEXP repo)
{
    SEXP result;
    int is_bare;
    git_repository *repository;

    repository= git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    is_bare = git_repository_is_bare(repository);
    git_repository_free(repository);

    PROTECT(result = allocVector(LGLSXP, 1));
    if (1 == is_bare)
        LOGICAL(result)[0] = 1;
    else
        LOGICAL(result)[0] = 0;
    UNPROTECT(1);

    return result;
}
예제 #25
0
/**
 * Remove an existing remote
 *
 * All remote-tracking branches and configuration settings for the
 * remote will be removed.
 * @param repo S4 class git_repository
 * @param name The name of the remote to remove
 * @return R_NilValue
 */
SEXP git2r_remote_remove(SEXP repo, SEXP name)
{
    int err;
    git_repository *repository = NULL;

    if (git2r_arg_check_string(name))
        git2r_error(__func__, NULL, "'name'", git2r_err_string_arg);

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    err = git_remote_delete(repository, CHAR(STRING_ELT(name, 0)));

    if (repository)
	git_repository_free(repository);

    if (err)
	git2r_error(__func__, giterr_last(), NULL, NULL);

    return R_NilValue;
}
예제 #26
0
/**
 * Make the repository HEAD point to the specified reference.
 *
 * @param repo S4 class git_repository
 * @param ref_name Canonical name of the reference the HEAD should point at
 * @return R_NilValue
 */
SEXP git2r_repository_set_head(SEXP repo, SEXP ref_name)
{
    int err;
    git_repository *repository = NULL;

    if (git2r_arg_check_string(ref_name))
        git2r_error(git2r_err_string_arg, __func__, "ref_name");

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    err = git_repository_set_head(repository, CHAR(STRING_ELT(ref_name, 0)));

    if (repository)
        git_repository_free(repository);

    if (GIT_OK != err)
        git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    return R_NilValue;
}
예제 #27
0
/**
 * Check if head of repository is detached
 *
 * @param repo S4 class git_repository
 * @return TRUE if detached else FALSE
 */
SEXP git2r_repository_head_detached(SEXP repo)
{
    SEXP result;
    int head_detached;
    git_repository *repository;

    repository= git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    head_detached = git_repository_head_detached(repository);
    git_repository_free(repository);
    if (head_detached < 0)
        git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    PROTECT(result = allocVector(LGLSXP, 1));
    if (1 == head_detached)
        LOGICAL(result)[0] = 1;
    else
        LOGICAL(result)[0] = 0;
    UNPROTECT(1);

    return result;
}
예제 #28
0
/**
 * Check if repository is empty.
 *
 * @param repo S4 class git_repository
 * @return TRUE if empty else FALSE
 */
SEXP git2r_repository_is_empty(SEXP repo)
{
    SEXP result;
    int is_empty;
    git_repository *repository;

    repository= git2r_repository_open(repo);
    if (!repository)
        git2r_error(git2r_err_invalid_repository, __func__, NULL);

    is_empty = git_repository_is_empty(repository);
    git_repository_free(repository);
    if (is_empty < 0)
        git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message);

    PROTECT(result = allocVector(LGLSXP, 1));
    if (1 == is_empty)
        LOGICAL(result)[0] = 1;
    else
        LOGICAL(result)[0] = 0;
    UNPROTECT(1);

    return result;
}
예제 #29
0
/**
 * Reset current HEAD to the specified state
 *
 * @param commit The commit to which the HEAD should be moved to.
 * @param reset_type Kind of reset operation to perform. 'soft' means
 * the Head will be moved to the commit. 'mixed' reset will trigger a
 * 'soft' reset, plus the index will be replaced with the content of
 * the commit tree. 'hard' reset will trigger a 'mixed' reset and the
 * working directory will be replaced with the content of the index.
 * @return R_NilValue
 */
SEXP git2r_reset(SEXP commit, SEXP reset_type)
{
    int error;
    SEXP repo;
    git_commit *target = NULL;
    git_repository *repository = NULL;

    if (git2r_arg_check_commit(commit))
        git2r_error(__func__, NULL, "'commit'", git2r_err_commit_arg);
    if (git2r_arg_check_integer(reset_type))
        git2r_error(__func__, NULL, "'reset_type'", git2r_err_integer_arg);

    repo = git2r_get_list_element(commit, "repo");
    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    error = git2r_commit_lookup(&target, repository, commit);
    if (error)
        goto cleanup;

    error = git_reset(
        repository,
        (git_object*)target,
        INTEGER(reset_type)[0],
        NULL);

cleanup:
    git_commit_free(target);
    git_repository_free(repository);

    if (error)
        git2r_error(__func__, GIT2R_ERROR_LAST(), NULL, NULL);

    return R_NilValue;
}
예제 #30
0
/**
 * Get the remote's url
 *
 * Based on https://github.com/libgit2/libgit2/blob/babdc376c7/examples/network/ls-remote.c
 * @param repo S4 class git_repository
 * @param name Character vector with URL of remote.
 * @return Character vector for each reference with the associated commit IDs.
 */
SEXP git2r_remote_ls(SEXP name, SEXP repo, SEXP credentials)
{
    const char *name_ = NULL;
    SEXP result = R_NilValue;
    SEXP names = R_NilValue;
    git_remote *remote = NULL;
    int err;
    const git_remote_head **refs;
    size_t refs_len, i;
    git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
    git2r_transfer_data payload = GIT2R_TRANSFER_DATA_INIT;
    git_repository *repository = NULL;

    if (git2r_arg_check_string(name))
        git2r_error(__func__, NULL, "'name'", git2r_err_string_arg);
    if (git2r_arg_check_credentials(credentials))
        git2r_error(__func__, NULL, "'credentials'", git2r_err_credentials_arg);

    repository = git2r_repository_open(repo);
    if (!repository)
        git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);

    name_ = CHAR(STRING_ELT(name, 0));
    err = git_remote_lookup(&remote, repository, name_);
    if (err) {
        err = git_remote_create_anonymous(&remote, repository, name_);
        if (err)
            goto cleanup;
    }

    payload.credentials = credentials;
    callbacks.payload = &payload;
    callbacks.credentials = &git2r_cred_acquire_cb;

    err = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks, NULL, NULL);
    if (err)
        goto cleanup;

    err = git_remote_ls(&refs, &refs_len, remote);
    if (err)
        goto cleanup;

    PROTECT(result = allocVector(STRSXP, refs_len));
    setAttrib(result, R_NamesSymbol, names = allocVector(STRSXP, refs_len));

    for (i = 0; i < refs_len; i++) {
        char oid[GIT_OID_HEXSZ + 1] = {0};
        git_oid_fmt(oid, &refs[i]->oid);
        SET_STRING_ELT(result, i, mkChar(oid));
        SET_STRING_ELT(names, i, mkChar(refs[i]->name));
    }

cleanup:
    if (repository)
        git_repository_free(repository);

    if (result != R_NilValue)
        UNPROTECT(1);

    if (err)
        git2r_error(__func__, giterr_last(), NULL, NULL);

    return(result);
}