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