summarylogtreecommitdiffstats
path: root/exclude-directory.patch
blob: 78ec33190febe424f72da4dedd9db623c6392ee1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
diff --git a/doc/diffutils.texi b/doc/diffutils.texi
index 3a780db..0553937 100644
--- a/doc/diffutils.texi
+++ b/doc/diffutils.texi
@@ -1827,6 +1827,11 @@ patterns in a file, one pattern per line, and use the
 @option{--exclude-from=@var{file}} (@option{-X @var{file}}) option.
 Trailing white space and empty lines are ignored in the pattern file.
 
+To ignore whole directories with exclude pattern instead of only
+basenames use the @option{--exclude-directory} option in addition to
+@option{--exclude=@var{pattern}} or
+@option{--exclude-from=@var{file}} options.
+
 If you have been comparing two directories and stopped partway through,
 later you might want to continue where you left off.  You can do this by
 using the @option{--starting-file=@var{file}} (@option{-S @var{file}})
diff --git a/src/diff.c b/src/diff.c
index e9c2b11..8e4e2ba 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -124,6 +124,7 @@ enum
   NO_IGNORE_FILE_NAME_CASE_OPTION,
   NORMAL_OPTION,
   SDIFF_MERGE_ASSIST_OPTION,
+  EXCLUDE_DIRECTORY_OPTION,
   STRIP_TRAILING_CR_OPTION,
   SUPPRESS_BLANK_EMPTY_OPTION,
   SUPPRESS_COMMON_LINES_OPTION,
@@ -210,6 +211,7 @@ static struct option const longopts[] =
   {"show-function-line", 1, 0, 'F'},
   {"side-by-side", 0, 0, 'y'},
   {"speed-large-files", 0, 0, 'H'},
+  {"exclude-directory", 0, 0, EXCLUDE_DIRECTORY_OPTION},
   {"starting-file", 1, 0, 'S'},
   {"strip-trailing-cr", 0, 0, STRIP_TRAILING_CR_OPTION},
   {"suppress-blank-empty", 0, 0, SUPPRESS_BLANK_EMPTY_OPTION},
@@ -596,6 +598,10 @@ main (int argc, char **argv)
           sdiff_merge_assist = true;
           break;
 
+	case EXCLUDE_DIRECTORY_OPTION:
+	  exclude_directory = true;
+	  break;
+
         case STRIP_TRAILING_CR_OPTION:
           strip_trailing_cr = true;
           break;
@@ -921,6 +927,7 @@ static char const * const option_help_msgid[] = {
   N_("    --no-ignore-file-name-case  consider case when comparing file names"),
   N_("-x, --exclude=PAT               exclude files that match PAT"),
   N_("-X, --exclude-from=FILE         exclude files that match any pattern in FILE"),
+  N_("    --exclude-directory         exclude directories matching exclude pattern"),
   N_("-S, --starting-file=FILE        start with FILE when comparing directories"),
   N_("    --from-file=FILE1           compare FILE1 to all operands;\n"
      "                                  FILE1 can be a directory"),
diff --git a/src/diff.h b/src/diff.h
index 5eb3008..dd73517 100644
--- a/src/diff.h
+++ b/src/diff.h
@@ -224,6 +224,9 @@ XTERN bool speed_large_files;
 /* Patterns that match file names to be excluded.  */
 XTERN struct exclude *excluded;
 
+/* Include directory as part of exclude matching. */
+XTERN bool exclude_directory;
+
 /* Don't discard lines.  This makes things slower (sometimes much
    slower) but will find a guaranteed minimal set of changes.  */
 XTERN bool minimal;
diff --git a/src/dir.c b/src/dir.c
index b02099a..ace29f2 100644
--- a/src/dir.c
+++ b/src/dir.c
@@ -96,8 +96,15 @@ dir_read (struct file_data const *dir, struct dirdata *dirdata)
               && (d_name[1] == 0 || (d_name[1] == '.' && d_name[2] == 0)))
             continue;
 
-          if (excluded_file_name (excluded, d_name))
-            continue;
+          /* Exclude filename matches from diff */
+          if (exclude_directory) {
+            if (excluded_file_name (excluded,
+              file_name_concat(dir->name, d_name, NULL)))
+              continue;
+          } else {
+            if (excluded_file_name (excluded, d_name))
+              continue;
+          }
 
           while (data_alloc < data_used + d_size)
             {
diff --git a/tests/exclude-directory b/tests/exclude-directory
new file mode 100755
index 0000000..825154a
--- /dev/null
+++ b/tests/exclude-directory
@@ -0,0 +1,48 @@
+#!/bin/sh
+# exclude directory tests
+
+. "${srcdir=.}/init.sh"; path_prepend_ ../src
+
+TZ=UTC0
+export TZ
+
+fail=0
+
+# Generate directory structure
+mkdir a
+mkdir b
+echo ac > a/c
+echo bc > b/c
+
+epoch='1970-01-01 00:00:00'
+touch --date="$epoch" a b a/c b/c
+
+gen_exp_default()
+{
+    printf '%s' \
+"diff -r '--exclude=b/*' a/c b/c
+1c1
+< ac
+---
+> bc
+"
+}
+
+gen_exp_excluded()
+{
+    printf '%s' \
+"Only in a: c
+"
+}
+
+diff -r --exclude="b/*" a b > out
+test $? = 1 || fail=1
+gen_exp_default > exp || framework_failure_
+compare exp out || fail=1
+
+diff -r --exclude-directory --exclude="b/*" a b > out
+test $? = 1 || fail=1
+gen_exp_excluded > exp || framework_failure_
+compare exp out || fail=1
+
+Exit $fail