1 /* Copyright (c) 2006-2014 Jonas Fonseca <jonas.fonseca@gmail.com>
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License as
5 * published by the Free Software Foundation; either version 2 of
6 * the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
17 #include "tig/refdb.h"
20 #define REPO_INFO_GIT_DIR "--git-dir"
21 #define REPO_INFO_WORK_TREE "--is-inside-work-tree"
22 #define REPO_INFO_SHOW_CDUP "--show-cdup"
23 #define REPO_INFO_SHOW_PREFIX "--show-prefix"
24 #define REPO_INFO_SYMBOLIC_HEAD "--symbolic-full-name"
25 #define REPO_INFO_RESOLVED_HEAD "HEAD"
27 struct repo_info_state
{
29 char head_id
[SIZEOF_REV
];
33 read_repo_info(char *name
, size_t namelen
, char *value
, size_t valuelen
, void *data
)
35 struct repo_info_state
*state
= data
;
36 const char *arg
= *state
->argv
? *state
->argv
++ : "";
38 if (!strcmp(arg
, REPO_INFO_GIT_DIR
)) {
39 string_ncopy(repo
.git_dir
, name
, namelen
);
41 } else if (!strcmp(arg
, REPO_INFO_WORK_TREE
)) {
42 /* This can be 3 different values depending on the
43 * version of git being used. If git-rev-parse does not
44 * understand --is-inside-work-tree it will simply echo
45 * the option else either "true" or "false" is printed.
46 * Default to true for the unknown case. */
47 repo
.is_inside_work_tree
= strcmp(name
, "false") ? TRUE
: FALSE
;
49 } else if (!strcmp(arg
, REPO_INFO_SHOW_CDUP
)) {
50 string_ncopy(repo
.cdup
, name
, namelen
);
52 } else if (!strcmp(arg
, REPO_INFO_SHOW_PREFIX
)) {
53 /* Some versions of Git does not emit anything for --show-prefix
54 * when the user is in the repository root directory. Try to detect
55 * this special case by looking at the emitted value. If it looks
56 * like a commit ID and there's no cdup path assume that no value
58 if (!*repo
.cdup
&& namelen
== 40 && iscommit(name
))
59 return read_repo_info(name
, namelen
, value
, valuelen
, data
);
61 string_ncopy(repo
.prefix
, name
, namelen
);
63 } else if (!strcmp(arg
, REPO_INFO_RESOLVED_HEAD
)) {
64 string_ncopy(state
->head_id
, name
, namelen
);
66 } else if (!strcmp(arg
, REPO_INFO_SYMBOLIC_HEAD
)) {
67 if (!prefixcmp(name
, "refs/heads/")) {
68 char *offset
= name
+ STRING_SIZE("refs/heads/");
70 string_ncopy(repo
.head
, offset
, strlen(offset
) + 1);
71 add_ref(state
->head_id
, name
, repo
.remote
, repo
.head
);
82 const char *rev_parse_argv
[] = {
83 "git", "rev-parse", REPO_INFO_GIT_DIR
, REPO_INFO_WORK_TREE
,
84 REPO_INFO_SHOW_CDUP
, REPO_INFO_SHOW_PREFIX
, \
85 REPO_INFO_RESOLVED_HEAD
, REPO_INFO_SYMBOLIC_HEAD
, "HEAD",
88 struct repo_info_state state
= { rev_parse_argv
+ 2 };
90 return io_run_load(rev_parse_argv
, "=", read_repo_info
, &state
);
93 struct repo_info repo
;
102 const char *update_index_argv
[] = {
103 "git", "update-index", "-q", "--unmerged", "--refresh", NULL
106 return io_run_bg(update_index_argv
);
110 index_diff(struct index_diff
*diff
, bool untracked
, bool count_all
)
112 const char *untracked_arg
= !untracked
? "--untracked-files=no" :
113 count_all
? "--untracked-files=all" :
114 "--untracked-files=normal";
115 const char *status_argv
[] = {
116 "git", "status", "--porcelain", "-z", untracked_arg
, NULL
122 memset(diff
, 0, sizeof(*diff
));
124 if (!io_run(&io
, IO_RD
, repo
.cdup
, NULL
, status_argv
))
127 while (io_get(&io
, &buf
, 0, TRUE
) && (ok
= buf
.size
> 3)) {
128 if (buf
.data
[0] == '?')
130 /* Ignore staged but unmerged entries. */
131 else if (buf
.data
[0] != ' ' && buf
.data
[0] != 'U')
133 if (buf
.data
[1] != ' ')
135 if (!count_all
&& diff
->staged
&& diff
->unstaged
&&
136 (!untracked
|| diff
->untracked
))
147 /* vim: set ts=8 sw=8 noexpandtab: */