rugged 0.17.0.b6 → 0.17.0.b7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +3 -3
- data/Rakefile +3 -1
- data/ext/rugged/rugged.c +30 -0
- data/ext/rugged/rugged.h +9 -0
- data/ext/rugged/rugged_branch.c +306 -0
- data/ext/rugged/rugged_config.c +16 -13
- data/ext/rugged/rugged_index.c +25 -0
- data/ext/rugged/rugged_object.c +6 -2
- data/ext/rugged/rugged_reference.c +11 -18
- data/ext/rugged/rugged_revwalk.c +1 -1
- data/lib/rugged.rb +1 -0
- data/lib/rugged/branch.rb +28 -0
- data/lib/rugged/commit.rb +5 -5
- data/lib/rugged/repository.rb +32 -7
- data/lib/rugged/tag.rb +5 -1
- data/lib/rugged/version.rb +1 -1
- data/test/branch_test.rb +227 -0
- data/test/config_test.rb +1 -1
- data/test/fixtures/testrepo.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 +0 -0
- data/test/fixtures/testrepo.git/objects/a3/e05719b428a2d0ed7a55c4ce53dcc5768c6d5e +0 -0
- data/test/index_test.rb +31 -0
- data/test/index_test.rb~ +218 -0
- data/test/lib_test.rb +22 -0
- data/test/reference_test.rb +5 -3
- data/vendor/libgit2/Makefile.embed +1 -1
- data/vendor/libgit2/include/git2.h +1 -0
- data/vendor/libgit2/include/git2/branch.h +17 -13
- data/vendor/libgit2/include/git2/checkout.h +83 -22
- data/vendor/libgit2/include/git2/clone.h +6 -3
- data/vendor/libgit2/include/git2/common.h +1 -8
- data/vendor/libgit2/include/git2/config.h +185 -26
- data/vendor/libgit2/include/git2/diff.h +229 -17
- data/vendor/libgit2/include/git2/errors.h +39 -1
- data/vendor/libgit2/include/git2/ignore.h +6 -3
- data/vendor/libgit2/include/git2/indexer.h +1 -0
- data/vendor/libgit2/include/git2/merge.h +1 -1
- data/vendor/libgit2/include/git2/object.h +7 -4
- data/vendor/libgit2/include/git2/odb.h +4 -2
- data/vendor/libgit2/include/git2/odb_backend.h +6 -0
- data/vendor/libgit2/include/git2/oid.h +2 -0
- data/vendor/libgit2/include/git2/pack.h +89 -0
- data/vendor/libgit2/include/git2/refs.h +88 -0
- data/vendor/libgit2/include/git2/refspec.h +0 -8
- data/vendor/libgit2/include/git2/remote.h +34 -1
- data/vendor/libgit2/include/git2/repository.h +238 -6
- data/vendor/libgit2/include/git2/reset.h +4 -1
- data/vendor/libgit2/include/git2/revwalk.h +1 -1
- data/vendor/libgit2/include/git2/status.h +19 -14
- data/vendor/libgit2/include/git2/strarray.h +54 -0
- data/vendor/libgit2/include/git2/submodule.h +451 -45
- data/vendor/libgit2/include/git2/tag.h +16 -0
- data/vendor/libgit2/include/git2/tree.h +2 -2
- data/vendor/libgit2/include/git2/types.h +4 -0
- data/vendor/libgit2/src/amiga/map.c +4 -7
- data/vendor/libgit2/src/attr.c +21 -13
- data/vendor/libgit2/src/attr.h +3 -1
- data/vendor/libgit2/src/attr_file.c +14 -14
- data/vendor/libgit2/src/attr_file.h +6 -5
- data/vendor/libgit2/src/blob.c +22 -12
- data/vendor/libgit2/src/branch.c +62 -66
- data/vendor/libgit2/src/buffer.c +63 -14
- data/vendor/libgit2/src/buffer.h +4 -0
- data/vendor/libgit2/src/cache.c +5 -4
- data/vendor/libgit2/src/checkout.c +381 -159
- data/vendor/libgit2/src/clone.c +221 -94
- data/vendor/libgit2/src/common.h +13 -3
- data/vendor/libgit2/src/compress.c +53 -0
- data/vendor/libgit2/src/compress.h +16 -0
- data/vendor/libgit2/src/config.c +380 -175
- data/vendor/libgit2/src/config.h +2 -5
- data/vendor/libgit2/src/config_file.c +63 -46
- data/vendor/libgit2/src/config_file.h +16 -4
- data/vendor/libgit2/src/crlf.c +4 -3
- data/vendor/libgit2/src/delta.c +491 -0
- data/vendor/libgit2/src/delta.h +112 -0
- data/vendor/libgit2/src/diff.c +310 -67
- data/vendor/libgit2/src/diff.h +10 -1
- data/vendor/libgit2/src/diff_output.c +1030 -337
- data/vendor/libgit2/src/diff_output.h +86 -0
- data/vendor/libgit2/src/errors.c +10 -1
- data/vendor/libgit2/src/fetch.c +108 -24
- data/vendor/libgit2/src/filebuf.c +8 -2
- data/vendor/libgit2/src/fileops.c +342 -177
- data/vendor/libgit2/src/fileops.h +84 -7
- data/vendor/libgit2/src/filter.c +0 -35
- data/vendor/libgit2/src/filter.h +0 -12
- data/vendor/libgit2/src/{compat/fnmatch.c → fnmatch.c} +16 -4
- data/vendor/libgit2/src/{compat/fnmatch.h → fnmatch.h} +4 -3
- data/vendor/libgit2/src/global.c +4 -0
- data/vendor/libgit2/src/ignore.c +122 -23
- data/vendor/libgit2/src/ignore.h +1 -0
- data/vendor/libgit2/src/index.c +56 -10
- data/vendor/libgit2/src/index.h +2 -0
- data/vendor/libgit2/src/indexer.c +8 -9
- data/vendor/libgit2/src/iterator.c +244 -31
- data/vendor/libgit2/src/iterator.h +30 -1
- data/vendor/libgit2/src/message.c +1 -1
- data/vendor/libgit2/src/netops.c +44 -4
- data/vendor/libgit2/src/object.c +80 -69
- data/vendor/libgit2/src/object.h +39 -0
- data/vendor/libgit2/src/odb.c +79 -15
- data/vendor/libgit2/src/odb.h +20 -5
- data/vendor/libgit2/src/odb_pack.c +65 -33
- data/vendor/libgit2/src/oid.c +0 -3
- data/vendor/libgit2/src/pack-objects.c +1315 -0
- data/vendor/libgit2/src/pack-objects.h +87 -0
- data/vendor/libgit2/src/pack.c +36 -12
- data/vendor/libgit2/src/pack.h +1 -0
- data/vendor/libgit2/src/path.c +42 -9
- data/vendor/libgit2/src/path.h +14 -0
- data/vendor/libgit2/src/pkt.c +52 -2
- data/vendor/libgit2/src/pkt.h +10 -0
- data/vendor/libgit2/src/pool.h +11 -0
- data/vendor/libgit2/src/posix.h +8 -0
- data/vendor/libgit2/src/protocol.c +24 -2
- data/vendor/libgit2/src/protocol.h +4 -0
- data/vendor/libgit2/src/reflog.c +1 -1
- data/vendor/libgit2/src/refs.c +292 -124
- data/vendor/libgit2/src/refs.h +4 -2
- data/vendor/libgit2/src/refspec.c +117 -19
- data/vendor/libgit2/src/refspec.h +19 -0
- data/vendor/libgit2/src/remote.c +152 -48
- data/vendor/libgit2/src/remote.h +4 -1
- data/vendor/libgit2/src/repo_template.h +58 -0
- data/vendor/libgit2/src/repository.c +594 -179
- data/vendor/libgit2/src/repository.h +23 -22
- data/vendor/libgit2/src/reset.c +71 -29
- data/vendor/libgit2/src/revparse.c +26 -17
- data/vendor/libgit2/src/revwalk.c +36 -19
- data/vendor/libgit2/src/sha1.h +7 -0
- data/vendor/libgit2/src/{sha1.c → sha1/sha1.c} +0 -0
- data/vendor/libgit2/src/signature.c +12 -10
- data/vendor/libgit2/src/status.c +52 -6
- data/vendor/libgit2/src/submodule.c +1363 -255
- data/vendor/libgit2/src/submodule.h +102 -0
- data/vendor/libgit2/src/tag.c +42 -26
- data/vendor/libgit2/src/thread-utils.h +7 -7
- data/vendor/libgit2/src/transport.h +15 -1
- data/vendor/libgit2/src/transports/git.c +1 -1
- data/vendor/libgit2/src/transports/http.c +197 -36
- data/vendor/libgit2/src/tree.c +3 -3
- data/vendor/libgit2/src/unix/map.c +2 -0
- data/vendor/libgit2/src/unix/posix.h +1 -8
- data/vendor/libgit2/src/util.c +6 -1
- data/vendor/libgit2/src/util.h +7 -0
- data/vendor/libgit2/src/vector.c +16 -0
- data/vendor/libgit2/src/vector.h +1 -0
- data/vendor/libgit2/src/win32/dir.c +8 -21
- data/vendor/libgit2/src/win32/findfile.c +149 -0
- data/vendor/libgit2/src/win32/findfile.h +23 -0
- data/vendor/libgit2/src/win32/posix.h +3 -7
- data/vendor/libgit2/src/win32/posix_w32.c +44 -102
- data/vendor/libgit2/src/win32/pthread.c +68 -0
- data/vendor/libgit2/src/win32/pthread.h +7 -0
- data/vendor/libgit2/src/win32/utf-conv.c +60 -71
- data/vendor/libgit2/src/win32/utf-conv.h +4 -3
- metadata +70 -71
- data/vendor/libgit2/include/git2/windows.h +0 -59
data/vendor/libgit2/src/buffer.c
CHANGED
|
@@ -144,31 +144,40 @@ int git_buf_puts(git_buf *buf, const char *string)
|
|
|
144
144
|
int git_buf_puts_escaped(
|
|
145
145
|
git_buf *buf, const char *string, const char *esc_chars, const char *esc_with)
|
|
146
146
|
{
|
|
147
|
-
const char *scan
|
|
148
|
-
size_t total = 0,
|
|
147
|
+
const char *scan;
|
|
148
|
+
size_t total = 0, esc_len = strlen(esc_with), count;
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
if (!string)
|
|
151
|
+
return 0;
|
|
152
|
+
|
|
153
|
+
for (scan = string; *scan; ) {
|
|
154
|
+
/* count run of non-escaped characters */
|
|
155
|
+
count = strcspn(scan, esc_chars);
|
|
156
|
+
total += count;
|
|
157
|
+
scan += count;
|
|
158
|
+
/* count run of escaped characters */
|
|
159
|
+
count = strspn(scan, esc_chars);
|
|
160
|
+
total += count * (esc_len + 1);
|
|
161
|
+
scan += count;
|
|
154
162
|
}
|
|
155
163
|
|
|
156
164
|
ENSURE_SIZE(buf, buf->size + total + 1);
|
|
157
165
|
|
|
158
166
|
for (scan = string; *scan; ) {
|
|
159
|
-
|
|
167
|
+
count = strcspn(scan, esc_chars);
|
|
160
168
|
|
|
161
169
|
memmove(buf->ptr + buf->size, scan, count);
|
|
162
170
|
scan += count;
|
|
163
171
|
buf->size += count;
|
|
164
172
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
buf->size
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
buf->size
|
|
173
|
+
for (count = strspn(scan, esc_chars); count > 0; --count) {
|
|
174
|
+
/* copy escape sequence */
|
|
175
|
+
memmove(buf->ptr + buf->size, esc_with, esc_len);
|
|
176
|
+
buf->size += esc_len;
|
|
177
|
+
/* copy character to be escaped */
|
|
178
|
+
buf->ptr[buf->size] = *scan;
|
|
179
|
+
buf->size++;
|
|
180
|
+
scan++;
|
|
172
181
|
}
|
|
173
182
|
}
|
|
174
183
|
|
|
@@ -177,6 +186,46 @@ int git_buf_puts_escaped(
|
|
|
177
186
|
return 0;
|
|
178
187
|
}
|
|
179
188
|
|
|
189
|
+
static const char b64str[64] =
|
|
190
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
191
|
+
|
|
192
|
+
int git_buf_put_base64(git_buf *buf, const char *data, size_t len)
|
|
193
|
+
{
|
|
194
|
+
size_t extra = len % 3;
|
|
195
|
+
uint8_t *write, a, b, c;
|
|
196
|
+
const uint8_t *read = (const uint8_t *)data;
|
|
197
|
+
|
|
198
|
+
ENSURE_SIZE(buf, buf->size + 4 * ((len / 3) + !!extra) + 1);
|
|
199
|
+
write = (uint8_t *)&buf->ptr[buf->size];
|
|
200
|
+
|
|
201
|
+
/* convert each run of 3 bytes into 4 output bytes */
|
|
202
|
+
for (len -= extra; len > 0; len -= 3) {
|
|
203
|
+
a = *read++;
|
|
204
|
+
b = *read++;
|
|
205
|
+
c = *read++;
|
|
206
|
+
|
|
207
|
+
*write++ = b64str[a >> 2];
|
|
208
|
+
*write++ = b64str[(a & 0x03) << 4 | b >> 4];
|
|
209
|
+
*write++ = b64str[(b & 0x0f) << 2 | c >> 6];
|
|
210
|
+
*write++ = b64str[c & 0x3f];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (extra > 0) {
|
|
214
|
+
a = *read++;
|
|
215
|
+
b = (extra > 1) ? *read++ : 0;
|
|
216
|
+
|
|
217
|
+
*write++ = b64str[a >> 2];
|
|
218
|
+
*write++ = b64str[(a & 0x03) << 4 | b >> 4];
|
|
219
|
+
*write++ = (extra > 1) ? b64str[(b & 0x0f) << 2] : '=';
|
|
220
|
+
*write++ = '=';
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
buf->size = ((char *)write) - buf->ptr;
|
|
224
|
+
buf->ptr[buf->size] = '\0';
|
|
225
|
+
|
|
226
|
+
return 0;
|
|
227
|
+
}
|
|
228
|
+
|
|
180
229
|
int git_buf_vprintf(git_buf *buf, const char *format, va_list ap)
|
|
181
230
|
{
|
|
182
231
|
int len;
|
data/vendor/libgit2/src/buffer.h
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
#define INCLUDE_buffer_h__
|
|
9
9
|
|
|
10
10
|
#include "common.h"
|
|
11
|
+
#include "git2/strarray.h"
|
|
11
12
|
#include <stdarg.h>
|
|
12
13
|
|
|
13
14
|
typedef struct {
|
|
@@ -154,4 +155,7 @@ bool git_buf_is_binary(const git_buf *buf);
|
|
|
154
155
|
/* Unescape all characters in a buffer */
|
|
155
156
|
void git_buf_unescape(git_buf *buf);
|
|
156
157
|
|
|
158
|
+
/* Write data as base64 encoded in buffer */
|
|
159
|
+
int git_buf_put_base64(git_buf *buf, const char *data, size_t len);
|
|
160
|
+
|
|
157
161
|
#endif
|
data/vendor/libgit2/src/cache.c
CHANGED
|
@@ -89,12 +89,13 @@ void *git_cache_try_store(git_cache *cache, void *_entry)
|
|
|
89
89
|
git_cached_obj_decref(node, cache->free_obj);
|
|
90
90
|
cache->nodes[hash & cache->size_mask] = entry;
|
|
91
91
|
}
|
|
92
|
+
|
|
93
|
+
/* increase the refcount again, because we are
|
|
94
|
+
* returning it to the user */
|
|
95
|
+
git_cached_obj_incref(entry);
|
|
96
|
+
|
|
92
97
|
}
|
|
93
98
|
git_mutex_unlock(&cache->lock);
|
|
94
99
|
|
|
95
|
-
/* increase the refcount again, because we are
|
|
96
|
-
* returning it to the user */
|
|
97
|
-
git_cached_obj_incref(entry);
|
|
98
|
-
|
|
99
100
|
return entry;
|
|
100
101
|
}
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
#include "git2/repository.h"
|
|
12
12
|
#include "git2/refs.h"
|
|
13
13
|
#include "git2/tree.h"
|
|
14
|
-
#include "git2/commit.h"
|
|
15
14
|
#include "git2/blob.h"
|
|
16
15
|
#include "git2/config.h"
|
|
16
|
+
#include "git2/diff.h"
|
|
17
17
|
|
|
18
18
|
#include "common.h"
|
|
19
19
|
#include "refs.h"
|
|
@@ -22,209 +22,431 @@
|
|
|
22
22
|
#include "filter.h"
|
|
23
23
|
#include "blob.h"
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
typedef struct tree_walk_data
|
|
25
|
+
struct checkout_diff_data
|
|
29
26
|
{
|
|
27
|
+
git_buf *path;
|
|
28
|
+
size_t workdir_len;
|
|
29
|
+
git_checkout_opts *checkout_opts;
|
|
30
30
|
git_indexer_stats *stats;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
bool
|
|
35
|
-
|
|
31
|
+
git_repository *owner;
|
|
32
|
+
bool can_symlink;
|
|
33
|
+
bool found_submodules;
|
|
34
|
+
bool create_submodules;
|
|
35
|
+
int error;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
static int buffer_to_file(
|
|
39
|
+
git_buf *buffer,
|
|
40
|
+
const char *path,
|
|
41
|
+
mode_t dir_mode,
|
|
42
|
+
int file_open_flags,
|
|
43
|
+
mode_t file_mode)
|
|
44
|
+
{
|
|
45
|
+
int fd, error, error_close;
|
|
36
46
|
|
|
47
|
+
if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
|
|
48
|
+
return error;
|
|
37
49
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
int retcode = GIT_ERROR;
|
|
42
|
-
git_blob *blob;
|
|
50
|
+
if ((fd = p_open(path, file_open_flags, file_mode)) < 0)
|
|
51
|
+
return fd;
|
|
43
52
|
|
|
44
|
-
|
|
45
|
-
if (!(retcode = git_blob_lookup(&blob, data->repo, id))) {
|
|
46
|
-
git_buf linktarget = GIT_BUF_INIT;
|
|
47
|
-
if (!(retcode = git_blob__getbuf(&linktarget, blob))) {
|
|
48
|
-
/* Create the link */
|
|
49
|
-
const char *new = git_buf_cstr(&linktarget),
|
|
50
|
-
*old = git_buf_cstr(fnbuf);
|
|
51
|
-
retcode = data->do_symlinks
|
|
52
|
-
? p_symlink(new, old)
|
|
53
|
-
: git_futils_fake_symlink(new, old);
|
|
54
|
-
}
|
|
55
|
-
git_buf_free(&linktarget);
|
|
56
|
-
git_blob_free(blob);
|
|
57
|
-
}
|
|
53
|
+
error = p_write(fd, git_buf_cstr(buffer), git_buf_len(buffer));
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
}
|
|
55
|
+
error_close = p_close(fd);
|
|
61
56
|
|
|
57
|
+
if (!error)
|
|
58
|
+
error = error_close;
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
if (!error &&
|
|
61
|
+
(file_mode & 0100) != 0 &&
|
|
62
|
+
(error = p_chmod(path, file_mode)) < 0)
|
|
63
|
+
giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
|
|
64
|
+
|
|
65
|
+
return error;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static int blob_content_to_file(
|
|
69
|
+
git_blob *blob,
|
|
70
|
+
const char *path,
|
|
71
|
+
mode_t entry_filemode,
|
|
72
|
+
git_checkout_opts *opts)
|
|
65
73
|
{
|
|
66
|
-
int
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
74
|
+
int error = -1, nb_filters = 0;
|
|
75
|
+
mode_t file_mode = opts->file_mode;
|
|
76
|
+
bool dont_free_filtered = false;
|
|
77
|
+
git_buf unfiltered = GIT_BUF_INIT, filtered = GIT_BUF_INIT;
|
|
78
|
+
git_vector filters = GIT_VECTOR_INIT;
|
|
79
|
+
|
|
80
|
+
if (opts->disable_filters ||
|
|
81
|
+
(nb_filters = git_filters_load(
|
|
82
|
+
&filters,
|
|
83
|
+
git_object_owner((git_object *)blob),
|
|
84
|
+
path,
|
|
85
|
+
GIT_FILTER_TO_WORKTREE)) == 0) {
|
|
86
|
+
|
|
87
|
+
/* Create a fake git_buf from the blob raw data... */
|
|
88
|
+
filtered.ptr = blob->odb_object->raw.data;
|
|
89
|
+
filtered.size = blob->odb_object->raw.len;
|
|
90
|
+
|
|
91
|
+
/* ... and make sure it doesn't get unexpectedly freed */
|
|
92
|
+
dont_free_filtered = true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (nb_filters < 0)
|
|
96
|
+
return nb_filters;
|
|
97
|
+
|
|
98
|
+
if (nb_filters > 0) {
|
|
99
|
+
if ((error = git_blob__getbuf(&unfiltered, blob)) < 0)
|
|
100
|
+
goto cleanup;
|
|
101
|
+
|
|
102
|
+
if ((error = git_filters_apply(&filtered, &unfiltered, &filters)) < 0)
|
|
103
|
+
goto cleanup;
|
|
86
104
|
}
|
|
87
|
-
if (retcode < 0) goto bctf_cleanup;
|
|
88
105
|
|
|
89
106
|
/* Allow overriding of file mode */
|
|
90
107
|
if (!file_mode)
|
|
91
|
-
file_mode =
|
|
108
|
+
file_mode = entry_filemode;
|
|
109
|
+
|
|
110
|
+
error = buffer_to_file(&filtered, path, opts->dir_mode, opts->file_open_flags, file_mode);
|
|
92
111
|
|
|
93
|
-
|
|
94
|
-
|
|
112
|
+
cleanup:
|
|
113
|
+
git_filters_free(&filters);
|
|
114
|
+
git_buf_free(&unfiltered);
|
|
115
|
+
if (!dont_free_filtered)
|
|
116
|
+
git_buf_free(&filtered);
|
|
95
117
|
|
|
96
|
-
|
|
97
|
-
|
|
118
|
+
return error;
|
|
119
|
+
}
|
|
98
120
|
|
|
99
|
-
|
|
100
|
-
|
|
121
|
+
static int blob_content_to_link(git_blob *blob, const char *path, bool can_symlink)
|
|
122
|
+
{
|
|
123
|
+
git_buf linktarget = GIT_BUF_INIT;
|
|
124
|
+
int error;
|
|
125
|
+
|
|
126
|
+
if ((error = git_blob__getbuf(&linktarget, blob)) < 0)
|
|
127
|
+
return error;
|
|
128
|
+
|
|
129
|
+
if (can_symlink)
|
|
130
|
+
error = p_symlink(git_buf_cstr(&linktarget), path);
|
|
101
131
|
else
|
|
102
|
-
|
|
103
|
-
|
|
132
|
+
error = git_futils_fake_symlink(git_buf_cstr(&linktarget), path);
|
|
133
|
+
|
|
134
|
+
git_buf_free(&linktarget);
|
|
104
135
|
|
|
105
|
-
|
|
106
|
-
git_buf_free(&contents);
|
|
107
|
-
return retcode;
|
|
136
|
+
return error;
|
|
108
137
|
}
|
|
109
138
|
|
|
110
|
-
static int
|
|
139
|
+
static int checkout_submodule(
|
|
140
|
+
struct checkout_diff_data *data,
|
|
141
|
+
const git_diff_file *file)
|
|
111
142
|
{
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
143
|
+
if (git_futils_mkdir(
|
|
144
|
+
file->path, git_repository_workdir(data->owner),
|
|
145
|
+
data->checkout_opts->dir_mode, GIT_MKDIR_PATH) < 0)
|
|
146
|
+
return -1;
|
|
147
|
+
|
|
148
|
+
/* TODO: two cases:
|
|
149
|
+
* 1 - submodule already checked out, but we need to move the HEAD
|
|
150
|
+
* to the new OID, or
|
|
151
|
+
* 2 - submodule not checked out and we should recursively check it out
|
|
152
|
+
*
|
|
153
|
+
* Checkout will not execute a pull request on the submodule, but a
|
|
154
|
+
* clone command should probably be able to. Do we need a submodule
|
|
155
|
+
* callback option?
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
return 0;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
static int checkout_blob(
|
|
162
|
+
struct checkout_diff_data *data,
|
|
163
|
+
const git_diff_file *file)
|
|
164
|
+
{
|
|
165
|
+
git_blob *blob;
|
|
166
|
+
int error;
|
|
167
|
+
|
|
168
|
+
git_buf_truncate(data->path, data->workdir_len);
|
|
169
|
+
if (git_buf_joinpath(data->path, git_buf_cstr(data->path), file->path) < 0)
|
|
170
|
+
return -1;
|
|
171
|
+
|
|
172
|
+
if ((error = git_blob_lookup(&blob, data->owner, &file->oid)) < 0)
|
|
173
|
+
return error;
|
|
174
|
+
|
|
175
|
+
if (S_ISLNK(file->mode))
|
|
176
|
+
error = blob_content_to_link(
|
|
177
|
+
blob, git_buf_cstr(data->path), data->can_symlink);
|
|
178
|
+
else
|
|
179
|
+
error = blob_content_to_file(
|
|
180
|
+
blob, git_buf_cstr(data->path), file->mode, data->checkout_opts);
|
|
181
|
+
|
|
182
|
+
git_blob_free(blob);
|
|
183
|
+
|
|
184
|
+
return error;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
static int checkout_remove_the_old(
|
|
188
|
+
void *cb_data, const git_diff_delta *delta, float progress)
|
|
189
|
+
{
|
|
190
|
+
struct checkout_diff_data *data = cb_data;
|
|
191
|
+
git_checkout_opts *opts = data->checkout_opts;
|
|
192
|
+
|
|
193
|
+
GIT_UNUSED(progress);
|
|
194
|
+
data->stats->processed++;
|
|
195
|
+
|
|
196
|
+
if ((delta->status == GIT_DELTA_UNTRACKED &&
|
|
197
|
+
(opts->checkout_strategy & GIT_CHECKOUT_REMOVE_UNTRACKED) != 0) ||
|
|
198
|
+
(delta->status == GIT_DELTA_TYPECHANGE &&
|
|
199
|
+
(opts->checkout_strategy & GIT_CHECKOUT_OVERWRITE_MODIFIED) != 0))
|
|
200
|
+
{
|
|
201
|
+
data->error = git_futils_rmdir_r(
|
|
202
|
+
delta->new_file.path,
|
|
203
|
+
git_repository_workdir(data->owner),
|
|
204
|
+
GIT_DIRREMOVAL_FILES_AND_DIRS);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return data->error;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
static int checkout_create_the_new(
|
|
211
|
+
void *cb_data, const git_diff_delta *delta, float progress)
|
|
212
|
+
{
|
|
213
|
+
int error = 0;
|
|
214
|
+
struct checkout_diff_data *data = cb_data;
|
|
215
|
+
git_checkout_opts *opts = data->checkout_opts;
|
|
216
|
+
bool do_checkout = false, do_notify = false;
|
|
217
|
+
|
|
218
|
+
GIT_UNUSED(progress);
|
|
219
|
+
data->stats->processed++;
|
|
220
|
+
|
|
221
|
+
if (delta->status == GIT_DELTA_MODIFIED ||
|
|
222
|
+
delta->status == GIT_DELTA_TYPECHANGE)
|
|
122
223
|
{
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
224
|
+
if ((opts->checkout_strategy & GIT_CHECKOUT_OVERWRITE_MODIFIED) != 0)
|
|
225
|
+
do_checkout = true;
|
|
226
|
+
else if (opts->skipped_notify_cb != NULL)
|
|
227
|
+
do_notify = !data->create_submodules;
|
|
228
|
+
}
|
|
229
|
+
else if (delta->status == GIT_DELTA_DELETED &&
|
|
230
|
+
(opts->checkout_strategy & GIT_CHECKOUT_CREATE_MISSING) != 0)
|
|
231
|
+
do_checkout = true;
|
|
232
|
+
|
|
233
|
+
if (do_notify) {
|
|
234
|
+
if (opts->skipped_notify_cb(
|
|
235
|
+
delta->old_file.path, &delta->old_file.oid,
|
|
236
|
+
delta->old_file.mode, opts->notify_payload))
|
|
237
|
+
{
|
|
238
|
+
giterr_clear();
|
|
239
|
+
error = GIT_EUSER;
|
|
139
240
|
}
|
|
140
|
-
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (do_checkout) {
|
|
244
|
+
bool is_submodule = S_ISGITLINK(delta->old_file.mode);
|
|
141
245
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
246
|
+
if (is_submodule)
|
|
247
|
+
data->found_submodules = true;
|
|
248
|
+
|
|
249
|
+
if (!is_submodule && !data->create_submodules)
|
|
250
|
+
error = checkout_blob(data, &delta->old_file);
|
|
251
|
+
|
|
252
|
+
else if (is_submodule && data->create_submodules)
|
|
253
|
+
error = checkout_submodule(data, &delta->old_file);
|
|
145
254
|
}
|
|
146
255
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return retcode;
|
|
150
|
-
}
|
|
256
|
+
if (error)
|
|
257
|
+
data->error = error;
|
|
151
258
|
|
|
259
|
+
return error;
|
|
260
|
+
}
|
|
152
261
|
|
|
153
|
-
int
|
|
262
|
+
static int retrieve_symlink_capabilities(git_repository *repo, bool *can_symlink)
|
|
154
263
|
{
|
|
155
|
-
int retcode = GIT_ERROR;
|
|
156
|
-
git_indexer_stats dummy_stats;
|
|
157
|
-
git_checkout_opts default_opts = {0};
|
|
158
|
-
git_tree *tree;
|
|
159
|
-
tree_walk_data payload;
|
|
160
264
|
git_config *cfg;
|
|
265
|
+
int error;
|
|
161
266
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
267
|
+
if (git_repository_config__weakptr(&cfg, repo) < 0)
|
|
268
|
+
return -1;
|
|
269
|
+
|
|
270
|
+
error = git_config_get_bool((int *)can_symlink, cfg, "core.symlinks");
|
|
271
|
+
|
|
272
|
+
/*
|
|
273
|
+
* When no "core.symlinks" entry is found in any of the configuration
|
|
274
|
+
* store (local, global or system), default value is "true".
|
|
275
|
+
*/
|
|
276
|
+
if (error == GIT_ENOTFOUND) {
|
|
277
|
+
*can_symlink = true;
|
|
278
|
+
error = 0;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return error;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
static void normalize_options(git_checkout_opts *normalized, git_checkout_opts *proposed)
|
|
285
|
+
{
|
|
286
|
+
assert(normalized);
|
|
287
|
+
|
|
288
|
+
if (!proposed)
|
|
289
|
+
memset(normalized, 0, sizeof(git_checkout_opts));
|
|
290
|
+
else
|
|
291
|
+
memmove(normalized, proposed, sizeof(git_checkout_opts));
|
|
165
292
|
|
|
166
293
|
/* Default options */
|
|
167
|
-
if (!
|
|
168
|
-
|
|
294
|
+
if (!normalized->checkout_strategy)
|
|
295
|
+
normalized->checkout_strategy = GIT_CHECKOUT_DEFAULT;
|
|
296
|
+
|
|
169
297
|
/* opts->disable_filters is false by default */
|
|
170
|
-
if (!
|
|
171
|
-
|
|
172
|
-
opts->file_open_flags = O_CREAT | O_TRUNC | O_WRONLY;
|
|
298
|
+
if (!normalized->dir_mode)
|
|
299
|
+
normalized->dir_mode = GIT_DIR_MODE;
|
|
173
300
|
|
|
174
|
-
if (
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
301
|
+
if (!normalized->file_open_flags)
|
|
302
|
+
normalized->file_open_flags = O_CREAT | O_TRUNC | O_WRONLY;
|
|
303
|
+
}
|
|
178
304
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
305
|
+
int git_checkout_index(
|
|
306
|
+
git_repository *repo,
|
|
307
|
+
git_checkout_opts *opts,
|
|
308
|
+
git_indexer_stats *stats)
|
|
309
|
+
{
|
|
310
|
+
git_diff_list *diff = NULL;
|
|
311
|
+
git_indexer_stats dummy_stats;
|
|
187
312
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
313
|
+
git_diff_options diff_opts = {0};
|
|
314
|
+
git_checkout_opts checkout_opts;
|
|
315
|
+
|
|
316
|
+
struct checkout_diff_data data;
|
|
317
|
+
git_buf workdir = GIT_BUF_INIT;
|
|
318
|
+
|
|
319
|
+
int error;
|
|
320
|
+
|
|
321
|
+
assert(repo);
|
|
322
|
+
|
|
323
|
+
if ((error = git_repository__ensure_not_bare(repo, "checkout")) < 0)
|
|
324
|
+
return error;
|
|
325
|
+
|
|
326
|
+
diff_opts.flags =
|
|
327
|
+
GIT_DIFF_INCLUDE_UNTRACKED |
|
|
328
|
+
GIT_DIFF_INCLUDE_TYPECHANGE |
|
|
329
|
+
GIT_DIFF_SKIP_BINARY_CHECK;
|
|
330
|
+
|
|
331
|
+
if (opts && opts->paths.count > 0)
|
|
332
|
+
diff_opts.pathspec = opts->paths;
|
|
333
|
+
|
|
334
|
+
if ((error = git_diff_workdir_to_index(repo, &diff_opts, &diff)) < 0)
|
|
335
|
+
goto cleanup;
|
|
336
|
+
|
|
337
|
+
if ((error = git_buf_puts(&workdir, git_repository_workdir(repo))) < 0)
|
|
338
|
+
goto cleanup;
|
|
339
|
+
|
|
340
|
+
normalize_options(&checkout_opts, opts);
|
|
341
|
+
|
|
342
|
+
if (!stats)
|
|
343
|
+
stats = &dummy_stats;
|
|
344
|
+
|
|
345
|
+
stats->processed = 0;
|
|
346
|
+
/* total based on 3 passes, but it might be 2 if no submodules */
|
|
347
|
+
stats->total = (unsigned int)git_diff_num_deltas(diff) * 3;
|
|
348
|
+
|
|
349
|
+
memset(&data, 0, sizeof(data));
|
|
350
|
+
|
|
351
|
+
data.path = &workdir;
|
|
352
|
+
data.workdir_len = git_buf_len(&workdir);
|
|
353
|
+
data.checkout_opts = &checkout_opts;
|
|
354
|
+
data.stats = stats;
|
|
355
|
+
data.owner = repo;
|
|
356
|
+
|
|
357
|
+
if ((error = retrieve_symlink_capabilities(repo, &data.can_symlink)) < 0)
|
|
358
|
+
goto cleanup;
|
|
359
|
+
|
|
360
|
+
/* Checkout is best performed with three passes through the diff.
|
|
361
|
+
*
|
|
362
|
+
* 1. First do removes, because we iterate in alphabetical order, thus
|
|
363
|
+
* a new untracked directory will end up sorted *after* a blob that
|
|
364
|
+
* should be checked out with the same name.
|
|
365
|
+
* 2. Then checkout all blobs.
|
|
366
|
+
* 3. Then checkout all submodules in case a new .gitmodules blob was
|
|
367
|
+
* checked out during pass #2.
|
|
368
|
+
*/
|
|
369
|
+
|
|
370
|
+
if (!(error = git_diff_foreach(
|
|
371
|
+
diff, &data, checkout_remove_the_old, NULL, NULL)) &&
|
|
372
|
+
!(error = git_diff_foreach(
|
|
373
|
+
diff, &data, checkout_create_the_new, NULL, NULL)) &&
|
|
374
|
+
data.found_submodules)
|
|
375
|
+
{
|
|
376
|
+
data.create_submodules = true;
|
|
377
|
+
error = git_diff_foreach(
|
|
378
|
+
diff, &data, checkout_create_the_new, NULL, NULL);
|
|
204
379
|
}
|
|
205
380
|
|
|
206
|
-
|
|
207
|
-
return retcode;
|
|
208
|
-
}
|
|
381
|
+
stats->processed = stats->total;
|
|
209
382
|
|
|
383
|
+
cleanup:
|
|
384
|
+
if (error == GIT_EUSER)
|
|
385
|
+
error = (data.error != 0) ? data.error : -1;
|
|
210
386
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
387
|
+
git_diff_list_free(diff);
|
|
388
|
+
git_buf_free(&workdir);
|
|
389
|
+
|
|
390
|
+
return error;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
int git_checkout_tree(
|
|
394
|
+
git_repository *repo,
|
|
395
|
+
git_object *treeish,
|
|
396
|
+
git_checkout_opts *opts,
|
|
397
|
+
git_indexer_stats *stats)
|
|
214
398
|
{
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
int retcode = GIT_ERROR;
|
|
399
|
+
git_index *index = NULL;
|
|
400
|
+
git_tree *tree = NULL;
|
|
218
401
|
|
|
219
|
-
|
|
220
|
-
git_reference_name(ref), true)) < 0)
|
|
221
|
-
return retcode;
|
|
402
|
+
int error;
|
|
222
403
|
|
|
223
|
-
|
|
404
|
+
assert(repo && treeish);
|
|
224
405
|
|
|
225
|
-
|
|
226
|
-
|
|
406
|
+
if (git_object_peel((git_object **)&tree, treeish, GIT_OBJ_TREE) < 0) {
|
|
407
|
+
giterr_set(GITERR_INVALID, "Provided treeish cannot be peeled into a tree.");
|
|
408
|
+
return GIT_ERROR;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if ((error = git_repository_index(&index, repo)) < 0)
|
|
412
|
+
goto cleanup;
|
|
413
|
+
|
|
414
|
+
if ((error = git_index_read_tree(index, tree, NULL)) < 0)
|
|
415
|
+
goto cleanup;
|
|
416
|
+
|
|
417
|
+
if ((error = git_index_write(index)) < 0)
|
|
418
|
+
goto cleanup;
|
|
419
|
+
|
|
420
|
+
error = git_checkout_index(repo, opts, stats);
|
|
421
|
+
|
|
422
|
+
cleanup:
|
|
423
|
+
git_index_free(index);
|
|
424
|
+
git_tree_free(tree);
|
|
425
|
+
return error;
|
|
227
426
|
}
|
|
228
427
|
|
|
428
|
+
int git_checkout_head(
|
|
429
|
+
git_repository *repo,
|
|
430
|
+
git_checkout_opts *opts,
|
|
431
|
+
git_indexer_stats *stats)
|
|
432
|
+
{
|
|
433
|
+
git_reference *head;
|
|
434
|
+
int error;
|
|
435
|
+
git_object *tree = NULL;
|
|
436
|
+
|
|
437
|
+
assert(repo);
|
|
438
|
+
|
|
439
|
+
if ((error = git_repository_head(&head, repo)) < 0)
|
|
440
|
+
return error;
|
|
441
|
+
|
|
442
|
+
if ((error = git_reference_peel(&tree, head, GIT_OBJ_TREE)) < 0)
|
|
443
|
+
goto cleanup;
|
|
444
|
+
|
|
445
|
+
error = git_checkout_tree(repo, tree, opts, stats);
|
|
229
446
|
|
|
230
|
-
|
|
447
|
+
cleanup:
|
|
448
|
+
git_reference_free(head);
|
|
449
|
+
git_object_free(tree);
|
|
450
|
+
|
|
451
|
+
return error;
|
|
452
|
+
}
|