Skip to content

Commit 324b6b1

Browse files
committed
Merge branch 'mh/check-attr-relative'
* mh/check-attr-relative: (29 commits) test-path-utils: Add subcommand "prefix_path" test-path-utils: Add subcommand "absolute_path" git-check-attr: Normalize paths git-check-attr: Demonstrate problems with relative paths git-check-attr: Demonstrate problems with unnormalized paths git-check-attr: test that no output is written to stderr Rename git_checkattr() to git_check_attr() git-check-attr: Fix command-line handling to match docs git-check-attr: Drive two tests using the same raw data git-check-attr: Add an --all option to show all attributes git-check-attr: Error out if no pathnames are specified git-check-attr: Process command-line args more systematically git-check-attr: Handle each error separately git-check-attr: Extract a function error_with_usage() git-check-attr: Introduce a new variable git-check-attr: Extract a function output_attr() Allow querying all attributes on a file Remove redundant check Remove redundant call to bootstrap_attr_stack() Extract a function collect_all_attrs() ...
2 parents da68bf3 + 9e81372 commit 324b6b1

File tree

14 files changed

+322
-115
lines changed

14 files changed

+322
-115
lines changed

Documentation/git-check-attr.txt

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ git-check-attr - Display gitattributes information
99
SYNOPSIS
1010
--------
1111
[verse]
12-
'git check-attr' attr... [--] pathname...
13-
'git check-attr' --stdin [-z] attr... < <list-of-paths>
12+
'git check-attr' [-a | --all | attr...] [--] pathname...
13+
'git check-attr' --stdin [-z] [-a | --all | attr...] < <list-of-paths>
1414

1515
DESCRIPTION
1616
-----------
@@ -19,6 +19,11 @@ For every pathname, this command will list if each attribute is 'unspecified',
1919

2020
OPTIONS
2121
-------
22+
-a, --all::
23+
List all attributes that are associated with the specified
24+
paths. If this option is used, then 'unspecified' attributes
25+
will not be included in the output.
26+
2227
--stdin::
2328
Read file names from stdin instead of from the command-line.
2429

@@ -28,8 +33,11 @@ OPTIONS
2833

2934
\--::
3035
Interpret all preceding arguments as attributes and all following
31-
arguments as path names. If not supplied, only the first argument will
32-
be treated as an attribute.
36+
arguments as path names.
37+
38+
If none of `--stdin`, `--all`, or `--` is used, the first argument
39+
will be treated as an attribute and the rest of the arguments as
40+
pathnames.
3341

3442
OUTPUT
3543
------
@@ -69,6 +77,13 @@ org/example/MyClass.java: diff: java
6977
org/example/MyClass.java: myAttr: set
7078
---------------
7179

80+
* Listing all attributes for a file:
81+
---------------
82+
$ git check-attr --all -- org/example/MyClass.java
83+
org/example/MyClass.java: diff: java
84+
org/example/MyClass.java: myAttr: set
85+
---------------
86+
7287
* Listing an attribute for multiple files:
7388
---------------
7489
$ git check-attr myAttr -- org/example/MyClass.java org/example/NoMyAttr.java

Documentation/gitattributes.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,9 @@ frotz unspecified
955955
----------------------------------------------------------------
956956

957957

958+
SEE ALSO
959+
--------
960+
linkgit:git-check-attr[1].
958961

959962
GIT
960963
---

Documentation/technical/api-gitattributes.txt

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,15 @@ Data Structure
1111
`struct git_attr`::
1212

1313
An attribute is an opaque object that is identified by its name.
14-
Pass the name and its length to `git_attr()` function to obtain
15-
the object of this type. The internal representation of this
16-
structure is of no interest to the calling programs.
14+
Pass the name to `git_attr()` function to obtain the object of
15+
this type. The internal representation of this structure is
16+
of no interest to the calling programs. The name of the
17+
attribute can be retrieved by calling `git_attr_name()`.
1718

1819
`struct git_attr_check`::
1920

2021
This structure represents a set of attributes to check in a call
21-
to `git_checkattr()` function, and receives the results.
22-
23-
24-
Calling Sequence
25-
----------------
26-
27-
* Prepare an array of `struct git_attr_check` to define the list of
28-
attributes you would want to check. To populate this array, you would
29-
need to define necessary attributes by calling `git_attr()` function.
30-
31-
* Call git_checkattr() to check the attributes for the path.
32-
33-
* Inspect `git_attr_check` structure to see how each of the attribute in
34-
the array is defined for the path.
22+
to `git_check_attr()` function, and receives the results.
3523

