rugged 0.17.0.b6 → 0.17.0.b7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. data/README.md +3 -3
  2. data/Rakefile +3 -1
  3. data/ext/rugged/rugged.c +30 -0
  4. data/ext/rugged/rugged.h +9 -0
  5. data/ext/rugged/rugged_branch.c +306 -0
  6. data/ext/rugged/rugged_config.c +16 -13
  7. data/ext/rugged/rugged_index.c +25 -0
  8. data/ext/rugged/rugged_object.c +6 -2
  9. data/ext/rugged/rugged_reference.c +11 -18
  10. data/ext/rugged/rugged_revwalk.c +1 -1
  11. data/lib/rugged.rb +1 -0
  12. data/lib/rugged/branch.rb +28 -0
  13. data/lib/rugged/commit.rb +5 -5
  14. data/lib/rugged/repository.rb +32 -7
  15. data/lib/rugged/tag.rb +5 -1
  16. data/lib/rugged/version.rb +1 -1
  17. data/test/branch_test.rb +227 -0
  18. data/test/config_test.rb +1 -1
  19. data/test/fixtures/testrepo.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 +0 -0
  20. data/test/fixtures/testrepo.git/objects/a3/e05719b428a2d0ed7a55c4ce53dcc5768c6d5e +0 -0
  21. data/test/index_test.rb +31 -0
  22. data/test/index_test.rb~ +218 -0
  23. data/test/lib_test.rb +22 -0
  24. data/test/reference_test.rb +5 -3
  25. data/vendor/libgit2/Makefile.embed +1 -1
  26. data/vendor/libgit2/include/git2.h +1 -0
  27. data/vendor/libgit2/include/git2/branch.h +17 -13
  28. data/vendor/libgit2/include/git2/checkout.h +83 -22
  29. data/vendor/libgit2/include/git2/clone.h +6 -3
  30. data/vendor/libgit2/include/git2/common.h +1 -8
  31. data/vendor/libgit2/include/git2/config.h +185 -26
  32. data/vendor/libgit2/include/git2/diff.h +229 -17
  33. data/vendor/libgit2/include/git2/errors.h +39 -1
  34. data/vendor/libgit2/include/git2/ignore.h +6 -3
  35. data/vendor/libgit2/include/git2/indexer.h +1 -0
  36. data/vendor/libgit2/include/git2/merge.h +1 -1
  37. data/vendor/libgit2/include/git2/object.h +7 -4
  38. data/vendor/libgit2/include/git2/odb.h +4 -2
  39. data/vendor/libgit2/include/git2/odb_backend.h +6 -0
  40. data/vendor/libgit2/include/git2/oid.h +2 -0
  41. data/vendor/libgit2/include/git2/pack.h +89 -0
  42. data/vendor/libgit2/include/git2/refs.h +88 -0
  43. data/vendor/libgit2/include/git2/refspec.h +0 -8
  44. data/vendor/libgit2/include/git2/remote.h +34 -1
  45. data/vendor/libgit2/include/git2/repository.h +238 -6
  46. data/vendor/libgit2/include/git2/reset.h +4 -1
  47. data/vendor/libgit2/include/git2/revwalk.h +1 -1
  48. data/vendor/libgit2/include/git2/status.h +19 -14
  49. data/vendor/libgit2/include/git2/strarray.h +54 -0
  50. data/vendor/libgit2/include/git2/submodule.h +451 -45
  51. data/vendor/libgit2/include/git2/tag.h +16 -0
  52. data/vendor/libgit2/include/git2/tree.h +2 -2
  53. data/vendor/libgit2/include/git2/types.h +4 -0
  54. data/vendor/libgit2/src/amiga/map.c +4 -7
  55. data/vendor/libgit2/src/attr.c +21 -13
  56. data/vendor/libgit2/src/attr.h +3 -1
  57. data/vendor/libgit2/src/attr_file.c +14 -14
  58. data/vendor/libgit2/src/attr_file.h +6 -5
  59. data/vendor/libgit2/src/blob.c +22 -12
  60. data/vendor/libgit2/src/branch.c +62 -66
  61. data/vendor/libgit2/src/buffer.c +63 -14
  62. data/vendor/libgit2/src/buffer.h +4 -0
  63. data/vendor/libgit2/src/cache.c +5 -4
  64. data/vendor/libgit2/src/checkout.c +381 -159
  65. data/vendor/libgit2/src/clone.c +221 -94
  66. data/vendor/libgit2/src/common.h +13 -3
  67. data/vendor/libgit2/src/compress.c +53 -0
  68. data/vendor/libgit2/src/compress.h +16 -0
  69. data/vendor/libgit2/src/config.c +380 -175
  70. data/vendor/libgit2/src/config.h +2 -5
  71. data/vendor/libgit2/src/config_file.c +63 -46
  72. data/vendor/libgit2/src/config_file.h +16 -4
  73. data/vendor/libgit2/src/crlf.c +4 -3
  74. data/vendor/libgit2/src/delta.c +491 -0
  75. data/vendor/libgit2/src/delta.h +112 -0
  76. data/vendor/libgit2/src/diff.c +310 -67
  77. data/vendor/libgit2/src/diff.h +10 -1
  78. data/vendor/libgit2/src/diff_output.c +1030 -337
  79. data/vendor/libgit2/src/diff_output.h +86 -0
  80. data/vendor/libgit2/src/errors.c +10 -1
  81. data/vendor/libgit2/src/fetch.c +108 -24
  82. data/vendor/libgit2/src/filebuf.c +8 -2
  83. data/vendor/libgit2/src/fileops.c +342 -177
  84. data/vendor/libgit2/src/fileops.h +84 -7
  85. data/vendor/libgit2/src/filter.c +0 -35
  86. data/vendor/libgit2/src/filter.h +0 -12
  87. data/vendor/libgit2/src/{compat/fnmatch.c → fnmatch.c} +16 -4
  88. data/vendor/libgit2/src/{compat/fnmatch.h → fnmatch.h} +4 -3
  89. data/vendor/libgit2/src/global.c +4 -0
  90. data/vendor/libgit2/src/ignore.c +122 -23
  91. data/vendor/libgit2/src/ignore.h +1 -0
  92. data/vendor/libgit2/src/index.c +56 -10
  93. data/vendor/libgit2/src/index.h +2 -0
  94. data/vendor/libgit2/src/indexer.c +8 -9
  95. data/vendor/libgit2/src/iterator.c +244 -31
  96. data/vendor/libgit2/src/iterator.h +30 -1
  97. data/vendor/libgit2/src/message.c +1 -1
  98. data/vendor/libgit2/src/netops.c +44 -4
  99. data/vendor/libgit2/src/object.c +80 -69
  100. data/vendor/libgit2/src/object.h +39 -0
  101. data/vendor/libgit2/src/odb.c +79 -15
  102. data/vendor/libgit2/src/odb.h +20 -5
  103. data/vendor/libgit2/src/odb_pack.c +65 -33
  104. data/vendor/libgit2/src/oid.c +0 -3
  105. data/vendor/libgit2/src/pack-objects.c +1315 -0
  106. data/vendor/libgit2/src/pack-objects.h +87 -0
  107. data/vendor/libgit2/src/pack.c +36 -12
  108. data/vendor/libgit2/src/pack.h +1 -0
  109. data/vendor/libgit2/src/path.c +42 -9
  110. data/vendor/libgit2/src/path.h +14 -0
  111. data/vendor/libgit2/src/pkt.c +52 -2
  112. data/vendor/libgit2/src/pkt.h +10 -0
  113. data/vendor/libgit2/src/pool.h +11 -0
  114. data/vendor/libgit2/src/posix.h +8 -0
  115. data/vendor/libgit2/src/protocol.c +24 -2
  116. data/vendor/libgit2/src/protocol.h +4 -0
  117. data/vendor/libgit2/src/reflog.c +1 -1
  118. data/vendor/libgit2/src/refs.c +292 -124
  119. data/vendor/libgit2/src/refs.h +4 -2
  120. data/vendor/libgit2/src/refspec.c +117 -19
  121. data/vendor/libgit2/src/refspec.h +19 -0
  122. data/vendor/libgit2/src/remote.c +152 -48
  123. data/vendor/libgit2/src/remote.h +4 -1
  124. data/vendor/libgit2/src/repo_template.h +58 -0
  125. data/vendor/libgit2/src/repository.c +594 -179
  126. data/vendor/libgit2/src/repository.h +23 -22
  127. data/vendor/libgit2/src/reset.c +71 -29
  128. data/vendor/libgit2/src/revparse.c +26 -17
  129. data/vendor/libgit2/src/revwalk.c +36 -19
  130. data/vendor/libgit2/src/sha1.h +7 -0
  131. data/vendor/libgit2/src/{sha1.c → sha1/sha1.c} +0 -0
  132. data/vendor/libgit2/src/signature.c +12 -10
  133. data/vendor/libgit2/src/status.c +52 -6
  134. data/vendor/libgit2/src/submodule.c +1363 -255
  135. data/vendor/libgit2/src/submodule.h +102 -0
  136. data/vendor/libgit2/src/tag.c +42 -26
  137. data/vendor/libgit2/src/thread-utils.h +7 -7
  138. data/vendor/libgit2/src/transport.h +15 -1
  139. data/vendor/libgit2/src/transports/git.c +1 -1
  140. data/vendor/libgit2/src/transports/http.c +197 -36
  141. data/vendor/libgit2/src/tree.c +3 -3
  142. data/vendor/libgit2/src/unix/map.c +2 -0
  143. data/vendor/libgit2/src/unix/posix.h +1 -8
  144. data/vendor/libgit2/src/util.c +6 -1
  145. data/vendor/libgit2/src/util.h +7 -0
  146. data/vendor/libgit2/src/vector.c +16 -0
  147. data/vendor/libgit2/src/vector.h +1 -0
  148. data/vendor/libgit2/src/win32/dir.c +8 -21
  149. data/vendor/libgit2/src/win32/findfile.c +149 -0
  150. data/vendor/libgit2/src/win32/findfile.h +23 -0
  151. data/vendor/libgit2/src/win32/posix.h +3 -7
  152. data/vendor/libgit2/src/win32/posix_w32.c +44 -102
  153. data/vendor/libgit2/src/win32/pthread.c +68 -0
  154. data/vendor/libgit2/src/win32/pthread.h +7 -0
  155. data/vendor/libgit2/src/win32/utf-conv.c +60 -71
  156. data/vendor/libgit2/src/win32/utf-conv.h +4 -3
  157. metadata +70 -71
  158. data/vendor/libgit2/include/git2/windows.h +0 -59
