Fix per-directory exclude handing for "git add"
[gitweb.git] / builtin-apply.c
index 01c9d60642d0faa9ea91d0d39b32985890e1ec7f..91f8752ff7fdb588e64f594519a2e9503c516630 100644 (file)
@@ -41,7 +41,7 @@ static int apply_in_reverse;
 static int apply_with_reject;
 static int apply_verbosely;
 static int no_add;
-static int show_index_info;
+static const char *fake_ancestor;
 static int line_termination = '\n';
 static unsigned long p_context = ULONG_MAX;
 static const char apply_usage[] =
@@ -152,7 +152,7 @@ struct patch {
        unsigned int is_rename:1;
        struct fragment *fragments;
        char *result;
-       unsigned long resultsize;
+       size_t resultsize;
        char old_sha1_prefix[41];
        char new_sha1_prefix[41];
        struct patch *next;
@@ -178,23 +178,18 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c
 #define CHUNKSIZE (8192)
 #define SLOP (16)
 
-static void *read_patch_file(int fd, unsigned long *sizep)
+static void read_patch_file(struct strbuf *sb, int fd)
 {
-       struct strbuf buf;
-
-       strbuf_init(&buf, 0);
-       if (strbuf_read(&buf, fd, 0) < 0)
+       if (strbuf_read(sb, fd, 0) < 0)
                die("git-apply: read returned %s", strerror(errno));
-       *sizep = buf.len;
 
        /*
         * Make sure that we have some slop in the buffer
         * so that we can do speculative "memcmp" etc, and
         * see to it that it is NUL-filled.
         */
-       strbuf_grow(&buf, SLOP);
-       memset(buf.buf + buf.len, 0, SLOP);
-       return strbuf_detach(&buf);
+       strbuf_grow(sb, SLOP);
+       memset(sb->buf + sb->len, 0, SLOP);
 }
 
 static unsigned long linelen(const char *buffer, unsigned long size)
@@ -253,7 +248,7 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
                                 */
                                strbuf_remove(&name, 0, cp - name.buf);
                                free(def);
-                               return name.buf;
+                               return strbuf_detach(&name, NULL);
                        }
                }
                strbuf_release(&name);
@@ -607,7 +602,7 @@ static char *git_header_name(char *line, int llen)
                        if (strcmp(cp + 1, first.buf))
                                goto free_and_fail1;
                        strbuf_release(&sp);
-                       return first.buf;
+                       return strbuf_detach(&first, NULL);
                }
 
                /* unquoted second */
@@ -618,7 +613,7 @@ static char *git_header_name(char *line, int llen)
                if (line + llen - cp != first.len + 1 ||
                    memcmp(first.buf, cp, first.len))
                        goto free_and_fail1;
-               return first.buf;
+               return strbuf_detach(&first, NULL);
 
        free_and_fail1:
                strbuf_release(&first);
@@ -655,7 +650,7 @@ static char *git_header_name(char *line, int llen)
                            isspace(name[len])) {
                                /* Good */
                                strbuf_remove(&sp, 0, np - sp.buf);
-                               return sp.buf;
+                               return strbuf_detach(&sp, NULL);
                        }
 
                free_and_fail2:
@@ -688,7 +683,6 @@ static char *git_header_name(char *line, int llen)
                        }
                }
        }
-       return NULL;
 }
 
 /* Verify that we recognize the lines following a git header */
@@ -1426,8 +1420,6 @@ static void show_stats(struct patch *patch)
 
 static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
 {
-       int fd;
-
        switch (st->st_mode & S_IFMT) {
        case S_IFLNK:
                strbuf_grow(buf, st->st_size);
@@ -1436,14 +1428,8 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
                strbuf_setlen(buf, st->st_size);
                return 0;
        case S_IFREG:
-               fd = open(path, O_RDONLY);
-               if (fd < 0)
-                       return error("unable to open %s", path);
-               if (strbuf_read(buf, fd, st->st_size) < 0) {
-                       close(fd);
-                       return -1;
-               }
-               close(fd);
+               if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
+                       return error("unable to open or read %s", path);
                convert_to_git(path, buf->buf, buf->len, buf);
                return 0;
        default:
@@ -1968,8 +1954,7 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
 
        if (apply_fragments(&buf, patch) < 0)
                return -1; /* note with --reject this succeeds. */
-       patch->result = buf.buf;
-       patch->resultsize = buf.len;
+       patch->result = strbuf_detach(&buf, &patch->resultsize);
 
        if (0 < patch->is_delete && patch->resultsize)
                return error("removal patch leaves file contents");
@@ -2007,7 +1992,7 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)
                        return -1;
                return 0;
        }
