1 /*
2  *             Copyright Andrej Mitrovic 2013.
3  *  Distributed under the Boost Software License, Version 1.0.
4  *     (See accompanying file LICENSE_1_0.txt or copy at
5  *           http://www.boost.org/LICENSE_1_0.txt)
6  */
7 module git.attribute;
8 
9 import std.file;
10 import std.path;
11 import std.stdio;
12 import std.string;
13 
14 import git.repository;
15 
16 import deimos.git2.attr;
17 import deimos.git2.common;
18 import deimos.git2.types;
19 import deimos.git2.util;
20 
21 /**
22     Git attributes, see:
23     http://git-scm.com/book/ch7-2.html
24 */
25 
26 unittest
27 {
28     auto repo = initRepo(_userRepo, OpenBare.yes);
29     scope(exit) rmdirRecurse(_userRepo);
30 
31     string[] attributes = [
32         "*.c foo"
33     ];
34 
35     std.file.write(buildPath(repo.path, ".gitattributes"), attributes.join());
36 }
37 
38 extern (C):
39 
40 /**
41  * GIT_ATTR_TRUE checks if an attribute is set on.  In core git
42  * parlance, this the value for "Set" attributes.
43  *
44  * For example, if the attribute file contains:
45  *
46  *    *.c foo
47  *
48  * Then for file `xyz.c` looking up attribute "foo" gives a value for
49  * which `GIT_ATTR_TRUE(value)` is true.
50  */
51 bool GIT_ATTR_TRUE(T)(T attr) { return git_attr_value(attr) == git_attr_t.GIT_ATTR_TRUE_T; }
52 
53 /**
54  * GIT_ATTR_FALSE checks if an attribute is set off.  In core git
55  * parlance, this is the value for attributes that are "Unset" (not to
56  * be confused with values that a "Unspecified").
57  *
58  * For example, if the attribute file contains:
59  *
60  *    *.h -foo
61  *
62  * Then for file `zyx.h` looking up attribute "foo" gives a value for
63  * which `GIT_ATTR_FALSE(value)` is true.
64  */
65 bool GIT_ATTR_FALSE(T)(T attr) { return git_attr_value(attr) == git_attr_t.GIT_ATTR_FALSE_T; }
66 
67 /**
68  * GIT_ATTR_UNSPECIFIED checks if an attribute is unspecified.  This
69  * may be due to the attribute not being mentioned at all or because
70  * the attribute was explicitly set unspecified via the `!` operator.
71  *
72  * For example, if the attribute file contains:
73  *
74  *    *.c foo
75  *    *.h -foo
76  *    onefile.c !foo
77  *
78  * Then for `onefile.c` looking up attribute "foo" yields a value with
79  * `GIT_ATTR_UNSPECIFIED(value)` of true.  Also, looking up "foo" on
80  * file `onefile.rb` or looking up "bar" on any file will all give
81  * `GIT_ATTR_UNSPECIFIED(value)` of true.
82  */
83 bool GIT_ATTR_UNSPECIFIED(T)(T attr) { return git_attr_value(attr) == git_attr_t.GIT_ATTR_UNSPECIFIED_T; }
84 
85 /**
86  * GIT_ATTR_HAS_VALUE checks if an attribute is set to a value (as
87  * opposed to TRUE, FALSE or UNSPECIFIED).  This would be the case if
88  * for a file with something like:
89  *
90  *    *.txt eol=lf
91  *
92  * Given this, looking up "eol" for `onefile.txt` will give back the
93  * string "lf" and `GIT_ATTR_SET_TO_VALUE(attr)` will return true.
94  */
95 bool GIT_ATTR_HAS_VALUE(T)(T attr) { return git_attr_value(attr) == git_attr_t.GIT_ATTR_VALUE_T; }
96 
97 enum git_attr_t
98 {
99     GIT_ATTR_UNSPECIFIED_T = 0,
100     GIT_ATTR_TRUE_T,
101     GIT_ATTR_FALSE_T,
102     GIT_ATTR_VALUE_T,
103 }
104 
105 /*
106  *	Return the value type for a given attribute.
107  *
108  *	This can be either `TRUE`, `FALSE`, `UNSPECIFIED` (if the attribute
109  *	was not set at all), or `VALUE`, if the attribute was set to
110  *	an actual string.
111  *
112  *	If the attribute has a `VALUE` string, it can be accessed normally
113  *	as a NULL-terminated C string.
114  *
115  *	@param attr The attribute
116  *	@return the value type for the attribute
117  */
118 git_attr_t git_attr_value(const(char)* attr);
119 
120 /**
121  * Check attribute flags: Reading values from index and working directory.
122  *
123  * When checking attributes, it is possible to check attribute files
124  * in both the working directory (if there is one) and the index (if
125  * there is one).  You can explicitly choose where to check and in
126  * which order using the following flags.
127  *
128  * Core git usually checks the working directory then the index,
129  * except during a checkout when it checks the index first.  It will
130  * use index only for creating archives or for a bare repo (if an
131  * index has been specified for the bare repo).
132  */
133 enum GIT_ATTR_CHECK_FILE_THEN_INDEX	= 0;
134 enum GIT_ATTR_CHECK_INDEX_THEN_FILE	= 1;
135 enum GIT_ATTR_CHECK_INDEX_ONLY      = 2;
136 
137 /**
138  * Check attribute flags: Using the system attributes file.
139  *
140  * Normally, attribute checks include looking in the /etc (or system
141  * equivalent) directory for a `gitattributes` file.  Passing this
142  * flag will cause attribute checks to ignore that file.
143  */
144 enum GIT_ATTR_CHECK_NO_SYSTEM = 1 << 2;
145 
146 /**
147  * Look up the value of one git attribute for path.
148  *
149  * @param value_out Output of the value of the attribute.  Use the GIT_ATTR_...
150  *             macros to test for TRUE, FALSE, UNSPECIFIED, etc. or just
151  *             use the string value for attributes set to a value.  You
152  *             should NOT modify or free this value.
153  * @param repo The repository containing the path.
154  * @param flags A combination of GIT_ATTR_CHECK... flags.
155  * @param path The path to check for attributes.  Relative paths are
156  *             interpreted relative to the repo root.  The file does
157  *             not have to exist, but if it does not, then it will be
158  *             treated as a plain file (not a directory).
159  * @param name The name of the attribute to look up.
160  */
161 int git_attr_get(
162 	const(char)** value_out,
163 	git_repository *repo,
164 	uint32_t flags,
165 	const(char)* path,
166 	const(char)* name);
167 
168 /**
169  * Look up a list of git attributes for path.
170  *
171  * Use this if you have a known list of attributes that you want to
172  * look up in a single call.  This is somewhat more efficient than
173  * calling `git_attr_get()` multiple times.
174  *
175  * For example, you might write:
176  *
177  *     const(char)*attrs[] = { "crlf", "diff", "foo" };
178  *     const(char)**values[3];
179  *     git_attr_get_many(values, repo, 0, "my/fun/file.c", 3, attrs);
180  *
181  * Then you could loop through the 3 values to get the settings for
182  * the three attributes you asked about.
183  *
184  * @param values_out An array of num_attr entries that will have string
185  *             pointers written into it for the values of the attributes.
186  *             You should not modify or free the values that are written
187  *             into this array (although of course, you should free the
188  *             array itself if you allocated it).
189  * @param repo The repository containing the path.
190  * @param flags A combination of GIT_ATTR_CHECK... flags.
191  * @param path The path inside the repo to check attributes.  This
192  *             does not have to exist, but if it does not, then
193  *             it will be treated as a plain file (i.e. not a directory).
194  * @param num_attr The number of attributes being looked up
195  * @param names An array of num_attr strings containing attribute names.
196  */
197 int git_attr_get_many(
198 	const(char)** values_out,
199 	git_repository *repo,
200 	uint32_t flags,
201 	const(char)* path,
202 	size_t num_attr,
203 	const(char)** names);
204 
205 alias git_attr_foreach_cb = int function(const(char)* name, const(char)* value, void *payload);
206 
207 /**
208  * Loop over all the git attributes for a path.
209  *
210  * @param repo The repository containing the path.
211  * @param flags A combination of GIT_ATTR_CHECK... flags.
212  * @param path Path inside the repo to check attributes.  This does not have
213  *             to exist, but if it does not, then it will be treated as a
214  *             plain file (i.e. not a directory).
215  * @param callback Function to invoke on each attribute name and value.  The
216  *             value may be NULL is the attribute is explicitly set to
217  *             UNSPECIFIED using the '!' sign.  Callback will be invoked
218  *             only once per attribute name, even if there are multiple
219  *             rules for a given file.  The highest priority rule will be
220  *             used.  Return a non-zero value from this to stop looping.
221  * @param payload Passed on as extra parameter to callback function.
222  * @return 0 on success, GIT_EUSER on non-zero callback, or error code
223  */
224 int git_attr_foreach(
225 	git_repository *repo,
226 	uint32_t flags,
227 	const(char)* path,
228 	git_attr_foreach_cb callback,
229 	void *payload);
230 
231 /**
232  * Flush the gitattributes cache.
233  *
234  * Call this if you have reason to believe that the attributes files on
235  * disk no longer match the cached contents of memory.  This will cause
236  * the attributes files to be reloaded the next time that an attribute
237  * access function is called.
238  */
239 void git_attr_cache_flush(
240 	git_repository *repo);
241 
242 /**
243  * Add a macro definition.
244  *
245  * Macros will automatically be loaded from the top level `.gitattributes`
246  * file of the repository (plus the build-in "binary" macro).  This
247  * function allows you to add others.  For example, to add the default
248  * macro, you would call:
249  *
250  *     git_attr_add_macro(repo, "binary", "-diff -crlf");
251  */
252 int git_attr_add_macro(
253 	git_repository *repo,
254 	const(char)* name,
255 	const(char)* values);