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 package org.eclipse.jgit.ignore;
44
45 import static org.junit.Assert.assertArrayEquals;
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertFalse;
48
49 import java.io.BufferedInputStream;
50 import java.io.BufferedReader;
51 import java.io.ByteArrayInputStream;
52 import java.io.File;
53 import java.io.IOException;
54 import java.io.InputStreamReader;
55 import java.util.LinkedHashSet;
56 import java.util.Set;
57
58 import org.eclipse.jgit.junit.RepositoryTestCase;
59 import org.eclipse.jgit.lib.Constants;
60 import org.eclipse.jgit.lib.StoredConfig;
61 import org.eclipse.jgit.treewalk.FileTreeIterator;
62 import org.eclipse.jgit.treewalk.TreeWalk;
63 import org.eclipse.jgit.treewalk.WorkingTreeIterator;
64 import org.eclipse.jgit.treewalk.filter.NotIgnoredFilter;
65 import org.eclipse.jgit.util.FS;
66 import org.eclipse.jgit.util.FS.ExecutionResult;
67 import org.eclipse.jgit.util.RawParseUtils;
68 import org.eclipse.jgit.util.TemporaryBuffer;
69 import org.junit.Before;
70 import org.junit.Test;
71
72
73
74
75
76 public class CGitIgnoreTest extends RepositoryTestCase {
77
78 @Before
79 public void initRepo() throws IOException {
80
81
82
83
84 File fakeUserGitignore = writeTrashFile(".fake_user_gitignore", "");
85 StoredConfig config = db.getConfig();
86 config.setString("core", null, "excludesFile",
87 fakeUserGitignore.getAbsolutePath());
88
89 config.setBoolean("core", null, "ignoreCase", false);
90 config.save();
91 }
92
93 private void createFiles(String... paths) throws IOException {
94 for (String path : paths) {
95 writeTrashFile(path, "x");
96 }
97 }
98
99 private String toString(TemporaryBuffer b) throws IOException {
100 return RawParseUtils.decode(b.toByteArray());
101 }
102
103 private String[] cgitIgnored() throws Exception {
104 FS fs = db.getFS();
105 ProcessBuilder builder = fs.runInShell("git", new String[] { "ls-files",
106 "--ignored", "--exclude-standard", "-o" });
107 builder.directory(db.getWorkTree());
108 builder.environment().put("HOME", fs.userHome().getAbsolutePath());
109 ExecutionResult result = fs.execute(builder,
110 new ByteArrayInputStream(new byte[0]));
111 String errorOut = toString(result.getStderr());
112 assertEquals("External git failed", "exit 0\n",
113 "exit " + result.getRc() + '\n' + errorOut);
114 try (BufferedReader r = new BufferedReader(new InputStreamReader(
115 new BufferedInputStream(result.getStdout().openInputStream()),
116 Constants.CHARSET))) {
117 return r.lines().toArray(String[]::new);
118 }
119 }
120
121 private LinkedHashSet<String> jgitIgnored() throws IOException {
122
123
124 LinkedHashSet<String> result = new LinkedHashSet<>();
125 try (TreeWalk walk = new TreeWalk(db)) {
126 walk.addTree(new FileTreeIterator(db));
127 walk.setRecursive(true);
128 while (walk.next()) {
129 if (walk.getTree(WorkingTreeIterator.class).isEntryIgnored()) {
130 result.add(walk.getPathString());
131 }
132 }
133 }
134 return result;
135 }
136
137 private void assertNoIgnoredVisited(Set<String> ignored) throws Exception {
138
139
140 try (TreeWalk walk = new TreeWalk(db)) {
141 walk.addTree(new FileTreeIterator(db));
142 walk.setFilter(new NotIgnoredFilter(0));
143 walk.setRecursive(true);
144 while (walk.next()) {
145 String path = walk.getPathString();
146 assertFalse("File " + path + " is ignored, should not appear",
147 ignored.contains(path));
148 }
149 }
150 }
151
152 private void assertSameAsCGit(String... notIgnored) throws Exception {
153 LinkedHashSet<String> ignored = jgitIgnored();
154 String[] cgit = cgitIgnored();
155 assertArrayEquals(cgit, ignored.toArray());
156 for (String notExcluded : notIgnored) {
157 assertFalse("File " + notExcluded + " should not be ignored",
158 ignored.contains(notExcluded));
159 }
160 assertNoIgnoredVisited(ignored);
161 }
162
163 @Test
164 public void testSimpleIgnored() throws Exception {
165 createFiles("a.txt", "a.tmp", "src/sub/a.txt", "src/a.tmp",
166 "src/a.txt/b.tmp", "ignored/a.tmp", "ignored/not_ignored/a.tmp",
167 "ignored/other/a.tmp");
168 writeTrashFile(".gitignore",
169 "*.txt\n" + "/ignored/*\n" + "!/ignored/not_ignored");
170 assertSameAsCGit("ignored/not_ignored/a.tmp");
171 }
172
173 @Test
174 public void testDirOnlyMatch() throws Exception {
175 createFiles("a.txt", "src/foo/a.txt", "src/a.txt", "foo/a.txt");
176 writeTrashFile(".gitignore", "foo/");
177 assertSameAsCGit();
178 }
179
180 @Test
181 public void testDirOnlyMatchDeep() throws Exception {
182 createFiles("a.txt", "src/foo/a.txt", "src/a.txt", "foo/a.txt");
183 writeTrashFile(".gitignore", "**/foo/");
184 assertSameAsCGit();
185 }
186
187 @Test
188 public void testStarMatchOnSlashNot() throws Exception {
189 createFiles("sub/a.txt", "foo/sext", "foo/s.txt");
190 writeTrashFile(".gitignore", "s*xt");
191 assertSameAsCGit("sub/a.txt");
192 }
193
194 @Test
195 public void testPrefixMatch() throws Exception {
196 createFiles("src/new/foo.txt");
197 writeTrashFile(".gitignore", "src/new");
198 assertSameAsCGit();
199 }
200
201 @Test
202 public void testDirectoryMatchSubRecursive() throws Exception {
203 createFiles("src/new/foo.txt", "foo/src/new/foo.txt", "sub/src/new");
204 writeTrashFile(".gitignore", "**/src/new/");
205 assertSameAsCGit();
206 }
207
208 @Test
209 public void testDirectoryMatchSubRecursiveBacktrack() throws Exception {
210 createFiles("src/new/foo.txt", "src/src/new/foo.txt");
211 writeTrashFile(".gitignore", "**/src/new/");
212 assertSameAsCGit();
213 }
214
215 @Test
216 public void testDirectoryMatchSubRecursiveBacktrack2() throws Exception {
217 createFiles("src/new/foo.txt", "src/src/new/foo.txt");
218 writeTrashFile(".gitignore", "**/**/src/new/");
219 assertSameAsCGit();
220 }
221
222 @Test
223 public void testDirectoryMatchSubRecursiveBacktrack3() throws Exception {
224 createFiles("x/a/a/b/foo.txt");
225 writeTrashFile(".gitignore", "**/*/a/b/");
226 assertSameAsCGit();
227 }
228
229 @Test
230 public void testDirectoryMatchSubRecursiveBacktrack4() throws Exception {
231 createFiles("x/a/a/b/foo.txt", "x/y/z/b/a/b/foo.txt",
232 "x/y/a/a/a/a/b/foo.txt", "x/y/a/a/a/a/b/a/b/foo.txt");
233 writeTrashFile(".gitignore", "**/*/a/b bar\n");
234 assertSameAsCGit();
235 }
236
237 @Test
238 public void testDirectoryMatchSubRecursiveBacktrack5() throws Exception {
239 createFiles("x/a/a/b/foo.txt", "x/y/a/b/a/b/foo.txt");
240 writeTrashFile(".gitignore", "**/*/**/a/b bar\n");
241 assertSameAsCGit();
242 }
243
244 }