source src/push.c
| Line | Flow | Count | Block(s) | Source |
|---|---|---|---|---|
| 1 | - | /* | ||
| 2 | - | * Copyright (C) the libgit2 contributors. All rights reserved. | ||
| 3 | - | * | ||
| 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. | ||
| 6 | - | */ | ||
| 7 | - | |||
| 8 | - | #include "push.h" | ||
| 9 | - | |||
| 10 | - | #include "git2.h" | ||
| 11 | - | |||
| 12 | - | #include "pack.h" | ||
| 13 | - | #include "pack-objects.h" | ||
| 14 | - | #include "remote.h" | ||
| 15 | - | #include "vector.h" | ||
| 16 | - | #include "tree.h" | ||
| 17 | - | |||
| 18 | ##### | 2 | static int push_spec_rref_cmp(const void *a, const void *b) | |
| 19 | - | { | ||
| 20 | ##### | 2 | const push_spec *push_spec_a = a, *push_spec_b = b; | |
| 21 | - | |||
| 22 | ##### | 2 | return strcmp(push_spec_a->refspec.dst, push_spec_b->refspec.dst); | |
| 23 | - | } | ||
| 24 | - | |||
| 25 | ##### | 2 | static int push_status_ref_cmp(const void *a, const void *b) | |
| 26 | - | { | ||
| 27 | ##### | 2 | const push_status *push_status_a = a, *push_status_b = b; | |
| 28 | - | |||
| 29 | ##### | 2 | return strcmp(push_status_a->ref, push_status_b->ref); | |
| 30 | - | } | ||
| 31 | - | |||
| 32 | 9 | 2 | int git_push_new(git_push **out, git_remote *remote) | |
| 33 | - | { | ||
| 34 | - | git_push *p; | ||
| 35 | - | |||
| 36 | 9 | 2 | *out = NULL; | |
| 37 | - | |||
| 38 | 9 | 2 | p = git__calloc(1, sizeof(*p)); | |
| 39 | 9 | 3,4 | GIT_ERROR_CHECK_ALLOC(p); | |
| 40 | - | |||
| 41 | 9 | 5 | p->repo = remote->repo; | |
| 42 | 9 | 5 | p->remote = remote; | |
| 43 | 9 | 5 | p->report_status = 1; | |
| 44 | 9 | 5 | p->pb_parallelism = 1; | |
| 45 | - | |||
| 46 | 9 | 5,6 | if (git_vector_init(&p->specs, 0, push_spec_rref_cmp) < 0) { | |
| 47 | ##### | 7 | git__free(p); | |
| 48 | ##### | 8 | return -1; | |
| 49 | - | } | ||
| 50 | - | |||
| 51 | 9 | 9,10 | if (git_vector_init(&p->status, 0, push_status_ref_cmp) < 0) { | |
| 52 | ##### | 11 | git_vector_free(&p->specs); | |
| 53 | ##### | 12 | git__free(p); | |
| 54 | ##### | 13 | return -1; | |
| 55 | - | } | ||
| 56 | - | |||
| 57 | 9 | 14,15 | if (git_vector_init(&p->updates, 0, NULL) < 0) { | |
| 58 | ##### | 16 | git_vector_free(&p->status); | |
| 59 | ##### | 17 | git_vector_free(&p->specs); | |
| 60 | ##### | 18 | git__free(p); | |
| 61 | ##### | 19 | return -1; | |
| 62 | - | } | ||
| 63 | - | |||
| 64 | 9 | 20 | *out = p; | |
| 65 | 9 | 20 | return 0; | |
| 66 | - | } | ||
| 67 | - | |||
| 68 | ![]() |
2 | 2 | int git_push_set_options(git_push *push, const git_push_options *opts) |
| 69 | - | { | ||
| 70 | 2 | 2,3 | if (!push || !opts) | |
| 71 | ##### | 4 | return -1; | |
| 72 | - | |||
| 73 | 2 | 5-7 | GIT_ERROR_CHECK_VERSION(opts, GIT_PUSH_OPTIONS_VERSION, "git_push_options"); | |
| 74 | - | |||
| 75 | 2 | 8 | push->pb_parallelism = opts->pb_parallelism; | |
| 76 | 2 | 8 | push->connection.custom_headers = &opts->custom_headers; | |
| 77 | 2 | 8 | push->connection.proxy = &opts->proxy_opts; | |
| 78 | - | |||
| 79 | 2 | 8 | return 0; | |
| 80 | - | } | ||
| 81 | - | |||
| 82 | 9 | 2 | static void free_refspec(push_spec *spec) | |
| 83 | - | { | ||
| 84 | 9 | 2 | if (spec == NULL) | |
| 85 | 9 | 3,6 | return; | |
| 86 | - | |||
| 87 | 9 | 4 | git_refspec__dispose(&spec->refspec); | |
| 88 | 9 | 5 | git__free(spec); | |
| 89 | - | } | ||
| 90 | - | |||
| 91 | 9 | 2 | static int check_rref(char *ref) | |
| 92 | - | { | ||
| 93 | 9 | 2,3 | if (git__prefixcmp(ref, "refs/")) { | |
| 94 | ##### | 4 | git_error_set(GIT_ERROR_INVALID, "not a valid reference '%s'", ref); | |
| 95 | ##### | 5 | return -1; | |
| 96 | - | } | ||
| 97 | - | |||
| 98 | 9 | 6 | return 0; | |
| 99 | - | } | ||
| 100 | - | |||
| 101 | 7 | 2 | static int check_lref(git_push *push, char *ref) | |
| 102 | - | { | ||
| 103 | - | /* lref must be resolvable to an existing object */ | ||
| 104 | - | git_object *obj; | ||
| 105 | 7 | 2 | int error = git_revparse_single(&obj, push->repo, ref); | |
| 106 | 7 | 3 | git_object_free(obj); | |
| 107 | - | |||
| 108 | 7 | 4 | if (!error) | |
| 109 | 7 | 5 | return 0; | |
| 110 | - | |||
| 111 | ##### | 6 | if (error == GIT_ENOTFOUND) | |
| 112 | ##### | 7 | git_error_set(GIT_ERROR_REFERENCE, | |
| 113 | - | "src refspec '%s' does not match any existing object", ref); | ||
| 114 | - | else | ||
| 115 | ##### | 8 | git_error_set(GIT_ERROR_INVALID, "not a valid reference '%s'", ref); | |
| 116 | ##### | 9 | return -1; | |
| 117 | - | } | ||
| 118 | - | |||
| 119 | ![]() |
9 | 2 | static int parse_refspec(git_push *push, push_spec **spec, const char *str) |
| 120 | - | { | ||
| 121 | - | push_spec *s; | ||
| 122 | - | |||
| 123 | 9 | 2 | *spec = NULL; | |
| 124 | - | |||
| 125 | 9 | 2 | s = git__calloc(1, sizeof(*s)); | |
| 126 | 9 | 3,4 | GIT_ERROR_CHECK_ALLOC(s); | |
| 127 | - | |||
| 128 | 9 | 5,6 | if (git_refspec__parse(&s->refspec, str, false) < 0) { | |
| 129 | ##### | 7 | git_error_set(GIT_ERROR_INVALID, "invalid refspec %s", str); | |
| 130 | ##### | 17 | goto on_error; | |
| 131 | - | } | ||
| 132 | - | |||
| 133 | 9 | 8,9,11 | if (s->refspec.src && s->refspec.src[0] != '\0' && | |
| 134 | 7 | 10 | check_lref(push, s->refspec.src) < 0) { | |
| 135 | ##### | 12 | goto on_error; | |
| 136 | - | } | ||
| 137 | - | |||
| 138 | 9 | 13,14 | if (check_rref(s->refspec.dst) < 0) | |
| 139 | ##### | 15 | goto on_error; | |
| 140 | - | |||
| 141 | 9 | 16 | *spec = s; | |
| 142 | 9 | 16 | return 0; | |
| 143 | - | |||
| 144 | - | on_error: | ||
| 145 | ##### | 18 | free_refspec(s); | |
| 146 | ##### | 19 | return -1; | |
| 147 | - | } | ||
| 148 | - | |||
| 149 | ![]() |
9 | 2 | int git_push_add_refspec(git_push *push, const char *refspec) |
| 150 | - | { | ||
| 151 | - | push_spec *spec; | ||
| 152 | - | |||
| 153 | 9 | 2,3,5 | if (parse_refspec(push, &spec, refspec) < 0 || | |
| 154 | 9 | 4 | git_vector_insert(&push->specs, spec) < 0) | |
| 155 | ##### | 6 | return -1; | |
| 156 | - | |||
| 157 | 9 | 7 | return 0; | |
| 158 | - | } | ||
| 159 | - | |||
| 160 | ![]() |
5 | 2 | int git_push_update_tips(git_push *push, const git_remote_callbacks *callbacks) |
| 161 | - | { | ||
| 162 | 5 | 2 | git_buf remote_ref_name = GIT_BUF_INIT; | |
| 163 | - | size_t i, j; | ||
| 164 | - | git_refspec *fetch_spec; | ||
| 165 | 5 | 2 | push_spec *push_spec = NULL; | |
| 166 | - | git_reference *remote_ref; | ||
| 167 | - | push_status *status; | ||
| 168 | 5 | 2 | int error = 0; | |
| 169 | - | |||
| 170 | 10 | 2,42-44 | git_vector_foreach(&push->status, i, status) { | |
| 171 | 5 | 3 | int fire_callback = 1; | |
| 172 | - | |||
| 173 | - | /* Skip unsuccessful updates which have non-empty messages */ | ||
| 174 | 5 | 3 | if (status->msg) | |
| 175 | ##### | 4 | continue; | |
| 176 | - | |||
| 177 | - | /* Find the corresponding remote ref */ | ||
| 178 | 5 | 5 | fetch_spec = git_remote__matching_refspec(push->remote, status->ref); | |
| 179 | 5 | 6 | if (!fetch_spec) | |
| 180 | ##### | 7 | continue; | |
| 181 | - | |||
| 182 | - | /* Clear the buffer which can be dirty from previous iteration */ | ||
| 183 | 5 | 8 | git_buf_clear(&remote_ref_name); | |
| 184 | - | |||
| 185 | 5 | 9,10 | if ((error = git_refspec_transform(&remote_ref_name, fetch_spec, status->ref)) < 0) | |
| 186 | ##### | 11 | goto on_error; | |
| 187 | - | |||
| 188 | - | /* Find matching push ref spec */ | ||
| 189 | 5 | 12,15-17 | git_vector_foreach(&push->specs, j, push_spec) { | |
| 190 | 5 | 13 | if (!strcmp(push_spec->refspec.dst, status->ref)) | |
| 191 | 5 | 14 | break; | |
| 192 | - | } | ||
| 193 | - | |||
| 194 | - | /* Could not find the corresponding push ref spec for this push update */ | ||
| 195 | 5 | 18 | if (j == push->specs.length) | |
| 196 | ##### | 19 | continue; | |
| 197 | - | |||
| 198 | - | /* Update the remote ref */ | ||
| 199 | 5 | 20,21 | if (git_oid_is_zero(&push_spec->loid)) { | |
| 200 | 2 | 22,23 | error = git_reference_lookup(&remote_ref, push->remote->repo, git_buf_cstr(&remote_ref_name)); | |
| 201 | - | |||
| 202 | 2 | 24 | if (error >= 0) { | |
| 203 | 1 | 25 | error = git_reference_delete(remote_ref); | |
| 204 | 2 | 26,27 | git_reference_free(remote_ref); | |
| 205 | - | } | ||
| 206 | - | } else { | ||
| 207 | 3 | 28,29 | error = git_reference_create(NULL, push->remote->repo, | |
| 208 | 3 | 28 | git_buf_cstr(&remote_ref_name), &push_spec->loid, 1, | |
| 209 | - | "update by push"); | ||
| 210 | - | } | ||
| 211 | - | |||
| 212 | 5 | 30 | if (error < 0) { | |
| 213 | 1 | 31 | if (error != GIT_ENOTFOUND) | |
| 214 | ##### | 32 | goto on_error; | |
| 215 | - | |||
| 216 | 1 | 33 | git_error_clear(); | |
| 217 | 1 | 34 | fire_callback = 0; | |
| 218 | - | } | ||
| 219 | - | |||
| 220 | 5 | 35-37 | if (fire_callback && callbacks && callbacks->update_tips) { | |
| 221 | ##### | 38,38,39 | error = callbacks->update_tips(git_buf_cstr(&remote_ref_name), | |
| 222 | ##### | 38 | &push_spec->roid, &push_spec->loid, callbacks->payload); | |
| 223 | - | |||
| 224 | ##### | 40 | if (error < 0) | |
| 225 | ##### | 41 | goto on_error; | |
| 226 | - | } | ||
| 227 | - | } | ||
| 228 | - | |||
| 229 | 5 | 45 | error = 0; | |
| 230 | - | |||
| 231 | - | on_error: | ||
| 232 | 5 | 46 | git_buf_dispose(&remote_ref_name); | |
| 233 | 5 | 47 | return error; | |
| 234 | - | } | ||
| 235 | - | |||
| 236 | - | /** | ||
| 237 | - | * Insert all tags until we find a non-tag object, which is returned | ||
| 238 | - | * in `out`. | ||
| 239 | - | */ | ||
| 240 | ![]() |
##### | 2 | static int enqueue_tag(git_object **out, git_push *push, git_oid *id) |
| 241 | - | { | ||
| 242 | ##### | 2 | git_object *obj = NULL, *target = NULL; | |
| 243 | - | int error; | ||
| 244 | - | |||
| 245 | ##### | 2,3 | if ((error = git_object_lookup(&obj, push->repo, id, GIT_OBJECT_TAG)) < 0) | |
| 246 | ##### | 4 | return error; | |
| 247 | - | |||
| 248 | ##### | 5,15,16 | while (git_object_type(obj) == GIT_OBJECT_TAG) { | |
| 249 | ##### | 6-8 | if ((error = git_packbuilder_insert(push->pb, git_object_id(obj), NULL)) < 0) | |
| 250 | ##### | 9 | break; | |
| 251 | - | |||
| 252 | ##### | 10,11 | if ((error = git_tag_target(&target, (git_tag *) obj)) < 0) | |
| 253 | ##### | 12 | break; | |
| 254 | - | |||
| 255 | ##### | 13 | git_object_free(obj); | |
| 256 | ##### | 14 | obj = target; | |
| 257 | - | } | ||
| 258 | - | |||
| 259 | ##### | 17 | if (error < 0) | |
| 260 | ##### | 18 | git_object_free(obj); | |
| 261 | - | else | ||
| 262 | ##### | 19 | *out = obj; | |
| 263 | - | |||
| 264 | ##### | 20 | return error; | |
| 265 | - | } | ||
| 266 | - | |||
| 267 | ![]() |
8 | 2 | static int queue_objects(git_push *push) |
| 268 | - | { | ||
| 269 | - | git_remote_head *head; | ||
| 270 | - | push_spec *spec; | ||
| 271 | - | git_revwalk *rw; | ||
| 272 | - | unsigned int i; | ||
| 273 | 8 | 2 | int error = -1; | |
| 274 | - | |||
| 275 | 8 | 2,3 | if (git_revwalk_new(&rw, push->repo) < 0) | |
| 276 | ##### | 4 | return -1; | |
| 277 | - | |||
| 278 | 8 | 5 | git_revwalk_sorting(rw, GIT_SORT_TIME); | |
| 279 | - | |||
| 280 | 16 | 6,60-62 | git_vector_foreach(&push->specs, i, spec) { | |
| 281 | - | git_object_t type; | ||
| 282 | - | size_t size; | ||
| 283 | - | |||
| 284 | 8 | 7,8 | if (git_oid_is_zero(&spec->loid)) | |
| 285 | - | /* | ||
| 286 | - | * Delete reference on remote side; | ||
| 287 | - | * nothing to do here. | ||
| 288 | - | */ | ||
| 289 | 8 | 9,58 | continue; | |
| 290 | - | |||
| 291 | 6 | 10,11 | if (git_oid_equal(&spec->loid, &spec->roid)) | |
| 292 | ##### | 12 | continue; /* up-to-date */ | |
| 293 | - | |||
| 294 | 6 | 13,14 | if (git_odb_read_header(&size, &type, push->repo->_odb, &spec->loid) < 0) | |
| 295 | ##### | 15,59 | goto on_error; | |
| 296 | - | |||
| 297 | 6 | 16 | if (type == GIT_OBJECT_TAG) { | |
| 298 | - | git_object *target; | ||
| 299 | - | |||
| 300 | ##### | 17,18 | if ((error = enqueue_tag(&target, push, &spec->loid)) < 0) | |
| 301 | ##### | 19,34 | goto on_error; | |
| 302 | - | |||
| 303 | ##### | 20,21 | if (git_object_type(target) == GIT_OBJECT_COMMIT) { | |
| 304 | ##### | 22-24 | if (git_revwalk_push(rw, git_object_id(target)) < 0) { | |
| 305 | ##### | 25 | git_object_free(target); | |
| 306 | ##### | 33 | goto on_error; | |
| 307 | - | } | ||
| 308 | - | } else { | ||
| 309 | ##### | 26-28 | if (git_packbuilder_insert( | |
| 310 | - | push->pb, git_object_id(target), NULL) < 0) { | ||
| 311 | ##### | 29 | git_object_free(target); | |
| 312 | ##### | 30 | goto on_error; | |
| 313 | - | } | ||
| 314 | - | } | ||
| 315 | ##### | 31,32 | git_object_free(target); | |
| 316 | 6 | 35,36 | } else if (git_revwalk_push(rw, &spec->loid) < 0) | |
| 317 | ##### | 37 | goto on_error; | |
| 318 | - | |||
| 319 | 6 | 38 | if (!spec->refspec.force) { | |
| 320 | - | git_oid base; | ||
| 321 | - | |||
| 322 | 6 | 39,40 | if (git_oid_is_zero(&spec->roid)) | |
| 323 | 6 | 41 | continue; | |
| 324 | - | |||
| 325 | ##### | 42,43 | if (!git_odb_exists(push->repo->_odb, &spec->roid)) { | |
| 326 | ##### | 44 | git_error_set(GIT_ERROR_REFERENCE, | |
| 327 | - | "cannot push because a reference that you are trying to update on the remote contains commits that are not present locally."); | ||
| 328 | ##### | 45 | error = GIT_ENONFASTFORWARD; | |
| 329 | ##### | 45,56,57 | goto on_error; | |
| 330 | - | } | ||
| 331 | - | |||
| 332 | ##### | 46 | error = git_merge_base(&base, push->repo, | |
| 333 | ##### | 46 | &spec->loid, &spec->roid); | |
| 334 | - | |||
| 335 | ##### | 47,48 | if (error == GIT_ENOTFOUND || | |
| 336 | ##### | 49,50 | (!error && !git_oid_equal(&base, &spec->roid))) { | |
| 337 | ##### | 51 | git_error_set(GIT_ERROR_REFERENCE, | |
| 338 | - | "cannot push non-fastforwardable reference"); | ||
| 339 | ##### | 52 | error = GIT_ENONFASTFORWARD; | |
| 340 | ##### | 52 | goto on_error; | |
| 341 | - | } | ||
| 342 | - | |||
| 343 | ##### | 53 | if (error < 0) | |
| 344 | ##### | 54,55 | goto on_error; | |
| 345 | - | } | ||
| 346 | - | } | ||
| 347 | - | |||
| 348 | 53 | 63,73-75 | git_vector_foreach(&push->remote->refs, i, head) { | |
| 349 | 45 | 64,65 | if (git_oid_is_zero(&head->oid)) | |
| 350 | ##### | 66 | continue; | |
| 351 | - | |||
| 352 | 45 | 67-69 | if ((error = git_revwalk_hide(rw, &head->oid)) < 0 && | |
| 353 | ##### | 70,71 | error != GIT_ENOTFOUND && error != GIT_EINVALIDSPEC && error != GIT_EPEEL) | |
| 354 | ##### | 72 | goto on_error; | |
| 355 | - | } | ||
| 356 | - | |||
| 357 | 8 | 76 | error = git_packbuilder_insert_walk(push->pb, rw); | |
| 358 | - | |||
| 359 | - | on_error: | ||
| 360 | 8 | 77 | git_revwalk_free(rw); | |
| 361 | 8 | 78 | return error; | |
| 362 | - | } | ||
| 363 | - | |||
| 364 | 8 | 2 | static int add_update(git_push *push, push_spec *spec) | |
| 365 | - | { | ||
| 366 | 8 | 2 | git_push_update *u = git__calloc(1, sizeof(git_push_update)); | |
| 367 | 8 | 3,4 | GIT_ERROR_CHECK_ALLOC(u); | |
| 368 | - | |||
| 369 | 8 | 5 | u->src_refname = git__strdup(spec->refspec.src); | |
| 370 | 8 | 6,7 | GIT_ERROR_CHECK_ALLOC(u->src_refname); | |
| 371 | - | |||
| 372 | 8 | 8 | u->dst_refname = git__strdup(spec->refspec.dst); | |
| 373 | 8 | 9,10 | GIT_ERROR_CHECK_ALLOC(u->dst_refname); | |
| 374 | - | |||
| 375 | 8 | 11 | git_oid_cpy(&u->src, &spec->roid); | |
| 376 | 8 | 12 | git_oid_cpy(&u->dst, &spec->loid); | |
| 377 | - | |||
| 378 | 8 | 13 | return git_vector_insert(&push->updates, u); | |
| 379 | - | } | ||
| 380 | - | |||
| 381 | ![]() |
8 | 2 | static int calculate_work(git_push *push) |
| 382 | - | { | ||
| 383 | - | git_remote_head *head; | ||
| 384 | - | push_spec *spec; | ||
| 385 | - | unsigned int i, j; | ||
| 386 | - | |||
| 387 | - | /* Update local and remote oids*/ | ||
| 388 | - | |||
| 389 | 16 | 2,19-21 | git_vector_foreach(&push->specs, i, spec) { | |
| 390 | 8 | 3,4 | if (spec->refspec.src && spec->refspec.src[0]!= '\0') { | |
| 391 | - | /* This is a create or update. Local ref must exist. */ | ||
| 392 | 6 | 5,6 | if (git_reference_name_to_id( | |
| 393 | 6 | 5 | &spec->loid, push->repo, spec->refspec.src) < 0) { | |
| 394 | ##### | 7 | git_error_set(GIT_ERROR_REFERENCE, "no such reference '%s'", spec->refspec.src); | |
| 395 | ##### | 8 | return -1; | |
| 396 | - | } | ||
| 397 | - | } | ||
| 398 | - | |||
| 399 | - | /* Remote ref may or may not (e.g. during create) already exist. */ | ||
| 400 | 35 | 9,12-14 | git_vector_foreach(&push->remote->refs, j, head) { | |
| 401 | 29 | 10 | if (!strcmp(spec->refspec.dst, head->name)) { | |
| 402 | 2 | 11 | git_oid_cpy(&spec->roid, &head->oid); | |
| 403 | 2 | 15 | break; | |
| 404 | - | } | ||
| 405 | - | } | ||
| 406 | - | |||
| 407 | 8 | 16,17 | if (add_update(push, spec) < 0) | |
| 408 | ##### | 18 | return -1; | |
| 409 | - | } | ||
| 410 | - | |||
| 411 | 8 | 22 | return 0; | |
| 412 | - | } | ||
| 413 | - | |||
| 414 | ![]() |
9 | 2 | static int do_push(git_push *push, const git_remote_callbacks *callbacks) |
| 415 | - | { | ||
| 416 | 9 | 2 | int error = 0; | |
| 417 | 9 | 2 | git_transport *transport = push->remote->transport; | |
| 418 | - | |||
| 419 | 9 | 2 | if (!transport->push) { | |
| 420 | 1 | 3 | git_error_set(GIT_ERROR_NET, "remote transport doesn't support push"); | |
| 421 | 1 | 4 | error = -1; | |
| 422 | 1 | 4 | goto on_error; | |
| 423 | - | } | ||
| 424 | - | |||
| 425 | - | /* | ||
| 426 | - | * A pack-file MUST be sent if either create or update command | ||
| 427 | - | * is used, even if the server already has all the necessary | ||
| 428 | - | * objects. In this case the client MUST send an empty pack-file. | ||
| 429 | - | */ | ||
| 430 | - | |||
| 431 | 8 | 5,6 | if ((error = git_packbuilder_new(&push->pb, push->repo)) < 0) | |
| 432 | ##### | 7 | goto on_error; | |
| 433 | - | |||
| 434 | 8 | 8 | git_packbuilder_set_threads(push->pb, push->pb_parallelism); | |
| 435 | - | |||
| 436 | 8 | 9,10 | if (callbacks && callbacks->pack_progress) | |
| 437 | ##### | 11,12 | if ((error = git_packbuilder_set_callbacks(push->pb, callbacks->pack_progress, callbacks->payload)) < 0) | |
| 438 | ##### | 13 | goto on_error; | |
| 439 | - | |||
| 440 | 8 | 14,15 | if ((error = calculate_work(push)) < 0) | |
| 441 | ##### | 16 | goto on_error; | |
| 442 | - | |||
| 443 | 8 | 17-20 | if (callbacks && callbacks->push_negotiation && | |
| 444 | 2 | 19 | (error = callbacks->push_negotiation((const git_push_update **) push->updates.contents, | |
| 445 | - | push->updates.length, callbacks->payload)) < 0) | ||
| 446 | ##### | 21 | goto on_error; | |
| 447 | - | |||
| 448 | 8 | 22-24 | if ((error = queue_objects(push)) < 0 || | |
| 449 | 8 | 24 | (error = transport->push(transport, push, callbacks)) < 0) | |
| 450 | - | goto on_error; | ||
| 451 | - | |||
| 452 | - | on_error: | ||
| 453 | 9 | 25 | git_packbuilder_free(push->pb); | |
| 454 | 9 | 26 | return error; | |
| 455 | - | } | ||
| 456 | - | |||
| 457 | ![]() |
9 | 2 | static int filter_refs(git_remote *remote) |
| 458 | - | { | ||
| 459 | - | const git_remote_head **heads; | ||
| 460 | - | size_t heads_len, i; | ||
| 461 | - | |||
| 462 | 9 | 2 | git_vector_clear(&remote->refs); | |
| 463 | - | |||
| 464 | 9 | 3,4 | if (git_remote_ls(&heads, &heads_len, remote) < 0) | |
| 465 | ##### | 5 | return -1; | |
| 466 | - | |||
| 467 | 76 | 6,10,11 | for (i = 0; i < heads_len; i++) { | |
| 468 | 67 | 7,8 | if (git_vector_insert(&remote->refs, (void *)heads[i]) < 0) | |
| 469 | ##### | 9 | return -1; | |
| 470 | - | } | ||
| 471 | - | |||
| 472 | 9 | 12 | return 0; | |
| 473 | - | } | ||
| 474 | - | |||
| 475 | ![]() |
9 | 2 | int git_push_finish(git_push *push, const git_remote_callbacks *callbacks) |
| 476 | - | { | ||
| 477 | - | int error; | ||
| 478 | - | |||
| 479 | 9 | 2-5 | if (!git_remote_connected(push->remote) && | |
| 480 | ##### | 4 | (error = git_remote__connect(push->remote, GIT_DIRECTION_PUSH, callbacks, &push->connection)) < 0) | |
| 481 | ##### | 6 | return error; | |
| 482 | - | |||
| 483 | 9 | 7-10 | if ((error = filter_refs(push->remote)) < 0 || | |
| 484 | - | (error = do_push(push, callbacks)) < 0) | ||
| 485 | 2 | 11 | return error; | |
| 486 | - | |||
| 487 | 7 | 12 | if (!push->unpack_ok) { | |
| 488 | ##### | 13 | error = -1; | |
| 489 | ##### | 13 | git_error_set(GIT_ERROR_NET, "unpacking the sent packfile failed on the remote"); | |
| 490 | - | } | ||
| 491 | - | |||
| 492 | 7 | 14 | return error; | |
| 493 | - | } | ||
| 494 | - | |||
| 495 | ![]() |
##### | 2 | int git_push_status_foreach(git_push *push, |
| 496 | - | int (*cb)(const char *ref, const char *msg, void *data), | ||
| 497 | - | void *data) | ||
| 498 | - | { | ||
| 499 | - | push_status *status; | ||
| 500 | - | unsigned int i; | ||
| 501 | - | |||
| 502 | ##### | 2,6-8 | git_vector_foreach(&push->status, i, status) { | |
| 503 | ##### | 3 | int error = cb(status->ref, status->msg, data); | |
| 504 | ##### | 4 | if (error) | |
| 505 | ##### | 5 | return git_error_set_after_callback(error); | |
| 506 | - | } | ||
| 507 | - | |||
| 508 | ##### | 9 | return 0; | |
| 509 | - | } | ||
| 510 | - | |||
| 511 | 7 | 2 | void git_push_status_free(push_status *status) | |
| 512 | - | { | ||
| 513 | 7 | 2 | if (status == NULL) | |
| 514 | 7 | 3,7 | return; | |
| 515 | - | |||
| 516 | 7 | 4 | git__free(status->msg); | |
| 517 | 7 | 5 | git__free(status->ref); | |
| 518 | 7 | 6 | git__free(status); | |
| 519 | - | } | ||
| 520 | - | |||
| 521 | 611 | 2 | void git_push_free(git_push *push) | |
| 522 | - | { | ||
| 523 | - | push_spec *spec; | ||
| 524 | - | push_status *status; | ||
| 525 | - | git_push_update *update; | ||
| 526 | - | unsigned int i; | ||
| 527 | - | |||
| 528 | 611 | 2 | if (push == NULL) | |
| 529 | 611 | 3,25 | return; | |
| 530 | - | |||
| 531 | 18 | 4,6-8 | git_vector_foreach(&push->specs, i, spec) { | |
| 532 | 9 | 5 | free_refspec(spec); | |
| 533 | - | } | ||
| 534 | 9 | 9 | git_vector_free(&push->specs); | |
| 535 | - | |||
| 536 | 16 | 10,12-14 | git_vector_foreach(&push->status, i, status) { | |
| 537 | 7 | 11 | git_push_status_free(status); | |
| 538 | - | } | ||
| 539 | 9 | 15 | git_vector_free(&push->status); | |
| 540 | - | |||
| 541 | 17 | 16,20-22 | git_vector_foreach(&push->updates, i, update) { | |
| 542 | 8 | 17 | git__free(update->src_refname); | |
| 543 | 8 | 18 | git__free(update->dst_refname); | |
| 544 | 8 | 19 | git__free(update); | |
| 545 | - | } | ||
| 546 | 9 | 23 | git_vector_free(&push->updates); | |
| 547 | - | |||
| 548 | 9 | 24 | git__free(push); | |
| 549 | - | } | ||
| 550 | - | |||
| 551 | ![]() |
1 | 2 | int git_push_options_init(git_push_options *opts, unsigned int version) |
| 552 | - | { | ||
| 553 | 1 | 2-4 | GIT_INIT_STRUCTURE_FROM_TEMPLATE( | |
| 554 | - | opts, version, git_push_options, GIT_PUSH_OPTIONS_INIT); | ||
| 555 | 1 | 5 | return 0; | |
| 556 | - | } | ||
| 557 | - | |||
| 558 | - | #ifndef GIT_DEPRECATE_HARD | ||
| 559 | ##### | 2 | int git_push_init_options(git_push_options *opts, unsigned int version) | |
| 560 | - | { | ||
| 561 | ##### | 2 | return git_push_options_init(opts, version); | |
| 562 | - | } | ||
| 563 | - | #endif |