1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 module libgit2_d.status;
8 
9 
10 private static import libgit2_d.diff;
11 private static import libgit2_d.strarray;
12 private static import libgit2_d.types;
13 
14 /**
15  * @file git2/status.h
16  * @brief Git file status routines
17  * @defgroup git_status Git file status routines
18  * @ingroup Git
19  * @{
20  */
21 extern (C):
22 nothrow @nogc:
23 public:
24 
25 /**
26  * Status flags for a single file.
27  *
28  * A combination of these values will be returned to indicate the status of
29  * a file.  Status compares the working directory, the index, and the
30  * current HEAD of the repository.  The `GIT_STATUS_INDEX` set of flags
31  * represents the status of file in the index relative to the HEAD, and the
32  * `GIT_STATUS_WT` set of flags represent the status of the file in the
33  * working directory relative to the index.
34  */
35 enum git_status_t
36 {
37 	GIT_STATUS_CURRENT = 0,
38 
39 	GIT_STATUS_INDEX_NEW = 1u << 0,
40 	GIT_STATUS_INDEX_MODIFIED = 1u << 1,
41 	GIT_STATUS_INDEX_DELETED = 1u << 2,
42 	GIT_STATUS_INDEX_RENAMED = 1u << 3,
43 	GIT_STATUS_INDEX_TYPECHANGE = 1u << 4,
44 
45 	GIT_STATUS_WT_NEW = 1u << 7,
46 	GIT_STATUS_WT_MODIFIED = 1u << 8,
47 	GIT_STATUS_WT_DELETED = 1u << 9,
48 	GIT_STATUS_WT_TYPECHANGE = 1u << 10,
49 	GIT_STATUS_WT_RENAMED = 1u << 11,
50 	GIT_STATUS_WT_UNREADABLE = 1u << 12,
51 
52 	GIT_STATUS_IGNORED = 1u << 14,
53 	GIT_STATUS_CONFLICTED = 1u << 15,
54 }
55 
56 /**
57  * Function pointer to receive status on individual files
58  *
59  * `path` is the relative path to the file from the root of the repository.
60  *
61  * `status_flags` is a combination of `git_status_t` values that apply.
62  *
63  * `payload` is the value you passed to the foreach function as payload.
64  */
65 alias git_status_cb = int function(const (char)* path, uint status_flags, void* payload);
66 
67 /**
68  * Select the files on which to report status.
69  *
70  * With `git_status_foreach_ext`, this will control which changes get
71  * callbacks.  With `git_status_list_new`, these will control which
72  * changes are included in the list.
73  *
74  * - GIT_STATUS_SHOW_INDEX_AND_WORKDIR is the default.  This roughly
75  *   matches `git status --porcelain` regarding which files are
76  *   included and in what order.
77  * - GIT_STATUS_SHOW_INDEX_ONLY only gives status based on HEAD to index
78  *   comparison, not looking at working directory changes.
79  * - GIT_STATUS_SHOW_WORKDIR_ONLY only gives status based on index to
80  *   working directory comparison, not comparing the index to the HEAD.
81  */
82 enum git_status_show_t
83 {
84 	GIT_STATUS_SHOW_INDEX_AND_WORKDIR = 0,
85 	GIT_STATUS_SHOW_INDEX_ONLY = 1,
86 	GIT_STATUS_SHOW_WORKDIR_ONLY = 2,
87 }
88 
89 /**
90  * Flags to control status callbacks
91  *
92  * - GIT_STATUS_OPT_INCLUDE_UNTRACKED says that callbacks should be made
93  *   on untracked files.  These will only be made if the workdir files are
94  *   included in the status "show" option.
95  * - GIT_STATUS_OPT_INCLUDE_IGNORED says that ignored files get callbacks.
96  *   Again, these callbacks will only be made if the workdir files are
97  *   included in the status "show" option.
98  * - GIT_STATUS_OPT_INCLUDE_UNMODIFIED indicates that callback should be
99  *   made even on unmodified files.
100  * - GIT_STATUS_OPT_EXCLUDE_SUBMODULES indicates that submodules should be
101  *   skipped.  This only applies if there are no pending typechanges to
102  *   the submodule (either from or to another type).
103  * - GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS indicates that all files in
104  *   untracked directories should be included.  Normally if an entire
105  *   directory is new, then just the top-level directory is included (with
106  *   a trailing slash on the entry name).  This flag says to include all
107  *   of the individual files in the directory instead.
108  * - GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH indicates that the given path
109  *   should be treated as a literal path, and not as a pathspec pattern.
110  * - GIT_STATUS_OPT_RECURSE_IGNORED_DIRS indicates that the contents of
111  *   ignored directories should be included in the status.  This is like
112  *   doing `git ls-files -o -i --exclude-standard` with core git.
113  * - GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX indicates that rename detection
114  *   should be processed between the head and the index and enables
115  *   the GIT_STATUS_INDEX_RENAMED as a possible status flag.
116  * - GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR indicates that rename
117  *   detection should be run between the index and the working directory
118  *   and enabled GIT_STATUS_WT_RENAMED as a possible status flag.
119  * - GIT_STATUS_OPT_SORT_CASE_SENSITIVELY overrides the native case
120  *   sensitivity for the file system and forces the output to be in
121  *   case-sensitive order
122  * - GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY overrides the native case
123  *   sensitivity for the file system and forces the output to be in
124  *   case-insensitive order
125  * - GIT_STATUS_OPT_RENAMES_FROM_REWRITES indicates that rename detection
126  *   should include rewritten files
127  * - GIT_STATUS_OPT_NO_REFRESH bypasses the default status behavior of
128  *   doing a "soft" index reload (i.e. reloading the index data if the
129  *   file on disk has been modified outside libgit2).
130  * - GIT_STATUS_OPT_UPDATE_INDEX tells libgit2 to refresh the stat cache
131  *   in the index for files that are unchanged but have out of date stat
132  *   information in the index.  It will result in less work being done on
133  *   subsequent calls to get status.  This is mutually exclusive with the
134  *   NO_REFRESH option.
135  *
136  * Calling `git_status_foreach()` is like calling the extended version
137  * with: GIT_STATUS_OPT_INCLUDE_IGNORED, GIT_STATUS_OPT_INCLUDE_UNTRACKED,
138  * and GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS.  Those options are bundled
139  * together as `GIT_STATUS_OPT_DEFAULTS` if you want them as a baseline.
140  */
141 enum git_status_opt_t
142 {
143 	GIT_STATUS_OPT_INCLUDE_UNTRACKED = 1u << 0,
144 	GIT_STATUS_OPT_INCLUDE_IGNORED = 1u << 1,
145 	GIT_STATUS_OPT_INCLUDE_UNMODIFIED = 1u << 2,
146 	GIT_STATUS_OPT_EXCLUDE_SUBMODULES = 1u << 3,
147 	GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS = 1u << 4,
148 	GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH = 1u << 5,
149 	GIT_STATUS_OPT_RECURSE_IGNORED_DIRS = 1u << 6,
150 	GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX = 1u << 7,
151 	GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR = 1u << 8,
152 	GIT_STATUS_OPT_SORT_CASE_SENSITIVELY = 1u << 9,
153 	GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY = 1u << 10,
154 	GIT_STATUS_OPT_RENAMES_FROM_REWRITES = 1u << 11,
155 	GIT_STATUS_OPT_NO_REFRESH = 1u << 12,
156 	GIT_STATUS_OPT_UPDATE_INDEX = 1u << 13,
157 	GIT_STATUS_OPT_INCLUDE_UNREADABLE = 1u << 14,
158 	GIT_STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED = 1u << 15,
159 }
160 
161 enum GIT_STATUS_OPT_DEFAULTS = .git_status_opt_t.GIT_STATUS_OPT_INCLUDE_IGNORED | .git_status_opt_t.GIT_STATUS_OPT_INCLUDE_UNTRACKED | .git_status_opt_t.GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS;
162 
163 /**
164  * Options to control how `git_status_foreach_ext()` will issue callbacks.
165  *
166  * Initialize with `GIT_STATUS_OPTIONS_INIT`. Alternatively, you can
167  * use `git_status_options_init`.
168  */
169 struct git_status_options
170 {
171 	/**
172 	 * The version
173 	 */
174 	uint version_;
175 
176 	/**
177 	 * The `show` value is one of the `git_status_show_t` constants that
178 	 * control which files to scan and in what order.
179 	 */
180 	.git_status_show_t show;
181 
182 	/**
183 	 * The `flags` value is an OR'ed combination of the `git_status_opt_t`
184 	 * values above.
185 	 */
186 	uint flags;
187 
188 	/**
189 	 * The `pathspec` is an array of path patterns to match (using
190 	 * fnmatch-style matching), or just an array of paths to match exactly if
191 	 * `git_status_opt_t.GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH` is specified in the flags.
192 	 */
193 	libgit2_d.strarray.git_strarray pathspec;
194 
195 	/**
196 	 * The `baseline` is the tree to be used for comparison to the working directory
197 	 * and index; defaults to HEAD.
198 	 */
199 	libgit2_d.types.git_tree* baseline;
200 }
201 
202 enum GIT_STATUS_OPTIONS_VERSION = 1;
203 
204 pragma(inline, true)
205 pure nothrow @safe @nogc
206 .git_status_options GIT_STATUS_OPTIONS_INIT()
207 
208 	do
209 	{
210 		.git_status_options OUTPUT =
211 		{
212 			version_: .GIT_STATUS_OPTIONS_VERSION,
213 		};
214 
215 		return OUTPUT;
216 	}
217 
218 /**
219  * Initialize git_status_options structure
220  *
221  * Initializes a `git_status_options` with default values. Equivalent to
222  * creating an instance with `GIT_STATUS_OPTIONS_INIT`.
223  *
224  * @param opts The `git_status_options` struct to initialize.
225  * @param version The struct version; pass `GIT_STATUS_OPTIONS_VERSION`.
226  * @return Zero on success; -1 on failure.
227  */
228 //GIT_EXTERN
229 int git_status_options_init(.git_status_options* opts, uint version_);
230 
231 /**
232  * A status entry, providing the differences between the file as it exists
233  * in HEAD and the index, and providing the differences between the index
234  * and the working directory.
235  *
236  * The `status` value provides the status flags for this file.
237  *
238  * The `head_to_index` value provides detailed information about the
239  * differences between the file in HEAD and the file in the index.
240  *
241  * The `index_to_workdir` value provides detailed information about the
242  * differences between the file in the index and the file in the
243  * working directory.
244  */
245 struct git_status_entry
246 {
247 	.git_status_t status;
248 	libgit2_d.diff.git_diff_delta* head_to_index;
249 	libgit2_d.diff.git_diff_delta* index_to_workdir;
250 }
251 
252 /**
253  * Gather file statuses and run a callback for each one.
254  *
255  * The callback is passed the path of the file, the status (a combination of
256  * the `git_status_t` values above) and the `payload` data pointer passed
257  * into this function.
258  *
259  * If the callback returns a non-zero value, this function will stop looping
260  * and return that value to caller.
261  *
262  * @param repo A repository object
263  * @param callback The function to call on each file
264  * @param payload Pointer to pass through to callback function
265  * @return 0 on success, non-zero callback return value, or error code
266  */
267 //GIT_EXTERN
268 int git_status_foreach(libgit2_d.types.git_repository* repo, .git_status_cb callback, void* payload);
269 
270 /**
271  * Gather file status information and run callbacks as requested.
272  *
273  * This is an extended version of the `git_status_foreach()` API that
274  * allows for more granular control over which paths will be processed and
275  * in what order.  See the `git_status_options` structure for details
276  * about the additional controls that this makes available.
277  *
278  * Note that if a `pathspec` is given in the `git_status_options` to filter
279  * the status, then the results from rename detection (if you enable it) may
280  * not be accurate.  To do rename detection properly, this must be called
281  * with no `pathspec` so that all files can be considered.
282  *
283  * @param repo Repository object
284  * @param opts Status options structure
285  * @param callback The function to call on each file
286  * @param payload Pointer to pass through to callback function
287  * @return 0 on success, non-zero callback return value, or error code
288  */
289 //GIT_EXTERN
290 int git_status_foreach_ext(libgit2_d.types.git_repository* repo, const (.git_status_options)* opts, .git_status_cb callback, void* payload);
291 
292 /**
293  * Get file status for a single file.
294  *
295  * This tries to get status for the filename that you give.  If no files
296  * match that name (in either the HEAD, index, or working directory), this
297  * returns git_error_code.GIT_ENOTFOUND.
298  *
299  * If the name matches multiple files (for example, if the `path` names a
300  * directory or if running on a case- insensitive filesystem and yet the
301  * HEAD has two entries that both match the path), then this returns
302  * git_error_code.GIT_EAMBIGUOUS because it cannot give correct results.
303  *
304  * This does not do any sort of rename detection.  Renames require a set of
305  * targets and because of the path filtering, there is not enough
306  * information to check renames correctly.  To check file status with rename
307  * detection, there is no choice but to do a full `git_status_list_new` and
308  * scan through looking for the path that you are interested in.
309  *
310  * @param status_flags Output combination of git_status_t values for file
311  * @param repo A repository object
312  * @param path The exact path to retrieve status for relative to the
313  * repository working directory
314  * @return 0 on success, git_error_code.GIT_ENOTFOUND if the file is not found in the HEAD,
315  *      index, and work tree, git_error_code.GIT_EAMBIGUOUS if `path` matches multiple files
316  *      or if it refers to a folder, and -1 on other errors.
317  */
318 //GIT_EXTERN
319 int git_status_file(uint* status_flags, libgit2_d.types.git_repository* repo, const (char)* path);
320 
321 /**
322  * Gather file status information and populate the `git_status_list`.
323  *
324  * Note that if a `pathspec` is given in the `git_status_options` to filter
325  * the status, then the results from rename detection (if you enable it) may
326  * not be accurate.  To do rename detection properly, this must be called
327  * with no `pathspec` so that all files can be considered.
328  *
329  * @param out_ Pointer to store the status results in
330  * @param repo Repository object
331  * @param opts Status options structure
332  * @return 0 on success or error code
333  */
334 //GIT_EXTERN
335 int git_status_list_new(libgit2_d.types.git_status_list** out_, libgit2_d.types.git_repository* repo, const (.git_status_options)* opts);
336 
337 /**
338  * Gets the count of status entries in this list.
339  *
340  * If there are no changes in status (at least according the options given
341  * when the status list was created), this can return 0.
342  *
343  * @param statuslist Existing status list object
344  * @return the number of status entries
345  */
346 //GIT_EXTERN
347 size_t git_status_list_entrycount(libgit2_d.types.git_status_list* statuslist);
348 
349 /**
350  * Get a pointer to one of the entries in the status list.
351  *
352  * The entry is not modifiable and should not be freed.
353  *
354  * @param statuslist Existing status list object
355  * @param idx Position of the entry
356  * @return Pointer to the entry; null if out of bounds
357  */
358 //GIT_EXTERN
359 const (.git_status_entry)* git_status_byindex(libgit2_d.types.git_status_list* statuslist, size_t idx);
360 
361 /**
362  * Free an existing status list
363  *
364  * @param statuslist Existing status list object
365  */
366 //GIT_EXTERN
367 void git_status_list_free(libgit2_d.types.git_status_list* statuslist);
368 
369 /**
370  * Test if the ignore rules apply to a given file.
371  *
372  * This function checks the ignore rules to see if they would apply to the
373  * given file.  This indicates if the file would be ignored regardless of
374  * whether the file is already in the index or committed to the repository.
375  *
376  * One way to think of this is if you were to do "git add ." on the
377  * directory containing the file, would it be added or not?
378  *
379  * @param ignored Boolean returning 0 if the file is not ignored, 1 if it is
380  * @param repo A repository object
381  * @param path The file to check ignores for, rooted at the repo's workdir.
382  * @return 0 if ignore rules could be processed for the file (regardless
383  *         of whether it exists or not), or an error < 0 if they could not.
384  */
385 //GIT_EXTERN
386 int git_status_should_ignore(int* ignored, libgit2_d.types.git_repository* repo, const (char)* path);
387 
388 /** @} */