3624

3725
Attribute Values
@@ -57,6 +45,19 @@ If none of the above returns true, `.value` member points at a string
5745
value of the attribute for the path.
5846

5947

48+
Querying Specific Attributes
49+
----------------------------
50+
51+
* Prepare an array of `struct git_attr_check` to define the list of
52+
attributes you would want to check. To populate this array, you would
53+
need to define necessary attributes by calling `git_attr()` function.
54+
55+
* Call `git_check_attr()` to check the attributes for the path.
56+
57+
* Inspect `git_attr_check` structure to see how each of the attribute in
58+
the array is defined for the path.
59+
60+
6061
Example
6162
-------
6263

@@ -72,18 +73,18 @@ static void setup_check(void)
7273
{
7374
if (check[0].attr)
7475
return; /* already done */
75-
check[0].attr = git_attr("crlf", 4);
76-
check[1].attr = git_attr("ident", 5);
76+
check[0].attr = git_attr("crlf");
77+
check[1].attr = git_attr("ident");
7778
}
7879
------------
7980

80-
. Call `git_checkattr()` with the prepared array of `struct git_attr_check`:
81+
. Call `git_check_attr()` with the prepared array of `struct git_attr_check`:
8182

8283
------------
8384
const char *path;
8485

8586
setup_check();
86-
git_checkattr(path, ARRAY_SIZE(check), check);
87+
git_check_attr(path, ARRAY_SIZE(check), check);
8788
------------
8889

8990
. Act on `.value` member of the result, left in `check[]`:
@@ -108,4 +109,20 @@ static void setup_check(void)
108109
}
109110
------------
110111

111-
(JC)
112+
113+
Querying All Attributes
114+
-----------------------
115+
116+
To get the values of all attributes associated with a file:
117+
118+
* Call `git_all_attrs()`, which returns an array of `git_attr_check`
119+
structures.
120+
121+
* Iterate over the `git_attr_check` array to examine the attribute
122+
names and values. The name of the attribute described by a
123+
`git_attr_check` object can be retrieved via
124+
`git_attr_name(check[i].attr)`. (Please note that no items will be
125+
returned for unset attributes, so `ATTR_UNSET()` will return false
126+
for all returned `git_array_check` objects.)
127+
128+
* Free the `git_array_check` array.

archive.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
123123
path_without_prefix = path.buf + args->baselen;
124124

