Skip to content

Commit

Permalink
Merge branch 'mh/check-attr-relative'
Browse files Browse the repository at this point in the history
* mh/check-attr-relative: (29 commits)
  test-path-utils: Add subcommand "prefix_path"
  test-path-utils: Add subcommand "absolute_path"
  git-check-attr: Normalize paths
  git-check-attr: Demonstrate problems with relative paths
  git-check-attr: Demonstrate problems with unnormalized paths
  git-check-attr: test that no output is written to stderr
  Rename git_checkattr() to git_check_attr()
  git-check-attr: Fix command-line handling to match docs
  git-check-attr: Drive two tests using the same raw data
  git-check-attr: Add an --all option to show all attributes
  git-check-attr: Error out if no pathnames are specified
  git-check-attr: Process command-line args more systematically
  git-check-attr: Handle each error separately
  git-check-attr: Extract a function error_with_usage()
  git-check-attr: Introduce a new variable
  git-check-attr: Extract a function output_attr()
  Allow querying all attributes on a file
  Remove redundant check
  Remove redundant call to bootstrap_attr_stack()
  Extract a function collect_all_attrs()
  ...
  • Loading branch information
Junio C Hamano committed Aug 18, 2011
2 parents da68bf3 + 9e81372 commit 324b6b1
Show file tree
Hide file tree
Showing 14 changed files with 322 additions and 115 deletions.
23 changes: 19 additions & 4 deletions Documentation/git-check-attr.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ git-check-attr - Display gitattributes information
SYNOPSIS
--------
[verse]
'git check-attr' attr... [--] pathname...
'git check-attr' --stdin [-z] attr... < <list-of-paths>
'git check-attr' [-a | --all | attr...] [--] pathname...
'git check-attr' --stdin [-z] [-a | --all | attr...] < <list-of-paths>

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

OPTIONS
-------
-a, --all::
List all attributes that are associated with the specified
paths. If this option is used, then 'unspecified' attributes
will not be included in the output.

--stdin::
Read file names from stdin instead of from the command-line.

Expand All @@ -28,8 +33,11 @@ OPTIONS

\--::
Interpret all preceding arguments as attributes and all following
arguments as path names. If not supplied, only the first argument will
be treated as an attribute.
arguments as path names.

If none of `--stdin`, `--all`, or `--` is used, the first argument
will be treated as an attribute and the rest of the arguments as
pathnames.

OUTPUT
------
Expand Down Expand Up @@ -69,6 +77,13 @@ org/example/MyClass.java: diff: java
org/example/MyClass.java: myAttr: set
---------------

* Listing all attributes for a file:
---------------
$ git check-attr --all -- org/example/MyClass.java
org/example/MyClass.java: diff: java
org/example/MyClass.java: myAttr: set
---------------

* Listing an attribute for multiple files:
---------------
$ git check-attr myAttr -- org/example/MyClass.java org/example/NoMyAttr.java
Expand Down
3 changes: 3 additions & 0 deletions Documentation/gitattributes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,9 @@ frotz unspecified
----------------------------------------------------------------


SEE ALSO
--------
linkgit:git-check-attr[1].

GIT
---
Expand Down
61 changes: 39 additions & 22 deletions Documentation/technical/api-gitattributes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,15 @@ Data Structure
`struct git_attr`::

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

`struct git_attr_check`::

This structure represents a set of attributes to check in a call
to `git_checkattr()` function, and receives the results.


Calling Sequence
----------------

* Prepare an array of `struct git_attr_check` to define the list of
attributes you would want to check. To populate this array, you would
need to define necessary attributes by calling `git_attr()` function.

* Call git_checkattr() to check the attributes for the path.

* Inspect `git_attr_check` structure to see how each of the attribute in
the array is defined for the path.
to `git_check_attr()` function, and receives the results.


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


Querying Specific Attributes
----------------------------

* Prepare an array of `struct git_attr_check` to define the list of
attributes you would want to check. To populate this array, you would
need to define necessary attributes by calling `git_attr()` function.

* Call `git_check_attr()` to check the attributes for the path.

* Inspect `git_attr_check` structure to see how each of the attribute in
the array is defined for the path.


Example
-------

Expand All @@ -72,18 +73,18 @@ static void setup_check(void)
{
if (check[0].attr)
return; /* already done */
check[0].attr = git_attr("crlf", 4);
check[1].attr = git_attr("ident", 5);
check[0].attr = git_attr("crlf");
check[1].attr = git_attr("ident");
}
------------

. Call `git_checkattr()` with the prepared array of `struct git_attr_check`:
. Call `git_check_attr()` with the prepared array of `struct git_attr_check`:

------------
const char *path;

setup_check();
git_checkattr(path, ARRAY_SIZE(check), check);
git_check_attr(path, ARRAY_SIZE(check), check);
------------

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

(JC)

Querying All Attributes
-----------------------

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

* Call `git_all_attrs()`, which returns an array of `git_attr_check`
structures.