@@ -11,6 +11,7 @@
11
11
  #include "git2/oid.h"
12
12
  #include "git2/refs.h"
13
13
  #include "strmap.h"
14
+ #include "buffer.h"
14
15
 
15
16
  #define GIT_REFS_DIR "refs/"
16
17
  #define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/"
@@ -52,8 +53,9 @@ typedef struct {
52
53
 
53
54
  void git_repository__refcache_free(git_refcache *refs);
54
55
 
55
- int git_reference__normalize_name(char *buffer_out, size_t out_size, const char *name);
56
- int git_reference__normalize_name_oid(char *buffer_out, size_t out_size, const char *name);
56
+ int git_reference__normalize_name_lax(char *buffer_out, size_t out_size, const char *name);
57
+ int git_reference__normalize_name(git_buf *buf, const char *name, unsigned int flags);
58
+ int git_reference__is_valid_name(const char *refname, unsigned int flags);
57
59
  int git_reference__update(git_repository *repo, const git_oid *oid, const char *ref_name);
58
60
 
59
61
  /**
@@ -11,36 +11,124 @@
11
11
  #include "refspec.h"
12
12
  #include "util.h"
13
13
  #include "posix.h"
14
+ #include "refs.h"
14
15
 
15
- int git_refspec_parse(git_refspec *refspec, const char *str)
16
+ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
16
17
  {
17
- char *delim;
18
+ // Ported from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/remote.c#L518-636
19
+
20
+ size_t llen;
21
+ int is_glob = 0;
22
+ const char *lhs, *rhs;
23
+ int flags;
24
+
25
+ assert(refspec && input);
18
26
 
19
27
  memset(refspec, 0x0, sizeof(git_refspec));
20
28
 
21
- if (*str == '+') {
29
+ lhs = input;
30
+ if (*lhs == '+') {
22
31
  refspec->force = 1;
23
- str++;
32
+ lhs++;
24
33
  }
25
34
 
26
- delim = strchr(str, ':');
27
- if (delim == NULL) {
28
- refspec->src = git__strdup(str);
29
- GITERR_CHECK_ALLOC(refspec->src);
35
+ rhs = strrchr(lhs, ':');
36
+
37
+ /*
38
+ * Before going on, special case ":" (or "+:") as a refspec
39
+ * for matching refs.
40
+ */
41
+ if (!is_fetch && rhs == lhs && rhs[1] == '\0') {
42
+ refspec->matching = 1;
30
43
  return 0;
31
44
  }
32
45
 
33
- refspec->src = git__strndup(str, delim - str);
34
- GITERR_CHECK_ALLOC(refspec->src);
46
+ if (rhs) {
47
+ size_t rlen = strlen(++rhs);
48
+ is_glob = (1 <= rlen && strchr(rhs, '*'));
49
+ refspec->dst = git__strndup(rhs, rlen);
50
+ }
35
51
 
36
- refspec->dst = git__strdup(delim + 1);
37
- if (refspec->dst == NULL) {
38
- git__free(refspec->src);
39
- refspec->src = NULL;
40
- return -1;
52
+ llen = (rhs ? (size_t)(rhs - lhs - 1) : strlen(lhs));
53
+ if (1 <= llen && memchr(lhs, '*', llen)) {
54
+ if ((rhs && !is_glob) || (!rhs && is_fetch))
55
+ goto invalid;
56
+ is_glob = 1;
57
+ } else if (rhs && is_glob)
58
+ goto invalid;
59
+
60
+ refspec->pattern = is_glob;
61
+ refspec->src = git__strndup(lhs, llen);
62
+ flags = GIT_REF_FORMAT_ALLOW_ONELEVEL
63
+ | (is_glob ? GIT_REF_FORMAT_REFSPEC_PATTERN : 0);
64
+
65
+ if (is_fetch) {
66
+ /*
67
+ * LHS
68
+ * - empty is allowed; it means HEAD.
69
+ * - otherwise it must be a valid looking ref.
70
+ */
71
+ if (!*refspec->src)
72
+ ; /* empty is ok */
73
+ else if (!git_reference__is_valid_name(refspec->src, flags))
74
+ goto invalid;
75
+ /*
76
+ * RHS
77
+ * - missing is ok, and is same as empty.
78
+ * - empty is ok; it means not to store.
79
+ * - otherwise it must be a valid looking ref.
80
+ */
81
+ if (!refspec->dst)
82
+ ; /* ok */
83
+ else if (!*refspec->dst)
84
+ ; /* ok */
85
+ else if (!git_reference__is_valid_name(refspec->dst, flags))
86
+ goto invalid;
87
+ } else {
88
+ /*
89
+ * LHS
90
+ * - empty is allowed; it means delete.
91
+ * - when wildcarded, it must be a valid looking ref.
92
+ * - otherwise, it must be an extended SHA-1, but
93
+ * there is no existing way to validate this.
94
+ */
95
+ if (!*refspec->src)
96
+ ; /* empty is ok */
97
+ else if (is_glob) {
98
+ if (!git_reference__is_valid_name(refspec->src, flags))
99
+ goto invalid;
100
+ }
101
+ else {
102
+ ; /* anything goes, for now */
103
+ }
104
+ /*
105
+ * RHS
106
+ * - missing is allowed, but LHS then must be a
107
+ * valid looking ref.
108
+ * - empty is not allowed.
109
+ * - otherwise it must be a valid looking ref.
110
+ */
111
+ if (!refspec->dst) {
112
+ if (!git_reference__is_valid_name(refspec->src, flags))
113
+ goto invalid;
114
+ } else if (!*refspec->dst) {
115
+ goto invalid;
116
+ } else {
117
+ if (!git_reference__is_valid_name(refspec->dst, flags))
118
+ goto invalid;
119
+ }
41
120
  }
42
121
 
43
122
  return 0;
123
+
124
+ invalid:
125
+ return -1;
126
+ }
127
+
128
+ void git_refspec__free(git_refspec *refspec)
129
+ {
130
+ git__free(refspec->src);
131
+ git__free(refspec->dst);
44
132
  }
45
133
 
46
134
  const char *git_refspec_src(const git_refspec *refspec)
@@ -106,20 +194,20 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con
106
194
  return 0;
107
195
  }
