Skip to content

Commit 7612699

Browse files
committed
Merge pull request #172 from jimhester/ls_remote
ls_remote function
2 parents d1b088d + 5b2067d commit 7612699

File tree

8 files changed

+165
-0
lines changed

8 files changed

+165
-0
lines changed

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export(libgit2_features)
1010
export(libgit2_sha)
1111
export(libgit2_version)
1212
export(punch_card)
13+
export(remote_ls)
1314
exportClasses(cred_env)
1415
exportClasses(cred_ssh_key)
1516
exportClasses(cred_token)
@@ -96,6 +97,7 @@ exportMethods(push)
9697
exportMethods(references)
9798
exportMethods(reflog)
9899
exportMethods(remote_add)
100+
exportMethods(remote_ls)
99101
exportMethods(remote_remove)
100102
exportMethods(remote_rename)
101103
exportMethods(remote_set_url)

NEWS

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

44
NEW FEATURES
55

6+
* Add 'remote_ls' method to list references in a remote repository akin to the
7+
`git ls-remote` command.
8+
69
* Add 'remote_set_url' method to set the remote's url in the
710
configuration.
811

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
358+
##' associated commit IDs. Akin to the 'git ls-remote' command.
359+
##' @rdname remote_ls-methods
360+
##' @docType methods
361+
##' @param name Character vector with the "remote" repository URL to query or
362+
##' the name of the remote if a \code{repo} argument is given.
363+
##' @param repo an optional repository object used if remotes are specified by name.
364+
##' @param credentials The credentials for the remote repository.
365+
##' @keywords methods
366+
##' @return Character vector for each reference with the associated commit IDs.
367+
##' @examples
368+
##' \dontrun{
369+
##' remote_ls("https://github.com/ropensci/git2r")
370+
##' }
371+
##' @export
372+
setGeneric("remote_ls",
373+
signature = c("name"),
374+
function(name,
375+
repo = NULL,
376+
credentials = NULL)
377+
standardGeneric("remote_ls"))
378+
379+
##' @rdname remote_ls-methods
380+
##' @export
381+
setMethod("remote_ls",
382+
signature(name = "character"),
383+
function(name, repo, credentials)
384+
{
385+
if (is.null(repo)) {
386+
path <- tempdir()
387+
repo <- git2r::init(path)
388+
on.exit(unlink(file.path(path, ".git"), recursive = TRUE))
389+
}
390+
391+
.Call(git2r_remote_ls, name, repo, credentials)
392+
}
393+
)

man/remote_ls-methods.Rd

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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{remote_ls}
5+
\alias{remote_ls}
6+
\alias{remote_ls,character-method}
7+
\title{List references in a remote repository}
8+
\usage{
9+
remote_ls(name, repo = NULL, credentials = NULL)
10+
11+
\S4method{remote_ls}{character}(name, repo = NULL, credentials = NULL)
12+
}
13+
\arguments{
14+
\item{name}{Character vector with the "remote" repository URL to query or
15+
the name of the remote if a \code{repo} argument is given.}
16+
17+
\item{repo}{an optional repository object used if remotes are specified by name.}
18+
19+
\item{credentials}{The credentials for the remote repository.}
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
26+
associated commit IDs. Akin to the 'git ls-remote' command.
27+
}
28+
\examples{
29+
\dontrun{
30+
remote_ls("https://github.com/ropensci/git2r")
31+
}
32+
}
33+
\keyword{methods}
34+

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_remote_ls", (DL_FUNC)&git2r_remote_ls, 3},
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: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,78 @@ SEXP git2r_remote_url(SEXP repo, SEXP remote)
391391

392392
return url;
393393
}
394+
395+
/**
396+
* Get the remote's url
397+
*
398+
* Based on https://github.com/libgit2/libgit2/blob/babdc376c7/examples/network/ls-remote.c
399+
* @param repo S4 class git_repository
400+
* @param name Character vector with URL of remote.
401+
* @return Character vector for each reference with the associated commit IDs.
402+
*/
403+
SEXP git2r_remote_ls(SEXP name, SEXP repo, SEXP credentials)
404+
{
405+
const char *name_ = CHAR(STRING_ELT(name, 0));
406+
SEXP result = R_NilValue;
407+
SEXP names = R_NilValue;
408+
git_remote *remote = NULL;
409+
int err;
410+
const git_remote_head **refs;
411+
size_t refs_len, i;
412+
git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
413+
git2r_transfer_data payload = GIT2R_TRANSFER_DATA_INIT;
414+
git_repository *repository = NULL;
415+
416+
if (git2r_arg_check_string(name))
417+
git2r_error(__func__, NULL, "'name'", git2r_err_string_arg);
418+
419+
if (git2r_arg_check_credentials(credentials))
420+
git2r_error(__func__, NULL, "'credentials'", git2r_err_credentials_arg);
421+
422+
repository = git2r_repository_open(repo);
423+
424+
if (!repository)
425+
git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL);
426+
427+
err = git_remote_lookup(&remote, repository, name_);
428+
if (err < 0) {
429+
err = git_remote_create_anonymous(&remote, repository, name_);
430+
if (err < 0) {
431+
goto cleanup;
432+
}
433+
}
434+
435+
payload.credentials = credentials;
436+
callbacks.payload = &payload;
437+
callbacks.credentials = &git2r_cred_acquire_cb;
438+
439+
err = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks);
440+
if (err < 0)
441+
goto cleanup;
442+
443+
err = git_remote_ls(&refs, &refs_len, remote);
444+
if (err < 0)
445+
goto cleanup;
446+
447+
PROTECT(result = allocVector(STRSXP, refs_len));
448+
setAttrib(result, R_NamesSymbol, names = allocVector(STRSXP, refs_len));
449+
450+
for (i = 0; i < refs_len; i++) {
451+
char oid[GIT_OID_HEXSZ + 1] = {0};
452+
git_oid_fmt(oid, &refs[i]->oid);
453+
SET_STRING_ELT(result, i, mkChar(oid));
454+
SET_STRING_ELT(names, i, mkChar(refs[i]->name));
455+
}
456+
457+
cleanup:
458+
if (repository)
459+
git_repository_free(repository);
460+
461+
if (result != R_NilValue)
462+
UNPROTECT(1);
463+
464+
if (err)
465+
git2r_error(__func__, giterr_last(), NULL, NULL);
466+
467+
return(result);
468+
}

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_remote_ls(SEXP name, SEXP repo, SEXP credentials);
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 <- remote_ls("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(remote_ls("bad"))
66+
5967
## Cleanup
6068
unlink(path, recursive=TRUE)

0 commit comments

Comments
 (0)