| #include "git-compat-util.h" | |
| #include "repack.h" | |
| #include "repository.h" | |
| #include "run-command.h" | |
| #include "string-list.h" | |
| #include "hex.h" | |
| #include "packfile.h" | |
| #include "list-objects-filter-options.h" | |
| #include "list-objects-filter.h" | |
| #include "odb.h" | |
| #include "promisor-remote.h" | |
| int write_filtered_pack(const struct write_pack_opts *opts, | |
| struct existing_packs *existing, | |
| struct string_list *names) | |
| { | |
| struct child_process cmd = CHILD_PROCESS_INIT; | |
| struct string_list_item *item; | |
| FILE *in; | |
| int ret; | |
| const char *caret; | |
| const char *pack_prefix = write_pack_opts_pack_prefix(opts); | |
| prepare_pack_objects(&cmd, opts->po_args, opts->destination); | |
| strvec_push(&cmd.args, "--stdin-packs"); | |
| for_each_string_list_item(item, &existing->kept_packs) | |
| strvec_pushf(&cmd.args, "--keep-pack=%s", item->string); | |
| cmd.in = -1; | |
| ret = start_command(&cmd); | |
| if (ret) | |
| return ret; | |
| /* | |
| * Here 'names' contains only the pack(s) that were just | |
| * written, which is exactly the packs we want to keep. Also | |
| * 'existing_kept_packs' already contains the packs in | |
| * 'keep_pack_list'. | |
| */ | |
| in = xfdopen(cmd.in, "w"); | |
| for_each_string_list_item(item, names) | |
| fprintf(in, "^%s-%s.pack\n", pack_prefix, item->string); | |
| for_each_string_list_item(item, &existing->non_kept_packs) | |
| fprintf(in, "%s.pack\n", item->string); | |
| for_each_string_list_item(item, &existing->cruft_packs) | |
| fprintf(in, "%s.pack\n", item->string); | |
| caret = opts->po_args->pack_kept_objects ? "" : "^"; | |
| for_each_string_list_item(item, &existing->kept_packs) | |
| fprintf(in, "%s%s.pack\n", caret, item->string); | |
| fclose(in); | |
| return finish_pack_objects_cmd(existing->repo->hash_algo, opts, &cmd, | |
| names); | |
| } | |
| struct collect_cb_data { | |
| struct repository *repo; | |
| struct oidset *set; | |
| }; | |
| static int collect_promisor_blob(const struct object_id *oid, | |
| struct object_info *oi UNUSED, | |
| void *cb_data) | |
| { | |
| struct collect_cb_data *data = cb_data; | |
| struct object_info info = OBJECT_INFO_INIT; | |
| enum object_type type; | |
| info.typep = &type; | |
| /* | |
| * Use OBJECT_INFO_SKIP_FETCH_OBJECT to avoid triggering a | |
| * lazy fetch while collecting promisor blobs. | |
| */ | |
| if (odb_read_object_info_extended(data->repo->objects, oid, &info, | |
| OBJECT_INFO_SKIP_FETCH_OBJECT) < 0) | |
| return 0; | |
| if (type == OBJ_BLOB) | |
| oidset_insert(data->set, oid); | |
| return 0; | |
| } | |
| int enumerate_promisor_blobs(struct repository *repo, | |
| const struct list_objects_filter_options *filter, | |
| struct oidset *to_drop) | |
| { | |
| struct oidset all_promisor_blobs = OIDSET_INIT; | |
| struct collect_cb_data cb = { | |
| .repo = repo, | |
| .set = &all_promisor_blobs | |
| }; | |
| int ret = 0; | |
| /* | |
| * The caller (cmd_repack) is responsible for validating that a | |
| * blob:limit filter and a promisor remote are present before | |
| * calling this function. | |
| * | |
| * Walk only promisor objects. Every object visited here is a | |
| * promisor object, so it is recoverable from the promisor remote | |
| * as long as the remote still has it, the same assumption the rest | |
| * of partial clone relies on. | |
| * | |
| * We do not use write_filtered_pack() here because git repack | |
| * routes promisor objects through repack_promisor_objects() | |
| * before the filter machinery runs, so the filtered pack never | |
| * contains promisor blobs. Direct enumeration via | |
| * ODB_FOR_EACH_OBJECT_PROMISOR_ONLY is the correct approach. | |
| */ | |
| ret = odb_for_each_object(repo->objects, NULL, | |
| collect_promisor_blob, &cb, | |
| ODB_FOR_EACH_OBJECT_PROMISOR_ONLY); | |
| if (ret) | |
| goto cleanup; | |
| /* | |
| * Apply the filter to find which blobs exceed the threshold. | |
| * The caller has to_drop and is responsible for clearing it. | |
| */ | |
| ret = list_objects_filter__filter_oidset(repo, | |
| filter, | |
| &all_promisor_blobs, | |
| to_drop); | |
| cleanup: | |
| oidset_clear(&all_promisor_blobs); | |
| return ret; | |
| } |