108
196
 
109
- int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name)
197
+ static int refspec_transform(git_buf *out, const char *from, const char *to, const char *name)
110
198
  {
111
- if (git_buf_sets(out, spec->dst) < 0)
199
+ if (git_buf_sets(out, to) < 0)
112
200
  return -1;
113
201
 
114
202
  /*
115
- * No '*' at the end means that it's mapped to one specific local
203
+ * No '*' at the end means that it's mapped to one specific
116
204
  * branch, so no actual transformation is needed.
117
205
  */
118
206
  if (git_buf_len(out) > 0 && out->ptr[git_buf_len(out) - 1] != '*')
119
207
  return 0;
120
208
 
121
209
  git_buf_truncate(out, git_buf_len(out) - 1); /* remove trailing '*' */
122
- git_buf_puts(out, name + strlen(spec->src) - 1);
210
+ git_buf_puts(out, name + strlen(from) - 1);
123
211
 
124
212
  if (git_buf_oom(out))
125
213
  return -1;
@@ -127,3 +215,13 @@ int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *n
127
215
  return 0;
128
216
  }
129
217
 
218
+ int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name)
219
+ {
220
+ return refspec_transform(out, spec->src, spec->dst, name);
221
+ }
222
+
223
+ int git_refspec_transform_l(git_buf *out, const git_refspec *spec, const char *name)
224
+ {
225
+ return refspec_transform(out, spec->dst, spec->src, name);
226
+ }
227
+
@@ -19,7 +19,15 @@ struct git_refspec {
19
19
  matching :1;
20
20
  };
