1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.api;
12
13 import static java.nio.charset.StandardCharsets.UTF_8;
14 import static org.eclipse.jgit.util.FileUtils.RECURSIVE;
15 import static org.junit.Assert.assertEquals;
16 import static org.junit.Assert.assertTrue;
17 import static org.junit.Assert.fail;
18 import static org.junit.Assume.assumeTrue;
19
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.io.PrintWriter;
24 import java.nio.file.Files;
25 import java.util.Set;
26
27 import org.eclipse.jgit.api.ResetCommand.ResetType;
28 import org.eclipse.jgit.api.errors.FilterFailedException;
29 import org.eclipse.jgit.api.errors.GitAPIException;
30 import org.eclipse.jgit.api.errors.NoFilepatternException;
31 import org.eclipse.jgit.attributes.FilterCommandRegistry;
32 import org.eclipse.jgit.dircache.DirCache;
33 import org.eclipse.jgit.dircache.DirCacheBuilder;
34 import org.eclipse.jgit.dircache.DirCacheEntry;
35 import org.eclipse.jgit.junit.JGitTestUtil;
36 import org.eclipse.jgit.junit.RepositoryTestCase;
37 import org.eclipse.jgit.lfs.BuiltinLFS;
38 import org.eclipse.jgit.lib.ConfigConstants;
39 import org.eclipse.jgit.lib.Constants;
40 import org.eclipse.jgit.lib.CoreConfig.SymLinks;
41 import org.eclipse.jgit.lib.FileMode;
42 import org.eclipse.jgit.lib.ObjectId;
43 import org.eclipse.jgit.lib.ObjectInserter;
44 import org.eclipse.jgit.lib.Repository;
45 import org.eclipse.jgit.lib.StoredConfig;
46 import org.eclipse.jgit.revwalk.RevCommit;
47 import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
48 import org.eclipse.jgit.treewalk.TreeWalk;
49 import org.eclipse.jgit.treewalk.WorkingTreeOptions;
50 import org.eclipse.jgit.util.FS;
51 import org.eclipse.jgit.util.FileUtils;
52 import org.junit.Test;
53 import org.junit.experimental.theories.DataPoints;
54 import org.junit.experimental.theories.Theories;
55 import org.junit.experimental.theories.Theory;
56 import org.junit.runner.RunWith;
57
58 @RunWith(Theories.class)
59 public class AddCommandTest extends RepositoryTestCase {
60 @DataPoints
61 public static boolean[] sleepBeforeAddOptions = { true, false };
62
63
64 @Override
65 public void setUp() throws Exception {
66 BuiltinLFS.register();
67 super.setUp();
68 }
69
70 @Test
71 public void testAddNothing() throws GitAPIException {
72 try (Git git = new Git(db)) {
73 git.add().call();
74 fail("Expected IllegalArgumentException");
75 } catch (NoFilepatternException e) {
76
77 }
78
79 }
80
81 @Test
82 public void testAddNonExistingSingleFile() throws GitAPIException {
83 try (Git git = new Git(db)) {
84 DirCache dc = git.add().addFilepattern("a.txt").call();
85 assertEquals(0, dc.getEntryCount());
86 }
87 }
88
89 @Test
90 public void testAddExistingSingleFile() throws IOException, GitAPIException {
91 File file = new File(db.getWorkTree(), "a.txt");
92 FileUtils.createNewFile(file);
93 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
94 writer.print("content");
95 }
96
97 try (Git git = new Git(db)) {
98 git.add().addFilepattern("a.txt").call();
99
100 assertEquals(
101 "[a.txt, mode:100644, content:content]",
102 indexState(CONTENT));
103 }
104 }
105
106 @Test
107 public void testAddLink() throws IOException, GitAPIException {
108 assumeTrue(db.getFS().supportsSymlinks());
109 try (Git git = new Git(db)) {
110 writeTrashFile("a.txt", "a");
111 File link = new File(db.getWorkTree(), "link");
112 db.getFS().createSymLink(link, "a.txt");
113 git.add().addFilepattern(".").call();
114 assertEquals(
115 "[a.txt, mode:100644, content:a][link, mode:120000, content:a.txt]",
116 indexState(CONTENT));
117 git.commit().setMessage("link").call();
118 StoredConfig config = db.getConfig();
119 config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
120 ConfigConstants.CONFIG_KEY_SYMLINKS, SymLinks.FALSE);
121 config.save();
122 Files.delete(link.toPath());
123 git.reset().setMode(ResetType.HARD).call();
124 assertTrue(Files.isRegularFile(link.toPath()));
125 assertEquals(
126 "[a.txt, mode:100644, content:a][link, mode:120000, content:a.txt]",
127 indexState(CONTENT));
128 writeTrashFile("link", "b.txt");
129 git.add().addFilepattern("link").call();
130 assertEquals(
131 "[a.txt, mode:100644, content:a][link, mode:120000, content:b.txt]",
132 indexState(CONTENT));
133 config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
134 ConfigConstants.CONFIG_KEY_SYMLINKS, SymLinks.TRUE);
135 config.save();
136 git.add().addFilepattern("link").call();
137 assertEquals(
138 "[a.txt, mode:100644, content:a][link, mode:100644, content:b.txt]",
139 indexState(CONTENT));
140 }
141 }
142
143 @Test
144 public void testCleanFilter() throws IOException, GitAPIException {
145 writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
146 writeTrashFile("src/a.tmp", "foo");
147
148
149 writeTrashFile("src/a.txt", "foo\n");
150 File script = writeTempFile("sed s/o/e/g");
151
152 try (Git git = new Git(db)) {
153 StoredConfig config = git.getRepository().getConfig();
154 config.setString("filter", "tstFilter", "clean",
155 "sh " + slashify(script.getPath()));
156 config.save();
157
158 git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp")
159 .call();
160
161 assertEquals(
162 "[src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:fee\n]",
163 indexState(CONTENT));
164 }
165 }
166
167 @Theory
168 public void testBuiltinFilters(boolean sleepBeforeAdd)
169 throws IOException,
170 GitAPIException, InterruptedException {
171 writeTrashFile(".gitattributes", "*.txt filter=lfs");
172 writeTrashFile("src/a.tmp", "foo");
173
174
175 File script = writeTempFile("sed s/o/e/g");
176 File f = writeTrashFile("src/a.txt", "foo\n");
177
178 try (Git git = new Git(db)) {
179 if (!sleepBeforeAdd) {
180 fsTick(f);
181 }
182 git.add().addFilepattern(".gitattributes").call();
183 StoredConfig config = git.getRepository().getConfig();
184 config.setString("filter", "lfs", "clean",
185 "sh " + slashify(script.getPath()));
186 config.setString("filter", "lfs", "smudge",
187 "sh " + slashify(script.getPath()));
188 config.setBoolean("filter", "lfs", "useJGitBuiltin", true);
189 config.save();
190
191 if (!sleepBeforeAdd) {
192 fsTick(f);
193 }
194 git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp")
195 .addFilepattern(".gitattributes").call();
196
197 assertEquals(
198 "[.gitattributes, mode:100644, content:*.txt filter=lfs][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c\nsize 4\n]",
199 indexState(CONTENT));
200
201 RevCommit c1 = git.commit().setMessage("c1").call();
202 assertTrue(git.status().call().isClean());
203 f = writeTrashFile("src/a.txt", "foobar\n");
204 if (!sleepBeforeAdd) {
205 fsTick(f);
206 }
207 git.add().addFilepattern("src/a.txt").call();
208 git.commit().setMessage("c2").call();
209 assertTrue(git.status().call().isClean());
210 assertEquals(
211 "[.gitattributes, mode:100644, content:*.txt filter=lfs][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f\nsize 7\n]",
212 indexState(CONTENT));
213 assertEquals("foobar\n", read("src/a.txt"));
214 git.checkout().setName(c1.getName()).call();
215 assertEquals(
216 "[.gitattributes, mode:100644, content:*.txt filter=lfs][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c\nsize 4\n]",
217 indexState(CONTENT));
218 assertEquals(
219 "foo\n", read("src/a.txt"));
220 }
221 }
222
223 @Theory
224 public void testBuiltinCleanFilter(boolean sleepBeforeAdd)
225 throws IOException, GitAPIException, InterruptedException {
226 writeTrashFile(".gitattributes", "*.txt filter=lfs");
227 writeTrashFile("src/a.tmp", "foo");
228
229
230 File script = writeTempFile("sed s/o/e/g");
231 File f = writeTrashFile("src/a.txt", "foo\n");
232
233
234 FilterCommandRegistry.unregister(
235 org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
236 + "lfs/smudge");
237
238 try (Git git = new Git(db)) {
239 if (!sleepBeforeAdd) {
240 fsTick(f);
241 }
242 git.add().addFilepattern(".gitattributes").call();
243 StoredConfig config = git.getRepository().getConfig();
244 config.setString("filter", "lfs", "clean",
245 "sh " + slashify(script.getPath()));
246 config.setString("filter", "lfs", "smudge",
247 "sh " + slashify(script.getPath()));
248 config.setBoolean("filter", "lfs", "useJGitBuiltin", true);
249 config.save();
250
251 if (!sleepBeforeAdd) {
252 fsTick(f);
253 }
254 git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp")
255 .addFilepattern(".gitattributes").call();
256
257 assertEquals(
258 "[.gitattributes, mode:100644, content:*.txt filter=lfs][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c\nsize 4\n]",
259 indexState(CONTENT));
260
261 RevCommit c1 = git.commit().setMessage("c1").call();
262 assertTrue(git.status().call().isClean());
263 f = writeTrashFile("src/a.txt", "foobar\n");
264 if (!sleepBeforeAdd) {
265 fsTick(f);
266 }
267 git.add().addFilepattern("src/a.txt").call();
268 git.commit().setMessage("c2").call();
269 assertTrue(git.status().call().isClean());
270 assertEquals(
271 "[.gitattributes, mode:100644, content:*.txt filter=lfs][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f\nsize 7\n]",
272 indexState(CONTENT));
273 assertEquals("foobar\n", read("src/a.txt"));
274 git.checkout().setName(c1.getName()).call();
275 assertEquals(
276 "[.gitattributes, mode:100644, content:*.txt filter=lfs][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c\nsize 4\n]",
277 indexState(CONTENT));
278
279
280
281
282
283 assertEquals(
284 "versien https://git-lfs.github.cem/spec/v1\neid sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c\nsize 4\n",
285 read("src/a.txt"));
286 }
287 }
288
289 @Test
290 public void testAttributesWithTreeWalkFilter()
291 throws IOException, GitAPIException {
292 writeTrashFile(".gitattributes", "*.txt filter=lfs");
293 writeTrashFile("src/a.tmp", "foo");
294 writeTrashFile("src/a.txt", "foo\n");
295 File script = writeTempFile("sed s/o/e/g");
296
297 try (Git git = new Git(db)) {
298 StoredConfig config = git.getRepository().getConfig();
299 config.setString("filter", "lfs", "clean",
300 "sh " + slashify(script.getPath()));
301 config.save();
302
303 git.add().addFilepattern(".gitattributes").call();
304 git.commit().setMessage("attr").call();
305 git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp")
306 .addFilepattern(".gitattributes").call();
307 git.commit().setMessage("c1").call();
308 assertTrue(git.status().call().isClean());
309 }
310 }
311
312 @Test
313 public void testAttributesConflictingMatch() throws Exception {
314 writeTrashFile(".gitattributes", "foo/** crlf=input\n*.jar binary");
315 writeTrashFile("foo/bar.jar", "\r\n");
316
317
318 try (Git git = new Git(db)) {
319 git.add().addFilepattern(".").call();
320 assertEquals(
321 "[.gitattributes, mode:100644, content:foo/** crlf=input\n*.jar binary]"
322 + "[foo/bar.jar, mode:100644, content:\r\n]",
323 indexState(CONTENT));
324 }
325 }
326
327 @Test
328 public void testCleanFilterEnvironment()
329 throws IOException, GitAPIException {
330 writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
331 writeTrashFile("src/a.txt", "foo");
332 File script = writeTempFile("echo $GIT_DIR; echo 1 >xyz");
333
334 try (Git git = new Git(db)) {
335 StoredConfig config = git.getRepository().getConfig();
336 config.setString("filter", "tstFilter", "clean",
337 "sh " + slashify(script.getPath()));
338 config.save();
339 git.add().addFilepattern("src/a.txt").call();
340
341 String gitDir = db.getDirectory().getAbsolutePath();
342 assertEquals("[src/a.txt, mode:100644, content:" + gitDir
343 + "\n]", indexState(CONTENT));
344 assertTrue(new File(db.getWorkTree(), "xyz").exists());
345 }
346 }
347
348 @Test
349 public void testMultipleCleanFilter() throws IOException, GitAPIException {
350 writeTrashFile(".gitattributes",
351 "*.txt filter=tstFilter\n*.tmp filter=tstFilter2");
352
353
354 writeTrashFile("src/a.tmp", "foo\n");
355 writeTrashFile("src/a.txt", "foo\n");
356 File script = writeTempFile("sed s/o/e/g");
357 File script2 = writeTempFile("sed s/f/x/g");
358
359 try (Git git = new Git(db)) {
360 StoredConfig config = git.getRepository().getConfig();
361 config.setString("filter", "tstFilter", "clean",
362 "sh " + slashify(script.getPath()));
363 config.setString("filter", "tstFilter2", "clean",
364 "sh " + slashify(script2.getPath()));
365 config.save();
366
367 git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp")
368 .call();
369
370 assertEquals(
371 "[src/a.tmp, mode:100644, content:xoo\n][src/a.txt, mode:100644, content:fee\n]",
372 indexState(CONTENT));
373
374
375 }
376 }
377
378
379
380
381
382
383
384
385
386 @Test
387 public void testCommandInjection() throws IOException, GitAPIException {
388
389
390 writeTrashFile("; echo virus", "foo\n");
391 File script = writeTempFile("sed s/o/e/g");
392
393 try (Git git = new Git(db)) {
394 StoredConfig config = git.getRepository().getConfig();
395 config.setString("filter", "tstFilter", "clean",
396 "sh " + slashify(script.getPath()) + " %f");
397 writeTrashFile(".gitattributes", "* filter=tstFilter");
398
399 git.add().addFilepattern("; echo virus").call();
400
401
402 assertEquals("[; echo virus, mode:100644, content:fee\n]",
403 indexState(CONTENT));
404 }
405 }
406
407 @Test
408 public void testBadCleanFilter() throws IOException, GitAPIException {
409 writeTrashFile("a.txt", "foo");
410 File script = writeTempFile("sedfoo s/o/e/g");
411
412 try (Git git = new Git(db)) {
413 StoredConfig config = git.getRepository().getConfig();
414 config.setString("filter", "tstFilter", "clean",
415 "sh " + script.getPath());
416 config.save();
417 writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
418
419 try {
420 git.add().addFilepattern("a.txt").call();
421 fail("Didn't received the expected exception");
422 } catch (FilterFailedException e) {
423 assertEquals(127, e.getReturnCode());
424 }
425 }
426 }
427
428 @Test
429 public void testBadCleanFilter2() throws IOException, GitAPIException {
430 writeTrashFile("a.txt", "foo");
431 File script = writeTempFile("sed s/o/e/g");
432
433 try (Git git = new Git(db)) {
434 StoredConfig config = git.getRepository().getConfig();
435 config.setString("filter", "tstFilter", "clean",
436 "shfoo " + script.getPath());
437 config.save();
438 writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
439
440 try {
441 git.add().addFilepattern("a.txt").call();
442 fail("Didn't received the expected exception");
443 } catch (FilterFailedException e) {
444 assertEquals(127, e.getReturnCode());
445 }
446 }
447 }
448
449 @Test
450 public void testCleanFilterReturning12() throws IOException,
451 GitAPIException {
452 writeTrashFile("a.txt", "foo");
453 File script = writeTempFile("exit 12");
454
455 try (Git git = new Git(db)) {
456 StoredConfig config = git.getRepository().getConfig();
457 config.setString("filter", "tstFilter", "clean",
458 "sh " + slashify(script.getPath()));
459 config.save();
460 writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
461
462 try {
463 git.add().addFilepattern("a.txt").call();
464 fail("Didn't received the expected exception");
465 } catch (FilterFailedException e) {
466 assertEquals(12, e.getReturnCode());
467 }
468 }
469 }
470
471 @Test
472 public void testNotApplicableFilter() throws IOException, GitAPIException {
473 writeTrashFile("a.txt", "foo");
474 File script = writeTempFile("sed s/o/e/g");
475
476 try (Git git = new Git(db)) {
477 StoredConfig config = git.getRepository().getConfig();
478 config.setString("filter", "tstFilter", "something",
479 "sh " + script.getPath());
480 config.save();
481 writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
482
483 git.add().addFilepattern("a.txt").call();
484
485 assertEquals("[a.txt, mode:100644, content:foo]",
486 indexState(CONTENT));
487 }
488 }
489
490 private File writeTempFile(String body) throws IOException {
491 File f = File.createTempFile("AddCommandTest_", "");
492 JGitTestUtil.write(f, body);
493 return f;
494 }
495
496 @Test
497 public void testAddExistingSingleSmallFileWithNewLine() throws IOException,
498 GitAPIException {
499 File file = new File(db.getWorkTree(), "a.txt");
500 FileUtils.createNewFile(file);
501 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
502 writer.print("row1\r\nrow2");
503 }
504
505 try (Git git = new Git(db)) {
506 db.getConfig().setString("core", null, "autocrlf", "false");
507 git.add().addFilepattern("a.txt").call();
508 assertEquals("[a.txt, mode:100644, content:row1\r\nrow2]",
509 indexState(CONTENT));
510 db.getConfig().setString("core", null, "autocrlf", "true");
511 git.add().addFilepattern("a.txt").call();
512 assertEquals("[a.txt, mode:100644, content:row1\r\nrow2]",
513 indexState(CONTENT));
514 db.getConfig().setString("core", null, "autocrlf", "input");
515 git.add().addFilepattern("a.txt").call();
516 assertEquals("[a.txt, mode:100644, content:row1\r\nrow2]",
517 indexState(CONTENT));
518 }
519 }
520
521 @Test
522 public void testAddExistingSingleMediumSizeFileWithNewLine()
523 throws IOException, GitAPIException {
524 File file = new File(db.getWorkTree(), "a.txt");
525 FileUtils.createNewFile(file);
526 StringBuilder data = new StringBuilder();
527 for (int i = 0; i < 1000; ++i) {
528 data.append("row1\r\nrow2");
529 }
530 String crData = data.toString();
531 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
532 writer.print(crData);
533 }
534 try (Git git = new Git(db)) {
535 db.getConfig().setString("core", null, "autocrlf", "false");
536 git.add().addFilepattern("a.txt").call();
537 assertEquals("[a.txt, mode:100644, content:" + crData + "]",
538 indexState(CONTENT));
539 db.getConfig().setString("core", null, "autocrlf", "true");
540 git.add().addFilepattern("a.txt").call();
541 assertEquals("[a.txt, mode:100644, content:" + crData + "]",
542 indexState(CONTENT));
543 db.getConfig().setString("core", null, "autocrlf", "input");
544 git.add().addFilepattern("a.txt").call();
545 assertEquals("[a.txt, mode:100644, content:" + crData + "]",
546 indexState(CONTENT));
547 }
548 }
549
550 @Test
551 public void testAddExistingSingleBinaryFile() throws IOException,
552 GitAPIException {
553 File file = new File(db.getWorkTree(), "a.txt");
554 FileUtils.createNewFile(file);
555 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
556 writer.print("row1\r\nrow2\u0000");
557 }
558
559 try (Git git = new Git(db)) {
560 db.getConfig().setString("core", null, "autocrlf", "false");
561 git.add().addFilepattern("a.txt").call();
562 assertEquals("[a.txt, mode:100644, content:row1\r\nrow2\u0000]",
563 indexState(CONTENT));
564 db.getConfig().setString("core", null, "autocrlf", "true");
565 git.add().addFilepattern("a.txt").call();
566 assertEquals("[a.txt, mode:100644, content:row1\r\nrow2\u0000]",
567 indexState(CONTENT));
568 db.getConfig().setString("core", null, "autocrlf", "input");
569 git.add().addFilepattern("a.txt").call();
570 assertEquals("[a.txt, mode:100644, content:row1\r\nrow2\u0000]",
571 indexState(CONTENT));
572 }
573 }
574
575 @Test
576 public void testAddExistingSingleFileInSubDir() throws IOException,
577 GitAPIException {
578 FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
579 File file = new File(db.getWorkTree(), "sub/a.txt");
580 FileUtils.createNewFile(file);
581 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
582 writer.print("content");
583 }
584
585 try (Git git = new Git(db)) {
586 git.add().addFilepattern("sub/a.txt").call();
587
588 assertEquals(
589 "[sub/a.txt, mode:100644, content:content]",
590 indexState(CONTENT));
591 }
592 }
593
594 @Test
595 public void testAddExistingSingleFileTwice() throws IOException,
596 GitAPIException {
597 File file = new File(db.getWorkTree(), "a.txt");
598 FileUtils.createNewFile(file);
599 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
600 writer.print("content");
601 }
602
603 try (Git git = new Git(db)) {
604 DirCache dc = git.add().addFilepattern("a.txt").call();
605
606 dc.getEntry(0).getObjectId();
607
608 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
609 writer.print("other content");
610 }
611
612 dc = git.add().addFilepattern("a.txt").call();
613
614 assertEquals(
615 "[a.txt, mode:100644, content:other content]",
616 indexState(CONTENT));
617 }
618 }
619
620 @Test
621 public void testAddExistingSingleFileTwiceWithCommit() throws Exception {
622 File file = new File(db.getWorkTree(), "a.txt");
623 FileUtils.createNewFile(file);
624 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
625 writer.print("content");
626 }
627
628 try (Git git = new Git(db)) {
629 DirCache dc = git.add().addFilepattern("a.txt").call();
630
631 dc.getEntry(0).getObjectId();
632
633 git.commit().setMessage("commit a.txt").call();
634
635 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
636 writer.print("other content");
637 }
638
639 dc = git.add().addFilepattern("a.txt").call();
640
641 assertEquals(
642 "[a.txt, mode:100644, content:other content]",
643 indexState(CONTENT));
644 }
645 }
646
647 @Test
648 public void testAddRemovedFile() throws Exception {
649 File file = new File(db.getWorkTree(), "a.txt");
650 FileUtils.createNewFile(file);
651 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
652 writer.print("content");
653 }
654
655 try (Git git = new Git(db)) {
656 DirCache dc = git.add().addFilepattern("a.txt").call();
657
658 dc.getEntry(0).getObjectId();
659 FileUtils.delete(file);
660
661
662 dc = git.add().addFilepattern("a.txt").call();
663
664 assertEquals(
665 "[a.txt, mode:100644, content:content]",
666 indexState(CONTENT));
667 }
668 }
669
670 @Test
671 public void testAddRemovedCommittedFile() throws Exception {
672 File file = new File(db.getWorkTree(), "a.txt");
673 FileUtils.createNewFile(file);
674 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
675 writer.print("content");
676 }
677
678 try (Git git = new Git(db)) {
679 DirCache dc = git.add().addFilepattern("a.txt").call();
680
681 git.commit().setMessage("commit a.txt").call();
682
683 dc.getEntry(0).getObjectId();
684 FileUtils.delete(file);
685
686
687 dc = git.add().addFilepattern("a.txt").call();
688
689 assertEquals(
690 "[a.txt, mode:100644, content:content]",
691 indexState(CONTENT));
692 }
693 }
694
695 @Test
696 public void testAddWithConflicts() throws Exception {
697
698
699 File file = new File(db.getWorkTree(), "a.txt");
700 FileUtils.createNewFile(file);
701 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
702 writer.print("content");
703 }
704
705 File file2 = new File(db.getWorkTree(), "b.txt");
706 FileUtils.createNewFile(file2);
707 try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) {
708 writer.print("content b");
709 }
710
711 DirCache dc = db.lockDirCache();
712 try (ObjectInserter newObjectInserter = db.newObjectInserter()) {
713 DirCacheBuilder builder = dc.builder();
714
715 addEntryToBuilder("b.txt", file2, newObjectInserter, builder, 0);
716 addEntryToBuilder("a.txt", file, newObjectInserter, builder, 1);
717
718 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
719 writer.print("other content");
720 }
721 addEntryToBuilder("a.txt", file, newObjectInserter, builder, 3);
722
723 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
724 writer.print("our content");
725 }
726 addEntryToBuilder("a.txt", file, newObjectInserter, builder, 2)
727 .getObjectId();
728
729 builder.commit();
730 }
731 assertEquals(
732 "[a.txt, mode:100644, stage:1, content:content]" +
733 "[a.txt, mode:100644, stage:2, content:our content]" +
734 "[a.txt, mode:100644, stage:3, content:other content]" +
735 "[b.txt, mode:100644, content:content b]",
736 indexState(CONTENT));
737
738
739
740 try (Git git = new Git(db)) {
741 dc = git.add().addFilepattern("a.txt").call();
742
743 assertEquals(
744 "[a.txt, mode:100644, content:our content]" +
745 "[b.txt, mode:100644, content:content b]",
746 indexState(CONTENT));
747 }
748 }
749
750 @Test
751 public void testAddTwoFiles() throws Exception {
752 File file = new File(db.getWorkTree(), "a.txt");
753 FileUtils.createNewFile(file);
754 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
755 writer.print("content");
756 }
757
758 File file2 = new File(db.getWorkTree(), "b.txt");
759 FileUtils.createNewFile(file2);
760 try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) {
761 writer.print("content b");
762 }
763
764 try (Git git = new Git(db)) {
765 git.add().addFilepattern("a.txt").addFilepattern("b.txt").call();
766 assertEquals(
767 "[a.txt, mode:100644, content:content]" +
768 "[b.txt, mode:100644, content:content b]",
769 indexState(CONTENT));
770 }
771 }
772
773 @Test
774 public void testAddFolder() throws Exception {
775 FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
776 File file = new File(db.getWorkTree(), "sub/a.txt");
777 FileUtils.createNewFile(file);
778 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
779 writer.print("content");
780 }
781
782 File file2 = new File(db.getWorkTree(), "sub/b.txt");
783 FileUtils.createNewFile(file2);
784 try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) {
785 writer.print("content b");
786 }
787
788 try (Git git = new Git(db)) {
789 git.add().addFilepattern("sub").call();
790 assertEquals(
791 "[sub/a.txt, mode:100644, content:content]" +
792 "[sub/b.txt, mode:100644, content:content b]",
793 indexState(CONTENT));
794 }
795 }
796
797 @Test
798 public void testAddIgnoredFile() throws Exception {
799 FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
800 File file = new File(db.getWorkTree(), "sub/a.txt");
801 FileUtils.createNewFile(file);
802 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
803 writer.print("content");
804 }
805
806 File ignoreFile = new File(db.getWorkTree(), ".gitignore");
807 FileUtils.createNewFile(ignoreFile);
808 try (PrintWriter writer = new PrintWriter(ignoreFile, UTF_8.name())) {
809 writer.print("sub/b.txt");
810 }
811
812 File file2 = new File(db.getWorkTree(), "sub/b.txt");
813 FileUtils.createNewFile(file2);
814 try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) {
815 writer.print("content b");
816 }
817
818 try (Git git = new Git(db)) {
819 git.add().addFilepattern("sub").call();
820
821 assertEquals(
822 "[sub/a.txt, mode:100644, content:content]",
823 indexState(CONTENT));
824 }
825 }
826
827 @Test
828 public void testAddWholeRepo() throws Exception {
829 FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
830 File file = new File(db.getWorkTree(), "sub/a.txt");
831 FileUtils.createNewFile(file);
832 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
833 writer.print("content");
834 }
835
836 File file2 = new File(db.getWorkTree(), "sub/b.txt");
837 FileUtils.createNewFile(file2);
838 try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) {
839 writer.print("content b");
840 }
841
842 try (Git git = new Git(db)) {
843 git.add().addFilepattern(".").call();
844 assertEquals(
845 "[sub/a.txt, mode:100644, content:content]" +
846 "[sub/b.txt, mode:100644, content:content b]",
847 indexState(CONTENT));
848 }
849 }
850
851
852
853
854
855 @Test
856 public void testAddWithoutParameterUpdate() throws Exception {
857 FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
858 File file = new File(db.getWorkTree(), "sub/a.txt");
859 FileUtils.createNewFile(file);
860 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
861 writer.print("content");
862 }
863
864 File file2 = new File(db.getWorkTree(), "sub/b.txt");
865 FileUtils.createNewFile(file2);
866 try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) {
867 writer.print("content b");
868 }
869
870 try (Git git = new Git(db)) {
871 git.add().addFilepattern("sub").call();
872
873 assertEquals(
874 "[sub/a.txt, mode:100644, content:content]" +
875 "[sub/b.txt, mode:100644, content:content b]",
876 indexState(CONTENT));
877
878 git.commit().setMessage("commit").call();
879
880
881 File file3 = new File(db.getWorkTree(), "sub/c.txt");
882 FileUtils.createNewFile(file3);
883 try (PrintWriter writer = new PrintWriter(file3, UTF_8.name())) {
884 writer.print("content c");
885 }
886
887
888 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
889 writer.print("modified content");
890 }
891
892
893 FileUtils.delete(file2);
894
895 git.add().addFilepattern("sub").call();
896
897
898
899 assertEquals(
900 "[sub/a.txt, mode:100644, content:modified content]" +
901 "[sub/b.txt, mode:100644, content:content b]" +
902 "[sub/c.txt, mode:100644, content:content c]",
903 indexState(CONTENT));
904 }
905 }
906
907
908
909
910 @Test
911 public void testAddWithParameterUpdate() throws Exception {
912 FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
913 File file = new File(db.getWorkTree(), "sub/a.txt");
914 FileUtils.createNewFile(file);
915 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
916 writer.print("content");
917 }
918
919 File file2 = new File(db.getWorkTree(), "sub/b.txt");
920 FileUtils.createNewFile(file2);
921 try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) {
922 writer.print("content b");
923 }
924
925 try (Git git = new Git(db)) {
926 git.add().addFilepattern("sub").call();
927
928 assertEquals(
929 "[sub/a.txt, mode:100644, content:content]" +
930 "[sub/b.txt, mode:100644, content:content b]",
931 indexState(CONTENT));
932
933 git.commit().setMessage("commit").call();
934
935
936 File file3 = new File(db.getWorkTree(), "sub/c.txt");
937 FileUtils.createNewFile(file3);
938 try (PrintWriter writer = new PrintWriter(file3, UTF_8.name())) {
939 writer.print("content c");
940 }
941
942
943 try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
944 writer.print("modified content");
945 }
946
947 FileUtils.delete(file2);
948
949
950
951
952 git.add().addFilepattern("sub").setUpdate(true).call();
953
954 assertEquals(
955 "[sub/a.txt, mode:100644, content:modified content]",
956 indexState(CONTENT));
957 }
958 }
959
960 @Test
961 public void testAssumeUnchanged() throws Exception {
962 try (Git git = new Git(db)) {
963 String path = "a.txt";
964 writeTrashFile(path, "content");
965 git.add().addFilepattern(path).call();
966 String path2 = "b.txt";
967 writeTrashFile(path2, "content");
968 git.add().addFilepattern(path2).call();
969 git.commit().setMessage("commit").call();
970 assertEquals("[a.txt, mode:100644, content:"
971 + "content, assume-unchanged:false]"
972 + "[b.txt, mode:100644, content:content, "
973 + "assume-unchanged:false]", indexState(CONTENT
974 | ASSUME_UNCHANGED));
975 assumeUnchanged(path2);
976 assertEquals("[a.txt, mode:100644, content:content, "
977 + "assume-unchanged:false][b.txt, mode:100644, "
978 + "content:content, assume-unchanged:true]", indexState(CONTENT
979 | ASSUME_UNCHANGED));
980 writeTrashFile(path, "more content");
981 writeTrashFile(path2, "more content");
982
983 git.add().addFilepattern(".").call();
984
985 assertEquals("[a.txt, mode:100644, content:more content,"
986 + " assume-unchanged:false][b.txt, mode:100644,"
987 + " content:content, assume-unchanged:true]",
988 indexState(CONTENT
989 | ASSUME_UNCHANGED));
990 }
991 }
992
993 @Test
994 public void testReplaceFileWithDirectory()
995 throws IOException, NoFilepatternException, GitAPIException {
996 try (Git git = new Git(db)) {
997 writeTrashFile("df", "before replacement");
998 git.add().addFilepattern("df").call();
999 assertEquals("[df, mode:100644, content:before replacement]",
1000 indexState(CONTENT));
1001 FileUtils.delete(new File(db.getWorkTree(), "df"));
1002 writeTrashFile("df/f", "after replacement");
1003 git.add().addFilepattern("df").call();
1004 assertEquals("[df/f, mode:100644, content:after replacement]",
1005 indexState(CONTENT));
1006 }
1007 }
1008
1009 @Test
1010 public void testReplaceDirectoryWithFile()
1011 throws IOException, NoFilepatternException, GitAPIException {
1012 try (Git git = new Git(db)) {
1013 writeTrashFile("df/f", "before replacement");
1014 git.add().addFilepattern("df").call();
1015 assertEquals("[df/f, mode:100644, content:before replacement]",
1016 indexState(CONTENT));
1017 FileUtils.delete(new File(db.getWorkTree(), "df"), RECURSIVE);
1018 writeTrashFile("df", "after replacement");
1019 git.add().addFilepattern("df").call();
1020 assertEquals("[df, mode:100644, content:after replacement]",
1021 indexState(CONTENT));
1022 }
1023 }
1024
1025 @Test
1026 public void testReplaceFileByPartOfDirectory()
1027 throws IOException, NoFilepatternException, GitAPIException {
1028 try (Git git = new Git(db)) {
1029 writeTrashFile("src/main", "df", "before replacement");
1030 writeTrashFile("src/main", "z", "z");
1031 writeTrashFile("z", "z2");
1032 git.add().addFilepattern("src/main/df")
1033 .addFilepattern("src/main/z")
1034 .addFilepattern("z")
1035 .call();
1036 assertEquals(
1037 "[src/main/df, mode:100644, content:before replacement]" +
1038 "[src/main/z, mode:100644, content:z]" +
1039 "[z, mode:100644, content:z2]",
1040 indexState(CONTENT));
1041 FileUtils.delete(new File(db.getWorkTree(), "src/main/df"));
1042 writeTrashFile("src/main/df", "a", "after replacement");
1043 writeTrashFile("src/main/df", "b", "unrelated file");
1044 git.add().addFilepattern("src/main/df/a").call();
1045 assertEquals(
1046 "[src/main/df/a, mode:100644, content:after replacement]" +
1047 "[src/main/z, mode:100644, content:z]" +
1048 "[z, mode:100644, content:z2]",
1049 indexState(CONTENT));
1050 }
1051 }
1052
1053 @Test
1054 public void testReplaceDirectoryConflictsWithFile()
1055 throws IOException, NoFilepatternException, GitAPIException {
1056 DirCache dc = db.lockDirCache();
1057 try (ObjectInserter oi = db.newObjectInserter()) {
1058 DirCacheBuilder builder = dc.builder();
1059 File f = writeTrashFile("a", "df", "content");
1060 addEntryToBuilder("a", f, oi, builder, 1);
1061
1062 f = writeTrashFile("a", "df", "other content");
1063 addEntryToBuilder("a/df", f, oi, builder, 3);
1064
1065 f = writeTrashFile("a", "df", "our content");
1066 addEntryToBuilder("a/df", f, oi, builder, 2);
1067
1068 f = writeTrashFile("z", "z");
1069 addEntryToBuilder("z", f, oi, builder, 0);
1070 builder.commit();
1071 }
1072 assertEquals(
1073 "[a, mode:100644, stage:1, content:content]" +
1074 "[a/df, mode:100644, stage:2, content:our content]" +
1075 "[a/df, mode:100644, stage:3, content:other content]" +
1076 "[z, mode:100644, content:z]",
1077 indexState(CONTENT));
1078
1079 try (Git git = new Git(db)) {
1080 FileUtils.delete(new File(db.getWorkTree(), "a"), RECURSIVE);
1081 writeTrashFile("a", "merged");
1082 git.add().addFilepattern("a").call();
1083 assertEquals("[a, mode:100644, content:merged]" +
1084 "[z, mode:100644, content:z]",
1085 indexState(CONTENT));
1086 }
1087 }
1088
1089 @Test
1090 public void testExecutableRetention() throws Exception {
1091 StoredConfig config = db.getConfig();
1092 config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
1093 ConfigConstants.CONFIG_KEY_FILEMODE, true);
1094 config.save();
1095
1096 FS executableFs = new FS() {
1097
1098 @Override
1099 public boolean supportsExecute() {
1100 return true;
1101 }
1102
1103 @Override
1104 public boolean setExecute(File f, boolean canExec) {
1105 return true;
1106 }
1107
1108 @Override
1109 public ProcessBuilder runInShell(String cmd, String[] args) {
1110 return null;
1111 }
1112
1113 @Override
1114 public boolean retryFailedLockFileCommit() {
1115 return false;
1116 }
1117
1118 @Override
1119 public FS newInstance() {
1120 return this;
1121 }
1122
1123 @Override
1124 protected File discoverGitExe() {
1125 return null;
1126 }
1127
1128 @Override
1129 public boolean canExecute(File f) {
1130 try {
1131 return read(f).startsWith("binary:");
1132 } catch (IOException e) {
1133 return false;
1134 }
1135 }
1136
1137 @Override
1138 public boolean isCaseSensitive() {
1139 return false;
1140 }
1141 };
1142
1143 String path = "a.txt";
1144 String path2 = "a.sh";
1145 writeTrashFile(path, "content");
1146 writeTrashFile(path2, "binary: content");
1147 try (Git git = Git.open(db.getDirectory(), executableFs)) {
1148 git.add().addFilepattern(path).addFilepattern(path2).call();
1149 RevCommit commit1 = git.commit().setMessage("commit").call();
1150 try (TreeWalk walk = new TreeWalk(db)) {
1151 walk.addTree(commit1.getTree());
1152 walk.next();
1153 assertEquals(path2, walk.getPathString());
1154 assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
1155 walk.next();
1156 assertEquals(path, walk.getPathString());
1157 assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0));
1158 }
1159 }
1160 config = db.getConfig();
1161 config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
1162 ConfigConstants.CONFIG_KEY_FILEMODE, false);
1163 config.save();
1164
1165 writeTrashFile(path2, "content2");
1166 writeTrashFile(path, "binary: content2");
1167 try (Git git2 = Git.open(db.getDirectory(), executableFs)) {
1168 git2.add().addFilepattern(path).addFilepattern(path2).call();
1169 RevCommit commit2 = git2.commit().setMessage("commit2").call();
1170 try (TreeWalk walk = new TreeWalk(db)) {
1171 walk.addTree(commit2.getTree());
1172 walk.next();
1173 assertEquals(path2, walk.getPathString());
1174 assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
1175 walk.next();
1176 assertEquals(path, walk.getPathString());
1177 assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0));
1178 }
1179 }
1180 }
1181
1182 @Test
1183 public void testAddGitlink() throws Exception {
1184 createNestedRepo("git-link-dir");
1185 try (Git git = new Git(db)) {
1186 git.add().addFilepattern("git-link-dir").call();
1187
1188 assertEquals(
1189 "[git-link-dir, mode:160000]",
1190 indexState(0));
1191 Set<String> untrackedFiles = git.status().call().getUntracked();
1192 assert (untrackedFiles.isEmpty());
1193 }
1194
1195 }
1196
1197 @Test
1198 public void testAddSubrepoWithDirNoGitlinks() throws Exception {
1199 createNestedRepo("nested-repo");
1200
1201
1202 StoredConfig config = db.getConfig();
1203 config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
1204 ConfigConstants.CONFIG_KEY_DIRNOGITLINKS, true);
1205 config.save();
1206
1207 assert (db.getConfig().get(WorkingTreeOptions.KEY).isDirNoGitLinks());
1208
1209 try (Git git = new Git(db)) {
1210 git.add().addFilepattern("nested-repo").call();
1211
1212 assertEquals(
1213 "[nested-repo/README1.md, mode:100644]" +
1214 "[nested-repo/README2.md, mode:100644]",
1215 indexState(0));
1216 }
1217
1218
1219
1220
1221 config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
1222 ConfigConstants.CONFIG_KEY_DIRNOGITLINKS, false);
1223 config.save();
1224
1225 writeTrashFile("nested-repo", "README3.md", "content");
1226
1227 try (Git git = new Git(db)) {
1228 git.add().addFilepattern("nested-repo").call();
1229
1230 assertEquals(
1231 "[nested-repo/README1.md, mode:100644]" +
1232 "[nested-repo/README2.md, mode:100644]" +
1233 "[nested-repo/README3.md, mode:100644]",
1234 indexState(0));
1235 }
1236 }
1237
1238 @Test
1239 public void testAddGitlinkDoesNotChange() throws Exception {
1240 createNestedRepo("nested-repo");
1241
1242 try (Git git = new Git(db)) {
1243 git.add().addFilepattern("nested-repo").call();
1244
1245 assertEquals(
1246 "[nested-repo, mode:160000]",
1247 indexState(0));
1248 }
1249
1250
1251 StoredConfig config = db.getConfig();
1252 config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
1253 ConfigConstants.CONFIG_KEY_DIRNOGITLINKS, true);
1254 config.save();
1255
1256 assertTrue(
1257 db.getConfig().get(WorkingTreeOptions.KEY).isDirNoGitLinks());
1258
1259 try (Git git = new Git(db)) {
1260 git.add().addFilepattern("nested-repo").call();
1261
1262 assertEquals(
1263 "[nested-repo/README1.md, mode:100644][nested-repo/README2.md, mode:100644]",
1264 indexState(0));
1265 }
1266 }
1267
1268 private static DirCacheEntry addEntryToBuilder(String path, File file,
1269 ObjectInserter newObjectInserter, DirCacheBuilder builder, int stage)
1270 throws IOException {
1271 ObjectId id;
1272 try (FileInputStream inputStream = new FileInputStream(file)) {
1273 id = newObjectInserter.insert(
1274 Constants.OBJ_BLOB, file.length(), inputStream);
1275 }
1276 DirCacheEntry entry = new DirCacheEntry(path, stage);
1277 entry.setObjectId(id);
1278 entry.setFileMode(FileMode.REGULAR_FILE);
1279 entry.setLastModified(FS.DETECTED.lastModifiedInstant(file));
1280 entry.setLength((int) file.length());
1281
1282 builder.add(entry);
1283 return entry;
1284 }
1285
1286 private void assumeUnchanged(String path) throws IOException {
1287 final DirCache dirc = db.lockDirCache();
1288 final DirCacheEntry ent = dirc.getEntry(path);
1289 if (ent != null)
1290 ent.setAssumeValid(true);
1291 dirc.write();
1292 if (!dirc.commit())
1293 throw new IOException("could not commit");
1294 }
1295
1296 private void createNestedRepo(String path) throws IOException {
1297 File gitLinkDir = new File(db.getWorkTree(), path);
1298 FileUtils.mkdir(gitLinkDir);
1299
1300 FileRepositoryBuilder nestedBuilder = new FileRepositoryBuilder();
1301 nestedBuilder.setWorkTree(gitLinkDir);
1302
1303 try (Repository nestedRepo = nestedBuilder.build()) {
1304 nestedRepo.create();
1305
1306 writeTrashFile(path, "README1.md", "content");
1307 writeTrashFile(path, "README2.md", "content");
1308
1309
1310 try (Git git = new Git(nestedRepo)) {
1311 git.add().addFilepattern(".").call();
1312 git.commit().setMessage("subrepo commit").call();
1313 } catch (GitAPIException e) {
1314 throw new RuntimeException(e);
1315 }
1316 }
1317 }
1318 }