2011-08-12 23:43:04 +02:00
|
|
|
/*
|
|
|
|
* Handle git attributes. See gitattributes(5) for a description of
|
2019-11-17 22:04:47 +01:00
|
|
|
* the file syntax, and attr.h for a description of the API.
|
2011-08-12 23:43:04 +02:00
|
|
|
*
|
|
|
|
* One basic design decision here is that we are not going to support
|
|
|
|
* an insanely large number of attributes.
|
|
|
|
*/
|
|
|
|
|
2023-05-16 08:33:57 +02:00
|
|
|
#include "git-compat-util.h"
|
2017-06-14 20:07:36 +02:00
|
|
|
#include "config.h"
|
2023-03-21 07:26:03 +01:00
|
|
|
#include "environment.h"
|
2018-04-10 23:26:18 +02:00
|
|
|
#include "exec-cmd.h"
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
#include "attr.h"
|
2011-10-11 17:53:31 +02:00
|
|
|
#include "dir.h"
|
2023-03-21 07:25:54 +01:00
|
|
|
#include "gettext.h"
|
2023-05-16 08:33:59 +02:00
|
|
|
#include "path.h"
|
2015-04-16 19:48:58 +02:00
|
|
|
#include "utf8.h"
|
2017-01-28 03:01:50 +01:00
|
|
|
#include "quote.h"
|
2023-05-16 08:33:56 +02:00
|
|
|
#include "read-cache-ll.h"
|
2023-01-14 09:30:38 +01:00
|
|
|
#include "revision.h"
|
2023-05-16 08:34:06 +02:00
|
|
|
#include "object-store-ll.h"
|
2023-03-21 07:26:05 +01:00
|
|
|
#include "setup.h"
|
2017-01-28 03:02:01 +01:00
|
|
|
#include "thread-utils.h"
|
2023-04-22 22:17:28 +02:00
|
|
|
#include "tree-walk.h"
|
2023-05-06 06:15:29 +02:00
|
|
|
#include "object-name.h"
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
|
2007-04-19 01:16:37 +02:00
|
|
|
const char git_attr__true[] = "(builtin)true";
|
|
|
|
const char git_attr__false[] = "\0(builtin)false";
|
|
|
|
static const char git_attr__unknown[] = "(builtin)unknown";
|
|
|
|
#define ATTR__TRUE git_attr__true
|
|
|
|
#define ATTR__FALSE git_attr__false
|
|
|
|
#define ATTR__UNSET NULL
|
|
|
|
#define ATTR__UNKNOWN git_attr__unknown
|
2007-04-17 06:33:31 +02:00
|
|
|
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
struct git_attr {
|
2022-12-01 15:45:36 +01:00
|
|
|
unsigned int attr_nr; /* unique attribute number */
|
2017-01-28 03:02:01 +01:00
|
|
|
char name[FLEX_ARRAY]; /* attribute name */
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
};
|
2017-01-28 03:01:53 +01:00
|
|
|
|
2017-01-28 03:01:48 +01:00
|
|
|
const char *git_attr_name(const struct git_attr *attr)
|
2011-08-04 06:36:17 +02:00
|
|
|
{
|
|
|
|
return attr->name;
|
|
|
|
}
|
|
|
|
|
2017-01-28 03:02:01 +01:00
|
|
|
struct attr_hashmap {
|
|
|
|
struct hashmap map;
|
|
|
|
pthread_mutex_t mutex;
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline void hashmap_lock(struct attr_hashmap *map)
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&map->mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void hashmap_unlock(struct attr_hashmap *map)
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
{
|
2017-01-28 03:02:01 +01:00
|
|
|
pthread_mutex_unlock(&map->mutex);
|
|
|
|
}
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
|
2017-01-28 03:02:01 +01:00
|
|
|
/* The container for objects stored in "struct attr_hashmap" */
|
|
|
|
struct attr_hash_entry {
|
2019-10-07 01:30:43 +02:00
|
|
|
struct hashmap_entry ent;
|
2017-01-28 03:02:01 +01:00
|
|
|
const char *key; /* the key; memory should be owned by value */
|
|
|
|
size_t keylen; /* length of the key */
|
|
|
|
void *value; /* the stored value */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* attr_hashmap comparison function */
|
2022-08-25 19:09:48 +02:00
|
|
|
static int attr_hash_entry_cmp(const void *cmp_data UNUSED,
|
2019-10-07 01:30:37 +02:00
|
|
|
const struct hashmap_entry *eptr,
|
|
|
|
const struct hashmap_entry *entry_or_key,
|
2022-08-25 19:09:48 +02:00
|
|
|
const void *keydata UNUSED)
|
2017-01-28 03:02:01 +01:00
|
|
|
{
|
2019-10-07 01:30:37 +02:00
|
|
|
const struct attr_hash_entry *a, *b;
|
|
|
|
|
|
|
|
a = container_of(eptr, const struct attr_hash_entry, ent);
|
|
|
|
b = container_of(entry_or_key, const struct attr_hash_entry, ent);
|
2017-01-28 03:02:01 +01:00
|
|
|
return (a->keylen != b->keylen) || strncmp(a->key, b->key, a->keylen);
|
|
|
|
}
|
|
|
|
|
2020-11-11 21:02:20 +01:00
|
|
|
/*
|
|
|
|
* The global dictionary of all interned attributes. This
|
|
|
|
* is a singleton object which is shared between threads.
|
|
|
|
* Access to this dictionary must be surrounded with a mutex.
|
|
|
|
*/
|
|
|
|
static struct attr_hashmap g_attr_hashmap = {
|
2022-03-17 18:27:17 +01:00
|
|
|
.map = HASHMAP_INIT(attr_hash_entry_cmp, NULL),
|
2020-11-11 21:02:20 +01:00
|
|
|
};
|
2017-01-28 03:02:01 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Retrieve the 'value' stored in a hashmap given the provided 'key'.
|
|
|
|
* If there is no matching entry, return NULL.
|
|
|
|
*/
|
|
|
|
static void *attr_hashmap_get(struct attr_hashmap *map,
|
|
|
|
const char *key, size_t keylen)
|
|
|
|
{
|
|
|
|
struct attr_hash_entry k;
|
|
|
|
struct attr_hash_entry *e;
|
|
|
|
|
2019-10-07 01:30:27 +02:00
|
|
|
hashmap_entry_init(&k.ent, memhash(key, keylen));
|
2017-01-28 03:02:01 +01:00
|
|
|
k.key = key;
|
|
|
|
k.keylen = keylen;
|
2019-10-07 01:30:42 +02:00
|
|
|
e = hashmap_get_entry(&map->map, &k, ent, NULL);
|
2017-01-28 03:02:01 +01:00
|
|
|
|
|
|
|
return e ? e->value : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add 'value' to a hashmap based on the provided 'key'. */
|
|
|
|
static void attr_hashmap_add(struct attr_hashmap *map,
|
|
|
|
const char *key, size_t keylen,
|
|
|
|
void *value)
|
|
|
|
{
|
|
|
|
struct attr_hash_entry *e;
|
|
|
|
|
|
|
|
e = xmalloc(sizeof(struct attr_hash_entry));
|
2019-10-07 01:30:27 +02:00
|
|
|
hashmap_entry_init(&e->ent, memhash(key, keylen));
|
2017-01-28 03:02:01 +01:00
|
|
|
e->key = key;
|
|
|
|
e->keylen = keylen;
|
|
|
|
e->value = value;
|
|
|
|
|
2019-10-07 01:30:29 +02:00
|
|
|
hashmap_add(&map->map, &e->ent);
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
}
|
|
|
|
|
2017-01-28 03:02:02 +01:00
|
|
|
struct all_attrs_item {
|
|
|
|
const struct git_attr *attr;
|
|
|
|
const char *value;
|
2017-01-28 03:02:03 +01:00
|
|
|
/*
|
|
|
|
* If 'macro' is non-NULL, indicates that 'attr' is a macro based on
|
|
|
|
* the current attribute stack and contains a pointer to the match_attr
|
|
|
|
* definition of the macro
|
|
|
|
*/
|
|
|
|
const struct match_attr *macro;
|
2017-01-28 03:02:02 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reallocate and reinitialize the array of all attributes (which is used in
|
|
|
|
* the attribute collection process) in 'check' based on the global dictionary
|
|
|
|
* of attributes.
|
|
|
|
*/
|
|
|
|
static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check)
|
|
|
|
{
|
|
|
|
int i;
|
2017-09-06 17:43:48 +02:00
|
|
|
unsigned int size;
|
2017-01-28 03:02:02 +01:00
|
|
|
|
|
|
|
hashmap_lock(map);
|
|
|
|
|
2017-09-06 17:43:48 +02:00
|
|
|
size = hashmap_get_size(&map->map);
|
|
|
|
if (size < check->all_attrs_nr)
|
2018-05-02 11:38:39 +02:00
|
|
|
BUG("interned attributes shouldn't be deleted");
|
2017-01-28 03:02:02 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the number of attributes in the global dictionary has increased
|
|
|
|
* (or this attr_check instance doesn't have an initialized all_attrs
|
|
|
|
* field), reallocate the provided attr_check instance's all_attrs
|
|
|
|
* field and fill each entry with its corresponding git_attr.
|
|
|
|
*/
|
2017-09-06 17:43:48 +02:00
|
|
|
if (size != check->all_attrs_nr) {
|
2017-01-28 03:02:02 +01:00
|
|
|
struct attr_hash_entry *e;
|
|
|
|
struct hashmap_iter iter;
|
|
|
|
|
2017-09-06 17:43:48 +02:00
|
|
|
REALLOC_ARRAY(check->all_attrs, size);
|
|
|
|
check->all_attrs_nr = size;
|
2017-01-28 03:02:02 +01:00
|
|
|
|
2019-10-07 01:30:38 +02:00
|
|
|
hashmap_for_each_entry(&map->map, &iter, e,
|
|
|
|
ent /* member name */) {
|
2017-01-28 03:02:02 +01:00
|
|
|
const struct git_attr *a = e->value;
|
|
|
|
check->all_attrs[a->attr_nr].attr = a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hashmap_unlock(map);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Re-initialize every entry in check->all_attrs.
|
|
|
|
* This re-initialization can live outside of the locked region since
|
|
|
|
* the attribute dictionary is no longer being accessed.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < check->all_attrs_nr; i++) {
|
|
|
|
check->all_attrs[i].value = ATTR__UNKNOWN;
|
2017-01-28 03:02:03 +01:00
|
|
|
check->all_attrs[i].macro = NULL;
|
2017-01-28 03:02:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-28 03:02:00 +01:00
|
|
|
static int attr_name_valid(const char *name, size_t namelen)
|
2007-04-15 23:56:09 +02:00
|
|
|
{
|
|
|
|
/*
|
2011-08-04 06:36:13 +02:00
|
|
|
* Attribute name cannot begin with '-' and must consist of
|
|
|
|
* characters from [-A-Za-z0-9_.].
|
2007-04-15 23:56:09 +02:00
|
|
|
*/
|
2011-08-04 06:36:14 +02:00
|
|
|
if (namelen <= 0 || *name == '-')
|
2017-01-28 03:02:00 +01:00
|
|
|
return 0;
|
2007-04-15 23:56:09 +02:00
|
|
|
while (namelen--) {
|
|
|
|
char ch = *name++;
|
|
|
|
if (! (ch == '-' || ch == '.' || ch == '_' ||
|
|
|
|
('0' <= ch && ch <= '9') ||
|
|
|
|
('a' <= ch && ch <= 'z') ||
|
|
|
|
('A' <= ch && ch <= 'Z')) )
|
2017-01-28 03:02:00 +01:00
|
|
|
return 0;
|
2007-04-15 23:56:09 +02:00
|
|
|
}
|
2017-01-28 03:02:00 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void report_invalid_attr(const char *name, size_t len,
|
|
|
|
const char *src, int lineno)
|
|
|
|
{
|
|
|
|
struct strbuf err = STRBUF_INIT;
|
|
|
|
strbuf_addf(&err, _("%.*s is not a valid attribute name"),
|
|
|
|
(int) len, name);
|
|
|
|
fprintf(stderr, "%s: %s:%d\n", err.buf, src, lineno);
|
|
|
|
strbuf_release(&err);
|
2007-04-15 23:56:09 +02:00
|
|
|
}
|
|
|
|
|
2017-01-28 03:02:01 +01:00
|
|
|
/*
|
|
|
|
* Given a 'name', lookup and return the corresponding attribute in the global
|
|
|
|
* dictionary. If no entry is found, create a new attribute and store it in
|
|
|
|
* the dictionary.
|
|
|
|
*/
|
2022-12-01 15:45:15 +01:00
|
|
|
static const struct git_attr *git_attr_internal(const char *name, size_t namelen)
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
{
|
|
|
|
struct git_attr *a;
|
|
|
|
|
2017-01-28 03:02:01 +01:00
|
|
|
if (!attr_name_valid(name, namelen))
|
2007-04-15 23:56:09 +02:00
|
|
|
return NULL;
|
|
|
|
|
2017-01-28 03:02:01 +01:00
|
|
|
hashmap_lock(&g_attr_hashmap);
|
|
|
|
|
|
|
|
a = attr_hashmap_get(&g_attr_hashmap, name, namelen);
|
|
|
|
|
|
|
|
if (!a) {
|
|
|
|
FLEX_ALLOC_MEM(a, name, name, namelen);
|
2017-09-06 17:43:48 +02:00
|
|
|
a->attr_nr = hashmap_get_size(&g_attr_hashmap.map);
|
2017-01-28 03:02:01 +01:00
|
|
|
|
|
|
|
attr_hashmap_add(&g_attr_hashmap, a->name, namelen, a);
|
2022-12-01 15:45:36 +01:00
|
|
|
if (a->attr_nr != hashmap_get_size(&g_attr_hashmap.map) - 1)
|
|
|
|
die(_("unable to add additional attribute"));
|
2017-01-28 03:02:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
hashmap_unlock(&g_attr_hashmap);
|
attribute macro support
This adds "attribute macros" (for lack of better name). So far,
we have low-level attributes such as crlf and diff, which are
defined in operational terms --- setting or unsetting them on a
particular path directly affects what is done to the path. For
example, in order to decline diffs or crlf conversions on a
binary blob, no diffs on PostScript files, and treat all other
files normally, you would have something like these:
* diff crlf
*.ps !diff
proprietary.o !diff !crlf
That is fine as the operation goes, but gets unwieldy rather
rapidly, when we start adding more low-level attributes that are
defined in operational terms. A near-term example of such an
attribute would be 'merge-3way' which would control if git
should attempt the usual 3-way file-level merge internally, or
leave merging to a specialized external program of user's
choice. When it is added, we do _not_ want to force the users
to update the above to:
* diff crlf merge-3way
*.ps !diff
proprietary.o !diff !crlf !merge-3way
The way this patch solves this issue is to realize that the
attributes the user is assigning to paths are not defined in
terms of operations but in terms of what they are.
All of the three low-level attributes usually make sense for
most of the files that sane SCM users have git operate on (these
files are typically called "text'). Only a few cases, such as
binary blob, need exception to decline the "usual treatment
given to text files" -- and people mark them as "binary".
So this allows the $GIT_DIR/info/alternates and .gitattributes
at the toplevel of the project to also specify attributes that
assigns other attributes. The syntax is '[attr]' followed by an
attribute name followed by a list of attribute names:
[attr] binary !diff !crlf !merge-3way
When "binary" attribute is set to a path, if the path has not
got diff/crlf/merge-3way attribute set or unset by other rules,
this rule unsets the three low-level attributes.
It is expected that the user level .gitattributes will be
expressed mostly in terms of attributes based on what the files
are, and the above sample would become like this:
(built-in attribute configuration)
[attr] binary !diff !crlf !merge-3way
* diff crlf merge-3way
(project specific .gitattributes)
proprietary.o binary
(user preference $GIT_DIR/info/attributes)
*.ps !diff
There are a few caveats.
* As described above, you can define these macros only in
$GIT_DIR/info/attributes and toplevel .gitattributes.
* There is no attempt to detect circular definition of macro
attributes, and definitions are evaluated from bottom to top
as usual to fill in other attributes that have not yet got
values. The following would work as expected:
[attr] text diff crlf
[attr] ps text !diff
*.ps ps
while this would most likely not (I haven't tried):
[attr] ps text !diff
[attr] text diff crlf
*.ps ps
* When a macro says "[attr] A B !C", saying that a path does
not have attribute A does not let you tell anything about
attributes B or C. That is, given this:
[attr] text diff crlf
[attr] ps text !diff
*.txt !ps
path hello.txt, which would match "*.txt" pattern, would have
"ps" attribute set to zero, but that does not make text
attribute of hello.txt set to false (nor diff attribute set to
true).
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-14 17:54:37 +02:00
|
|
|
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
2017-01-28 03:02:04 +01:00
|
|
|
const struct git_attr *git_attr(const char *name)
|
2010-01-17 05:39:59 +01:00
|
|
|
{
|
|
|
|
return git_attr_internal(name, strlen(name));
|
|
|
|
}
|
|
|
|
|
2007-04-17 06:33:31 +02:00
|
|
|
/* What does a matched pattern decide? */
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
struct attr_state {
|
2017-01-28 03:02:04 +01:00
|
|
|
const struct git_attr *attr;
|
2007-04-19 01:16:37 +02:00
|
|
|
const char *setto;
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
};
|
|
|
|
|
2012-10-15 08:24:39 +02:00
|
|
|
struct pattern {
|
|
|
|
const char *pattern;
|
|
|
|
int patternlen;
|
|
|
|
int nowildcardlen;
|
2019-09-03 20:04:56 +02:00
|
|
|
unsigned flags; /* PATTERN_FLAG_* */
|
2012-10-15 08:24:39 +02:00
|
|
|
};
|
|
|
|
|
2011-08-12 23:43:05 +02:00
|
|
|
/*
|
|
|
|
* One rule, as from a .gitattributes file.
|
|
|
|
*
|
|
|
|
* If is_macro is true, then u.attr is a pointer to the git_attr being
|
|
|
|
* defined.
|
|
|
|
*
|
2017-01-28 03:01:43 +01:00
|
|
|
* If is_macro is false, then u.pat is the filename pattern to which the
|
|
|
|
* rule applies.
|
2011-08-12 23:43:05 +02:00
|
|
|
*
|
|
|
|
* In either case, num_attr is the number of attributes affected by
|
|
|
|
* this rule, and state is an array listing them. The attributes are
|
|
|
|
* listed as they appear in the file (macros unexpanded).
|
|
|
|
*/
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
struct match_attr {
|
attribute macro support
This adds "attribute macros" (for lack of better name). So far,
we have low-level attributes such as crlf and diff, which are
defined in operational terms --- setting or unsetting them on a
particular path directly affects what is done to the path. For
example, in order to decline diffs or crlf conversions on a
binary blob, no diffs on PostScript files, and treat all other
files normally, you would have something like these:
* diff crlf
*.ps !diff
proprietary.o !diff !crlf
That is fine as the operation goes, but gets unwieldy rather
rapidly, when we start adding more low-level attributes that are
defined in operational terms. A near-term example of such an
attribute would be 'merge-3way' which would control if git
should attempt the usual 3-way file-level merge internally, or
leave merging to a specialized external program of user's
choice. When it is added, we do _not_ want to force the users
to update the above to:
* diff crlf merge-3way
*.ps !diff
proprietary.o !diff !crlf !merge-3way
The way this patch solves this issue is to realize that the
attributes the user is assigning to paths are not defined in
terms of operations but in terms of what they are.
All of the three low-level attributes usually make sense for
most of the files that sane SCM users have git operate on (these
files are typically called "text'). Only a few cases, such as
binary blob, need exception to decline the "usual treatment
given to text files" -- and people mark them as "binary".
So this allows the $GIT_DIR/info/alternates and .gitattributes
at the toplevel of the project to also specify attributes that
assigns other attributes. The syntax is '[attr]' followed by an
attribute name followed by a list of attribute names:
[attr] binary !diff !crlf !merge-3way
When "binary" attribute is set to a path, if the path has not
got diff/crlf/merge-3way attribute set or unset by other rules,
this rule unsets the three low-level attributes.
It is expected that the user level .gitattributes will be
expressed mostly in terms of attributes based on what the files
are, and the above sample would become like this:
(built-in attribute configuration)
[attr] binary !diff !crlf !merge-3way
* diff crlf merge-3way
(project specific .gitattributes)
proprietary.o binary
(user preference $GIT_DIR/info/attributes)
*.ps !diff
There are a few caveats.
* As described above, you can define these macros only in
$GIT_DIR/info/attributes and toplevel .gitattributes.
* There is no attempt to detect circular definition of macro
attributes, and definitions are evaluated from bottom to top
as usual to fill in other attributes that have not yet got
values. The following would work as expected:
[attr] text diff crlf
[attr] ps text !diff
*.ps ps
while this would most likely not (I haven't tried):
[attr] ps text !diff
[attr] text diff crlf
*.ps ps
* When a macro says "[attr] A B !C", saying that a path does
not have attribute A does not let you tell anything about
attributes B or C. That is, given this:
[attr] text diff crlf
[attr] ps text !diff
*.txt !ps
path hello.txt, which would match "*.txt" pattern, would have
"ps" attribute set to zero, but that does not make text
attribute of hello.txt set to false (nor diff attribute set to
true).
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-14 17:54:37 +02:00
|
|
|
union {
|
2012-10-15 08:24:39 +02:00
|
|
|
struct pattern pat;
|
2017-01-28 03:02:04 +01:00
|
|
|
const struct git_attr *attr;
|
attribute macro support
This adds "attribute macros" (for lack of better name). So far,
we have low-level attributes such as crlf and diff, which are
defined in operational terms --- setting or unsetting them on a
particular path directly affects what is done to the path. For
example, in order to decline diffs or crlf conversions on a
binary blob, no diffs on PostScript files, and treat all other
files normally, you would have something like these:
* diff crlf
*.ps !diff
proprietary.o !diff !crlf
That is fine as the operation goes, but gets unwieldy rather
rapidly, when we start adding more low-level attributes that are
defined in operational terms. A near-term example of such an
attribute would be 'merge-3way' which would control if git
should attempt the usual 3-way file-level merge internally, or
leave merging to a specialized external program of user's
choice. When it is added, we do _not_ want to force the users
to update the above to:
* diff crlf merge-3way
*.ps !diff
proprietary.o !diff !crlf !merge-3way
The way this patch solves this issue is to realize that the
attributes the user is assigning to paths are not defined in
terms of operations but in terms of what they are.
All of the three low-level attributes usually make sense for
most of the files that sane SCM users have git operate on (these
files are typically called "text'). Only a few cases, such as
binary blob, need exception to decline the "usual treatment
given to text files" -- and people mark them as "binary".
So this allows the $GIT_DIR/info/alternates and .gitattributes
at the toplevel of the project to also specify attributes that
assigns other attributes. The syntax is '[attr]' followed by an
attribute name followed by a list of attribute names:
[attr] binary !diff !crlf !merge-3way
When "binary" attribute is set to a path, if the path has not
got diff/crlf/merge-3way attribute set or unset by other rules,
this rule unsets the three low-level attributes.
It is expected that the user level .gitattributes will be
expressed mostly in terms of attributes based on what the files
are, and the above sample would become like this:
(built-in attribute configuration)
[attr] binary !diff !crlf !merge-3way
* diff crlf merge-3way
(project specific .gitattributes)
proprietary.o binary
(user preference $GIT_DIR/info/attributes)
*.ps !diff
There are a few caveats.
* As described above, you can define these macros only in
$GIT_DIR/info/attributes and toplevel .gitattributes.
* There is no attempt to detect circular definition of macro
attributes, and definitions are evaluated from bottom to top
as usual to fill in other attributes that have not yet got
values. The following would work as expected:
[attr] text diff crlf
[attr] ps text !diff
*.ps ps
while this would most likely not (I haven't tried):
[attr] ps text !diff
[attr] text diff crlf
*.ps ps
* When a macro says "[attr] A B !C", saying that a path does
not have attribute A does not let you tell anything about
attributes B or C. That is, given this:
[attr] text diff crlf
[attr] ps text !diff
*.txt !ps
path hello.txt, which would match "*.txt" pattern, would have
"ps" attribute set to zero, but that does not make text
attribute of hello.txt set to false (nor diff attribute set to
true).
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-14 17:54:37 +02:00
|
|
|
} u;
|
|
|
|
char is_macro;
|
2022-12-01 15:45:27 +01:00
|
|
|
size_t num_attr;
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
struct attr_state state[FLEX_ARRAY];
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char blank[] = " \t\r\n";
|
|
|
|
|
2021-02-16 15:44:25 +01:00
|
|
|
/* Flags usable in read_attr() and parse_attr_line() family of functions. */
|
|
|
|
#define READ_ATTR_MACRO_OK (1<<0)
|
attr: do not respect symlinks for in-tree .gitattributes
The attributes system may sometimes read in-tree files from the
filesystem, and sometimes from the index. In the latter case, we do not
resolve symbolic links (and are not likely to ever start doing so).
Let's open filesystem links with O_NOFOLLOW so that the two cases behave
consistently.
As a bonus, this means that git will not follow such symlinks to read
and parse out-of-tree paths. In some cases this could have security
implications, as a malicious repository can cause Git to open and read
arbitrary files. It could already feed arbitrary content to the parser,
but in certain setups it might be able to exfiltrate data from those
paths (e.g., if an automated service operating on the malicious repo
reveals its stderr to an attacker).
Note that O_NOFOLLOW only prevents following links for the path itself,
not intermediate directories in the path. At first glance, it seems
like
ln -s /some/path in-repo
might still look at "in-repo/.gitattributes", following the symlink to
"/some/path/.gitattributes". However, if "in-repo" is a symbolic link,
then we know that it has no git paths below it, and will never look at
its .gitattributes file.
We will continue to support out-of-tree symbolic links (e.g., in
$GIT_DIR/info/attributes); this just affects in-tree links. When a
symbolic link is encountered, the contents are ignored and a warning is
printed. POSIX specifies ELOOP in this case, so the user would generally
see something like:
warning: unable to access '.gitattributes': Too many levels of symbolic links
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-02-16 15:44:32 +01:00
|
|
|
#define READ_ATTR_NOFOLLOW (1<<1)
|
2021-02-16 15:44:25 +01:00
|
|
|
|
2011-08-12 23:43:07 +02:00
|
|
|
/*
|
|
|
|
* Parse a whitespace-delimited attribute state (i.e., "attr",
|
|
|
|
* "-attr", "!attr", or "attr=value") from the string starting at src.
|
|
|
|
* If e is not NULL, write the results to *e. Return a pointer to the
|
|
|
|
* remainder of the string (with leading whitespace removed), or NULL
|
|
|
|
* if there was an error.
|
|
|
|
*/
|
2007-04-17 06:33:31 +02:00
|
|
|
static const char *parse_attr(const char *src, int lineno, const char *cp,
|
2011-08-12 23:43:07 +02:00
|
|
|
struct attr_state *e)
|
2007-04-17 06:33:31 +02:00
|
|
|
{
|
|
|
|
const char *ep, *equals;
|
2022-12-01 15:45:23 +01:00
|
|
|
size_t len;
|
2007-04-17 06:33:31 +02:00
|
|
|
|
|
|
|
ep = cp + strcspn(cp, blank);
|
|
|
|
equals = strchr(cp, '=');
|
|
|
|
if (equals && ep < equals)
|
|
|
|
equals = NULL;
|
|
|
|
if (equals)
|
|
|
|
len = equals - cp;
|
|
|
|
else
|
|
|
|
len = ep - cp;
|
2011-08-12 23:43:07 +02:00
|
|
|
if (!e) {
|
2007-04-17 06:33:31 +02:00
|
|
|
if (*cp == '-' || *cp == '!') {
|
|
|
|
cp++;
|
|
|
|
len--;
|
|
|
|
}
|
2017-01-28 03:02:00 +01:00
|
|
|
if (!attr_name_valid(cp, len)) {
|
|
|
|
report_invalid_attr(cp, len, src, lineno);
|
2007-04-17 06:33:31 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
2017-01-28 03:01:44 +01:00
|
|
|
/*
|
|
|
|
* As this function is always called twice, once with
|
|
|
|
* e == NULL in the first pass and then e != NULL in
|
2017-01-28 03:02:00 +01:00
|
|
|
* the second pass, no need for attr_name_valid()
|
2017-01-28 03:01:44 +01:00
|
|
|
* check here.
|
|
|
|
*/
|
2007-04-17 06:33:31 +02:00
|
|
|
if (*cp == '-' || *cp == '!') {
|
|
|
|
e->setto = (*cp == '-') ? ATTR__FALSE : ATTR__UNSET;
|
|
|
|
cp++;
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
else if (!equals)
|
|
|
|
e->setto = ATTR__TRUE;
|
|
|
|
else {
|
2007-09-16 00:32:36 +02:00
|
|
|
e->setto = xmemdupz(equals + 1, ep - equals - 1);
|
2007-04-17 06:33:31 +02:00
|
|
|
}
|
2010-01-17 05:39:59 +01:00
|
|
|
e->attr = git_attr_internal(cp, len);
|
2007-04-17 06:33:31 +02:00
|
|
|
}
|
|
|
|
return ep + strspn(ep, blank);
|
|
|
|
}
|
|
|
|
|
attribute macro support
This adds "attribute macros" (for lack of better name). So far,
we have low-level attributes such as crlf and diff, which are
defined in operational terms --- setting or unsetting them on a
particular path directly affects what is done to the path. For
example, in order to decline diffs or crlf conversions on a
binary blob, no diffs on PostScript files, and treat all other
files normally, you would have something like these:
* diff crlf
*.ps !diff
proprietary.o !diff !crlf
That is fine as the operation goes, but gets unwieldy rather
rapidly, when we start adding more low-level attributes that are
defined in operational terms. A near-term example of such an
attribute would be 'merge-3way' which would control if git
should attempt the usual 3-way file-level merge internally, or
leave merging to a specialized external program of user's
choice. When it is added, we do _not_ want to force the users
to update the above to:
* diff crlf merge-3way
*.ps !diff
proprietary.o !diff !crlf !merge-3way
The way this patch solves this issue is to realize that the
attributes the user is assigning to paths are not defined in
terms of operations but in terms of what they are.
All of the three low-level attributes usually make sense for
most of the files that sane SCM users have git operate on (these
files are typically called "text'). Only a few cases, such as
binary blob, need exception to decline the "usual treatment
given to text files" -- and people mark them as "binary".
So this allows the $GIT_DIR/info/alternates and .gitattributes
at the toplevel of the project to also specify attributes that
assigns other attributes. The syntax is '[attr]' followed by an
attribute name followed by a list of attribute names:
[attr] binary !diff !crlf !merge-3way
When "binary" attribute is set to a path, if the path has not
got diff/crlf/merge-3way attribute set or unset by other rules,
this rule unsets the three low-level attributes.
It is expected that the user level .gitattributes will be
expressed mostly in terms of attributes based on what the files
are, and the above sample would become like this:
(built-in attribute configuration)
[attr] binary !diff !crlf !merge-3way
* diff crlf merge-3way
(project specific .gitattributes)
proprietary.o binary
(user preference $GIT_DIR/info/attributes)
*.ps !diff
There are a few caveats.
* As described above, you can define these macros only in
$GIT_DIR/info/attributes and toplevel .gitattributes.
* There is no attempt to detect circular definition of macro
attributes, and definitions are evaluated from bottom to top
as usual to fill in other attributes that have not yet got
values. The following would work as expected:
[attr] text diff crlf
[attr] ps text !diff
*.ps ps
while this would most likely not (I haven't tried):
[attr] ps text !diff
[attr] text diff crlf
*.ps ps
* When a macro says "[attr] A B !C", saying that a path does
not have attribute A does not let you tell anything about
attributes B or C. That is, given this:
[attr] text diff crlf
[attr] ps text !diff
*.txt !ps
path hello.txt, which would match "*.txt" pattern, would have
"ps" attribute set to zero, but that does not make text
attribute of hello.txt set to false (nor diff attribute set to
true).
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-14 17:54:37 +02:00
|
|
|
static struct match_attr *parse_attr_line(const char *line, const char *src,
|
2021-02-16 15:44:25 +01:00
|
|
|
int lineno, unsigned flags)
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
{
|
2022-12-01 15:45:27 +01:00
|
|
|
size_t namelen, num_attr, i;
|
2011-08-12 23:43:08 +02:00
|
|
|
const char *cp, *name, *states;
|
2007-04-17 06:33:31 +02:00
|
|
|
struct match_attr *res = NULL;
|
attribute macro support
This adds "attribute macros" (for lack of better name). So far,
we have low-level attributes such as crlf and diff, which are
defined in operational terms --- setting or unsetting them on a
particular path directly affects what is done to the path. For
example, in order to decline diffs or crlf conversions on a
binary blob, no diffs on PostScript files, and treat all other
files normally, you would have something like these:
* diff crlf
*.ps !diff
proprietary.o !diff !crlf
That is fine as the operation goes, but gets unwieldy rather
rapidly, when we start adding more low-level attributes that are
defined in operational terms. A near-term example of such an
attribute would be 'merge-3way' which would control if git
should attempt the usual 3-way file-level merge internally, or
leave merging to a specialized external program of user's
choice. When it is added, we do _not_ want to force the users
to update the above to:
* diff crlf merge-3way
*.ps !diff
proprietary.o !diff !crlf !merge-3way
The way this patch solves this issue is to realize that the
attributes the user is assigning to paths are not defined in
terms of operations but in terms of what they are.
All of the three low-level attributes usually make sense for
most of the files that sane SCM users have git operate on (these
files are typically called "text'). Only a few cases, such as
binary blob, need exception to decline the "usual treatment
given to text files" -- and people mark them as "binary".
So this allows the $GIT_DIR/info/alternates and .gitattributes
at the toplevel of the project to also specify attributes that
assigns other attributes. The syntax is '[attr]' followed by an
attribute name followed by a list of attribute names:
[attr] binary !diff !crlf !merge-3way
When "binary" attribute is set to a path, if the path has not
got diff/crlf/merge-3way attribute set or unset by other rules,
this rule unsets the three low-level attributes.
It is expected that the user level .gitattributes will be
expressed mostly in terms of attributes based on what the files
are, and the above sample would become like this:
(built-in attribute configuration)
[attr] binary !diff !crlf !merge-3way
* diff crlf merge-3way
(project specific .gitattributes)
proprietary.o binary
(user preference $GIT_DIR/info/attributes)
*.ps !diff
There are a few caveats.
* As described above, you can define these macros only in
$GIT_DIR/info/attributes and toplevel .gitattributes.
* There is no attempt to detect circular definition of macro
attributes, and definitions are evaluated from bottom to top
as usual to fill in other attributes that have not yet got
values. The following would work as expected:
[attr] text diff crlf
[attr] ps text !diff
*.ps ps
while this would most likely not (I haven't tried):
[attr] ps text !diff
[attr] text diff crlf
*.ps ps
* When a macro says "[attr] A B !C", saying that a path does
not have attribute A does not let you tell anything about
attributes B or C. That is, given this:
[attr] text diff crlf
[attr] ps text !diff
*.txt !ps
path hello.txt, which would match "*.txt" pattern, would have
"ps" attribute set to zero, but that does not make text
attribute of hello.txt set to false (nor diff attribute set to
true).
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-14 17:54:37 +02:00
|
|
|
int is_macro;
|
2017-01-28 03:01:50 +01:00
|
|
|
struct strbuf pattern = STRBUF_INIT;
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
|
|
|
|
cp = line + strspn(line, blank);
|
|
|
|
if (!*cp || *cp == '#')
|
|
|
|
return NULL;
|
|
|
|
name = cp;
|
2017-01-28 03:01:50 +01:00
|
|
|
|
2022-12-01 15:45:48 +01:00
|
|
|
if (strlen(line) >= ATTR_MAX_LINE_LENGTH) {
|
|
|
|
warning(_("ignoring overly long attributes line %d"), lineno);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-01-28 03:01:50 +01:00
|
|
|
if (*cp == '"' && !unquote_c_style(&pattern, name, &states)) {
|
|
|
|
name = pattern.buf;
|
|
|
|
namelen = pattern.len;
|
|
|
|
} else {
|
|
|
|
namelen = strcspn(name, blank);
|
|
|
|
states = name + namelen;
|
|
|
|
}
|
|
|
|
|
attribute macro support
This adds "attribute macros" (for lack of better name). So far,
we have low-level attributes such as crlf and diff, which are
defined in operational terms --- setting or unsetting them on a
particular path directly affects what is done to the path. For
example, in order to decline diffs or crlf conversions on a
binary blob, no diffs on PostScript files, and treat all other
files normally, you would have something like these:
* diff crlf
*.ps !diff
proprietary.o !diff !crlf
That is fine as the operation goes, but gets unwieldy rather
rapidly, when we start adding more low-level attributes that are
defined in operational terms. A near-term example of such an
attribute would be 'merge-3way' which would control if git
should attempt the usual 3-way file-level merge internally, or
leave merging to a specialized external program of user's
choice. When it is added, we do _not_ want to force the users
to update the above to:
* diff crlf merge-3way
*.ps !diff
proprietary.o !diff !crlf !merge-3way
The way this patch solves this issue is to realize that the
attributes the user is assigning to paths are not defined in
terms of operations but in terms of what they are.
All of the three low-level attributes usually make sense for
most of the files that sane SCM users have git operate on (these
files are typically called "text'). Only a few cases, such as
binary blob, need exception to decline the "usual treatment
given to text files" -- and people mark them as "binary".
So this allows the $GIT_DIR/info/alternates and .gitattributes
at the toplevel of the project to also specify attributes that
assigns other attributes. The syntax is '[attr]' followed by an
attribute name followed by a list of attribute names:
[attr] binary !diff !crlf !merge-3way
When "binary" attribute is set to a path, if the path has not
got diff/crlf/merge-3way attribute set or unset by other rules,
this rule unsets the three low-level attributes.
It is expected that the user level .gitattributes will be
expressed mostly in terms of attributes based on what the files
are, and the above sample would become like this:
(built-in attribute configuration)
[attr] binary !diff !crlf !merge-3way
* diff crlf merge-3way
(project specific .gitattributes)
proprietary.o binary
(user preference $GIT_DIR/info/attributes)
*.ps !diff
There are a few caveats.
* As described above, you can define these macros only in
$GIT_DIR/info/attributes and toplevel .gitattributes.
* There is no attempt to detect circular definition of macro
attributes, and definitions are evaluated from bottom to top
as usual to fill in other attributes that have not yet got
values. The following would work as expected:
[attr] text diff crlf
[attr] ps text !diff
*.ps ps
while this would most likely not (I haven't tried):
[attr] ps text !diff
[attr] text diff crlf
*.ps ps
* When a macro says "[attr] A B !C", saying that a path does
not have attribute A does not let you tell anything about
attributes B or C. That is, given this:
[attr] text diff crlf
[attr] ps text !diff
*.txt !ps
path hello.txt, which would match "*.txt" pattern, would have
"ps" attribute set to zero, but that does not make text
attribute of hello.txt set to false (nor diff attribute set to
true).
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-14 17:54:37 +02:00
|
|
|
if (strlen(ATTRIBUTE_MACRO_PREFIX) < namelen &&
|
2013-11-30 21:55:40 +01:00
|
|
|
starts_with(name, ATTRIBUTE_MACRO_PREFIX)) {
|
2021-02-16 15:44:25 +01:00
|
|
|
if (!(flags & READ_ATTR_MACRO_OK)) {
|
2018-11-10 06:16:03 +01:00
|
|
|
fprintf_ln(stderr, _("%s not allowed: %s:%d"),
|
|
|
|
name, src, lineno);
|
2017-01-28 03:01:49 +01:00
|
|
|
goto fail_return;
|
attribute macro support
This adds "attribute macros" (for lack of better name). So far,
we have low-level attributes such as crlf and diff, which are
defined in operational terms --- setting or unsetting them on a
particular path directly affects what is done to the path. For
example, in order to decline diffs or crlf conversions on a
binary blob, no diffs on PostScript files, and treat all other
files normally, you would have something like these:
* diff crlf
*.ps !diff
proprietary.o !diff !crlf
That is fine as the operation goes, but gets unwieldy rather
rapidly, when we start adding more low-level attributes that are
defined in operational terms. A near-term example of such an
attribute would be 'merge-3way' which would control if git
should attempt the usual 3-way file-level merge internally, or
leave merging to a specialized external program of user's
choice. When it is added, we do _not_ want to force the users
to update the above to:
* diff crlf merge-3way
*.ps !diff
proprietary.o !diff !crlf !merge-3way
The way this patch solves this issue is to realize that the
attributes the user is assigning to paths are not defined in
terms of operations but in terms of what they are.
All of the three low-level attributes usually make sense for
most of the files that sane SCM users have git operate on (these
files are typically called "text'). Only a few cases, such as
binary blob, need exception to decline the "usual treatment
given to text files" -- and people mark them as "binary".
So this allows the $GIT_DIR/info/alternates and .gitattributes
at the toplevel of the project to also specify attributes that
assigns other attributes. The syntax is '[attr]' followed by an
attribute name followed by a list of attribute names:
[attr] binary !diff !crlf !merge-3way
When "binary" attribute is set to a path, if the path has not
got diff/crlf/merge-3way attribute set or unset by other rules,
this rule unsets the three low-level attributes.
It is expected that the user level .gitattributes will be
expressed mostly in terms of attributes based on what the files
are, and the above sample would become like this:
(built-in attribute configuration)
[attr] binary !diff !crlf !merge-3way
* diff crlf merge-3way
(project specific .gitattributes)
proprietary.o binary
(user preference $GIT_DIR/info/attributes)
*.ps !diff
There are a few caveats.
* As described above, you can define these macros only in
$GIT_DIR/info/attributes and toplevel .gitattributes.
* There is no attempt to detect circular definition of macro
attributes, and definitions are evaluated from bottom to top
as usual to fill in other attributes that have not yet got
values. The following would work as expected:
[attr] text diff crlf
[attr] ps text !diff
*.ps ps
while this would most likely not (I haven't tried):
[attr] ps text !diff
[attr] text diff crlf
*.ps ps
* When a macro says "[attr] A B !C", saying that a path does
not have attribute A does not let you tell anything about
attributes B or C. That is, given this:
[attr] text diff crlf
[attr] ps text !diff
*.txt !ps
path hello.txt, which would match "*.txt" pattern, would have
"ps" attribute set to zero, but that does not make text
attribute of hello.txt set to false (nor diff attribute set to
true).
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-14 17:54:37 +02:00
|
|
|
}
|
|
|
|
is_macro = 1;
|
|
|
|
name += strlen(ATTRIBUTE_MACRO_PREFIX);
|
|
|
|
name += strspn(name, blank);
|
|
|
|
namelen = strcspn(name, blank);
|
2017-01-28 03:02:00 +01:00
|
|
|
if (!attr_name_valid(name, namelen)) {
|
|
|
|
report_invalid_attr(name, namelen, src, lineno);
|
2017-01-28 03:01:49 +01:00
|
|
|
goto fail_return;
|
2007-04-15 23:56:09 +02:00
|
|
|
}
|
attribute macro support
This adds "attribute macros" (for lack of better name). So far,
we have low-level attributes such as crlf and diff, which are
defined in operational terms --- setting or unsetting them on a
particular path directly affects what is done to the path. For
example, in order to decline diffs or crlf conversions on a
binary blob, no diffs on PostScript files, and treat all other
files normally, you would have something like these:
* diff crlf
*.ps !diff
proprietary.o !diff !crlf
That is fine as the operation goes, but gets unwieldy rather
rapidly, when we start adding more low-level attributes that are
defined in operational terms. A near-term example of such an
attribute would be 'merge-3way' which would control if git
should attempt the usual 3-way file-level merge internally, or
leave merging to a specialized external program of user's
choice. When it is added, we do _not_ want to force the users
to update the above to:
* diff crlf merge-3way
*.ps !diff
proprietary.o !diff !crlf !merge-3way
The way this patch solves this issue is to realize that the
attributes the user is assigning to paths are not defined in
terms of operations but in terms of what they are.
All of the three low-level attributes usually make sense for
most of the files that sane SCM users have git operate on (these
files are typically called "text'). Only a few cases, such as
binary blob, need exception to decline the "usual treatment
given to text files" -- and people mark them as "binary".
So this allows the $GIT_DIR/info/alternates and .gitattributes
at the toplevel of the project to also specify attributes that
assigns other attributes. The syntax is '[attr]' followed by an
attribute name followed by a list of attribute names:
[attr] binary !diff !crlf !merge-3way
When "binary" attribute is set to a path, if the path has not
got diff/crlf/merge-3way attribute set or unset by other rules,
this rule unsets the three low-level attributes.
It is expected that the user level .gitattributes will be
expressed mostly in terms of attributes based on what the files
are, and the above sample would become like this:
(built-in attribute configuration)
[attr] binary !diff !crlf !merge-3way
* diff crlf merge-3way
(project specific .gitattributes)
proprietary.o binary
(user preference $GIT_DIR/info/attributes)
*.ps !diff
There are a few caveats.
* As described above, you can define these macros only in
$GIT_DIR/info/attributes and toplevel .gitattributes.
* There is no attempt to detect circular definition of macro
attributes, and definitions are evaluated from bottom to top
as usual to fill in other attributes that have not yet got
values. The following would work as expected:
[attr] text diff crlf
[attr] ps text !diff
*.ps ps
while this would most likely not (I haven't tried):
[attr] ps text !diff
[attr] text diff crlf
*.ps ps
* When a macro says "[attr] A B !C", saying that a path does
not have attribute A does not let you tell anything about
attributes B or C. That is, given this:
[attr] text diff crlf
[attr] ps text !diff
*.txt !ps
path hello.txt, which would match "*.txt" pattern, would have
"ps" attribute set to zero, but that does not make text
attribute of hello.txt set to false (nor diff attribute set to
true).
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-14 17:54:37 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
is_macro = 0;
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
|
2011-08-12 23:43:08 +02:00
|
|
|
states += strspn(states, blank);
|
|
|
|
|
2011-08-12 23:43:10 +02:00
|
|
|
/* First pass to count the attr_states */
|
|
|
|
for (cp = states, num_attr = 0; *cp; num_attr++) {
|
|
|
|
cp = parse_attr(src, lineno, cp, NULL);
|
|
|
|
if (!cp)
|
2017-01-28 03:01:49 +01:00
|
|
|
goto fail_return;
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
}
|
2011-08-12 23:43:10 +02:00
|
|
|
|
2022-12-01 15:45:40 +01:00
|
|
|
res = xcalloc(1, st_add3(sizeof(*res),
|
|
|
|
st_mult(sizeof(struct attr_state), num_attr),
|
|
|
|
is_macro ? 0 : namelen + 1));
|
2014-12-28 00:39:47 +01:00
|
|
|
if (is_macro) {
|
2011-08-12 23:43:10 +02:00
|
|
|
res->u.attr = git_attr_internal(name, namelen);
|
2014-12-28 00:39:47 +01:00
|
|
|
} else {
|
2012-10-15 08:24:39 +02:00
|
|
|
char *p = (char *)&(res->state[num_attr]);
|
|
|
|
memcpy(p, name, namelen);
|
|
|
|
res->u.pat.pattern = p;
|
2019-09-03 20:04:57 +02:00
|
|
|
parse_path_pattern(&res->u.pat.pattern,
|
2012-10-15 08:24:39 +02:00
|
|
|
&res->u.pat.patternlen,
|
|
|
|
&res->u.pat.flags,
|
|
|
|
&res->u.pat.nowildcardlen);
|
2019-09-03 20:04:56 +02:00
|
|
|
if (res->u.pat.flags & PATTERN_FLAG_NEGATIVE) {
|
2013-03-01 21:06:17 +01:00
|
|
|
warning(_("Negative patterns are ignored in git attributes\n"
|
|
|
|
"Use '\\!' for literal leading exclamation."));
|
2017-01-28 03:01:49 +01:00
|
|
|
goto fail_return;
|
2013-03-01 21:06:17 +01:00
|
|
|
}
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
}
|
2011-08-12 23:43:10 +02:00
|
|
|
res->is_macro = is_macro;
|
|
|
|
res->num_attr = num_attr;
|
|
|
|
|
|
|
|
/* Second pass to fill the attr_states */
|
|
|
|
for (cp = states, i = 0; *cp; i++) {
|
|
|
|
cp = parse_attr(src, lineno, cp, &(res->state[i]));
|
|
|
|
}
|
|
|
|
|
2017-01-28 03:01:50 +01:00
|
|
|
strbuf_release(&pattern);
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
return res;
|
2017-01-28 03:01:49 +01:00
|
|
|
|
|
|
|
fail_return:
|
2017-01-28 03:01:50 +01:00
|
|
|
strbuf_release(&pattern);
|
2017-01-28 03:01:49 +01:00
|
|
|
free(res);
|
|
|
|
return NULL;
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Like info/exclude and .gitignore, the attribute information can
|
|
|
|
* come from many places.
|
|
|
|
*
|
2019-03-06 10:14:44 +01:00
|
|
|
* (1) .gitattributes file of the same directory;
|
|
|
|
* (2) .gitattributes file of the parent directory if (1) does not have
|
2007-04-17 06:33:31 +02:00
|
|
|
* any match; this goes recursively upwards, just like .gitignore.
|
|
|
|
* (3) $GIT_DIR/info/attributes, which overrides both of the above.
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
*
|
|
|
|
* In the same file, later entries override the earlier match, so in the
|
|
|
|
* global list, we would have entries from info/attributes the earliest
|
2019-03-06 10:14:44 +01:00
|
|
|
* (reading the file from top to bottom), .gitattributes of the root
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
* directory (again, reading the file from top to bottom) down to the
|
|
|
|
* current directory, and then scan the list backwards to find the first match.
|
2012-12-27 03:32:25 +01:00
|
|
|
* This is exactly the same as what is_excluded() does in dir.c to deal with
|
2017-01-28 03:01:45 +01:00
|
|
|
* .gitignore file and info/excludes file as a fallback.
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
*/
|
|
|
|
|
2017-01-28 03:02:05 +01:00
|
|
|
struct attr_stack {
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
struct attr_stack *prev;
|
|
|
|
char *origin;
|
2012-10-05 06:41:01 +02:00
|
|
|
size_t originlen;
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
unsigned num_matches;
|
2007-08-14 10:40:45 +02:00
|
|
|
unsigned alloc;
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
struct match_attr **attrs;
|
2017-01-28 03:02:05 +01:00
|
|
|
};
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
|
2017-01-28 03:02:05 +01:00
|
|
|
static void attr_stack_free(struct attr_stack *e)
|
Add basic infrastructure to assign attributes to paths
This adds the basic infrastructure to assign attributes to
paths, in a way similar to what the exclusion mechanism does
based on $GIT_DIR/info/exclude and .gitignore files.
An attribute is just a simple string that does not contain any
whitespace. They can be specified in $GIT_DIR/info/attributes
file, and .gitattributes file in each directory.
Each line in these files defines a pattern matching rule.
Similar to the exclusion mechanism, a later match overrides an
earlier match in the same file, and entries from .gitattributes
file in the same directory takes precedence over the ones from
parent directories. Lines in $GIT_DIR/info/attributes file are
used as the lowest precedence default rules.
A line is either a comment (an empty line, or a line that begins
with a '#'), or a rule, which is a whitespace separated list of
tokens. The first token on the line is a shell glob pattern.
The rest are names of attributes, each of which can optionally
be prefixed with '!'. Such a line means "if a path matches this
glob, this attribute is set (or unset -- if the attribute name
is prefixed with '!'). For glob matching, the same "if the
pattern does not have a slash in it, the basename of the path is
matched with fnmatch(3) against the pattern, otherwise, the path
is matched with the pattern with FNM_PATHNAME" rule as the
exclusion mechanism is used.
This does not define what an attribute means. Tying an
attribute to various effects it has on git operation for paths
that have it will be specified separately.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-12 10:07:32 +02:00
|
|
|
{
|
2022-12-01 15:45:31 +01:00
|
|
|
unsigned i;
|
|