21
21
 
22
+ #define GIT_REFSPEC_TAGS "refs/tags/*:refs/tags/*"
23
+
22
24
  int git_refspec_parse(struct git_refspec *refspec, const char *str);
25
+ int git_refspec__parse(
26
+ struct git_refspec *refspec,
27
+ const char *str,
28
+ bool is_fetch);
29
+
30
+ void git_refspec__free(git_refspec *refspec);
23
31
 
24
32
  /**
25
33
  * Transform a reference to its target following the refspec's rules,
@@ -32,4 +40,15 @@ int git_refspec_parse(struct git_refspec *refspec, const char *str);
32
40
  */
33
41
  int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name);
34
42
 
43
+ /**
44
+ * Transform a reference from its target following the refspec's rules,
45
+ * and writes the results into a git_buf.
46
+ *
47
+ * @param out where to store the source name
48
+ * @param spec the refspec
49
+ * @param name the name of the reference to transform
50
+ * @return 0 or error if buffer allocation fails
51
+ */
52
+ int git_refspec_transform_l(git_buf *out, const git_refspec *spec, const char *name);
53
+
35
54
  #endif
@@ -18,41 +18,42 @@
18
18
 
19
19
  #include <regex.h>
20
20
 
21
- static int refspec_parse(git_refspec *refspec, const char *str)
21
+ static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var, bool is_fetch)
22
22
  {
23
- char *delim;
24
-
25
- memset(refspec, 0x0, sizeof(git_refspec));
26
-
27
- if (*str == '+') {
28
- refspec->force = 1;
29
- str++;
30
- }
31
-
32
- delim = strchr(str, ':');
33
- if (delim == NULL) {
34
- giterr_set(GITERR_NET, "Invalid refspec, missing ':'");
35
- return -1;
36
- }
37
-
38
- refspec->src = git__strndup(str, delim - str);
39
- GITERR_CHECK_ALLOC(refspec->src);
23
+ int error;
24
+ const char *val;
40
25
 
41
- refspec->dst = git__strdup(delim + 1);
42
- GITERR_CHECK_ALLOC(refspec->dst);
26
+ if ((error = git_config_get_string(&val, cfg, var)) < 0)
27
+ return error;
43
28
 
44
- return 0;
29
+ return git_refspec__parse(refspec, val, is_fetch);
45
30
  }
