Skip to content

Commit 916aa33

Browse files
committed
ls_remote function
Analogous to git ls-remote, returns all references from a remote repository.
1 parent d1b088d commit 916aa33

File tree

8 files changed

+156
-0
lines changed

8 files changed

+156
-0
lines changed

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export(is_commit)
99
export(libgit2_features)
1010
export(libgit2_sha)
1111
export(libgit2_version)
12+
export(ls_remote)
1213
export(punch_card)
1314
exportClasses(cred_env)
1415
exportClasses(cred_ssh_key)
@@ -80,6 +81,7 @@ exportMethods(is_merge)
8081
exportMethods(is_shallow)
8182
exportMethods(length)
8283
exportMethods(lookup)
84+
exportMethods(ls_remote)
8385
exportMethods(merge)
8486
exportMethods(merge_base)
8587
exportMethods(note_create)

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ git2r 0.11.0.9000
33

44
NEW FEATURES
55

6+
* Add 'ls_remote' method to list references in a remote repository.
7+
68
* Add 'remote_set_url' method to set the remote's url in the
79
configuration.
810

R/remote.r

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,3 +350,44 @@ setMethod("remote_url",
350350
.Call(git2r_remote_url, repo, remote)
351351
}
352352
)
353+
354+
355+
##' List references in a remote repository
356+
##'
357+
##' Displays references available in a remote repository along with the associated commit IDs.
358+
##' @rdname ls_remote-methods
359+
##' @docType methods
360+
##' @param name Character vector with the with "remote" repository URL to query.
361+
##' @return Character vector for each reference with the associated commit IDs.
362+
##' @param repo an optional repository object used to store data temporarily.
363+
##' @keywords methods
364+
##' @examples
365+
##' \dontrun{
366+
##' ls_remote("https://github.com/ropensci/git2r")
367+
##' }
368+
##' @export
369+
setGeneric("ls_remote",
370+
signature = c("name", "repo"),
371+
function(name, repo)
372+
standardGeneric("ls_remote"))
373+
374+
##' @rdname ls_remote-methods
375+
##' @export
376+
setMethod("ls_remote",
377+
signature(name = "character",
378+
repo = "missing"),
379+
function(name)
380+
{
381+
.Call(git2r_ls_remote, git2r::init(tempdir()), name)
382+
}
383+
)
384+
##' @rdname ls_remote-methods
385+
##' @export
386+
setMethod("ls_remote",
387+
signature(name = "character",
388+
repo = "git_repository"),
389+
function(name, repo)
390+
{
391+
.Call(git2r_ls_remote, repo, name)
392+
}
393+
)

man/ls_remote-methods.Rd

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
% Generated by roxygen2 (4.1.1): do not edit by hand
2+
% Please edit documentation in R/remote.r
3+
\docType{methods}
4+
\name{ls_remote}
5+
\alias{ls_remote}
6+
\alias{ls_remote,character,git_repository-method}
7+
\alias{ls_remote,character,missing-method}
8+
\title{List references in a remote repository}
9+
\usage{
10+
ls_remote(name, repo)
11+
12+
\S4method{ls_remote}{character,missing}(name)
13+
14+
\S4method{ls_remote}{character,git_repository}(name, repo)
15+
}
16+
\arguments{
17+
\item{name}{Character vector with the with "remote" repository URL to query.}
18+
19+
\item{repo}{an optional repository object used to store data temporarily.}
20+
}
21+
\value{
22+
Character vector for each reference with the associated commit IDs.
23+
}
24+
\description{
25+
Displays references available in a remote repository along with the associated commit IDs.
26+
}
27+
\examples{
28+
\dontrun{
29+
ls_remote("https://github.com/ropensci/git2r")
30+
}
31+
}
32+
\keyword{methods}
33+

