b2977cf16c3b1f98304bf4b1630947409560e80f
[git.git] / merge-cache.c
1 #include <sys/types.h>
2 #include <sys/wait.h>
3
4 #include "cache.h"
5
6 static const char *pgm = NULL;
7 static const char *arguments[8];
8 static int err;
9
10 static void run_program(void)
11 {
12         int pid = fork(), status;
13
14         if (pid < 0)
15                 die("unable to fork");
16         if (!pid) {
17                 execlp(pgm, arguments[0],
18                             arguments[1],
19                             arguments[2],
20                             arguments[3],
21                             arguments[4],
22                             arguments[5],
23                             arguments[6],
24                             arguments[7],
25                             NULL);
26                 die("unable to execute '%s'", pgm);
27         }
28         if (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status))
29                 err++;
30 }
31
32 static int merge_entry(int pos, const char *path)
33 {
34         int found;
35         
36         if (pos >= active_nr)
37                 die("merge-cache: %s not in the cache", path);
38         arguments[0] = pgm;
39         arguments[1] = "";
40         arguments[2] = "";
41         arguments[3] = "";
42         arguments[4] = path;
43         arguments[5] = "";
44         arguments[6] = "";
45         arguments[7] = "";
46         found = 0;
47         do {
48                 static char hexbuf[4][60];
49                 static char ownbuf[4][60];
50                 struct cache_entry *ce = active_cache[pos];
51                 int stage = ce_stage(ce);
52
53                 if (strcmp(ce->name, path))
54                         break;
55                 found++;
56                 strcpy(hexbuf[stage], sha1_to_hex(ce->sha1));
57                 sprintf(ownbuf[stage], "%o", ntohl(ce->ce_mode) & (~S_IFMT));
58                 arguments[stage] = hexbuf[stage];
59                 arguments[stage + 4] = ownbuf[stage];
60         } while (++pos < active_nr);
61         if (!found)
62                 die("merge-cache: %s not in the cache", path);
63         run_program();
64         return found;
65 }
66
67 static void merge_file(const char *path)
68 {
69         int pos = cache_name_pos(path, strlen(path));
70
71         /*
72          * If it already exists in the cache as stage0, it's
73          * already merged and there is nothing to do.
74          */
75         if (pos < 0)
76                 merge_entry(-pos-1, path);
77 }
78
79 static void merge_all(void)
80 {
81         int i;
82         for (i = 0; i < active_nr; i++) {
83                 struct cache_entry *ce = active_cache[i];
84                 if (!ce_stage(ce))
85                         continue;
86                 i += merge_entry(i, ce->name)-1;
87         }
88 }
89
90 int main(int argc, char **argv)
91 {
92         int i, force_file = 0;
93
94         if (argc < 3)
95                 usage("merge-cache <merge-program> (-a | <filename>*)");
96
97         read_cache();
98
99         pgm = argv[1];
100         for (i = 2; i < argc; i++) {
101                 char *arg = argv[i];
102                 if (!force_file && *arg == '-') {
103                         if (!strcmp(arg, "--")) {
104                                 force_file = 1;
105                                 continue;
106                         }
107                         if (!strcmp(arg, "-a")) {
108                                 merge_all();
109                                 continue;
110                         }
111                         die("merge-cache: unknown option %s", arg);
112                 }
113                 merge_file(arg);
114         }
115         if (err)
116                 die("merge program failed");
117         return 0;
118 }