46
31
 
47
- static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var)
32
+ static int download_tags_value(git_remote *remote, git_config *cfg)
48
33
  {
49
- int error;
50
34
  const char *val;
35
+ git_buf buf = GIT_BUF_INIT;
36
+ int error;
51
37
 
52
- if ((error = git_config_get_string(&val, cfg, var)) < 0)
53
- return error;
38
+ if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_UNSET)
39
+ return 0;
54
40
 
55
- return refspec_parse(refspec, val);
41
+ /* This is the default, let's see if we need to change it */
42
+ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
43
+ if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
44
+ return -1;
45
+
46
+ error = git_config_get_string(&val, cfg, git_buf_cstr(&buf));
47
+ git_buf_free(&buf);
48
+ if (!error && !strcmp(val, "--no-tags"))
49
+ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
50
+ else if (!error && !strcmp(val, "--tags"))
51
+ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
52
+
53
+ if (error == GIT_ENOTFOUND)
54
+ error = 0;
55
+
56
+ return error;
56
57
  }
57
58
 
58
59
  int git_remote_new(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
@@ -81,10 +82,15 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *name, con
81
82
  }
82
83
 
83
84
  if (fetch != NULL) {
84
- if (refspec_parse(&remote->fetch, fetch) < 0)
85
+ if (git_refspec__parse(&remote->fetch, fetch, true) < 0)
85
86
  goto on_error;
86
87
  }
