1#' Submodules
2#'
3#' Interact with submodules in the repository.
4#'
5#' @export
6#' @rdname git_submodule
7#' @inheritParams git_open
8#' @useDynLib gert R_git_submodule_list
9git_submodule_list <- function(repo = '.'){
10  repo <- git_open(repo)
11  .Call(R_git_submodule_list, repo)
12}
13
14#' @export
15#' @rdname git_submodule
16#' @useDynLib gert R_git_submodule_info
17git_submodule_info <- function(submodule, repo = '.'){
18  repo <- git_open(repo)
19  submodule <- as.character(submodule)
20  .Call(R_git_submodule_info, repo, submodule)
21}
22
23#' @export
24#' @rdname git_submodule
25#' @useDynLib gert R_git_submodule_init
26#' @param submodule name of the submodule
27#' @param overwrite overwrite existing entries
28git_submodule_init <- function(submodule, overwrite = FALSE, repo = '.'){
29  repo <- git_open(repo)
30  submodule <- as.character(submodule)
31  overwrite <- as.logical(overwrite)
32  .Call(R_git_submodule_init, repo, submodule, overwrite)
33}
34
35#' @export
36#' @rdname git_submodule
37#' @useDynLib gert R_git_submodule_set_to
38#' @param ref branch or tag to point the submodule at. If checkout = FALSE, you
39#' can pass a commit hash before downloading the submodule.
40#' @param checkout actually switch the contents of the directory to this commit
41git_submodule_set_to <- function(submodule, ref, checkout = TRUE, repo = '.'){
42  repo <- git_open(repo)
43  submodule <- as.character(submodule)
44  info <- git_submodule_info(submodule, repo = repo)
45  if(isTRUE(checkout)){
46    git_reset_hard(ref = ref, repo = I(info$path))
47    ref <- git_info(repo = I(info$path))$commit
48  } else if(!is_full_hash(ref)) {
49    ref <- git_commit_info(ref, repo = I(info$path))$id
50  }
51  if(!is_full_hash(ref))
52    stop("When checkout = FALSE, parameter ref must be a full hash")
53 .Call(R_git_submodule_set_to, repo, submodule, ref)
54}
55
56#' @export
57#' @rdname git_submodule
58#' @param url full git url of the submodule
59#' @param path relative of the submodule
60#' @param ref a branch or tag or hash with
61#' @param ... extra arguments for [git_fetch] for authentication things
62git_submodule_add <- function(url, path = basename(url), ref = 'HEAD', ..., repo = '.'){
63  if(!is_a_hash(ref)){
64    upstream_refs <- git_remote_ls(url, ..., repo = repo)
65    ref_match <- sub("refs/(heads|tags)/","", upstream_refs$ref) == ref
66    if(!any(ref_match)){
67      stop(sprintf("Upstream repo %s does not have a branch or tag named '%s'",
68                   basename(url), ref))
69    }
70    ref <- upstream_refs$oid[ref_match]
71  }
72  submodule <- git_submodule_setup(url = url, path = path, repo = repo)
73  git_fetch('origin', ..., repo = submodule)
74  git_reset_hard(ref, repo = submodule)
75  git_submodule_save(path, repo = repo)
76  git_submodule_info(path, repo = repo)
77}
78
79#' @export
80#' @rdname git_submodule
81git_submodule_fetch <- function(submodule, ..., repo = '.'){
82  sm <- git_submodule_info(submodule = submodule, repo = repo)
83  subrepo = I(sm$path)
84  tryCatch({
85    git_fetch('origin', ..., repo = subrepo)
86  }, GIT_ENOTFOUND = function(e){
87    inform("Initial clone for submodule '%s'", submodule)
88    git_clone(sm$url, ..., path = subrepo)
89  })
90  if(length(sm$branch) && !is.na(sm$branch)){
91    git_reset_hard(sm$branch, repo = subrepo)
92  } else {
93    remote_head <- git_remote_info('origin', repo = subrepo)$head
94    if(!length(remote_head)){
95      git_remote_ls('origin', ..., repo = subrepo)
96      remote_head <- git_remote_info('origin', repo = subrepo)$head
97    }
98    git_reset_hard(remote_head, repo = I(sm$path))
99  }
100  git_commit_id(repo = subrepo)
101}
102
103#' @useDynLib gert R_git_submodule_setup
104git_submodule_setup <- function(url, path, repo){
105  repo <- git_open(repo)
106  path <- as.character(path)
107  url <- as.character(url)
108  .Call(R_git_submodule_setup, repo, url, path)
109}
110
111#' @useDynLib gert R_git_submodule_save
112git_submodule_save <- function(submodule, repo){
113  repo <- git_open(repo)
114  submodule <- as.character(submodule)
115  .Call(R_git_submodule_save, repo, submodule)
116}
117
118# I find this confusing, also doesn't support auth.
119# Better use git_submodule_fetch()
120#' @useDynLib gert R_git_submodule_update
121git_submodule_update <- function(submodule, init = TRUE, repo = '.'){
122  repo <- git_open(repo)
123  submodule <- as.character(submodule)
124  init <- as.logical(init)
125  .Call(R_git_submodule_update, repo, submodule, init)
126}
127
128is_a_hash <- function(x){
129  grepl('^[a-f0-9]{7,}$', tolower(x))
130}
131
132is_full_hash <- function(x){
133  grepl('^[a-f0-9]{40}$', tolower(x))
134}
135