Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2005 Junio C Hamano |
| 3 | */ |
| 4 | #include <sys/types.h> |
| 5 | #include <sys/wait.h> |
Junio C Hamano | 532149d | 2005-04-28 10:13:01 -0700 | [diff] [blame] | 6 | #include <signal.h> |
Thomas Glanzmann | a1df57a | 2005-05-07 10:41:41 +0200 | [diff] [blame] | 7 | #include <limits.h> |
Junio C Hamano | 86436c2 | 2005-04-25 18:22:47 -0700 | [diff] [blame] | 8 | #include "cache.h" |
| 9 | #include "diff.h" |
| 10 | |
Junio C Hamano | d19938a | 2005-05-09 17:57:56 -0700 | [diff] [blame] | 11 | static const char *diff_opts = "-pu"; |
Junio C Hamano | 86436c2 | 2005-04-25 18:22:47 -0700 | [diff] [blame] | 12 | |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 13 | static const char *external_diff(void) |
Junio C Hamano | 86436c2 | 2005-04-25 18:22:47 -0700 | [diff] [blame] | 14 | { |
Junio C Hamano | d19938a | 2005-05-09 17:57:56 -0700 | [diff] [blame] | 15 | static const char *external_diff_cmd = NULL; |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 16 | static int done_preparing = 0; |
| 17 | |
| 18 | if (done_preparing) |
| 19 | return external_diff_cmd; |
| 20 | |
Junio C Hamano | 86436c2 | 2005-04-25 18:22:47 -0700 | [diff] [blame] | 21 | /* |
| 22 | * Default values above are meant to match the |
| 23 | * Linux kernel development style. Examples of |
| 24 | * alternative styles you can specify via environment |
| 25 | * variables are: |
| 26 | * |
Junio C Hamano | 86436c2 | 2005-04-25 18:22:47 -0700 | [diff] [blame] | 27 | * GIT_DIFF_OPTS="-c"; |
| 28 | */ |
Junio C Hamano | d19938a | 2005-05-09 17:57:56 -0700 | [diff] [blame] | 29 | if (gitenv("GIT_EXTERNAL_DIFF")) |
| 30 | external_diff_cmd = gitenv("GIT_EXTERNAL_DIFF"); |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 31 | |
| 32 | /* In case external diff fails... */ |
Junio C Hamano | d19938a | 2005-05-09 17:57:56 -0700 | [diff] [blame] | 33 | diff_opts = gitenv("GIT_DIFF_OPTS") ? : diff_opts; |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 34 | |
| 35 | done_preparing = 1; |
| 36 | return external_diff_cmd; |
Junio C Hamano | 86436c2 | 2005-04-25 18:22:47 -0700 | [diff] [blame] | 37 | } |
| 38 | |
| 39 | /* Help to copy the thing properly quoted for the shell safety. |
| 40 | * any single quote is replaced with '\'', and the caller is |
| 41 | * expected to enclose the result within a single quote pair. |
| 42 | * |
| 43 | * E.g. |
| 44 | * original sq_expand result |
| 45 | * name ==> name ==> 'name' |
| 46 | * a b ==> a b ==> 'a b' |
| 47 | * a'b ==> a'\''b ==> 'a'\''b' |
| 48 | */ |
| 49 | static char *sq_expand(const char *src) |
| 50 | { |
| 51 | static char *buf = NULL; |
| 52 | int cnt, c; |
| 53 | const char *cp; |
| 54 | char *bp; |
| 55 | |
| 56 | /* count bytes needed to store the quoted string. */ |
| 57 | for (cnt = 1, cp = src; *cp; cnt++, cp++) |
| 58 | if (*cp == '\'') |
| 59 | cnt += 3; |
| 60 | |
Christopher Li | 812666c | 2005-04-26 12:00:58 -0700 | [diff] [blame] | 61 | buf = xmalloc(cnt); |
Junio C Hamano | 86436c2 | 2005-04-25 18:22:47 -0700 | [diff] [blame] | 62 | bp = buf; |
| 63 | while ((c = *src++)) { |
| 64 | if (c != '\'') |
| 65 | *bp++ = c; |
| 66 | else { |
| 67 | bp = strcpy(bp, "'\\''"); |
| 68 | bp += 4; |
| 69 | } |
| 70 | } |
| 71 | *bp = 0; |
| 72 | return buf; |
| 73 | } |
| 74 | |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 75 | static struct diff_tempfile { |
| 76 | const char *name; |
| 77 | char hex[41]; |
| 78 | char mode[10]; |
| 79 | char tmp_path[50]; |
| 80 | } diff_temp[2]; |
Junio C Hamano | 86436c2 | 2005-04-25 18:22:47 -0700 | [diff] [blame] | 81 | |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 82 | static void builtin_diff(const char *name, |
| 83 | struct diff_tempfile *temp) |
| 84 | { |
Junio C Hamano | 2f97813 | 2005-04-28 08:04:39 -0700 | [diff] [blame] | 85 | int i, next_at; |
Junio C Hamano | 273b983 | 2005-05-13 18:40:14 -0700 | [diff] [blame] | 86 | const char *git_prefix = "# mode: "; |
Junio C Hamano | c983370 | 2005-05-01 09:33:12 -0700 | [diff] [blame] | 87 | const char *diff_cmd = "diff -L'%s%s' -L'%s%s'"; |
Junio C Hamano | 6fa2806 | 2005-05-04 01:38:06 -0700 | [diff] [blame] | 88 | const char *diff_arg = "'%s' '%s'||:"; /* "||:" is to return 0 */ |
Junio C Hamano | 2f97813 | 2005-04-28 08:04:39 -0700 | [diff] [blame] | 89 | const char *input_name_sq[2]; |
| 90 | const char *path0[2]; |
| 91 | const char *path1[2]; |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 92 | const char *name_sq = sq_expand(name); |
Junio C Hamano | 2f97813 | 2005-04-28 08:04:39 -0700 | [diff] [blame] | 93 | char *cmd; |
| 94 | |
Junio C Hamano | c983370 | 2005-05-01 09:33:12 -0700 | [diff] [blame] | 95 | /* diff_cmd and diff_arg have 6 %s in total which makes |
| 96 | * the sum of these strings 12 bytes larger than required. |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 97 | * we use 2 spaces around diff-opts, and we need to count |
Junio C Hamano | c983370 | 2005-05-01 09:33:12 -0700 | [diff] [blame] | 98 | * terminating NUL, so we subtract 9 here. |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 99 | */ |
Junio C Hamano | 2f97813 | 2005-04-28 08:04:39 -0700 | [diff] [blame] | 100 | int cmd_size = (strlen(diff_cmd) + strlen(diff_opts) + |
Junio C Hamano | c983370 | 2005-05-01 09:33:12 -0700 | [diff] [blame] | 101 | strlen(diff_arg) - 9); |
Junio C Hamano | 2f97813 | 2005-04-28 08:04:39 -0700 | [diff] [blame] | 102 | for (i = 0; i < 2; i++) { |
| 103 | input_name_sq[i] = sq_expand(temp[i].name); |
| 104 | if (!strcmp(temp[i].name, "/dev/null")) { |
| 105 | path0[i] = "/dev/null"; |
| 106 | path1[i] = ""; |
Junio C Hamano | 2f97813 | 2005-04-28 08:04:39 -0700 | [diff] [blame] | 107 | } else { |
Linus Torvalds | 0980d9b | 2005-05-01 21:53:36 -0700 | [diff] [blame] | 108 | path0[i] = i ? "b/" : "a/"; |
Junio C Hamano | 2f97813 | 2005-04-28 08:04:39 -0700 | [diff] [blame] | 109 | path1[i] = name_sq; |
Junio C Hamano | 2f97813 | 2005-04-28 08:04:39 -0700 | [diff] [blame] | 110 | } |
| 111 | cmd_size += (strlen(path0[i]) + strlen(path1[i]) + |
Junio C Hamano | c983370 | 2005-05-01 09:33:12 -0700 | [diff] [blame] | 112 | strlen(input_name_sq[i])); |
Junio C Hamano | 2f97813 | 2005-04-28 08:04:39 -0700 | [diff] [blame] | 113 | } |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 114 | |
Junio C Hamano | 2f97813 | 2005-04-28 08:04:39 -0700 | [diff] [blame] | 115 | cmd = xmalloc(cmd_size); |
| 116 | |
| 117 | next_at = 0; |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 118 | next_at += snprintf(cmd+next_at, cmd_size-next_at, |
Junio C Hamano | 2f97813 | 2005-04-28 08:04:39 -0700 | [diff] [blame] | 119 | diff_cmd, |
Junio C Hamano | c983370 | 2005-05-01 09:33:12 -0700 | [diff] [blame] | 120 | path0[0], path1[0], path0[1], path1[1]); |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 121 | next_at += snprintf(cmd+next_at, cmd_size-next_at, |
| 122 | " %s ", diff_opts); |
| 123 | next_at += snprintf(cmd+next_at, cmd_size-next_at, |
Junio C Hamano | 2f97813 | 2005-04-28 08:04:39 -0700 | [diff] [blame] | 124 | diff_arg, input_name_sq[0], input_name_sq[1]); |
| 125 | |
Junio C Hamano | c983370 | 2005-05-01 09:33:12 -0700 | [diff] [blame] | 126 | if (!path1[0][0]) |
Junio C Hamano | 273b983 | 2005-05-13 18:40:14 -0700 | [diff] [blame] | 127 | printf("%s. %s %s\n", git_prefix, temp[1].mode, name); |
Junio C Hamano | c983370 | 2005-05-01 09:33:12 -0700 | [diff] [blame] | 128 | else if (!path1[1][0]) |
Junio C Hamano | 273b983 | 2005-05-13 18:40:14 -0700 | [diff] [blame] | 129 | printf("%s%s . %s\n", git_prefix, temp[0].mode, name); |
| 130 | else { |
| 131 | if (strcmp(temp[0].mode, temp[1].mode)) |
| 132 | printf("%s%s %s %s\n", git_prefix, |
| 133 | temp[0].mode, temp[1].mode, name); |
| 134 | |
| 135 | if (strncmp(temp[0].mode, temp[1].mode, 3)) |
| 136 | /* we do not run diff between different kind |
| 137 | * of objects. |
| 138 | */ |
Junio C Hamano | b28858b | 2005-05-05 16:10:21 -0700 | [diff] [blame] | 139 | exit(0); |
| 140 | } |
Junio C Hamano | c983370 | 2005-05-01 09:33:12 -0700 | [diff] [blame] | 141 | fflush(NULL); |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 142 | execlp("/bin/sh","sh", "-c", cmd, NULL); |
Junio C Hamano | 86436c2 | 2005-04-25 18:22:47 -0700 | [diff] [blame] | 143 | } |
| 144 | |
Junio C Hamano | b46f0b6 | 2005-05-04 01:45:24 -0700 | [diff] [blame] | 145 | /* |
| 146 | * Given a name and sha1 pair, if the dircache tells us the file in |
| 147 | * the work tree has that object contents, return true, so that |
| 148 | * prepare_temp_file() does not have to inflate and extract. |
| 149 | */ |
| 150 | static int work_tree_matches(const char *name, const unsigned char *sha1) |
| 151 | { |
| 152 | struct cache_entry *ce; |
| 153 | struct stat st; |
| 154 | int pos, len; |
| 155 | |
| 156 | /* We do not read the cache ourselves here, because the |
| 157 | * benchmark with my previous version that always reads cache |
| 158 | * shows that it makes things worse for diff-tree comparing |
| 159 | * two linux-2.6 kernel trees in an already checked out work |
| 160 | * tree. This is because most diff-tree comparison deals with |
| 161 | * only a small number of files, while reading the cache is |
| 162 | * expensive for a large project, and its cost outweighs the |
| 163 | * savings we get by not inflating the object to a temporary |
| 164 | * file. Practically, this code only helps when we are used |
| 165 | * by diff-cache --cached, which does read the cache before |
| 166 | * calling us. |
| 167 | */ |
| 168 | if (!active_cache) |
| 169 | return 0; |
| 170 | |
| 171 | len = strlen(name); |
| 172 | pos = cache_name_pos(name, len); |
| 173 | if (pos < 0) |
| 174 | return 0; |
| 175 | ce = active_cache[pos]; |
Junio C Hamano | b28858b | 2005-05-05 16:10:21 -0700 | [diff] [blame] | 176 | if ((lstat(name, &st) < 0) || |
| 177 | !S_ISREG(st.st_mode) || |
Brad Roberts | 5d728c8 | 2005-05-14 19:04:25 -0700 | [diff] [blame] | 178 | ce_match_stat(ce, &st) || |
Junio C Hamano | b46f0b6 | 2005-05-04 01:45:24 -0700 | [diff] [blame] | 179 | memcmp(sha1, ce->sha1, 20)) |
| 180 | return 0; |
| 181 | return 1; |
| 182 | } |
| 183 | |
Junio C Hamano | b28858b | 2005-05-05 16:10:21 -0700 | [diff] [blame] | 184 | static void prep_temp_blob(struct diff_tempfile *temp, |
| 185 | void *blob, |
| 186 | unsigned long size, |
| 187 | unsigned char *sha1, |
| 188 | int mode) |
| 189 | { |
| 190 | int fd; |
| 191 | |
| 192 | strcpy(temp->tmp_path, ".diff_XXXXXX"); |
| 193 | fd = mkstemp(temp->tmp_path); |
| 194 | if (fd < 0) |
| 195 | die("unable to create temp-file"); |
| 196 | if (write(fd, blob, size) != size) |
| 197 | die("unable to write temp-file"); |
| 198 | close(fd); |
| 199 | temp->name = temp->tmp_path; |
| 200 | strcpy(temp->hex, sha1_to_hex(sha1)); |
| 201 | temp->hex[40] = 0; |
| 202 | sprintf(temp->mode, "%06o", mode); |
| 203 | } |
| 204 | |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 205 | static void prepare_temp_file(const char *name, |
| 206 | struct diff_tempfile *temp, |
| 207 | struct diff_spec *one) |
Junio C Hamano | 86436c2 | 2005-04-25 18:22:47 -0700 | [diff] [blame] | 208 | { |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 209 | static unsigned char null_sha1[20] = { 0, }; |
Junio C Hamano | b46f0b6 | 2005-05-04 01:45:24 -0700 | [diff] [blame] | 210 | int use_work_tree = 0; |
Junio C Hamano | 86436c2 | 2005-04-25 18:22:47 -0700 | [diff] [blame] | 211 | |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 212 | if (!one->file_valid) { |
| 213 | not_a_valid_file: |
Junio C Hamano | 532149d | 2005-04-28 10:13:01 -0700 | [diff] [blame] | 214 | /* A '-' entry produces this for file-2, and |
| 215 | * a '+' entry produces this for file-1. |
| 216 | */ |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 217 | temp->name = "/dev/null"; |
| 218 | strcpy(temp->hex, "."); |
| 219 | strcpy(temp->mode, "."); |
Junio C Hamano | 86436c2 | 2005-04-25 18:22:47 -0700 | [diff] [blame] | 220 | return; |
| 221 | } |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 222 | |
| 223 | if (one->sha1_valid && |
Junio C Hamano | b46f0b6 | 2005-05-04 01:45:24 -0700 | [diff] [blame] | 224 | (!memcmp(one->blob_sha1, null_sha1, sizeof(null_sha1)) || |
| 225 | work_tree_matches(name, one->blob_sha1))) |
| 226 | use_work_tree = 1; |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 227 | |
Junio C Hamano | b46f0b6 | 2005-05-04 01:45:24 -0700 | [diff] [blame] | 228 | if (!one->sha1_valid || use_work_tree) { |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 229 | struct stat st; |
Junio C Hamano | b46f0b6 | 2005-05-04 01:45:24 -0700 | [diff] [blame] | 230 | temp->name = name; |
Junio C Hamano | b28858b | 2005-05-05 16:10:21 -0700 | [diff] [blame] | 231 | if (lstat(temp->name, &st) < 0) { |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 232 | if (errno == ENOENT) |
| 233 | goto not_a_valid_file; |
| 234 | die("stat(%s): %s", temp->name, strerror(errno)); |
| 235 | } |
Junio C Hamano | b28858b | 2005-05-05 16:10:21 -0700 | [diff] [blame] | 236 | if (S_ISLNK(st.st_mode)) { |
| 237 | int ret; |
| 238 | char *buf, buf_[1024]; |
| 239 | buf = ((sizeof(buf_) < st.st_size) ? |
| 240 | xmalloc(st.st_size) : buf_); |
| 241 | ret = readlink(name, buf, st.st_size); |
| 242 | if (ret < 0) |
| 243 | die("readlink(%s)", name); |
| 244 | prep_temp_blob(temp, buf, st.st_size, |
| 245 | (one->sha1_valid ? |
| 246 | one->blob_sha1 : null_sha1), |
| 247 | (one->sha1_valid ? |
| 248 | one->mode : S_IFLNK)); |
| 249 | } |
| 250 | else { |
| 251 | if (!one->sha1_valid) |
| 252 | strcpy(temp->hex, sha1_to_hex(null_sha1)); |
| 253 | else |
| 254 | strcpy(temp->hex, sha1_to_hex(one->blob_sha1)); |
| 255 | sprintf(temp->mode, "%06o", |
| 256 | S_IFREG |ce_permissions(st.st_mode)); |
| 257 | } |
| 258 | return; |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 259 | } |
| 260 | else { |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 261 | void *blob; |
| 262 | char type[20]; |
| 263 | unsigned long size; |
| 264 | |
Junio C Hamano | b46f0b6 | 2005-05-04 01:45:24 -0700 | [diff] [blame] | 265 | blob = read_sha1_file(one->blob_sha1, type, &size); |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 266 | if (!blob || strcmp(type, "blob")) |
| 267 | die("unable to read blob object for %s (%s)", |
Junio C Hamano | b46f0b6 | 2005-05-04 01:45:24 -0700 | [diff] [blame] | 268 | name, sha1_to_hex(one->blob_sha1)); |
Junio C Hamano | b28858b | 2005-05-05 16:10:21 -0700 | [diff] [blame] | 269 | prep_temp_blob(temp, blob, size, one->blob_sha1, one->mode); |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 270 | free(blob); |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 271 | } |
| 272 | } |
| 273 | |
| 274 | static void remove_tempfile(void) |
| 275 | { |
| 276 | int i; |
| 277 | |
| 278 | for (i = 0; i < 2; i++) |
| 279 | if (diff_temp[i].name == diff_temp[i].tmp_path) { |
| 280 | unlink(diff_temp[i].name); |
| 281 | diff_temp[i].name = NULL; |
| 282 | } |
| 283 | } |
| 284 | |
Junio C Hamano | 532149d | 2005-04-28 10:13:01 -0700 | [diff] [blame] | 285 | static void remove_tempfile_on_signal(int signo) |
| 286 | { |
| 287 | remove_tempfile(); |
| 288 | } |
| 289 | |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 290 | /* An external diff command takes: |
| 291 | * |
| 292 | * diff-cmd name infile1 infile1-sha1 infile1-mode \ |
| 293 | * infile2 infile2-sha1 infile2-mode. |
| 294 | * |
| 295 | */ |
| 296 | void run_external_diff(const char *name, |
| 297 | struct diff_spec *one, |
| 298 | struct diff_spec *two) |
| 299 | { |
| 300 | struct diff_tempfile *temp = diff_temp; |
Junio C Hamano | 532149d | 2005-04-28 10:13:01 -0700 | [diff] [blame] | 301 | pid_t pid; |
| 302 | int status; |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 303 | static int atexit_asked = 0; |
| 304 | |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 305 | if (one && two) { |
| 306 | prepare_temp_file(name, &temp[0], one); |
| 307 | prepare_temp_file(name, &temp[1], two); |
| 308 | if (! atexit_asked && |
| 309 | (temp[0].name == temp[0].tmp_path || |
| 310 | temp[1].name == temp[1].tmp_path)) { |
| 311 | atexit_asked = 1; |
| 312 | atexit(remove_tempfile); |
| 313 | } |
Junio C Hamano | 532149d | 2005-04-28 10:13:01 -0700 | [diff] [blame] | 314 | signal(SIGINT, remove_tempfile_on_signal); |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 315 | } |
| 316 | |
| 317 | fflush(NULL); |
| 318 | pid = fork(); |
| 319 | if (pid < 0) |
| 320 | die("unable to fork"); |
| 321 | if (!pid) { |
| 322 | const char *pgm = external_diff(); |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 323 | if (pgm) { |
| 324 | if (one && two) |
| 325 | execlp(pgm, pgm, |
| 326 | name, |
| 327 | temp[0].name, temp[0].hex, temp[0].mode, |
| 328 | temp[1].name, temp[1].hex, temp[1].mode, |
| 329 | NULL); |
| 330 | else |
| 331 | execlp(pgm, pgm, name, NULL); |
| 332 | } |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 333 | /* |
| 334 | * otherwise we use the built-in one. |
| 335 | */ |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 336 | if (one && two) |
| 337 | builtin_diff(name, temp); |
| 338 | else |
| 339 | printf("* Unmerged path %s\n", name); |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 340 | exit(0); |
| 341 | } |
Junio C Hamano | 6fa2806 | 2005-05-04 01:38:06 -0700 | [diff] [blame] | 342 | if (waitpid(pid, &status, 0) < 0 || |
| 343 | !WIFEXITED(status) || WEXITSTATUS(status)) { |
| 344 | /* Earlier we did not check the exit status because |
Junio C Hamano | 532149d | 2005-04-28 10:13:01 -0700 | [diff] [blame] | 345 | * diff exits non-zero if files are different, and |
Junio C Hamano | 6fa2806 | 2005-05-04 01:38:06 -0700 | [diff] [blame] | 346 | * we are not interested in knowing that. It was a |
| 347 | * mistake which made it harder to quit a diff-* |
| 348 | * session that uses the git-apply-patch-script as |
| 349 | * the GIT_EXTERNAL_DIFF. A custom GIT_EXTERNAL_DIFF |
| 350 | * should also exit non-zero only when it wants to |
| 351 | * abort the entire diff-* session. |
Junio C Hamano | 532149d | 2005-04-28 10:13:01 -0700 | [diff] [blame] | 352 | */ |
| 353 | remove_tempfile(); |
Junio C Hamano | 6fa2806 | 2005-05-04 01:38:06 -0700 | [diff] [blame] | 354 | fprintf(stderr, "external diff died, stopping at %s.\n", name); |
| 355 | exit(1); |
Junio C Hamano | 532149d | 2005-04-28 10:13:01 -0700 | [diff] [blame] | 356 | } |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 357 | remove_tempfile(); |
| 358 | } |
| 359 | |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 360 | void diff_addremove(int addremove, unsigned mode, |
| 361 | const unsigned char *sha1, |
| 362 | const char *base, const char *path) |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 363 | { |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 364 | char concatpath[PATH_MAX]; |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 365 | struct diff_spec spec[2], *one, *two; |
| 366 | |
Junio C Hamano | b46f0b6 | 2005-05-04 01:45:24 -0700 | [diff] [blame] | 367 | memcpy(spec[0].blob_sha1, sha1, 20); |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 368 | spec[0].mode = mode; |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 369 | spec[0].sha1_valid = spec[0].file_valid = 1; |
| 370 | spec[1].file_valid = 0; |
| 371 | |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 372 | if (addremove == '+') { |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 373 | one = spec + 1; two = spec; |
| 374 | } else { |
| 375 | one = spec; two = one + 1; |
| 376 | } |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 377 | |
| 378 | if (path) { |
| 379 | strcpy(concatpath, base); |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 380 | strcat(concatpath, path); |
| 381 | } |
| 382 | run_external_diff(path ? concatpath : base, one, two); |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 383 | } |
| 384 | |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 385 | void diff_change(unsigned old_mode, unsigned new_mode, |
| 386 | const unsigned char *old_sha1, |
| 387 | const unsigned char *new_sha1, |
| 388 | const char *base, const char *path) { |
| 389 | char concatpath[PATH_MAX]; |
| 390 | struct diff_spec spec[2]; |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 391 | |
Junio C Hamano | b46f0b6 | 2005-05-04 01:45:24 -0700 | [diff] [blame] | 392 | memcpy(spec[0].blob_sha1, old_sha1, 20); |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 393 | spec[0].mode = old_mode; |
Junio C Hamano | b46f0b6 | 2005-05-04 01:45:24 -0700 | [diff] [blame] | 394 | memcpy(spec[1].blob_sha1, new_sha1, 20); |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 395 | spec[1].mode = new_mode; |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 396 | spec[0].sha1_valid = spec[0].file_valid = 1; |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 397 | spec[1].sha1_valid = spec[1].file_valid = 1; |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 398 | |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 399 | if (path) { |
| 400 | strcpy(concatpath, base); |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 401 | strcat(concatpath, path); |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 402 | } |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 403 | run_external_diff(path ? concatpath : base, &spec[0], &spec[1]); |
| 404 | } |
Junio C Hamano | be3cfa8 | 2005-04-26 09:25:05 -0700 | [diff] [blame] | 405 | |
Junio C Hamano | 77eb272 | 2005-04-27 09:21:00 -0700 | [diff] [blame] | 406 | void diff_unmerge(const char *path) |
| 407 | { |
| 408 | run_external_diff(path, NULL, NULL); |
Junio C Hamano | 86436c2 | 2005-04-25 18:22:47 -0700 | [diff] [blame] | 409 | } |