87
88
 
89
+ /* A remote without a name doesn't download tags */
90
+ if (!name) {
91
+ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
92
+ }
93
+
88
94
  *out = remote;
89
95
  return 0;
90
96
 
@@ -157,7 +163,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
157
163
  goto cleanup;
158
164
  }
159
165
 
160
- error = parse_remote_refspec(config, &remote->fetch, git_buf_cstr(&buf));
166
+ error = parse_remote_refspec(config, &remote->fetch, git_buf_cstr(&buf), true);
161
167
  if (error == GIT_ENOTFOUND)
162
168
  error = 0;
163
169
 
@@ -172,7 +178,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
172
178
  goto cleanup;
173
179
  }
174
180
 
175
- error = parse_remote_refspec(config, &remote->push, git_buf_cstr(&buf));
181
+ error = parse_remote_refspec(config, &remote->push, git_buf_cstr(&buf), false);
176
182
  if (error == GIT_ENOTFOUND)
177
183
  error = 0;
178
184
 
@@ -181,6 +187,9 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
181
187
  goto cleanup;
182
188
  }
183
189
 
190
+ if (download_tags_value(remote, config) < 0)
191
+ goto cleanup;
192
+
184
193
  *out = remote;
185
194
 
186
195
  cleanup:
@@ -194,7 +203,9 @@ cleanup:
194
203
 
195
204
  int git_remote_save(const git_remote *remote)
196
205
  {
206
+ int error;
197
207
  git_config *config;
208
+ const char *tagopt = NULL;
198
209
  git_buf buf = GIT_BUF_INIT, value = GIT_BUF_INIT;
199
210
 
200
211
  if (git_repository_config__weakptr(&config, remote->repo) < 0)
@@ -256,6 +267,38 @@ int git_remote_save(const git_remote *remote)
256
267
  goto on_error;
257
268
  }
258
269
 
270
+ /*
271
+ * What action to take depends on the old and new values. This
272
+ * is describes by the table below. tagopt means whether the
273
+ * is already a value set in the config
274
+ *
275
+ * AUTO ALL or NONE
276
+ * +-----------------------+
277
+ * tagopt | remove | set |
278
+ * +---------+-------------|
279
+ * !tagopt | nothing | set |
280
+ * +---------+-------------+
281
+ */
282
+
283
+ git_buf_clear(&buf);
284
+ if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
285
+ goto on_error;
286
+
287
+ error = git_config_get_string(&tagopt, config, git_buf_cstr(&buf));
288
+ if (error < 0 && error != GIT_ENOTFOUND)
289
+ goto on_error;
290
+
291
+ if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
292
+ if (git_config_set_string(config, git_buf_cstr(&buf), "--tags") < 0)
293
+ goto on_error;
294
+ } else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
295
+ if (git_config_set_string(config, git_buf_cstr(&buf), "--no-tags") < 0)
296
+ goto on_error;
297
+ } else if (tagopt) {
298
+ if (git_config_delete(config, git_buf_cstr(&buf)) < 0)
299
+ goto on_error;
300
+ }
301
+
259
302
  git_buf_free(&buf);
