Add directory pattern matching to attributes
The manpage of gitattributes says: "The rules how the pattern matches paths are the same as in .gitignore files" and the gitignore pattern matching has a pattern ending with / for directory matching. This rule is specifically relevant for the 'export-ignore' rule used for git archive. Signed-off-by: Jean-Noel Avila <jn.avila@free.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									24a62db7bb
								
							
						
					
					
						commit
						94bc671a1f
					
				|  | @ -120,6 +120,8 @@ static int write_archive_entry(const unsigned char *sha1, const char *base, | |||
| 	strbuf_add(&path, args->base, args->baselen); | ||||
| 	strbuf_add(&path, base, baselen); | ||||
| 	strbuf_addstr(&path, filename); | ||||
| 	if (S_ISDIR(mode) || S_ISGITLINK(mode)) | ||||
| 		strbuf_addch(&path, '/'); | ||||
| 	path_without_prefix = path.buf + args->baselen; | ||||
|  | ||||
| 	setup_archive_check(check); | ||||
|  | @ -130,7 +132,6 @@ static int write_archive_entry(const unsigned char *sha1, const char *base, | |||
| 	} | ||||
|  | ||||
| 	if (S_ISDIR(mode) || S_ISGITLINK(mode)) { | ||||
| 		strbuf_addch(&path, '/'); | ||||
| 		if (args->verbose) | ||||
| 			fprintf(stderr, "%.*s\n", (int)path.len, path.buf); | ||||
| 		err = write_entry(args, sha1, path.buf, path.len, mode); | ||||
|  |  | |||
							
								
								
									
										25
									
								
								attr.c
								
								
								
								
							
							
						
						
									
										25
									
								
								attr.c
								
								
								
								
							|  | @ -564,17 +564,24 @@ static void bootstrap_attr_stack(void) | |||
| 	attr_stack = elem; | ||||
| } | ||||
|  | ||||
| static const char *find_basename(const char *path) | ||||
| { | ||||
| 	const char *cp, *last_slash = NULL; | ||||
|  | ||||
| 	for (cp = path; *cp; cp++) { | ||||
| 		if (*cp == '/' && cp[1]) | ||||
| 			last_slash = cp; | ||||
| 	} | ||||
| 	return last_slash ? last_slash + 1 : path; | ||||
| } | ||||
|  | ||||
| static void prepare_attr_stack(const char *path) | ||||
| { | ||||
| 	struct attr_stack *elem, *info; | ||||
| 	int dirlen, len; | ||||
| 	const char *cp; | ||||
|  | ||||
| 	cp = strrchr(path, '/'); | ||||
| 	if (!cp) | ||||
| 		dirlen = 0; | ||||
| 	else | ||||
| 		dirlen = cp - path; | ||||
| 	dirlen = find_basename(path) - path; | ||||
|  | ||||
| 	/* | ||||
| 	 * At the bottom of the attribute stack is the built-in | ||||
|  | @ -668,6 +675,10 @@ static int path_matches(const char *pathname, int pathlen, | |||
| 	const char *pattern = pat->pattern; | ||||
| 	int prefix = pat->nowildcardlen; | ||||
|  | ||||
| 	if ((pat->flags & EXC_FLAG_MUSTBEDIR) && | ||||
| 	    ((!pathlen) || (pathname[pathlen-1] != '/'))) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (pat->flags & EXC_FLAG_NODIR) { | ||||
| 		return match_basename(basename, | ||||
| 				      pathlen - (basename - pathname), | ||||
|  | @ -758,9 +769,7 @@ static void collect_all_attrs(const char *path) | |||
| 	for (i = 0; i < attr_nr; i++) | ||||
| 		check_all_attr[i].value = ATTR__UNKNOWN; | ||||
|  | ||||
| 	basename = strrchr(path, '/'); | ||||
| 	basename = basename ? basename + 1 : path; | ||||
|  | ||||
| 	basename = find_basename(path); | ||||
| 	pathlen = strlen(path); | ||||
| 	rem = attr_nr; | ||||
| 	for (stk = attr_stack; 0 < rem && stk; stk = stk->prev) | ||||
|  |  | |||
|  | @ -0,0 +1,57 @@ | |||
| #!/bin/sh | ||||
|  | ||||
| test_description='git archive attribute pattern tests' | ||||
|  | ||||
| . ./test-lib.sh | ||||
|  | ||||
| test_expect_exists() { | ||||
| 	test_expect_success " $1 exists" "test -e $1" | ||||
| } | ||||
|  | ||||
| test_expect_missing() { | ||||
| 	test_expect_success " $1 does not exist" "test ! -e $1" | ||||
| } | ||||
|  | ||||
| test_expect_success 'setup' ' | ||||
| 	echo ignored >ignored && | ||||
| 	echo ignored export-ignore >>.git/info/attributes && | ||||
| 	git add ignored && | ||||
|  | ||||
| 	mkdir not-ignored-dir && | ||||
| 	echo ignored-in-tree >not-ignored-dir/ignored && | ||||
| 	echo not-ignored-in-tree >not-ignored-dir/ignored-only-if-dir && | ||||
| 	git add not-ignored-dir && | ||||
|  | ||||
| 	mkdir ignored-only-if-dir && | ||||
| 	echo ignored by ignored dir >ignored-only-if-dir/ignored-by-ignored-dir && | ||||
| 	echo ignored-only-if-dir/ export-ignore >>.git/info/attributes && | ||||
| 	git add ignored-only-if-dir && | ||||
|  | ||||
|  | ||||
| 	mkdir -p one-level-lower/two-levels-lower/ignored-only-if-dir && | ||||
| 	echo ignored by ignored dir >one-level-lower/two-levels-lower/ignored-only-if-dir/ignored-by-ignored-dir && | ||||
| 	git add one-level-lower && | ||||
|  | ||||
| 	git commit -m. && | ||||
|  | ||||
| 	git clone --bare . bare && | ||||
| 	cp .git/info/attributes bare/info/attributes | ||||
| ' | ||||
|  | ||||
| test_expect_success 'git archive' ' | ||||
| 	git archive HEAD >archive.tar && | ||||
| 	(mkdir archive && cd archive && "$TAR" xf -) <archive.tar | ||||
| ' | ||||
|  | ||||
| test_expect_missing	archive/ignored | ||||
| test_expect_missing	archive/not-ignored-dir/ignored | ||||
| test_expect_exists	archive/not-ignored-dir/ignored-only-if-dir | ||||
| test_expect_exists	archive/not-ignored-dir/ | ||||
| test_expect_missing	archive/ignored-only-if-dir/ | ||||
| test_expect_missing	archive/ignored-ony-if-dir/ignored-by-ignored-dir | ||||
| test_expect_exists	archive/one-level-lower/ | ||||
| test_expect_missing	archive/one-level-lower/two-levels-lower/ignored-only-if-dir/ | ||||
| test_expect_missing	archive/one-level-lower/two-levels-lower/ignored-ony-if-dir/ignored-by-ignored-dir | ||||
|  | ||||
|  | ||||
| test_done | ||||
		Loading…
	
		Reference in New Issue
	
	 Jean-Noël AVILA
						Jean-Noël AVILA