Skip to content

Commit e0fac9c

Browse files
committed
Merge branch 'sb/attr' into pu
The attributes API has been updated so that it can later be optimized using the knowledge of which attributes are queried. * sb/attr: (28 commits) attr: convert to new threadsafe API attr: make git_check_attr_counted static attr: make git_attr_counted static attr.c: outline the future plans by heavily commenting attr.c: always pass check[] to collect_some_attrs() attr.c: introduce empty_attr_check_elems() attr.c: correct ugly hack for git_all_attrs() attr.c: rename a local variable check attr.c: pass struct git_attr_check down the callchain attr.c: add push_stack() helper attr: support quoting pathname patterns in C style attr: expose validity check for attribute names attr: add counted string version of git_attr() attr: add counted string version of git_check_attr() attr: retire git_check_attrs() API attr: convert git_check_attrs() callers to use the new API attr: convert git_all_attrs() to use "struct git_attr_check" attr: (re)introduce git_check_attr() and struct git_attr_check attr: rename function and struct related to checking attributes attr.c: plug small leak in parse_attr_line() ...
2 parents 51b8c66 + c69dc92 commit e0fac9c

File tree

13 files changed

+561
-306
lines changed

13 files changed

+561
-306
lines changed

Documentation/gitattributes.txt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ Each line in `gitattributes` file is of form:
2121
pattern attr1 attr2 ...
2222

2323
That is, a pattern followed by an attributes list,
24-
separated by whitespaces. When the pattern matches the
25-
path in question, the attributes listed on the line are given to
26-
the path.
24+
separated by whitespaces. Leading and trailing whitespaces are
25+
ignored. Lines that begin with '#' are ignored. Patterns
26+
that begin with a double quote are quoted in C style.
27+
When the pattern matches the path in question, the attributes
28+
listed on the line are given to the path.
2729

2830
Each attribute can be in one of these states for a given path:
2931

Documentation/technical/api-gitattributes.txt

Lines changed: 85 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,18 @@ attributes to set of paths.
88
Data Structure
99
--------------
1010

11+
extern struct git_attr *git_attr(const char *);
12+
13+
/*
14+
* Return the name of the attribute represented by the argument. The
15+
* return value is a pointer to a null-delimited string that is part
16+
* of the internal data structure; it should not be modified or freed.
17+
*/
18+
extern const char *git_attr_name(const struct git_attr *);
19+
20+
extern int attr_name_valid(const char *name, size_t namelen);
21+
extern void invalid_attr_name_message(struct strbuf *, const char *, int);
22+
1123
`struct git_attr`::
1224

1325
An attribute is an opaque object that is identified by its name.
@@ -18,8 +30,15 @@ Data Structure
1830

1931
`struct git_attr_check`::
2032

21-
This structure represents a set of attributes to check in a call
22-
to `git_check_attr()` function, and receives the results.
33+
This structure represents a collection of `struct git_attrs`.
34+
It is passed to `git_check_attr()` function, specifying the
35+
attributes to check, and receives their values into a corresponding
36+
`struct git_attr_result`.
37+
38+
`struct git_attr_result`::
39+
40+
This structure represents a collection of results to its
41+
corresponding `struct git_attr_check`, that has the same order.
2342

2443

2544
Attribute Values
@@ -48,49 +67,62 @@ value of the attribute for the path.
4867
Querying Specific Attributes
4968
----------------------------
5069

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.
70+
* Prepare `struct git_attr_check` using git_attr_check_initl()
71+
function, enumerating the names of attributes whose values you are
72+
interested in, terminated with a NULL pointer. Alternatively, an
73+
empty `struct git_attr_check` as alloced by git_attr_check_alloc()
74+
can be prepared by calling `git_attr_check_alloc()` function and
75+
then attributes you want to ask about can be added to it with
76+
`git_attr_check_append()` function.
77+
git_attr_check_initl is thread safe, i.e. you can call it
78+
from different threads at the same time; internally however only one
79+
call at a time is processed. If the calls from different threads have
80+
the same arguments, the returned `git_attr_check` may be the same.
5481

55-
* Call `git_check_attr()` to check the attributes for the path.
82+
* Call `git_check_attr()` to check the attributes for the path,
83+
the returned `git_attr_result` contains the result.
5684

57-
* Inspect `git_attr_check` structure to see how each of the attribute in
58-
the array is defined for the path.
85+
* Inspect the returned `git_attr_result` structure to see how
86+
each of the attribute in the array is defined for the path.
5987

88+
* Do not free the result as the memory is owned by the attr subsystem.
6089

6190
Example
6291
-------
6392

64-
To see how attributes "crlf" and "indent" are set for different paths.
93+
To see how attributes "crlf" and "ident" are set for different paths.
6594

66-
. Prepare an array of `struct git_attr_check` with two elements (because
67-
we are checking two attributes). Initialize their `attr` member with
68-
pointers to `struct git_attr` obtained by calling `git_attr()`:
95+
. Prepare a `struct git_attr_check` with two elements (because
96+
we are checking two attributes):
6997