260
303
  git_buf_free(&value);
261
304
 
@@ -317,11 +360,10 @@ int git_remote_set_fetchspec(git_remote *remote, const char *spec)
317
360
 
318
361
  assert(remote && spec);
319
362
 
320
- if (refspec_parse(&refspec, spec) < 0)
363
+ if (git_refspec__parse(&refspec, spec, true) < 0)
321
364
  return -1;
322
365
 
323
- git__free(remote->fetch.src);
324
- git__free(remote->fetch.dst);
366
+ git_refspec__free(&remote->fetch);
325
367
  remote->fetch.src = refspec.src;
326
368
  remote->fetch.dst = refspec.dst;
327
369
 
@@ -340,11 +382,10 @@ int git_remote_set_pushspec(git_remote *remote, const char *spec)
340
382
 
341
383
  assert(remote && spec);
342
384
 
343
- if (refspec_parse(&refspec, spec) < 0)
385
+ if (git_refspec__parse(&refspec, spec, false) < 0)
344
386
  return -1;
345
387
 
346
- git__free(remote->push.src);
347
- git__free(remote->push.dst);
388
+ git_refspec__free(&remote->push);
348
389
  remote->push.src = refspec.src;
349
390
  remote->push.dst = refspec.dst;
350
391
 
@@ -386,6 +427,9 @@ int git_remote_connect(git_remote *remote, int direction)
386
427
  if (git_transport_new(&t, url) < 0)
387
428
  return -1;
388
429
 
430
+ t->progress_cb = remote->callbacks.progress;
431
+ t->cb_data = remote->callbacks.data;
432
+
389
433
  t->check_cert = remote->check_cert;
390
434
  if (t->connect(t, direction) < 0) {
391
435
  goto on_error;
@@ -442,25 +486,35 @@ int git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats
442
486
 
443
487
  int git_remote_update_tips(git_remote *remote)
444
488
  {
445
- int error = 0;
489
+ int error = 0, autotag;
446
490
  unsigned int i = 0;
447
491
  git_buf refname = GIT_BUF_INIT;
448
492
  git_oid old;
493
+ git_pkt *pkt;
494
+ git_odb *odb;
449
495
  git_vector *refs;
450
496
  git_remote_head *head;
451
497
  git_reference *ref;
452
498
  struct git_refspec *spec;
499
+ git_refspec tagspec;
453
500
 
454
501
  assert(remote);
455
502
 
456
- refs = &remote->refs;
503
+ refs = &remote->transport->refs;
457
504
  spec = &remote->fetch;
458
505
 
459
506
  if (refs->length == 0)
460
507
  return 0;
461
508
 
509
+ if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
510
+ return -1;
511
+
512
+ if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
513
+ return -1;
514
+
462
515
  /* HEAD is only allowed to be the first in the list */
463
- head = refs->contents[0];
516
+ pkt = refs->contents[0];
517
+ head = &((git_pkt_ref *)pkt)->head;
464
518
  if (!strcmp(head->name, GIT_HEAD_FILE)) {
465
519
  if (git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1) < 0)
466
520
  return -1;
@@ -470,10 +524,38 @@ int git_remote_update_tips(git_remote *remote)
470
524
  }
471
525
 
472
526
  for (; i < refs->length; ++i) {
473
- head = refs->contents[i];
527
+ git_pkt *pkt = refs->contents[i];
528
+ autotag = 0;
474
529
 
475
- if (git_refspec_transform_r(&refname, spec, head->name) < 0)
476
- goto on_error;
530
+ if (pkt->type == GIT_PKT_REF)
531
+ head = &((git_pkt_ref *)pkt)->head;
532
+ else
533
+ continue;
534
+
535
+ /* Ignore malformed ref names (which also saves us from tag^{} */
536
+ if (!git_reference_is_valid_name(head->name))
537
+ continue;
538
+
539
+ if (git_refspec_src_matches(spec, head->name)) {
540
+ if (git_refspec_transform_r(&refname, spec, head->name) < 0)
541
+ goto on_error;
542
+ } else if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
543
+
544
+ if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_ALL)
545
+ autotag = 1;
546
+
547
+ if (!git_refspec_src_matches(&tagspec, head->name))
548
+ continue;
549
+
550
+ git_buf_clear(&refname);
551
+ if (git_buf_puts(&refname, head->name) < 0)
552
+ goto on_error;
553
+ } else {
554
+ continue;
555
+ }
556
+
557
+ if (autotag && !git_odb_exists(odb, &head->oid))
558
+ continue;
477
559
 
