From: Junio C Hamano <gitster@pobox.com>
To: Karthik Nayak <karthik.188@gmail.com>
Cc: git@vger.kernel.org, Toon Claes <toon@iotcl.com>
Subject: Re: [PATCH v5 2/2] attr: add flag `--source` to work with tree-ish
Date: Tue, 03 Jan 2023 08:38:02 +0900 [thread overview]
Message-ID: <xmqq1qocwlr9.fsf@gitster.g> (raw)
In-Reply-To: 23813496fc73b7e5cb9f09b166e05c9a02bac43c.1671793109.git.karthik.188@gmail.com
Karthik Nayak <karthik.188@gmail.com> writes:
> The contents of the .gitattributes files may evolve over time, but "git
> check-attr" always checks attributes against them in the working tree
> and/or in the index. It may be beneficial to optionally allow the users
> to check attributes taken from a commit other than HEAD against paths.
>
> Add a new flag `--source` which will allow users to check the
> attributes against a commit (actually any tree-ish would do). When the
> user uses this flag, we go through the stack of .gitattributes files but
> instead of checking the current working tree and/or in the index, we
> check the blobs from the provided tree-ish object. This allows the
> command to also be used in bare repositories.
>
> Since we use a tree-ish object, the user can pass "--source
> HEAD:subdirectory" and all the attributes will be looked up as if
> subdirectory was the root directory of the repository.
>
> We cannot simply use the `<rev>:<path>` syntax without the `--source`
> flag, similar to how it is used in `git show` because any non-flag
> parameter before `--` is treated as an attribute and any parameter after
> `--` is treated as a pathname.
>
> The change involves creating a new function `read_attr_from_blob`, which
> given the path reads the blob for the path against the provided source and
> parses the attributes line by line. This function is plugged into
> `read_attr()` function wherein we go through the stack of attributes
> files.
>
> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
> Signed-off-by: Toon Claes <toon@iotcl.com>
> Co-authored-by: toon@iotcl.com
> ---
> Documentation/git-check-attr.txt | 10 +++-
> archive.c | 2 +-
> attr.c | 97 +++++++++++++++++++++++---------
> attr.h | 5 +-
> builtin/check-attr.c | 35 +++++++-----
> builtin/pack-objects.c | 2 +-
> convert.c | 2 +-
> ll-merge.c | 4 +-
> pathspec.c | 2 +-
> t/t0003-attributes.sh | 42 +++++++++++++-
> userdiff.c | 2 +-
> ws.c | 2 +-
> 12 files changed, 152 insertions(+), 53 deletions(-)
>
> diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt
> index 84f41a8e82..fb15c44598 100644
> --- a/Documentation/git-check-attr.txt
> +++ b/Documentation/git-check-attr.txt
> @@ -9,8 +9,8 @@ git-check-attr - Display gitattributes information
> SYNOPSIS
> --------
> [verse]
> -'git check-attr' [-a | --all | <attr>...] [--] <pathname>...
> -'git check-attr' --stdin [-z] [-a | --all | <attr>...]
> +'git check-attr' [--source <tree>] [-a | --all | <attr>...] [--] <pathname>...
> +'git check-attr' --stdin [-z] [--source <tree>] [-a | --all | <attr>...]
>
> DESCRIPTION
> -----------
> @@ -36,6 +36,12 @@ OPTIONS
> If `--stdin` is also given, input paths are separated
> with a NUL character instead of a linefeed character.
>
> +--source=<tree>::
> + Check attributes against the specified tree-ish. Paths provided as part
> + of the revision will be treated as the root directory. It is common to
> + specify the source tree by naming a commit, branch or tag associated
> + with it.
> +
> \--::
> Interpret all preceding arguments as attributes and all following
> arguments as path names.
> diff --git a/archive.c b/archive.c
> index 941495f5d7..81ff76fce9 100644
> --- a/archive.c
> +++ b/archive.c
> @@ -120,7 +120,7 @@ static const struct attr_check *get_archive_attrs(struct index_state *istate,
> static struct attr_check *check;
> if (!check)
> check = attr_check_initl("export-ignore", "export-subst", NULL);
> - git_check_attr(istate, path, check);
> + git_check_attr(istate, NULL, path, check);
> return check;
> }
>
> diff --git a/attr.c b/attr.c
> index 42ad6de8c7..a63f267187 100644
> --- a/attr.c
> +++ b/attr.c
> @@ -13,6 +13,8 @@
> #include "dir.h"
> #include "utf8.h"
> #include "quote.h"
> +#include "revision.h"
> +#include "object-store.h"
> #include "thread-utils.h"
>
> const char git_attr__true[] = "(builtin)true";
> @@ -729,14 +731,62 @@ static struct attr_stack *read_attr_from_file(const char *path, unsigned flags)
> return res;
> }
>
> -static struct attr_stack *read_attr_from_index(struct index_state *istate,
> - const char *path,
> - unsigned flags)
> +static struct attr_stack *read_attr_from_buf(char *buf, const char *path,
> + unsigned flags)
> {
> struct attr_stack *res;
> - char *buf, *sp;
> + char *sp;
> int lineno = 0;
>
> + if (!buf)
> + return NULL;
> +
> + CALLOC_ARRAY(res, 1);
> + for (sp = buf; *sp;) {
> + char *ep;
> + int more;
> +
> + ep = strchrnul(sp, '\n');
> + more = (*ep == '\n');
> + *ep = '\0';
> + handle_attr_line(res, sp, path, ++lineno, flags);
> + sp = ep + more;
> + }
> + free(buf);
> +
> + return res;
> +}
> +
> +static struct attr_stack *read_attr_from_blob(struct index_state *istate,
> + const struct object_id *tree_oid,
> + const char *path, unsigned flags)
> +{
> + struct object_id oid;
> + unsigned long sz;
> + enum object_type type;
> + void *buf;
> + unsigned short mode;
> +
> + if (!tree_oid)
> + return NULL;
> +
> + if (get_tree_entry(istate->repo, tree_oid, path, &oid, &mode))
> + return NULL;
> +
> + buf = read_object_file(&oid, &type, &sz);
> + if (!buf || type != OBJ_BLOB) {
> + free(buf);
> + return NULL;
> + }
> +
> + return read_attr_from_buf(buf, path, flags);
> +}
> +
> +static struct attr_stack *read_attr_from_index(struct index_state *istate,
> + const char *path, unsigned flags)
> +{
> + char *buf;
> +
> if (!istate)
> return NULL;
>
> @@ -758,28 +808,19 @@ static struct attr_stack *read_attr_from_index(struct index_state *istate,
> if (!buf)
> return NULL;
>
> - CALLOC_ARRAY(res, 1);
> - for (sp = buf; *sp; ) {
> - char *ep;
> - int more;
> -
> - ep = strchrnul(sp, '\n');
> - more = (*ep == '\n');
> - *ep = '\0';
> - handle_attr_line(res, sp, path, ++lineno, flags);
> - sp = ep + more;
> - }
> - free(buf);
> - return res;
> + return read_attr_from_buf(buf, path, flags);
> }
>
> static struct attr_stack *read_attr(struct index_state *istate,
> + const struct object_id *tree_oid,
> const char *path, unsigned flags)
> {
> struct attr_stack *res = NULL;
>
> if (direction == GIT_ATTR_INDEX) {
> res = read_attr_from_index(istate, path, flags);
> + } else if (tree_oid) {
> + res = read_attr_from_blob(istate, tree_oid, path, flags);
> } else if (!is_bare_repository()) {
> if (direction == GIT_ATTR_CHECKOUT) {
> res = read_attr_from_index(istate, path, flags);
> @@ -839,6 +880,7 @@ static void push_stack(struct attr_stack **attr_stack_p,
> }
>
> static void bootstrap_attr_stack(struct index_state *istate,
> + const struct object_id *tree_oid,
> struct attr_stack **stack)
> {
> struct attr_stack *e;
> @@ -864,7 +906,7 @@ static void bootstrap_attr_stack(struct index_state *istate,
> }
>
> /* root directory */
> - e = read_attr(istate, GITATTRIBUTES_FILE, flags | READ_ATTR_NOFOLLOW);
> + e = read_attr(istate, tree_oid, GITATTRIBUTES_FILE, flags | READ_ATTR_NOFOLLOW);
> push_stack(stack, e, xstrdup(""), 0);
>
> /* info frame */
> @@ -878,6 +920,7 @@ static void bootstrap_attr_stack(struct index_state *istate,
> }
>
> static void prepare_attr_stack(struct index_state *istate,
> + const struct object_id *tree_oid,
> const char *path, int dirlen,
> struct attr_stack **stack)
> {
> @@ -899,7 +942,7 @@ static void prepare_attr_stack(struct index_state *istate,
> * .gitattributes in deeper directories to shallower ones,
> * and finally use the built-in set as the default.
> */
> - bootstrap_attr_stack(istate, stack);
> + bootstrap_attr_stack(istate, tree_oid, stack);
>
> /*
> * Pop the "info" one that is always at the top of the stack.
> @@ -954,7 +997,7 @@ static void prepare_attr_stack(struct index_state *istate,
> strbuf_add(&pathbuf, path + pathbuf.len, (len - pathbuf.len));
> strbuf_addf(&pathbuf, "/%s", GITATTRIBUTES_FILE);
>
> - next = read_attr(istate, pathbuf.buf, READ_ATTR_NOFOLLOW);
> + next = read_attr(istate, tree_oid, pathbuf.buf, READ_ATTR_NOFOLLOW);
>
> /* reset the pathbuf to not include "/.gitattributes" */
> strbuf_setlen(&pathbuf, len);
> @@ -1074,8 +1117,8 @@ static void determine_macros(struct all_attrs_item *all_attrs,
> * Otherwise all attributes are collected.
> */
> static void collect_some_attrs(struct index_state *istate,
> - const char *path,
> - struct attr_check *check)
> + const struct object_id *tree_oid,
> + const char *path, struct attr_check *check)
> {
> int pathlen, rem, dirlen;
> const char *cp, *last_slash = NULL;
> @@ -1094,7 +1137,7 @@ static void collect_some_attrs(struct index_state *istate,
> dirlen = 0;
> }
>
> - prepare_attr_stack(istate, path, dirlen, &check->stack);
> + prepare_attr_stack(istate, tree_oid, path, dirlen, &check->stack);
> all_attrs_init(&g_attr_hashmap, check);
> determine_macros(check->all_attrs, check->stack);
>
> @@ -1103,12 +1146,12 @@ static void collect_some_attrs(struct index_state *istate,
> }
>
> void git_check_attr(struct index_state *istate,
> - const char *path,
> + const struct object_id *tree_oid, const char *path,
> struct attr_check *check)
> {
> int i;
>
> - collect_some_attrs(istate, path, check);
> + collect_some_attrs(istate, tree_oid, path, check);
>
> for (i = 0; i < check->nr; i++) {
> size_t n = check->items[i].attr->attr_nr;
> @@ -1119,13 +1162,13 @@ void git_check_attr(struct index_state *istate,
> }
> }
>
> -void git_all_attrs(struct index_state *istate,
> +void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
> const char *path, struct attr_check *check)
> {
> int i;
>
> attr_check_reset(check);
> - collect_some_attrs(istate, path, check);
> + collect_some_attrs(istate, tree_oid, path, check);
>
> for (i = 0; i < check->all_attrs_nr; i++) {
> const char *name = check->all_attrs[i].attr->name;
> diff --git a/attr.h b/attr.h
> index 3fb40cced0..84a3279215 100644
> --- a/attr.h
> +++ b/attr.h
> @@ -190,13 +190,14 @@ void attr_check_free(struct attr_check *check);
> const char *git_attr_name(const struct git_attr *);
>
> void git_check_attr(struct index_state *istate,
> - const char *path, struct attr_check *check);
> + const struct object_id *tree_oid, const char *path,
> + struct attr_check *check);
FYI, this breaks "make hdr-check".
> /*
> * Retrieve all attributes that apply to the specified path.
> * check holds the attributes and their values.
> */
> -void git_all_attrs(struct index_state *istate,
> +void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
> const char *path, struct attr_check *check);
Likewise.
Perhaps squash something like this in in the next iteration?
attr.h | 1 +
1 file changed, 1 insertion(+)
diff --git i/attr.h w/attr.h
index 84a3279215..fca6c30430 100644
--- i/attr.h
+++ w/attr.h
@@ -108,6 +108,7 @@
*/
struct index_state;
+struct object_id;
/**
* An attribute is an opaque object that is identified by its name. Pass the
next prev parent reply other threads:[~2023-01-02 23:38 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <https://lore.kernel.org/git/cover.1671630304.git.karthik.188@gmail.com/>
2023-01-02 11:04 ` [PATCH v5 0/2] check-attr: add support to work with tree-ish Karthik Nayak
2023-01-02 11:04 ` [PATCH v5 1/2] t0003: move setup for `--all` into new block Karthik Nayak
2023-01-02 11:04 ` [PATCH v5 2/2] attr: add flag `--source` to work with tree-ish Karthik Nayak
2023-01-02 23:38 ` Junio C Hamano [this message]
2023-01-04 10:25 ` Karthik Nayak
2023-01-11 11:30 ` Phillip Wood
2023-01-12 10:53 ` Karthik Nayak
2023-01-12 13:20 ` Ævar Arnfjörð Bjarmason
2023-01-14 8:26 ` Karthik Nayak
2023-01-09 9:10 ` [PATCH v5 0/2] check-attr: add support " Karthik Nayak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=xmqq1qocwlr9.fsf@gitster.g \
--to=gitster@pobox.com \
--cc=git@vger.kernel.org \
--cc=karthik.188@gmail.com \
--cc=toon@iotcl.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.