dir: allow exclusions from blob in addition to file

Refactor add_excludes() to separate the reading of the exclude file into a buffer and the parsing of the buffer into exclude_list items. Add add_excludes_from_blob_to_list() to allow an exclude file be specified with an OID without assuming a local worktree or index exists. Refactor read_skip_worktree_file_from_index() and add do_read_blob() to eliminate duplication of preliminary processing of blob contents. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Reviewed-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff Hostetler committed Nov 21, 2017 at 20:58 UTC 578d81d0c445f714dce46d5f4e3f599ac3a94c75
2 files changed +104 -31
dir.c
+101 -31
@@ -220,6 +220,57 @@ int within_depth(const char *name, int namelen,
220 return 1;
221 }
222
223 +/*
224 + * Read the contents of the blob with the given OID into a buffer.
225 + * Append a trailing LF to the end if the last line doesn't have one.
226 + *
227 + * Returns:
228 + * -1 when the OID is invalid or unknown or does not refer to a blob.
229 + * 0 when the blob is empty.
230 + * 1 along with { data, size } of the (possibly augmented) buffer
231 + * when successful.
232 + *
233 + * Optionally updates the given sha1_stat with the given OID (when valid).
234 + */
235 +static int do_read_blob(const struct object_id *oid,
236 + struct sha1_stat *sha1_stat,
237 + size_t *size_out,
238 + char **data_out)
239 +{
240 + enum object_type type;
241 + unsigned long sz;
242 + char *data;
243 +
244 + *size_out = 0;
245 + *data_out = NULL;
246 +
247 + data = read_sha1_file(oid->hash, &type, &sz);
248 + if (!data || type != OBJ_BLOB) {
249 + free(data);
250 + return -1;
251 + }
252 +
253 + if (sha1_stat) {
254 + memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat));
255 + hashcpy(sha1_stat->sha1, oid->hash);
256 + }
257 +
258 + if (sz == 0) {
259 + free(data);
260 + return 0;
261 + }
262 +
263 + if (data[sz - 1] != '\n') {
264 + data = xrealloc(data, st_add(sz, 1));
265 + data[sz++] = '\n';
266 + }
267 +
268 + *size_out = xsize_t(sz);
269 + *data_out = data;
270 +
271 + return 1;
272 +}
273 +
274 #define DO_MATCH_EXCLUDE (1<<0)
275 #define DO_MATCH_DIRECTORY (1<<1)
276 #define DO_MATCH_SUBMODULE (1<<2)
@@ -600,32 +651,22 @@ void add_exclude(const char *string, const char *base,
651 x->el = el;
652 }
653
603 -static void *read_skip_worktree_file_from_index(const struct index_state *istate,
604 - const char *path, size_t *size,
605 - struct sha1_stat *sha1_stat)
654 +static int read_skip_worktree_file_from_index(const struct index_state *istate,
655 + const char *path,
656 + size_t *size_out,
657 + char **data_out,
658 + struct sha1_stat *sha1_stat)
659 {
660 int pos, len;
608 - unsigned long sz;
609 - enum object_type type;
610 - void *data;
661
662 len = strlen(path);
663 pos = index_name_pos(istate, path, len);
664 if (pos < 0)
615 - return NULL;
665 + return -1;
666 if (!ce_skip_worktree(istate->cache[pos]))
617 - return NULL;
618 - data = read_sha1_file(istate->cache[pos]->oid.hash, &type, &sz);
619 - if (!data || type != OBJ_BLOB) {
620 - free(data);
621 - return NULL;
622 - }
623 - *size = xsize_t(sz);
624 - if (sha1_stat) {
625 - memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat));
626 - hashcpy(sha1_stat->sha1, istate->cache[pos]->oid.hash);
627 - }
628 - return data;
667 + return -1;
668 +
669 + return do_read_blob(&istate->cache[pos]->oid, sha1_stat, size_out, data_out);
670 }
671
672 /*
@@ -739,6 +780,10 @@ static void invalidate_directory(struct untracked_cache *uc,
780 dir->dirs[i]->recurse = 0;
781 }
782
783 +static int add_excludes_from_buffer(char *buf, size_t size,
784 + const char *base, int baselen,
785 + struct exclude_list *el);
786 +
787 /*
788 * Given a file with name "fname", read it (either from disk, or from
789 * an index if 'istate' is non-null), parse it and store the
@@ -754,9 +799,10 @@ static int add_excludes(const char *fname, const char *base, int baselen,
799 struct sha1_stat *sha1_stat)
800 {
801 struct stat st;
757 - int fd, i, lineno = 1;
802 + int r;
803 + int fd;
804 size_t size = 0;
759 - char *buf, *entry;
805 + char *buf;
806
807 fd = open(fname, O_RDONLY);
808 if (fd < 0 || fstat(fd, &st) < 0) {
@@ -764,17 +810,13 @@ static int add_excludes(const char *fname, const char *base, int baselen,
810 warn_on_fopen_errors(fname);
811 else
812 close(fd);
767 - if (!istate ||
768 - (buf = read_skip_worktree_file_from_index(istate, fname, &size, sha1_stat)) == NULL)
813 + if (!istate)
814 return -1;
770 - if (size == 0) {
771 - free(buf);
772 - return 0;
773 - }
774 - if (buf[size-1] != '\n') {
775 - buf = xrealloc(buf, st_add(size, 1));
776 - buf[size++] = '\n';
777 - }
815 + r = read_skip_worktree_file_from_index(istate, fname,
816 + &size, &buf,
817 + sha1_stat);
818 + if (r != 1)
819 + return r;
820 } else {
821 size = xsize_t(st.st_size);
822 if (size == 0) {
@@ -813,6 +855,17 @@ static int add_excludes(const char *fname, const char *base, int baselen,
855 }
856 }
857
858 + add_excludes_from_buffer(buf, size, base, baselen, el);
859 + return 0;
860 +}
861 +
862 +static int add_excludes_from_buffer(char *buf, size_t size,
863 + const char *base, int baselen,
864 + struct exclude_list *el)
865 +{
866 + int i, lineno = 1;
867 + char *entry;
868 +
869 el->filebuf = buf;
870
871 if (skip_utf8_bom(&buf, size))
@@ -841,6 +894,23 @@ int add_excludes_from_file_to_list(const char *fname, const char *base,
894 return add_excludes(fname, base, baselen, el, istate, NULL);
895 }
896
897 +int add_excludes_from_blob_to_list(
898 + struct object_id *oid,
899 + const char *base, int baselen,
900 + struct exclude_list *el)
901 +{
902 + char *buf;
903 + size_t size;
904 + int r;
905 +
906 + r = do_read_blob(oid, NULL, &size, &buf);
907 + if (r != 1)
908 + return r;
909 +
910 + add_excludes_from_buffer(buf, size, base, baselen, el);
911 + return 0;
912 +}
913 +
914 struct exclude_list *add_exclude_list(struct dir_struct *dir,
915 int group_type, const char *src)
916 {
dir.h
+3
@@ -256,6 +256,9 @@ extern struct exclude_list *add_exclude_list(struct dir_struct *dir,
256 extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,
257 struct exclude_list *el, struct index_state *istate);
258 extern void add_excludes_from_file(struct dir_struct *, const char *fname);
259 +extern int add_excludes_from_blob_to_list(struct object_id *oid,
260 + const char *base, int baselen,
261 + struct exclude_list *el);
262 extern void parse_exclude_pattern(const char **string, int *patternlen, unsigned *flags, int *nowildcardlen);
263 extern void add_exclude(const char *string, const char *base,
264 int baselen, struct exclude_list *el, int srcpos);