/** * Check string argument * * Compared to git2r_arg_check_string_vec, also checks that length of vector * is one and non-NA. * @param arg the arg to check * @return 0 if OK, else 1 */ int git2r_arg_check_string(SEXP arg) { if (git2r_arg_check_string_vec(arg)) return 1; if (1 != length(arg) || NA_STRING == STRING_ELT(arg, 0)) return 1; return 0; }
/** * Check credentials argument * * @param arg the arg to check * @return 0 if OK, else 1 */ int git2r_arg_check_credentials(SEXP arg) { SEXP class_name; /* It's ok if the credentials is R_NilValue */ if (R_NilValue == arg) return 0; if (S4SXP != TYPEOF(arg)) return 1; class_name = getAttrib(arg, R_ClassSymbol); if (0 == strcmp(CHAR(STRING_ELT(class_name, 0)), "cred_plaintext")) { /* Check username and password */ if (git2r_arg_check_string(GET_SLOT(arg, Rf_install("username"))) || git2r_arg_check_string(GET_SLOT(arg, Rf_install("password")))) return 1; } else if (0 == strcmp(CHAR(STRING_ELT(class_name, 0)), "cred_ssh_key")) { SEXP passphrase; /* Check public and private key */ if (git2r_arg_check_string(GET_SLOT(arg, Rf_install("publickey"))) || git2r_arg_check_string(GET_SLOT(arg, Rf_install("privatekey")))) return 1; /* Check that passphrase is a character vector */ passphrase = GET_SLOT(arg, Rf_install("passphrase")); if (git2r_arg_check_string_vec(passphrase)) return 1; /* Check that length of passphrase < 2, i.e. it's either * character(0) or some "passphrase" */ switch (length(passphrase)) { case 0: break; case 1: if (NA_STRING == STRING_ELT(passphrase, 0)) return 1; break; default: return 1; } } else { return 1; } return 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; }
/** * 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; }
/** * 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 * @param verbose Print information each time a reference is updated locally. * @param refspecs The refspecs to use for this fetch. Pass R_NilValue * to use the base refspecs. * @return R_NilValue */ SEXP git2r_remote_fetch( SEXP repo, SEXP name, SEXP credentials, SEXP msg, SEXP verbose, SEXP refspecs) { int err; SEXP result = R_NilValue; const git_transfer_progress *stats; git_remote *remote = NULL; git_repository *repository = NULL; git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT; git2r_transfer_data payload = GIT2R_TRANSFER_DATA_INIT; git_strarray refs = {0}; 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); if (git2r_arg_check_string(msg)) git2r_error(__func__, NULL, "'msg'", git2r_err_string_arg); if (git2r_arg_check_logical(verbose)) git2r_error(__func__, NULL, "'verbose'", git2r_err_logical_arg); if (refspecs != R_NilValue && git2r_arg_check_string_vec(refspecs)) git2r_error(__func__, NULL, "'refspecs'", git2r_err_string_vec_arg); repository = git2r_repository_open(repo); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); err = git_remote_lookup(&remote, repository, CHAR(STRING_ELT(name, 0))); if (err) goto cleanup; if (refspecs != R_NilValue) { size_t i, len; /* Count number of non NA values */ len = length(refspecs); for (i = 0; i < len; i++) if (NA_STRING != STRING_ELT(refspecs, i)) refs.count++; if (refs.count) { /* Allocate the strings in refs */ refs.strings = malloc(refs.count * sizeof(char*)); if (!refs.strings) { giterr_set_str(GITERR_NONE, git2r_err_alloc_memory_buffer); err = GIT_ERROR; goto cleanup; } /* Populate the strings in refs */ for (i = 0; i < refs.count; i++) if (NA_STRING != STRING_ELT(refspecs, i)) refs.strings[i] = (char *)CHAR(STRING_ELT(refspecs, i)); } } if (LOGICAL(verbose)[0]) payload.verbose = 1; payload.credentials = credentials; fetch_opts.callbacks.payload = &payload; fetch_opts.callbacks.credentials = &git2r_cred_acquire_cb; fetch_opts.callbacks.update_tips = &git2r_update_tips_cb; err = git_remote_fetch(remote, &refs, &fetch_opts, CHAR(STRING_ELT(msg, 0))); if (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 (refs.strings) free(refs.strings); 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 (err) git2r_error( __func__, giterr_last(), git2r_err_unable_to_authenticate, NULL); return result; }