-       return ce_match_stat(ce, st, 1);
+       return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID);
 }
 
 static int check_patch(struct patch *patch, struct patch *prev_patch)
@@ -2156,9 +2141,12 @@ static int get_current_sha1(const char *path, unsigned char *sha1)
        return 0;
 }
 
-static void show_index_list(struct patch *list)
+/* Build an index that contains the just the files needed for a 3way merge */
+static void build_fake_ancestor(struct patch *list, const char *filename)
 {
        struct patch *patch;
+       struct index_state result = { 0 };
+       int fd;
 
        /* Once we start supporting the reverse patch, it may be
         * worth showing the new sha1 prefix, but until then...
@@ -2166,11 +2154,12 @@ static void show_index_list(struct patch *list)
        for (patch = list; patch; patch = patch->next) {
                const unsigned char *sha1_ptr;
                unsigned char sha1[20];
+               struct cache_entry *ce;
                const char *name;
 
                name = patch->old_name ? patch->old_name : patch->new_name;
                if (0 < patch->is_new)
-                       sha1_ptr = null_sha1;
+                       continue;
                else if (get_sha1(patch->old_sha1_prefix, sha1))
                        /* git diff has no index line for mode/type changes */
                        if (!patch->lines_added && !patch->lines_deleted) {
@@ -2185,13 +2174,16 @@ static void show_index_list(struct patch *list)
                else
                        sha1_ptr = sha1;
 
-               printf("%06o %s ",patch->old_mode, sha1_to_hex(sha1_ptr));
-               if (line_termination && quote_c_style(name, NULL, NULL, 0))
-                       quote_c_style(name, NULL, stdout, 0);
-               else
-                       fputs(name, stdout);
-               putchar(line_termination);
+               ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0);
+               if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD))
+                       die ("Could not add %s to temporary index", name);
        }
+
+       fd = open(filename, O_WRONLY | O_CREAT, 0666);
+       if (fd < 0 || write_index(&result, fd) || close(fd))
+               die ("Could not write temporary index to %s", filename);
+
+       discard_index(&result);
 }
 
 static void stat_patch_list(struct patch *patch)
@@ -2643,22 +2635,22 @@ static void prefix_patches(struct patch *p)
 
 static int apply_patch(int fd, const char *filename, int inaccurate_eof)
 {
-       unsigned long offset, size;
-       char *buffer = read_patch_file(fd, &size);
+       size_t offset;
+       struct strbuf buf;
        struct patch *list = NULL, **listp = &list;
        int skipped_patch = 0;
 
+       strbuf_init(&buf, 0);
        patch_input_file = filename;
-       if (!buffer)
-               return -1;
+       read_patch_file(&buf, fd);
        offset = 0;
-       while (size > 0) {
+       while (offset < buf.len) {
                struct patch *patch;
                int nr;
 
                patch = xcalloc(1, sizeof(*patch));
                patch->inaccurate_eof = inaccurate_eof;
-               nr = parse_chunk(buffer + offset, size, patch);
+               nr = parse_chunk(buf.buf + offset, buf.len - offset, patch);
                if (nr < 0)
                        break;
                if (apply_in_reverse)
@@ -2676,7 +2668,6 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
                        skipped_patch++;
                }
                offset += nr;
-               size -= nr;
        }
 
        if (whitespace_error && (new_whitespace == error_on_whitespace))
@@ -2699,8 +2690,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
        if (apply && write_out_results(list, skipped_patch))
                exit(1);
 
-       if (show_index_info)
-               show_index_list(list);
+       if (fake_ancestor)
+               build_fake_ancestor(list, fake_ancestor);
 
        if (diffstat)
                stat_patch_list(list);
@@ -2711,7 +2702,7 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
        if (summary)
                summary_patch_list(list);
 
-       free(buffer);
+       strbuf_release(&buf);
        return 0;
 }
 
@@ -2808,9 +2799,11 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                        apply = 1;
                        continue;
                }
-               if (!strcmp(arg, "--index-info")) {
+               if (!strcmp(arg, "--build-fake-ancestor")) {
                        apply = 0;
-                       show_index_info = 1;
+                       if (++i >= argc)
+                               die ("need a filename");
+                       fake_ancestor = argv[i];
                        continue;
                }
                if (!strcmp(arg, "-z")) {