125125
setup_archive_check(check);
126-
if (!git_checkattr(path_without_prefix, ARRAY_SIZE(check), check)) {
126+
if (!git_check_attr(path_without_prefix, ARRAY_SIZE(check), check)) {
127127
if (ATTR_TRUE(check[0].value))
128128
return 0;
129129
convert = ATTR_TRUE(check[1].value);

attr.c

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ static int attr_nr;
3636
static struct git_attr_check *check_all_attr;
3737
static struct git_attr *(git_attr_hash[HASHSIZE]);
3838

39+
char *git_attr_name(struct git_attr *attr)
40+
{
41+
return attr->name;
42+
}
43+
3944
static unsigned hash_name(const char *name, int namelen)
4045
{
4146
unsigned val = 0, c;
@@ -50,12 +55,10 @@ static unsigned hash_name(const char *name, int namelen)
5055
static int invalid_attr_name(const char *name, int namelen)
5156
{
5257
/*
53-
* Attribute name cannot begin with '-' and from
54-
* [-A-Za-z0-9_.]. We'd specifically exclude '=' for now,
55-
* as we might later want to allow non-binary value for
56-
* attributes, e.g. "*.svg merge=special-merge-program-for-svg"
58+
* Attribute name cannot begin with '-' and must consist of
59+
* characters from [-A-Za-z0-9_.].
5760
*/
58-
if (*name == '-')
61+
if (namelen <= 0 || *name == '-')
5962
return -1;
6063
while (namelen--) {
6164
char ch = *name++;
@@ -532,11 +535,18 @@ static void bootstrap_attr_stack(void)
532535
}
533536
}
534537

535-
static void prepare_attr_stack(const char *path, int dirlen)
538+
static void prepare_attr_stack(const char *path)
536539
{
537540
struct attr_stack *elem, *info;
538-
int len;
541+
int dirlen, len;
539542
struct strbuf pathbuf;
543+
const char *cp;
544+
545+
cp = strrchr(path, '/');
546+
if (!cp)
547+
dirlen = 0;
548+
else
549+
dirlen = cp - path;
540550

541551
strbuf_init(&pathbuf, dirlen+2+strlen(GITATTRIBUTES_FILE));
542552

@@ -555,8 +565,7 @@ static void prepare_attr_stack(const char *path, int dirlen)
555565
* .gitattributes in deeper directories to shallower ones,
556566
* and finally use the built-in set as the default.
557567
*/
558-
if (!attr_stack)
559-
bootstrap_attr_stack();
568+
bootstrap_attr_stack();
560569

561570
/*
562571
* Pop the "info" one that is always at the top of the stack.
@@ -703,26 +712,30 @@ static int macroexpand_one(int attr_nr, int rem)
703712
return rem;
704713
}
705714

706-
int git_checkattr(const char *path, int num, struct git_attr_check *check)
715+
/*
716+
* Collect all attributes for path into the array pointed to by
717+
* check_all_attr.
718+
*/
719+
static void collect_all_attrs(const char *path)
707720
{
708721
struct attr_stack *stk;
709-
const char *cp;
710-
int dirlen, pathlen, i, rem;
722+
int i, pathlen, rem;
711723

712-
bootstrap_attr_stack();
724+
prepare_attr_stack(path);
713725
for (i = 0; i < attr_nr; i++)
714726
check_all_attr[i].value = ATTR__UNKNOWN;
715727

716728
pathlen = strlen(path);
717-
cp = strrchr(path, '/');
718-
if (!cp)
719-
dirlen = 0;
720-
else
721-
dirlen = cp - path;
722-
prepare_attr_stack(path, dirlen);
723729
rem = attr_nr;
724730
for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
725731
rem = fill(path, pathlen, stk, rem);
732+
}
733+
734+
int git_check_attr(const char *path, int num, struct git_attr_check *check)
735+
{
736+
int i;
737+
738+
collect_all_attrs(path);
726739

727740
for (i = 0; i < num; i++) {
728741
const char *value = check_all_attr[check[i].attr->attr_nr].value;
@@ -734,6 +747,34 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)
734747
return 0;
735748
}
736749

750+
int git_all_attrs(const char *path, int *num, struct git_attr_check **check)
751+
{
752+
int i, count, j;
753+
754+
collect_all_attrs(path);
755+
756+
/* Count the number of attributes that are set. */
757+
count = 0;
758+
for (i = 0; i < attr_nr; i++) {
759+
const char *value = check_all_attr[i].value;
760+
if (value != ATTR__UNSET && value != ATTR__UNKNOWN)
761+
++count;
762+
}
763+
*num = count;
764+
*check = xmalloc(sizeof(**check) * count);
765+
j = 0;
766+
for (i = 0; i < attr_nr; i++) {
767+
const char *value = check_all_attr[i].value;
768+
if (value != ATTR__UNSET && value != ATTR__UNKNOWN) {
769+
(*check)[j].attr = check_all_attr[i].attr;
770+
(*check)[j].value = value;
771+
++j;
772+
}
773+
}
774+
775+
return 0;
776+
}
777+
737778
void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate)
738779
{
739780
enum git_attr_direction old = direction;

attr.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ extern const char git_attr__false[];
2020
#define ATTR_UNSET(v) ((v) == NULL)
2121

2222
/*
23-
* Send one or more git_attr_check to git_checkattr(), and
23+
* Send one or more git_attr_check to git_check_attr(), and
2424
* each 'value' member tells what its value is.
2525
* Unset one is returned as NULL.
2626
*/
@@ -29,7 +29,23 @@ struct git_attr_check {
2929
const char *value;
3030
};
3131

32-
int git_checkattr(const char *path, int, struct git_attr_check *);
32+
/*
33+
* Return the name of the attribute represented by the argument. The
34+
* return value is a pointer to a null-delimited string that is part
35+
* of the internal data structure; it should not be modified or freed.
36+
*/
37+
char *git_attr_name(struct git_attr *);
38+
39+
int git_check_attr(const char *path, int, struct git_attr_check *);
40+
41+
/*
42+
* Retrieve all attributes that apply to the specified path. *num
43+
* will be set the the number of attributes on the path; **check will
44+
* be set to point at a newly-allocated array of git_attr_check
45+
* objects describing the attributes and their values. *check must be
46+
* free()ed by the caller.
47+
*/
48+
int git_all_attrs(const char *path, int *num, struct git_attr_check **check);
3349

3450
enum git_attr_direction {
3551
GIT_ATTR_CHECKIN,

0 commit comments

Comments
 (0)