7098
------------
71-
static struct git_attr_check check[2];
99+
static struct git_attr_check *check;
72100
static void setup_check(void)
73101
{
74-
if (check[0].attr)
102+
if (check)
75103
return; /* already done */
76-
check[0].attr = git_attr("crlf");
77-
check[1].attr = git_attr("ident");
104+
check = git_attr_check_initl("crlf", "ident", NULL);
78105
}
79106
------------
80107

81-
. Call `git_check_attr()` with the prepared array of `struct git_attr_check`:
108+
. Call `git_check_attr()` with the prepared `struct git_attr_check`:
82109

83110
------------
84111
const char *path;
112+
struct git_attr_result *result;
85113

86114
setup_check();
87-
git_check_attr(path, ARRAY_SIZE(check), check);
115+
result = git_check_attr(path, check);
88116
------------
89117

90-
. Act on `.value` member of the result, left in `check[]`:
118+
The `result` must not be free'd as it is owned by the attr subsystem.
119+
It is reused by the same thread, so a subsequent call to git_check_attr
120+
in the same thread will overwrite the result.
121+
122+
. Act on `result->value[]`:
91123

92124
------------
93-
const char *value = check[0].value;
125+
const char *value = result->value[0];
94126

95127
if (ATTR_TRUE(value)) {
96128
The attribute is Set, by listing only the name of the
@@ -109,20 +141,44 @@ static void setup_check(void)
109141
}
110142
------------
111143

144+
To see how attributes in argv[] are set for different paths, only
145+
the first step in the above would be different.
146+
147+
------------
148+
static struct git_attr_check *check;
149+
static void setup_check(const char **argv)
150+
{
151+
if (check)
152+
return; /* already done */
153+
check = git_attr_check_alloc();
154+
while (*argv) {
155+
struct git_attr *attr = git_attr(*argv);
156+
git_attr_check_append(check, attr);
157+
argv++;
158+
}
159+
}
160+
------------
161+
112162

113163
Querying All Attributes
114164
-----------------------
115165

116166
To get the values of all attributes associated with a file:
117167

118-
* Call `git_all_attrs()`, which returns an array of `git_attr_check`
119-
structures.
168+
* Setup a local variables on the stack for both the question
169+
`struct git_attr_check` as well as the result `struct git_attr_result`.
170+
Zero them out via their respective _INIT macro.
171+
172+
* Call `git_all_attrs()`
120173

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.)
174+
* Iterate over the `git_attr_check.attr[]` array to examine the
175+
attribute names. The name of the attribute described by a
176+
`git_attr_check.attr[]` object can be retrieved via
177+
`git_attr_name(check->attr[i])`. (Please note that no items
178+
will be returned for unset attributes, so `ATTR_UNSET()` will return
179+
false for all returned `git_array_check` objects.)
180+
The respective value for an attribute can be found in the same
181+
index position in of `git_attr_result`.
127182

128-
* Free the `git_array_check` array.
183+
* Clear the local variables by calling `git_attr_check_clear()` and
184+
`git_attr_result_clear()`.

archive.c

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,6 @@ void *sha1_file_to_archive(const struct archiver_args *args,
8787
return buffer;
8888
}
8989

90-
static void setup_archive_check(struct git_attr_check *check)
91-
{
92-
static struct git_attr *attr_export_ignore;
93-
static struct git_attr *attr_export_subst;
94-
95-
if (!attr_export_ignore) {
96-
attr_export_ignore = git_attr("export-ignore");
97-
attr_export_subst = git_attr("export-subst");
98-
}
99-
check[0].attr = attr_export_ignore;
100-
check[1].attr = attr_export_subst;
101-
}
102-
10390
struct directory {
10491
struct directory *up;
10592
struct object_id oid;
@@ -123,7 +110,8 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
123110
struct archiver_context *c = context;
124111
struct archiver_args *args = c->args;
125112
write_archive_entry_fn_t write_entry = c->write_entry;
126-
struct git_attr_check check[2];
113+
static struct git_attr_check *check;
114+
struct git_attr_result *result;
127115
const char *path_without_prefix;
128116
int err;
129117

@@ -137,11 +125,14 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
137125
strbuf_addch(&path, '/');
138126
path_without_prefix = path.buf + args->baselen;
139127

140-
setup_archive_check(check);
141-
if (!git_check_attr(path_without_prefix, ARRAY_SIZE(check), check)) {
142-
if (ATTR_TRUE(check[0].value))
128+
if (!check)
129+
git_attr_check_initl(&check, "export-ignore", "export-subst", NULL);
130+
131+
result = git_check_attr(path_without_prefix, check);
132+
if (result) {
133+
if (ATTR_TRUE(result->value[0]))
143134
return 0;
144-
args->convert = ATTR_TRUE(check[1].value);
135+
args->convert = ATTR_TRUE(result->value[1]);
145136
}
146137

147138
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {

0 commit comments

Comments
 (0)