* Iterate over the `git_attr_check` array to examine the attribute
names and values. The name of the attribute described by a
`git_attr_check` object can be retrieved via
`git_attr_name(check[i].attr)`. (Please note that no items will be
returned for unset attributes, so `ATTR_UNSET()` will return false
for all returned `git_array_check` objects.)

* Free the `git_array_check` array.
2 changes: 1 addition & 1 deletion archive.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
path_without_prefix = path.buf + args->baselen;

setup_archive_check(check);
if (!git_checkattr(path_without_prefix, ARRAY_SIZE(check), check)) {
if (!git_check_attr(path_without_prefix, ARRAY_SIZE(check), check)) {
if (ATTR_TRUE(check[0].value))
return 0;
convert = ATTR_TRUE(check[1].value);
Expand Down
79 changes: 60 additions & 19 deletions attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ static int attr_nr;
static struct git_attr_check *check_all_attr;
static struct git_attr *(git_attr_hash[HASHSIZE]);

char *git_attr_name(struct git_attr *attr)
{
return attr->name;
}

static unsigned hash_name(const char *name, int namelen)
{
unsigned val = 0, c;
Expand All @@ -50,12 +55,10 @@ static unsigned hash_name(const char *name, int namelen)
static int invalid_attr_name(const char *name, int namelen)
{
/*
* Attribute name cannot begin with '-' and from
* [-A-Za-z0-9_.]. We'd specifically exclude '=' for now,
* as we might later want to allow non-binary value for
* attributes, e.g. "*.svg merge=special-merge-program-for-svg"
* Attribute name cannot begin with '-' and must consist of
* characters from [-A-Za-z0-9_.].
*/
if (*name == '-')
if (namelen <= 0 || *name == '-')
return -1;
while (namelen--) {
char ch = *name++;
Expand Down Expand Up @@ -532,11 +535,18 @@ static void bootstrap_attr_stack(void)
}
}

static void prepare_attr_stack(const char *path, int dirlen)
static void prepare_attr_stack(const char *path)
{
struct attr_stack *elem, *info;
int len;
int dirlen, len;
struct strbuf pathbuf;
const char *cp;

cp = strrchr(path, '/');
if (!cp)
dirlen = 0;
else
dirlen = cp - path;

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

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

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

int git_checkattr(const char *path, int num, struct git_attr_check *check)
/*
* Collect all attributes for path into the array pointed to by
* check_all_attr.
*/
static void collect_all_attrs(const char *path)
{
struct attr_stack *stk;
const char *cp;
int dirlen, pathlen, i, rem;
int i, pathlen, rem;

bootstrap_attr_stack();
prepare_attr_stack(path);
for (i = 0; i < attr_nr; i++)
check_all_attr[i].value = ATTR__UNKNOWN;

pathlen = strlen(path);
cp = strrchr(path, '/');
if (!cp)
dirlen = 0;
else
dirlen = cp - path;
prepare_attr_stack(path, dirlen);
rem = attr_nr;
for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
rem = fill(path, pathlen, stk, rem);
}

int git_check_attr(const char *path, int num, struct git_attr_check *check)
{
int i;

collect_all_attrs(path);

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

int git_all_attrs(const char *path, int *num, struct git_attr_check **check)
{
int i, count, j;

collect_all_attrs(path);

/* Count the number of attributes that are set. */
count = 0;
for (i = 0; i < attr_nr; i++) {
const char *value = check_all_attr[i].value;
if (value != ATTR__UNSET && value != ATTR__UNKNOWN)
++count;
}
*num = count;
*check = xmalloc(sizeof(**check) * count);
j = 0;
for (i = 0; i < attr_nr; i++) {
const char *value = check_all_attr[i].value;
if (value != ATTR__UNSET && value != ATTR__UNKNOWN) {
(*check)[j].attr = check_all_attr[i].attr;
(*check)[j].value = value;
++j;
}
}

return 0;
}

void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate)
{
enum git_attr_direction old = direction;
Expand Down
20 changes: 18 additions & 2 deletions attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ extern const char git_attr__false[];
#define ATTR_UNSET(v) ((v) == NULL)

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

int git_checkattr(const char *path, int, struct git_attr_check *);
/*
* Return the name of the attribute represented by the argument. The
* return value is a pointer to a null-delimited string that is part
* of the internal data structure; it should not be modified or freed.
*/
char *git_attr_name(struct git_attr *);

int git_check_attr(const char *path, int, struct git_attr_check *);

/*
* Retrieve all attributes that apply to the specified path. *num
* will be set the the number of attributes on the path; **check will
* be set to point at a newly-allocated array of git_attr_check
* objects describing the attributes and their values. *check must be
* free()ed by the caller.
*/
int git_all_attrs(const char *path, int *num, struct git_attr_check **check);

enum git_attr_direction {
GIT_ATTR_CHECKIN,
Expand Down
Loading

0 comments on commit 324b6b1

Please sign in to comment.