Add option to install Tig with Homebrew
[tig.git] / src / repo.c
blob967c3b4d89b1fbdabe69d4aa372cd6282869fb75
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.
14 #include "tig/tig.h"
15 #include "tig/repo.h"
16 #include "tig/io.h"
17 #include "tig/refdb.h"
18 #include "tig/git.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 {
28 const char **argv;
29 char head_id[SIZEOF_REV];
32 static int
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
57 * was emitted. */
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);
73 state->argv++;
76 return OK;
79 int
80 load_repo_info(void)
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",
86 NULL
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;
96 * Git index utils.
99 bool
100 update_index(void)
102 const char *update_index_argv[] = {
103 "git", "update-index", "-q", "--unmerged", "--refresh", NULL
106 return io_run_bg(update_index_argv);
109 bool
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
118 struct io io;
119 struct buffer buf;
120 bool ok = TRUE;
122 memset(diff, 0, sizeof(*diff));
124 if (!io_run(&io, IO_RD, repo.cdup, NULL, status_argv))
125 return FALSE;
127 while (io_get(&io, &buf, 0, TRUE) && (ok = buf.size > 3)) {
128 if (buf.data[0] == '?')
129 diff->untracked++;
130 /* Ignore staged but unmerged entries. */
131 else if (buf.data[0] != ' ' && buf.data[0] != 'U')
132 diff->staged++;
133 if (buf.data[1] != ' ')
134 diff->unstaged++;
135 if (!count_all && diff->staged && diff->unstaged &&
136 (!untracked || diff->untracked))
137 break;
140 if (io_error(&io))
141 ok = FALSE;
143 io_done(&io);
144 return ok;
147 /* vim: set ts=8 sw=8 noexpandtab: */