/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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(¬e_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, ¬e_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; }
/** * 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(¬es_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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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); }