]>
Commit | Line | Data |
---|---|---|
e1f4a761 | 1 | /* |
359fc2d2 | 2 | * Copyright (C) the libgit2 contributors. All rights reserved. |
e1f4a761 | 3 | * |
bb742ede VM |
4 | * This file is part of libgit2, distributed under the GNU GPL v2 with |
5 | * a Linking Exception. For full terms see the included COPYING file. | |
e1f4a761 CMN |
6 | */ |
7 | ||
eae0bfdc PP |
8 | #include "fetch.h" |
9 | ||
e1f4a761 CMN |
10 | #include "git2/oid.h" |
11 | #include "git2/refs.h" | |
65fbc48a | 12 | #include "git2/revwalk.h" |
41fb1ca0 | 13 | #include "git2/transport.h" |
e1f4a761 | 14 | |
e1f4a761 CMN |
15 | #include "remote.h" |
16 | #include "refspec.h" | |
01ad7b3a | 17 | #include "pack.h" |
2c982daa | 18 | #include "netops.h" |
114f5a6c RB |
19 | #include "repository.h" |
20 | #include "refs.h" | |
7bcd9e23 | 21 | |
35a8a8c5 | 22 | static int maybe_want(git_remote *remote, git_remote_head *head, git_odb *odb, git_refspec *tagspec, git_remote_autotag_option_t tagopt) |
d88d4311 | 23 | { |
3230a44f | 24 | int match = 0; |
e1f4a761 | 25 | |
3230a44f CMN |
26 | if (!git_reference_is_valid_name(head->name)) |
27 | return 0; | |
28 | ||
35a8a8c5 | 29 | if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) { |
505b5d0c | 30 | /* |
e284c451 POL |
31 | * If tagopt is --tags, always request tags |
32 | * in addition to the remote's refspecs | |
505b5d0c | 33 | */ |
359dce72 | 34 | if (git_refspec_src_matches(tagspec, head->name)) |
3230a44f | 35 | match = 1; |
e284c451 POL |
36 | } |
37 | ||
38 | if (!match && git_remote__matching_refspec(remote, head->name)) | |
39 | match = 1; | |
11678b37 | 40 | |
3230a44f CMN |
41 | if (!match) |
42 | return 0; | |
e1f4a761 | 43 | |
d88d4311 | 44 | /* If we have the object, mark it so we don't ask for it */ |
3536c168 | 45 | if (git_odb_exists(odb, &head->oid)) { |
d88d4311 | 46 | head->local = 1; |
3536c168 | 47 | } |
d88d4311 | 48 | else |
359dce72 | 49 | remote->need_pack = 1; |
d88d4311 | 50 | |
359dce72 | 51 | return git_vector_insert(&remote->refs, head); |
d88d4311 VM |
52 | } |
53 | ||
35a8a8c5 | 54 | static int filter_wants(git_remote *remote, const git_fetch_options *opts) |
d88d4311 | 55 | { |
359dce72 | 56 | git_remote_head **heads; |
af613ecd | 57 | git_refspec tagspec, head; |
359dce72 CMN |
58 | int error = 0; |
59 | git_odb *odb; | |
60 | size_t i, heads_len; | |
35a8a8c5 CMN |
61 | git_remote_autotag_option_t tagopt = remote->download_tags; |
62 | ||
c2418f46 | 63 | if (opts && opts->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED) |
35a8a8c5 | 64 | tagopt = opts->download_tags; |
d88d4311 | 65 | |
359dce72 CMN |
66 | git_vector_clear(&remote->refs); |
67 | if ((error = git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true)) < 0) | |
68206c54 | 68 | return error; |
9462c471 | 69 | |
4a3b18a6 CMN |
70 | /* |
71 | * The fetch refspec can be NULL, and what this means is that the | |
72 | * user didn't specify one. This is fine, as it means that we're | |
73 | * not interested in any particular branch but just the remote's | |
74 | * HEAD, which will be stored in FETCH_HEAD after the fetch. | |
75 | */ | |
af613ecd CMN |
76 | if (remote->active_refspecs.length == 0) { |
77 | if ((error = git_refspec__parse(&head, "HEAD", true)) < 0) | |
78 | goto cleanup; | |
79 | ||
1c967df3 | 80 | error = git_refspec__dwim_one(&remote->active_refspecs, &head, &remote->refs); |
ac3d33df | 81 | git_refspec__dispose(&head); |
1c967df3 CMN |
82 | |
83 | if (error < 0) | |
af613ecd CMN |
84 | goto cleanup; |
85 | } | |
86 | ||
359dce72 CMN |
87 | if (git_repository_odb__weakptr(&odb, remote->repo) < 0) |
88 | goto cleanup; | |
e1f4a761 | 89 | |
359dce72 | 90 | if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0) |
68206c54 | 91 | goto cleanup; |
e1f4a761 | 92 | |
359dce72 | 93 | for (i = 0; i < heads_len; i++) { |
35a8a8c5 | 94 | if ((error = maybe_want(remote, heads[i], odb, &tagspec, tagopt)) < 0) |
359dce72 CMN |
95 | break; |
96 | } | |
68206c54 | 97 | |
98 | cleanup: | |
ac3d33df | 99 | git_refspec__dispose(&tagspec); |
68206c54 | 100 | |
101 | return error; | |
e1f4a761 | 102 | } |
65fbc48a | 103 | |
65fbc48a CMN |
104 | /* |
105 | * In this first version, we push all our refs in and start sending | |
106 | * them out. When we get an ACK we hide that commit and continue | |
107 | * traversing until we're done | |
108 | */ | |
35a8a8c5 | 109 | int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) |
65fbc48a | 110 | { |
b5a8aa94 | 111 | git_transport *t = remote->transport; |
25e0b157 | 112 | |
35a8a8c5 | 113 | remote->need_pack = 0; |
31143b36 | 114 | |
35a8a8c5 | 115 | if (filter_wants(remote, opts) < 0) { |
ac3d33df | 116 | git_error_set(GIT_ERROR_NET, "failed to filter the reference list for wants"); |
5eb8affb CMN |
117 | return -1; |
118 | } | |
e1d88030 | 119 | |
da290220 | 120 | /* Don't try to negotiate when we don't want anything */ |
af613ecd | 121 | if (!remote->need_pack) |
5eb8affb | 122 | return 0; |
427ca3d3 | 123 | |
7e1a94db | 124 | /* |
64d01de8 | 125 | * Now we have everything set up so we can start tell the |
41fb1ca0 | 126 | * server what we want and what we have. |
64d01de8 | 127 | */ |
41fb1ca0 PK |
128 | return t->negotiate_fetch(t, |
129 | remote->repo, | |
130 | (const git_remote_head * const *)remote->refs.contents, | |
131 | remote->refs.length); | |
65fbc48a CMN |
132 | } |
133 | ||
8f0104ec | 134 | int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *callbacks) |
2c982daa | 135 | { |
41fb1ca0 | 136 | git_transport *t = remote->transport; |
8f0104ec CMN |
137 | git_transfer_progress_cb progress = NULL; |
138 | void *payload = NULL; | |
2c982daa | 139 | |
25e0b157 | 140 | if (!remote->need_pack) |
e03e71da | 141 | return 0; |
dee5515a | 142 | |
8f0104ec CMN |
143 | if (callbacks) { |
144 | progress = callbacks->transfer_progress; | |
145 | payload = callbacks->payload; | |
146 | } | |
147 | ||
148 | return t->download_pack(t, remote->repo, &remote->stats, progress, payload); | |
149 | } | |
150 | ||
151 | int git_fetch_init_options(git_fetch_options *opts, unsigned int version) | |
152 | { | |
153 | GIT_INIT_STRUCTURE_FROM_TEMPLATE( | |
154 | opts, version, git_fetch_options, GIT_FETCH_OPTIONS_INIT); | |
155 | return 0; | |
dee5515a | 156 | } |