Merge branch 'maint'
[git] / submodule.c
1 #include "cache.h"
2 #include "submodule.h"
3 #include "dir.h"
4 #include "diff.h"
5 #include "commit.h"
6 #include "revision.h"
7 #include "run-command.h"
8 #include "diffcore.h"
9 #include "string-list.h"
10
11 struct string_list config_name_for_path;
12 struct string_list config_ignore_for_name;
13
14 static int add_submodule_odb(const char *path)
15 {
16         struct strbuf objects_directory = STRBUF_INIT;
17         struct alternate_object_database *alt_odb;
18         int ret = 0;
19         const char *git_dir;
20
21         strbuf_addf(&objects_directory, "%s/.git", path);
22         git_dir = read_gitfile_gently(objects_directory.buf);
23         if (git_dir) {
24                 strbuf_reset(&objects_directory);
25                 strbuf_addstr(&objects_directory, git_dir);
26         }
27         strbuf_addstr(&objects_directory, "/objects/");
28         if (!is_directory(objects_directory.buf)) {
29                 ret = -1;
30                 goto done;
31         }
32         /* avoid adding it twice */
33         for (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb->next)
34                 if (alt_odb->name - alt_odb->base == objects_directory.len &&
35                                 !strncmp(alt_odb->base, objects_directory.buf,
36                                         objects_directory.len))
37                         goto done;
38
39         alt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb));
40         alt_odb->next = alt_odb_list;
41         strcpy(alt_odb->base, objects_directory.buf);
42         alt_odb->name = alt_odb->base + objects_directory.len;
43         alt_odb->name[2] = '/';
44         alt_odb->name[40] = '\0';
45         alt_odb->name[41] = '\0';
46         alt_odb_list = alt_odb;
47         prepare_alt_odb();
48 done:
49         strbuf_release(&objects_directory);
50         return ret;
51 }
52
53 void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
54                                              const char *path)
55 {
56         struct string_list_item *path_option, *ignore_option;
57         path_option = unsorted_string_list_lookup(&config_name_for_path, path);
58         if (path_option) {
59                 ignore_option = unsorted_string_list_lookup(&config_ignore_for_name, path_option->util);
60                 if (ignore_option)
61                         handle_ignore_submodules_arg(diffopt, ignore_option->util);
62         }
63 }
64
65 static int submodule_config(const char *var, const char *value, void *cb)
66 {
67         if (!prefixcmp(var, "submodule."))
68                 return parse_submodule_config_option(var, value);
69         return 0;
70 }
71
72 void gitmodules_config(void)
73 {
74         const char *work_tree = get_git_work_tree();
75         if (work_tree) {
76                 struct strbuf gitmodules_path = STRBUF_INIT;
77                 strbuf_addstr(&gitmodules_path, work_tree);
78                 strbuf_addstr(&gitmodules_path, "/.gitmodules");
79                 git_config_from_file(submodule_config, gitmodules_path.buf, NULL);
80                 strbuf_release(&gitmodules_path);
81         }
82 }
83
84 int parse_submodule_config_option(const char *var, const char *value)
85 {
86         int len;
87         struct string_list_item *config;
88         struct strbuf submodname = STRBUF_INIT;
89
90         var += 10;              /* Skip "submodule." */
91
92         len = strlen(var);
93         if ((len > 5) && !strcmp(var + len - 5, ".path")) {
94                 strbuf_add(&submodname, var, len - 5);
95                 config = unsorted_string_list_lookup(&config_name_for_path, value);
96                 if (config)
97                         free(config->util);
98                 else
99                         config = string_list_append(&config_name_for_path, xstrdup(value));
100                 config->util = strbuf_detach(&submodname, NULL);
101                 strbuf_release(&submodname);
102         } else if ((len > 7) && !strcmp(var + len - 7, ".ignore")) {
103                 if (strcmp(value, "untracked") && strcmp(value, "dirty") &&
104                     strcmp(value, "all") && strcmp(value, "none")) {
105                         warning("Invalid parameter \"%s\" for config option \"submodule.%s.ignore\"", value, var);
106                         return 0;
107                 }
108
109                 strbuf_add(&submodname, var, len - 7);
110                 config = unsorted_string_list_lookup(&config_ignore_for_name, submodname.buf);
111                 if (config)
112                         free(config->util);
113                 else
114                         config = string_list_append(&config_ignore_for_name,
115                                                     strbuf_detach(&submodname, NULL));
116                 strbuf_release(&submodname);
117                 config->util = xstrdup(value);
118                 return 0;
119         }
120         return 0;
121 }
122
123 void handle_ignore_submodules_arg(struct diff_options *diffopt,
124                                   const char *arg)
125 {
126         DIFF_OPT_CLR(diffopt, IGNORE_SUBMODULES);
127         DIFF_OPT_CLR(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);
128         DIFF_OPT_CLR(diffopt, IGNORE_DIRTY_SUBMODULES);
129
130         if (!strcmp(arg, "all"))
131                 DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
132         else if (!strcmp(arg, "untracked"))
133                 DIFF_OPT_SET(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);
134         else if (!strcmp(arg, "dirty"))
135                 DIFF_OPT_SET(diffopt, IGNORE_DIRTY_SUBMODULES);
136         else if (strcmp(arg, "none"))
137                 die("bad --ignore-submodules argument: %s", arg);
138 }
139
140 void show_submodule_summary(FILE *f, const char *path,
141                 unsigned char one[20], unsigned char two[20],
142                 unsigned dirty_submodule,
143                 const char *del, const char *add, const char *reset)
144 {
145         struct rev_info rev;
146         struct commit *commit, *left = left, *right = right;
147         struct commit_list *merge_bases, *list;
148         const char *message = NULL;
149         struct strbuf sb = STRBUF_INIT;
150         static const char *format = "  %m %s";
151         int fast_forward = 0, fast_backward = 0;
152
153         if (is_null_sha1(two))
154                 message = "(submodule deleted)";
155         else if (add_submodule_odb(path))
156                 message = "(not checked out)";
157         else if (is_null_sha1(one))
158                 message = "(new submodule)";
159         else if (!(left = lookup_commit_reference(one)) ||
160                  !(right = lookup_commit_reference(two)))
161                 message = "(commits not present)";
162
163         if (!message) {
164                 init_revisions(&rev, NULL);
165                 setup_revisions(0, NULL, &rev, NULL);
166                 rev.left_right = 1;
167                 rev.first_parent_only = 1;
168                 left->object.flags |= SYMMETRIC_LEFT;
169                 add_pending_object(&rev, &left->object, path);
170                 add_pending_object(&rev, &right->object, path);
171                 merge_bases = get_merge_bases(left, right, 1);
172                 if (merge_bases) {
173                         if (merge_bases->item == left)
174                                 fast_forward = 1;
175                         else if (merge_bases->item == right)
176                                 fast_backward = 1;
177                 }
178                 for (list = merge_bases; list; list = list->next) {
179                         list->item->object.flags |= UNINTERESTING;
180                         add_pending_object(&rev, &list->item->object,
181                                 sha1_to_hex(list->item->object.sha1));
182                 }
183                 if (prepare_revision_walk(&rev))
184                         message = "(revision walker failed)";
185         }
186
187         if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
188                 fprintf(f, "Submodule %s contains untracked content\n", path);
189         if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
190                 fprintf(f, "Submodule %s contains modified content\n", path);
191
192         if (!hashcmp(one, two)) {
193                 strbuf_release(&sb);
194                 return;
195         }
196
197         strbuf_addf(&sb, "Submodule %s %s..", path,
198                         find_unique_abbrev(one, DEFAULT_ABBREV));
199         if (!fast_backward && !fast_forward)
200                 strbuf_addch(&sb, '.');
201         strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV));
202         if (message)
203                 strbuf_addf(&sb, " %s\n", message);
204         else
205                 strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : "");
206         fwrite(sb.buf, sb.len, 1, f);
207
208         if (!message) {
209                 while ((commit = get_revision(&rev))) {
210                         struct pretty_print_context ctx = {0};
211                         ctx.date_mode = rev.date_mode;
212                         strbuf_setlen(&sb, 0);
213                         if (commit->object.flags & SYMMETRIC_LEFT) {
214                                 if (del)
215                                         strbuf_addstr(&sb, del);
216                         }
217                         else if (add)
218                                 strbuf_addstr(&sb, add);
219                         format_commit_message(commit, format, &sb, &ctx);
220                         if (reset)
221                                 strbuf_addstr(&sb, reset);
222                         strbuf_addch(&sb, '\n');
223                         fprintf(f, "%s", sb.buf);
224                 }
225                 clear_commit_marks(left, ~0);
226                 clear_commit_marks(right, ~0);
227         }
228         strbuf_release(&sb);
229 }
230
231 unsigned is_submodule_modified(const char *path, int ignore_untracked)
232 {
233         ssize_t len;
234         struct child_process cp;
235         const char *argv[] = {
236                 "status",
237                 "--porcelain",
238                 NULL,
239                 NULL,
240         };
241         struct strbuf buf = STRBUF_INIT;
242         unsigned dirty_submodule = 0;
243         const char *line, *next_line;
244         const char *git_dir;
245
246         strbuf_addf(&buf, "%s/.git", path);
247         git_dir = read_gitfile_gently(buf.buf);
248         if (!git_dir)
249                 git_dir = buf.buf;
250         if (!is_directory(git_dir)) {
251                 strbuf_release(&buf);
252                 /* The submodule is not checked out, so it is not modified */
253                 return 0;
254
255         }
256         strbuf_reset(&buf);
257
258         if (ignore_untracked)
259                 argv[2] = "-uno";
260
261         memset(&cp, 0, sizeof(cp));
262         cp.argv = argv;
263         cp.env = local_repo_env;
264         cp.git_cmd = 1;
265         cp.no_stdin = 1;
266         cp.out = -1;
267         cp.dir = path;
268         if (start_command(&cp))
269                 die("Could not run git status --porcelain");
270
271         len = strbuf_read(&buf, cp.out, 1024);
272         line = buf.buf;
273         while (len > 2) {
274                 if ((line[0] == '?') && (line[1] == '?')) {
275                         dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
276                         if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
277                                 break;
278                 } else {
279                         dirty_submodule |= DIRTY_SUBMODULE_MODIFIED;
280                         if (ignore_untracked ||
281                             (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED))
282                                 break;
283                 }
284                 next_line = strchr(line, '\n');
285                 if (!next_line)
286                         break;
287                 next_line++;
288                 len -= (next_line - line);
289                 line = next_line;
290         }
291         close(cp.out);
292
293         if (finish_command(&cp))
294                 die("git status --porcelain failed");
295
296         strbuf_release(&buf);
297         return dirty_submodule;
298 }