src/git2r.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ static const R_CallMethodDef callMethods[] =
119119
{"git2r_remote_rename", (DL_FUNC)&git2r_remote_rename, 3},
120120
{"git2r_remote_set_url", (DL_FUNC)&git2r_remote_set_url, 3},
121121
{"git2r_remote_url", (DL_FUNC)&git2r_remote_url, 2},
122+
{"git2r_ls_remote", (DL_FUNC)&git2r_ls_remote, 2},
122123
{"git2r_repository_can_open", (DL_FUNC)&git2r_repository_can_open, 1},
123124
{"git2r_repository_discover", (DL_FUNC)&git2r_repository_discover, 1},
124125
{"git2r_repository_fetch_heads", (DL_FUNC)&git2r_repository_fetch_heads, 1},

src/git2r_remote.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,71 @@ SEXP git2r_remote_url(SEXP repo, SEXP remote)
391391

392392
return url;
393393
}
394+
395+
SEXP git2r_ls_remote(SEXP repo, SEXP name)
396+
{
397+
if (git2r_arg_check_string(name))
398+
git2r_error(__func__, NULL, "'name'", git2r_err_string_arg);
399+
400+
const char *name_ = CHAR(STRING_ELT(name, 0));
401+
SEXP result = R_NilValue;
402+
SEXP names = R_NilValue;
403+
git_remote *remote = NULL;
404+
int error;
405+
const git_remote_head **refs;
406+
size_t refs_len, i;
407+
git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
408+
git_repository *repo_ = NULL;
409+
410+
repo_ = git2r_repository_open(repo);
411+
412+
error = git_remote_lookup(&remote, repo_, name_);
413+
if (error < 0) {
414+
error = git_remote_create_anonymous(&remote, repo_, name_);
415+
if (error < 0) {
416+
goto cleanup;
417+
}
418+
}
419+
420+
/**
421+
* Connect to the remote and call the printing function for
422+
* each of the remote references.
423+
*/
424+
callbacks.credentials = git2r_cred_acquire_cb;
425+
426+
error = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks);
427+
if (error < 0) {
428+
goto cleanup;
429+
}
430+
431+
/**
432+
* Get the list of references on the remote and print out
433+
* their name next to what they point to.
434+
*/
435+
if (git_remote_ls(&refs, &refs_len, remote) < 0) {
436+
goto cleanup;
437+
}
438+
439+
PROTECT(result = allocVector(STRSXP, refs_len));
440+
PROTECT(names = allocVector(STRSXP, refs_len));
441+
442+
for (i = 0; i < refs_len; i++) {
443+
char oid[GIT_OID_HEXSZ + 1] = {0};
444+
git_oid_fmt(oid, &refs[i]->oid);
445+
SET_STRING_ELT(result, i, mkChar(oid));
446+
SET_STRING_ELT(names, i, mkChar(refs[i]->name));
447+
}
448+
setAttrib(result, R_NamesSymbol, names);
449+
450+
cleanup:
451+
if (repo_)
452+
git_repository_free(repo_);
453+
454+
if (result != R_NilValue)
455+
UNPROTECT(2);
456+
457+
if (error)
458+
git2r_error(__func__, giterr_last(), NULL, NULL);
459+
460+
return(result);
461+
}

src/git2r_remote.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,6 @@ SEXP git2r_remote_remove(SEXP repo, SEXP remote);
3333
SEXP git2r_remote_rename(SEXP repo, SEXP oldname, SEXP newname);
3434
SEXP git2r_remote_set_url(SEXP repo, SEXP name, SEXP url);
3535
SEXP git2r_remote_url(SEXP repo, SEXP remote);
36+
SEXP git2r_ls_remote(SEXP repo, SEXP name);
3637

3738
#endif

tests/remotes.R

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,13 @@ remote_remove(repo, "foobar")
5656

5757
stopifnot(identical(remotes(repo), character(0)))
5858

59+
refs <- ls_remote("https://github.com/ropensci/git2r")
60+
stopifnot(length(refs) > 0)
61+
stopifnot(names(refs) > 0)
62+
stopifnot(any(names(refs) == "HEAD"))
63+
64+
# an invalid URL should throw an error
65+
tools::assertError(ls_remote("bad"))
66+
5967
## Cleanup
6068
unlink(path, recursive=TRUE)

0 commit comments

Comments
 (0)