@matheusbsbs / matheus-bagliano / commits / c397aac02f
Fork 0

convert: provide additional metadata to filters

Now that we have the codebase wired up to pass any additional metadata to filters, let's collect the additional metadata that we'd like to pass. The two main places we pass this metadata are checkouts and archives. In these two situations, reading HEAD isn't a valid option, since HEAD isn't updated for checkouts until after the working tree is written and archives can accept an arbitrary tree. In other situations, HEAD will usually reflect the refname of the branch in current use. We pass a smaller amount of data in other cases, such as git cat-file, where we can really only logically know about the blob. This commit updates only the parts of the checkout code where we don't use unpack_trees. That function and callers of it will be handled in a future commit. In the archive code, we leak a small amount of memory, since nothing we pass in the archiver argument structure is freed. Signed-off-by: brian m. carlson <bk2204@github.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

brian m. carlson committed Mar 16, 2020 at 18:05 UTC c397aac02f9f97976f675115aa5df6ca01e26d59
10 files changed +83 -7
archive.c
+10 -3
@@ -77,6 +77,11 @@ void *object_file_to_archive(const struct archiver_args *args,
77 {
78 void *buffer;
79 const struct commit *commit = args->convert ? args->commit : NULL;
80 + struct checkout_metadata meta;
81 +
82 + init_checkout_metadata(&meta, args->refname,
83 + args->commit_oid ? args->commit_oid :
84 + (args->tree ? &args->tree->object.oid : NULL), oid);
85
86 path += args->baselen;
87 buffer = read_object_file(oid, type, sizep);
@@ -85,7 +90,7 @@ void *object_file_to_archive(const struct archiver_args *args,
90 size_t size = 0;
91
92 strbuf_attach(&buf, buffer, *sizep, *sizep + 1);
88 - convert_to_working_tree(args->repo->index, path, buf.buf, buf.len, &buf, NULL);
93 + convert_to_working_tree(args->repo->index, path, buf.buf, buf.len, &buf, &meta);
94 if (commit)
95 format_subst(commit, buf.buf, buf.len, &buf);
96 buffer = strbuf_detach(&buf, &size);
@@ -385,16 +390,17 @@ static void parse_treeish_arg(const char **argv,
390 struct tree *tree;
391 const struct commit *commit;
392 struct object_id oid;
393 + char *ref = NULL;
394
395 /* Remotes are only allowed to fetch actual refs */
396 if (remote && !remote_allow_unreachable) {
391 - char *ref = NULL;
397 const char *colon = strchrnul(name, ':');
398 int refnamelen = colon - name;
399
400 if (!dwim_ref(name, refnamelen, &oid, &ref))
401 die(_("no such ref: %.*s"), refnamelen, name);
397 - free(ref);
402 + } else {
403 + dwim_ref(name, strlen(name), &oid, &ref);
404 }
405
406 if (get_oid(name, &oid))
@@ -427,6 +433,7 @@ static void parse_treeish_arg(const char **argv,
433
434 tree = parse_tree_indirect(&tree_oid);
435 }
436 + ar_args->refname = ref;
437 ar_args->tree = tree;
438 ar_args->commit_oid = commit_oid;
439 ar_args->commit = commit;
archive.h
+1
@@ -8,6 +8,7 @@ struct repository;
8
9 struct archiver_args {
10 struct repository *repo;
11 + const char *refname;
12 const char *base;
13 size_t baselen;
14 struct tree *tree;
builtin/cat-file.c
+4 -1
@@ -42,7 +42,10 @@ static int filter_object(const char *path, unsigned mode,
42 oid_to_hex(oid), path);
43 if ((type == OBJ_BLOB) && S_ISREG(mode)) {
44 struct strbuf strbuf = STRBUF_INIT;
45 - if (convert_to_working_tree(&the_index, path, *buf, *size, &strbuf, NULL)) {
45 + struct checkout_metadata meta;
46 +
47 + init_checkout_metadata(&meta, NULL, NULL, oid);
48 + if (convert_to_working_tree(&the_index, path, *buf, *size, &strbuf, &meta)) {
49 free(*buf);
50 *size = strbuf.len;
51 *buf = strbuf_detach(&strbuf, NULL);
builtin/checkout.c
+13
@@ -92,6 +92,8 @@ struct branch_info {
92 const char *name; /* The short name used */
93 const char *path; /* The full name of a real branch */
94 struct commit *commit; /* The named commit */
95 + char *refname; /* The full name of the ref being checked out. */
96 + struct object_id oid; /* The object ID of the commit being checked out. */
97 /*
98 * if not null the branch is detached because it's already
99 * checked out in this checkout
@@ -360,6 +362,10 @@ static int checkout_worktree(const struct checkout_opts *opts,
362 state.refresh_cache = 1;
363 state.istate = &the_index;
364
365 + init_checkout_metadata(&state.meta, info->refname,
366 + info->commit ? &info->commit->object.oid : &info->oid,
367 + NULL);
368 +
369 enable_delayed_checkout(&state);
370 for (pos = 0; pos < active_nr; pos++) {
371 struct cache_entry *ce = active_cache[pos];
@@ -636,6 +642,13 @@ static void setup_branch_path(struct branch_info *branch)
642 {
643 struct strbuf buf = STRBUF_INIT;
644
645 + /*
646 + * If this is a ref, resolve it; otherwise, look up the OID for our
647 + * expression. Failure here is okay.
648 + */
649 + if (!dwim_ref(branch->name, strlen(branch->name), &branch->oid, &branch->refname))
650 + repo_get_oid_committish(the_repository, branch->name, &branch->oid);
651 +
652 strbuf_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
653 if (strcmp(buf.buf, branch->name))
654 branch->name = xstrdup(buf.buf);
cache.h
+1
@@ -1679,6 +1679,7 @@ struct checkout {
1679 const char *base_dir;
1680 int base_dir_len;
1681 struct delayed_checkout *delayed_checkout;
1682 + struct checkout_metadata meta;
1683 unsigned force:1,
1684 quiet:1,
1685 not_new:1,
convert.c
+22
@@ -2006,3 +2006,25 @@ int stream_filter(struct stream_filter *filter,
2006 {
2007 return filter->vtbl->filter(filter, input, isize_p, output, osize_p);
2008 }
2009 +
2010 +void init_checkout_metadata(struct checkout_metadata *meta, const char *refname,
2011 + const struct object_id *treeish,
2012 + const struct object_id *blob)
2013 +{
2014 + memset(meta, 0, sizeof(*meta));
2015 + if (refname)
2016 + meta->refname = refname;
2017 + if (treeish)
2018 + oidcpy(&meta->treeish, treeish);
2019 + if (blob)
2020 + oidcpy(&meta->blob, blob);
2021 +}
2022 +
2023 +void clone_checkout_metadata(struct checkout_metadata *dst,
2024 + const struct checkout_metadata *src,
2025 + const struct object_id *blob)
2026 +{
2027 + memcpy(dst, src, sizeof(*dst));
2028 + if (blob)
2029 + oidcpy(&dst->blob, blob);
2030 +}
convert.h
+17
@@ -102,6 +102,23 @@ void convert_to_git_filter_fd(const struct index_state *istate,
102 int would_convert_to_git_filter_fd(const struct index_state *istate,
103 const char *path);
104
105 +/*
106 + * Initialize the checkout metadata with the given values. Any argument may be
107 + * NULL if it is not applicable. The treeish should be a commit if that is
108 + * available, and a tree otherwise.
109 + *
110 + * The refname is not copied and must be valid for the lifetime of the struct.
111 + * THe object IDs are copied.
112 + */
113 +void init_checkout_metadata(struct checkout_metadata *meta, const char *refname,
114 + const struct object_id *treeish,
115 + const struct object_id *blob);
116 +
117 +/* Copy the metadata from src to dst, updating the blob. */
118 +void clone_checkout_metadata(struct checkout_metadata *dst,
119 + const struct checkout_metadata *src,
120 + const struct object_id *blob);
121 +
122 /*
123 * Reset the internal list of attributes used by convert_to_git and
124 * convert_to_working_tree.
diff.c
+4 -1
@@ -4062,6 +4062,9 @@ static void prep_temp_blob(struct index_state *istate,
4062 struct strbuf tempfile = STRBUF_INIT;
4063 char *path_dup = xstrdup(path);
4064 const char *base = basename(path_dup);
4065 + struct checkout_metadata meta;
4066 +
4067 + init_checkout_metadata(&meta, NULL, NULL, oid);
4068
4069 /* Generate "XXXXXX_basename.ext" */
4070 strbuf_addstr(&tempfile, "XXXXXX_");
@@ -4071,7 +4074,7 @@ static void prep_temp_blob(struct index_state *istate,
4074 if (!temp->tempfile)
4075 die_errno("unable to create temp-file");
4076 if (convert_to_working_tree(istate, path,
4074 - (const char *)blob, (size_t)size, &buf, NULL)) {
4077 + (const char *)blob, (size_t)size, &buf, &meta)) {
4078 blob = buf.buf;
4079 size = buf.len;
4080 }
entry.c
+5 -2
@@ -264,6 +264,9 @@ static int write_entry(struct cache_entry *ce,
264 size_t newsize = 0;
265 struct stat st;
266 const struct submodule *sub;
267 + struct checkout_metadata meta;
268 +
269 + clone_checkout_metadata(&meta, &state->meta, &ce->oid);
270
271 if (ce_mode_s_ifmt == S_IFREG) {
272 struct stream_filter *filter = get_stream_filter(state->istate, ce->name,
@@ -315,13 +318,13 @@ static int write_entry(struct cache_entry *ce,
318 */
319 if (dco && dco->state != CE_NO_DELAY) {
320 ret = async_convert_to_working_tree(state->istate, ce->name, new_blob,
318 - size, &buf, NULL, dco);
321 + size, &buf, &meta, dco);
322 if (ret && string_list_has_string(&dco->paths, ce->name)) {
323 free(new_blob);
324 goto delayed;
325 }
326 } else
324 - ret = convert_to_working_tree(state->istate, ce->name, new_blob, size, &buf, NULL);
327 + ret = convert_to_working_tree(state->istate, ce->name, new_blob, size, &buf, &meta);
328
329 if (ret) {
330 free(new_blob);
t/t0021/rot13-filter.pl
+6
@@ -135,7 +135,13 @@ while (1) {
135 if ( exists $DELAY{$pathname} and $DELAY{$pathname}{"requested"} == 0 ) {
136 $DELAY{$pathname}{"requested"} = 1;
137 }
138 + } elsif ($buffer =~ /^(ref|treeish|blob)=/) {
139 + # Do nothing.
140 } else {
141 + # In general, filters need to be graceful about
142 + # new metadata, since it's documented that we
143 + # can pass any key-value pairs, but for tests,
144 + # let's be a little stricter.
145 die "Unknown message '$buffer'";
146 }
147