Code

read-trees: refactor the unpack_trees() part
[git.git] / unpack-trees.c
1 #include <signal.h>
2 #include <sys/time.h>
3 #include "cache.h"
4 #include "tree.h"
5 #include "tree-walk.h"
6 #include "unpack-trees.h"
8 struct tree_entry_list {
9         struct tree_entry_list *next;
10         unsigned directory : 1;
11         unsigned executable : 1;
12         unsigned symlink : 1;
13         unsigned int mode;
14         const char *name;
15         const unsigned char *sha1;
16 };
18 static struct tree_entry_list *create_tree_entry_list(struct tree *tree)
19 {
20         struct tree_desc desc;
21         struct name_entry one;
22         struct tree_entry_list *ret = NULL;
23         struct tree_entry_list **list_p = &ret;
25         desc.buf = tree->buffer;
26         desc.size = tree->size;
28         while (tree_entry(&desc, &one)) {
29                 struct tree_entry_list *entry;
31                 entry = xmalloc(sizeof(struct tree_entry_list));
32                 entry->name = one.path;
33                 entry->sha1 = one.sha1;
34                 entry->mode = one.mode;
35                 entry->directory = S_ISDIR(one.mode) != 0;
36                 entry->executable = (one.mode & S_IXUSR) != 0;
37                 entry->symlink = S_ISLNK(one.mode) != 0;
38                 entry->next = NULL;
40                 *list_p = entry;
41                 list_p = &entry->next;
42         }
43         return ret;
44 }
46 static int entcmp(const char *name1, int dir1, const char *name2, int dir2)
47 {
48         int len1 = strlen(name1);
49         int len2 = strlen(name2);
50         int len = len1 < len2 ? len1 : len2;
51         int ret = memcmp(name1, name2, len);
52         unsigned char c1, c2;
53         if (ret)
54                 return ret;
55         c1 = name1[len];
56         c2 = name2[len];
57         if (!c1 && dir1)
58                 c1 = '/';
59         if (!c2 && dir2)
60                 c2 = '/';
61         ret = (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
62         if (c1 && c2 && !ret)
63                 ret = len1 - len2;
64         return ret;
65 }
67 static int unpack_trees_rec(struct tree_entry_list **posns, int len,
68                             const char *base, struct unpack_trees_options *o,
69                             int *indpos,
70                             struct tree_entry_list *df_conflict_list)
71 {
72         int baselen = strlen(base);
73         int src_size = len + 1;
74         do {
75                 int i;
76                 const char *first;
77                 int firstdir = 0;
78                 int pathlen;
79                 unsigned ce_size;
80                 struct tree_entry_list **subposns;
81                 struct cache_entry **src;
82                 int any_files = 0;
83                 int any_dirs = 0;
84                 char *cache_name;
85                 int ce_stage;
87                 /* Find the first name in the input. */
89                 first = NULL;
90                 cache_name = NULL;
92                 /* Check the cache */
93                 if (o->merge && *indpos < active_nr) {
94                         /* This is a bit tricky: */
95                         /* If the index has a subdirectory (with
96                          * contents) as the first name, it'll get a
97                          * filename like "foo/bar". But that's after
98                          * "foo", so the entry in trees will get
99                          * handled first, at which point we'll go into
100                          * "foo", and deal with "bar" from the index,
101                          * because the base will be "foo/". The only
102                          * way we can actually have "foo/bar" first of
103                          * all the things is if the trees don't
104                          * contain "foo" at all, in which case we'll
105                          * handle "foo/bar" without going into the
106                          * directory, but that's fine (and will return
107                          * an error anyway, with the added unknown
108                          * file case.
109                          */
111                         cache_name = active_cache[*indpos]->name;
112                         if (strlen(cache_name) > baselen &&
113                             !memcmp(cache_name, base, baselen)) {
114                                 cache_name += baselen;
115                                 first = cache_name;
116                         } else {
117                                 cache_name = NULL;
118                         }
119                 }
121 #if DBRT_DEBUG > 1
122                 if (first)
123                         printf("index %s\n", first);
124 #endif
125                 for (i = 0; i < len; i++) {
126                         if (!posns[i] || posns[i] == df_conflict_list)
127                                 continue;
128 #if DBRT_DEBUG > 1
129                         printf("%d %s\n", i + 1, posns[i]->name);
130 #endif
131                         if (!first || entcmp(first, firstdir,
132                                              posns[i]->name,
133                                              posns[i]->directory) > 0) {
134                                 first = posns[i]->name;
135                                 firstdir = posns[i]->directory;
136                         }
137                 }
138                 /* No name means we're done */
139                 if (!first)
140                         return 0;
142                 pathlen = strlen(first);
143                 ce_size = cache_entry_size(baselen + pathlen);
145                 src = xcalloc(src_size, sizeof(struct cache_entry *));
147                 subposns = xcalloc(len, sizeof(struct tree_list_entry *));
149                 if (cache_name && !strcmp(cache_name, first)) {
150                         any_files = 1;
151                         src[0] = active_cache[*indpos];
152                         remove_cache_entry_at(*indpos);
153                 }
155                 for (i = 0; i < len; i++) {
156                         struct cache_entry *ce;
158                         if (!posns[i] ||
159                             (posns[i] != df_conflict_list &&
160                              strcmp(first, posns[i]->name))) {
161                                 continue;
162                         }
164                         if (posns[i] == df_conflict_list) {
165                                 src[i + o->merge] = o->df_conflict_entry;
166                                 continue;
167                         }
169                         if (posns[i]->directory) {
170                                 struct tree *tree = lookup_tree(posns[i]->sha1);
171                                 any_dirs = 1;
172                                 parse_tree(tree);
173                                 subposns[i] = create_tree_entry_list(tree);
174                                 posns[i] = posns[i]->next;
175                                 src[i + o->merge] = o->df_conflict_entry;
176                                 continue;
177                         }
179                         if (!o->merge)
180                                 ce_stage = 0;
181                         else if (i + 1 < o->head_idx)
182                                 ce_stage = 1;
183                         else if (i + 1 > o->head_idx)
184                                 ce_stage = 3;
185                         else
186                                 ce_stage = 2;
188                         ce = xcalloc(1, ce_size);
189                         ce->ce_mode = create_ce_mode(posns[i]->mode);
190                         ce->ce_flags = create_ce_flags(baselen + pathlen,
191                                                        ce_stage);
192                         memcpy(ce->name, base, baselen);
193                         memcpy(ce->name + baselen, first, pathlen + 1);
195                         any_files = 1;
197                         memcpy(ce->sha1, posns[i]->sha1, 20);
198                         src[i + o->merge] = ce;
199                         subposns[i] = df_conflict_list;
200                         posns[i] = posns[i]->next;
201                 }
202                 if (any_files) {
203                         if (o->merge) {
204                                 int ret;
206 #if DBRT_DEBUG > 1
207                                 printf("%s:\n", first);
208                                 for (i = 0; i < src_size; i++) {
209                                         printf(" %d ", i);
210                                         if (src[i])
211                                                 printf("%s\n", sha1_to_hex(src[i]->sha1));
212                                         else
213                                                 printf("\n");
214                                 }
215 #endif
216                                 ret = o->fn(src, o);
218 #if DBRT_DEBUG > 1
219                                 printf("Added %d entries\n", ret);
220 #endif
221                                 *indpos += ret;
222                         } else {
223                                 for (i = 0; i < src_size; i++) {
224                                         if (src[i]) {
225                                                 add_cache_entry(src[i], ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
226                                         }
227                                 }
228                         }
229                 }
230                 if (any_dirs) {
231                         char *newbase = xmalloc(baselen + 2 + pathlen);
232                         memcpy(newbase, base, baselen);
233                         memcpy(newbase + baselen, first, pathlen);
234                         newbase[baselen + pathlen] = '/';
235                         newbase[baselen + pathlen + 1] = '\0';
236                         if (unpack_trees_rec(subposns, len, newbase, o,
237                                              indpos, df_conflict_list))
238                                 return -1;
239                         free(newbase);
240                 }
241                 free(subposns);
242                 free(src);
243         } while (1);
246 /* Unlink the last component and attempt to remove leading
247  * directories, in case this unlink is the removal of the
248  * last entry in the directory -- empty directories are removed.
249  */
250 static void unlink_entry(char *name)
252         char *cp, *prev;
254         if (unlink(name))
255                 return;
256         prev = NULL;
257         while (1) {
258                 int status;
259                 cp = strrchr(name, '/');
260                 if (prev)
261                         *prev = '/';
262                 if (!cp)
263                         break;
265                 *cp = 0;
266                 status = rmdir(name);
267                 if (status) {
268                         *cp = '/';
269                         break;
270                 }
271                 prev = cp;
272         }
275 static volatile int progress_update = 0;
277 static void progress_interval(int signum)
279         progress_update = 1;
282 static void setup_progress_signal(void)
284         struct sigaction sa;
285         struct itimerval v;
287         memset(&sa, 0, sizeof(sa));
288         sa.sa_handler = progress_interval;
289         sigemptyset(&sa.sa_mask);
290         sa.sa_flags = SA_RESTART;
291         sigaction(SIGALRM, &sa, NULL);
293         v.it_interval.tv_sec = 1;
294         v.it_interval.tv_usec = 0;
295         v.it_value = v.it_interval;
296         setitimer(ITIMER_REAL, &v, NULL);
299 static struct checkout state;
300 static void check_updates(struct cache_entry **src, int nr,
301                 struct unpack_trees_options *o)
303         unsigned short mask = htons(CE_UPDATE);
304         unsigned last_percent = 200, cnt = 0, total = 0;
306         if (o->update && o->verbose_update) {
307                 for (total = cnt = 0; cnt < nr; cnt++) {
308                         struct cache_entry *ce = src[cnt];
309                         if (!ce->ce_mode || ce->ce_flags & mask)
310                                 total++;
311                 }
313                 /* Don't bother doing this for very small updates */
314                 if (total < 250)
315                         total = 0;
317                 if (total) {
318                         fprintf(stderr, "Checking files out...\n");
319                         setup_progress_signal();
320                         progress_update = 1;
321                 }
322                 cnt = 0;
323         }
325         while (nr--) {
326                 struct cache_entry *ce = *src++;
328                 if (total) {
329                         if (!ce->ce_mode || ce->ce_flags & mask) {
330                                 unsigned percent;
331                                 cnt++;
332                                 percent = (cnt * 100) / total;
333                                 if (percent != last_percent ||
334                                     progress_update) {
335                                         fprintf(stderr, "%4u%% (%u/%u) done\r",
336                                                 percent, cnt, total);
337                                         last_percent = percent;
338                                         progress_update = 0;
339                                 }
340                         }
341                 }
342                 if (!ce->ce_mode) {
343                         if (o->update)
344                                 unlink_entry(ce->name);
345                         continue;
346                 }
347                 if (ce->ce_flags & mask) {
348                         ce->ce_flags &= ~mask;
349                         if (o->update)
350                                 checkout_entry(ce, &state, NULL);
351                 }
352         }
353         if (total) {
354                 signal(SIGALRM, SIG_IGN);
355                 fputc('\n', stderr);
356         }
359 int unpack_trees(struct object_list *trees, struct unpack_trees_options *o)
361         int indpos = 0;
362         unsigned len = object_list_length(trees);
363         struct tree_entry_list **posns;
364         int i;
365         struct object_list *posn = trees;
366         struct tree_entry_list df_conflict_list;
367         struct cache_entry df_conflict_entry;
369         memset(&df_conflict_list, 0, sizeof(df_conflict_list));
370         df_conflict_list.next = &df_conflict_list;
371         state.base_dir = "";
372         state.force = 1;
373         state.quiet = 1;
374         state.refresh_cache = 1;
376         o->merge_size = len;
377         o->df_conflict_entry = &df_conflict_entry;
379         if (len) {
380                 posns = xmalloc(len * sizeof(struct tree_entry_list *));
381                 for (i = 0; i < len; i++) {
382                         posns[i] = create_tree_entry_list((struct tree *) posn->item);
383                         posn = posn->next;
384                 }
385                 if (unpack_trees_rec(posns, len, o->prefix ? o->prefix : "",
386                                      o, &indpos, &df_conflict_list))
387                         return -1;
388         }
390         if (o->trivial_merges_only && o->nontrivial_merge)
391                 die("Merge requires file-level merging");
393         check_updates(active_cache, active_nr, o);
394         return 0;