478
560
  error = git_reference_name_to_oid(&old, remote->repo, refname.ptr);
479
561
  if (error < 0 && error != GIT_ENOTFOUND)
@@ -485,7 +567,9 @@ int git_remote_update_tips(git_remote *remote)
485
567
  if (!git_oid_cmp(&old, &head->oid))
486
568
  continue;
487
569
 
488
- if (git_reference_create_oid(&ref, remote->repo, refname.ptr, &head->oid, 1) < 0)
570
+ /* In autotag mode, don't overwrite any locally-existing tags */
571
+ error = git_reference_create_oid(&ref, remote->repo, refname.ptr, &head->oid, !autotag);
572
+ if (error < 0 && error != GIT_EEXISTS)
489
573
  goto on_error;
490
574
 
491
575
  git_reference_free(ref);
@@ -496,10 +580,12 @@ int git_remote_update_tips(git_remote *remote)
496
580
  }
497
581
  }
498
582
 
583
+ git_refspec__free(&tagspec);
499
584
  git_buf_free(&refname);
500
585
  return 0;
501
586
 
502
587
  on_error:
588
+ git_refspec__free(&tagspec);
503
589
  git_buf_free(&refname);
504
590
  return -1;
505
591
 
@@ -511,6 +597,11 @@ int git_remote_connected(git_remote *remote)
511
597
  return remote->transport == NULL ? 0 : remote->transport->connected;
512
598
  }
513
599
 
600
+ void git_remote_stop(git_remote *remote)
601
+ {
602
+ git_atomic_set(&remote->transport->cancel, 1);
603
+ }
604
+
514
605
  void git_remote_disconnect(git_remote *remote)
515
606
  {
516
607
  assert(remote);
@@ -533,10 +624,8 @@ void git_remote_free(git_remote *remote)
533
624
 
534
625
  git_vector_free(&remote->refs);
535
626
 
536
- git__free(remote->fetch.src);
537
- git__free(remote->fetch.dst);
538
- git__free(remote->push.src);
539
- git__free(remote->push.dst);
627
+ git_refspec__free(&remote->fetch);
628
+ git_refspec__free(&remote->push);
540
629
  git__free(remote->url);
541
630
  git__free(remote->pushurl);
542
631
  git__free(remote->name);
@@ -548,12 +637,12 @@ struct cb_data {
548
637
  regex_t *preg;
549
638
  };
550
639
 
551
- static int remote_list_cb(const char *name, const char *value, void *data_)
640
+ static int remote_list_cb(const git_config_entry *entry, void *data_)
552
641
  {
553
642
  struct cb_data *data = (struct cb_data *)data_;
554
643
  size_t nmatch = 2;
555
644
  regmatch_t pmatch[2];
556
- GIT_UNUSED(value);
645
+ const char *name = entry->name;
557
646
 
558
647
  if (!regexec(data->preg, name, nmatch, pmatch, 0)) {
559
648
  char *remote_name = git__strndup(&name[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so);
@@ -646,4 +735,19 @@ void git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callback
646
735
  assert(remote && callbacks);
647
736
 
648
737
  memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks));
738
+
739
+ if (remote->transport) {
740
+ remote->transport->progress_cb = remote->callbacks.progress;
741
+ remote->transport->cb_data = remote->callbacks.data;
742
+ }
743
+ }
744
+
745
+ int git_remote_autotag(git_remote *remote)
746
+ {
747
+ return remote->download_tags;
748
+ }
749
+
750
+ void git_remote_set_autotag(git_remote *remote, int value)
751
+ {
752
+ remote->download_tags = value;
649
753
  }