/** * 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; }
/** * Init slots in S3 class git_stash * * @param source The commit oid of the stashed state. * @param repository The repository * @param repo S3 class git_repository that contains the stash * @param dest S3 class git_stash to initialize * @return int 0 on success, or an error code. */ int git2r_stash_init( const git_oid *source, git_repository *repository, SEXP repo, SEXP dest) { int error; git_commit *commit = NULL; error = git_commit_lookup(&commit, repository, source); if (error) return error; git2r_commit_init(commit, repo, dest); git_commit_free(commit); return 0; }
/** * Find a merge base between two commits * * @param one One of the commits * @param two The other commit * @return The commit of a merge base between 'one' and 'two' * or NULL if not found */ SEXP git2r_merge_base(SEXP one, SEXP two) { int err; SEXP result = R_NilValue; SEXP repo; SEXP sha; git_oid oid; git_oid oid_one; git_oid oid_two; git_commit *commit = NULL; git_repository *repository = NULL; if (git2r_arg_check_commit(one)) git2r_error(__func__, NULL, "'one'", git2r_err_commit_arg); if (git2r_arg_check_commit(two)) git2r_error(__func__, NULL, "'two'", git2r_err_commit_arg); repo = GET_SLOT(one, Rf_install("repo")); repository = git2r_repository_open(repo); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); sha = GET_SLOT(one, Rf_install("sha")); err = git_oid_fromstr(&oid_one, CHAR(STRING_ELT(sha, 0))); if (err) goto cleanup; sha = GET_SLOT(two, Rf_install("sha")); err = git_oid_fromstr(&oid_two, CHAR(STRING_ELT(sha, 0))); if (err) goto cleanup; err = git_merge_base(&oid, repository, &oid_one, &oid_two); if (err) { if (GIT_ENOTFOUND == err) err = GIT_OK; goto cleanup; } err = git_commit_lookup(&commit, repository, &oid); if (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 (repository) git_repository_free(repository); if (R_NilValue != result) UNPROTECT(1); if (err) git2r_error(__func__, giterr_last(), NULL, NULL); return result; }
/** * Lookup an object in a repository * * @param repo S4 class git_repository * @param hex 4 to 40 char hexadecimal string * @return S4 object with lookup */ SEXP git2r_object_lookup(SEXP repo, SEXP hex) { int err; size_t len; SEXP result = R_NilValue; git_object *object = NULL; git_oid oid; git_repository *repository = NULL; if (git2r_error_check_hex_arg(hex)) error("Invalid arguments to git2r_object_lookup"); repository = git2r_repository_open(repo); if (!repository) error(git2r_err_invalid_repository); len = LENGTH(STRING_ELT(hex, 0)); if (GIT_OID_HEXSZ == len) { git_oid_fromstr(&oid, CHAR(STRING_ELT(hex, 0))); err = git_object_lookup(&object, repository, &oid, GIT_OBJ_ANY); if (err < 0) goto cleanup; } else { git_oid_fromstrn(&oid, CHAR(STRING_ELT(hex, 0)), len); err = git_object_lookup_prefix(&object, repository, &oid, len, GIT_OBJ_ANY); if (err < 0) goto cleanup; } switch (git_object_type(object)) { case GIT_OBJ_COMMIT: PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_commit"))); git2r_commit_init((git_commit*)object, repo, result); break; case GIT_OBJ_TREE: PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_tree"))); git2r_tree_init((git_tree*)object, repo, result); break; case GIT_OBJ_BLOB: PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_blob"))); git2r_blob_init((git_blob*)object, repo, result); break; case GIT_OBJ_TAG: PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_tag"))); git2r_tag_init((git_tag*)object, repo, result); break; default: error("Unimplemented"); } cleanup: if (object) git_object_free(object); if (repository) git_repository_free(repository); if (R_NilValue != result) UNPROTECT(1); if (err < 0) error("Error: %s\n", giterr_last()->message); return result; }
/** * Invoked 'callback' for each tag * * @param name The name of the tag * @param oid The id of the tag * @param payload Payload data passed to 'git_tag_foreach' * @return 0 on success, else error code */ static int git2r_tag_foreach_cb(const char *name, git_oid *oid, void *payload) { int err = 0; git_object *object = NULL; git2r_tag_foreach_cb_data *cb_data = (git2r_tag_foreach_cb_data*)payload; /* Check if we have a list to populate */ if (R_NilValue != cb_data->tags) { int skip = 0; SEXP item; err = git_object_lookup(&object, cb_data->repository, oid, GIT_OBJ_ANY); if (err) goto cleanup; switch (git_object_type(object)) { case GIT_OBJ_COMMIT: SET_VECTOR_ELT( cb_data->tags, cb_data->n, item = NEW_OBJECT(MAKE_CLASS("git_commit"))); git2r_commit_init((git_commit*)object, cb_data->repo, item); break; case GIT_OBJ_TREE: SET_VECTOR_ELT( cb_data->tags, cb_data->n, item = NEW_OBJECT(MAKE_CLASS("git_tree"))); git2r_tree_init((git_tree*)object, cb_data->repo, item); break; case GIT_OBJ_BLOB: SET_VECTOR_ELT( cb_data->tags, cb_data->n, item = NEW_OBJECT(MAKE_CLASS("git_blob"))); git2r_blob_init((git_blob*)object, cb_data->repo, item); break; case GIT_OBJ_TAG: SET_VECTOR_ELT( cb_data->tags, cb_data->n, item = NEW_OBJECT(MAKE_CLASS("git_tag"))); git2r_tag_init((git_tag*)object, cb_data->repo, item); break; default: git2r_error(__func__, NULL, git2r_err_object_type, NULL); } if (git__prefixcmp(name, "refs/tags/") == 0) skip = strlen("refs/tags/"); SET_STRING_ELT( getAttrib(cb_data->tags, R_NamesSymbol), cb_data->n, mkChar(name + skip)); if (object) git_object_free(object); object = NULL; } cb_data->n += 1; cleanup: if (object) git_object_free(object); return err; }
/** * Commit * * @param repo S4 class git_repository * @param message The message for the commit * @param author S4 class git_signature * @param committer S4 class git_signature * @return S4 class git_commit */ SEXP git2r_commit( SEXP repo, SEXP message, SEXP author, SEXP committer) { int err; SEXP result = R_NilValue; git_signature *c_author = NULL; git_signature *c_committer = NULL; git_index *index = NULL; git_oid oid; git_repository *repository = NULL; git_commit *commit = NULL; if (git2r_arg_check_string(message)) git2r_error(git2r_err_string_arg, __func__, "message"); 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"); repository = git2r_repository_open(repo); if (!repository) git2r_error(git2r_err_invalid_repository, __func__, NULL); err = git2r_signature_from_arg(&c_author, author); if (GIT_OK != err) goto cleanup; err = git2r_signature_from_arg(&c_committer, committer); if (GIT_OK != err) goto cleanup; err = git2r_any_changes_in_index(repository); if (GIT_OK != err) goto cleanup; err = git_repository_index(&index, repository); if (GIT_OK != err) goto cleanup; err = git2r_commit_create( &oid, repository, index, CHAR(STRING_ELT(message, 0)), c_author, c_committer); if (GIT_OK != err) goto cleanup; err = git_commit_lookup(&commit, repository, &oid); if (GIT_OK != err) goto cleanup; PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_commit"))); git2r_commit_init(commit, repo, result); cleanup: if (c_author) git_signature_free(c_author); if (c_committer) git_signature_free(c_committer); if (index) git_index_free(index); if (repository) git_repository_free(repository); if (commit) git_commit_free(commit); if (R_NilValue != result) UNPROTECT(1); if (GIT_OK != err) git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message); return result; }
/** * Find object specified by revision * * @param repo S4 class git_repository * @param revision The revision string, see * http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions * @return S4 object of class git_commit, git_tag or git_tree. */ SEXP git2r_revparse_single(SEXP repo, SEXP revision) { int err; SEXP result = R_NilValue; git_repository *repository = NULL; git_object *treeish = NULL; if (git2r_arg_check_string(revision)) git2r_error(git2r_err_string_arg, __func__, "revision"); repository = git2r_repository_open(repo); if (!repository) git2r_error(git2r_err_invalid_repository, __func__, NULL); err = git_revparse_single( &treeish, repository, CHAR(STRING_ELT(revision, 0))); if (GIT_OK != err) goto cleanup; switch (git_object_type(treeish)) { case GIT_OBJ_COMMIT: PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_commit"))); git2r_commit_init((git_commit*)treeish, repo, result); break; case GIT_OBJ_TAG: PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_tag"))); git2r_tag_init((git_tag*)treeish, repo, result); break; case GIT_OBJ_TREE: PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_tree"))); git2r_tree_init((git_tree*)treeish, repo, result); break; default: giterr_set_str(GITERR_NONE, git2r_err_revparse_single); err = GIT_ERROR; break; } cleanup: if (treeish) git_object_free(treeish); if (repository) git_repository_free(repository); if (R_NilValue != result) UNPROTECT(1); if (GIT_OK != err) { if (GIT_ENOTFOUND == err) { git2r_error( git2r_err_from_libgit2, __func__, "Requested object could not be found"); } else { git2r_error( git2r_err_from_libgit2, __func__, giterr_last()->message); } } return result; }