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.pgm;
44
45 import static java.nio.charset.StandardCharsets.UTF_8;
46 import static org.junit.Assert.assertArrayEquals;
47 import static org.junit.Assert.assertEquals;
48 import static org.junit.Assert.fail;
49 import static org.junit.Assume.assumeNoException;
50
51 import java.io.BufferedInputStream;
52 import java.io.BufferedReader;
53 import java.io.ByteArrayInputStream;
54 import java.io.File;
55 import java.io.FileInputStream;
56 import java.io.FileOutputStream;
57 import java.io.IOException;
58 import java.io.InputStreamReader;
59 import java.io.OutputStream;
60 import java.util.ArrayList;
61 import java.util.Arrays;
62 import java.util.List;
63 import java.util.concurrent.Callable;
64 import java.util.concurrent.ExecutorService;
65 import java.util.concurrent.Executors;
66 import java.util.concurrent.Future;
67 import java.util.zip.ZipEntry;
68 import java.util.zip.ZipInputStream;
69
70 import org.eclipse.jgit.api.Git;
71 import org.eclipse.jgit.dircache.DirCache;
72 import org.eclipse.jgit.lib.CLIRepositoryTestCase;
73 import org.eclipse.jgit.lib.FileMode;
74 import org.junit.Before;
75 import org.junit.Test;
76
77 public class ArchiveTest extends CLIRepositoryTestCase {
78 private Git git;
79 private String emptyTree;
80
81 @Override
82 @Before
83 public void setUp() throws Exception {
84 super.setUp();
85 git = new Git(db);
86 git.commit().setMessage("initial commit").call();
87 emptyTree = db.resolve("HEAD^{tree}").abbreviate(12).name();
88 }
89
90 @Test
91 public void testEmptyArchive() throws Exception {
92 byte[] result = CLIGitCommand.executeRaw(
93 "git archive --format=zip " + emptyTree, db).outBytes();
94 assertArrayEquals(new String[0], listZipEntries(result));
95 }
96
97 @Test
98 public void testEmptyTar() throws Exception {
99 byte[] result = CLIGitCommand.executeRaw(
100 "git archive --format=tar " + emptyTree, db).outBytes();
101 assertArrayEquals(new String[0], listTarEntries(result));
102 }
103
104 @Test
105 public void testUnrecognizedFormat() throws Exception {
106 String[] expect = new String[] {
107 "fatal: Unknown archive format 'nonsense'", "" };
108 String[] actual = executeUnchecked(
109 "git archive --format=nonsense " + emptyTree);
110 assertArrayEquals(expect, actual);
111 }
112
113 @Test
114 public void testArchiveWithFiles() throws Exception {
115 writeTrashFile("a", "a file with content!");
116 writeTrashFile("c", "");
117 writeTrashFile("unrelated", "another file, just for kicks");
118 git.add().addFilepattern("a").call();
119 git.add().addFilepattern("c").call();
120 git.commit().setMessage("populate toplevel").call();
121
122 byte[] result = CLIGitCommand.executeRaw(
123 "git archive --format=zip HEAD", db).outBytes();
124 assertArrayEquals(new String[] { "a", "c" },
125 listZipEntries(result));
126 }
127
128 private void commitGreeting() throws Exception {
129 writeTrashFile("greeting", "hello, world!");
130 git.add().addFilepattern("greeting").call();
131 git.commit().setMessage("a commit with a file").call();
132 }
133
134 @Test
135 public void testDefaultFormatIsTar() throws Exception {
136 commitGreeting();
137 byte[] result = CLIGitCommand.executeRaw(
138 "git archive HEAD", db).outBytes();
139 assertArrayEquals(new String[] { "greeting" },
140 listTarEntries(result));
141 }
142
143 private static String shellQuote(String s) {
144 return "'" + s.replace("'", "'\\''") + "'";
145 }
146
147 @Test
148 public void testFormatOverridesFilename() throws Exception {
149 File archive = new File(db.getWorkTree(), "format-overrides-name.tar");
150 String path = archive.getAbsolutePath();
151
152 commitGreeting();
153 assertArrayEquals(new String[] { "" },
154 execute("git archive " +
155 "--format=zip " +
156 shellQuote("--output=" + path) + " " +
157 "HEAD"));
158 assertContainsEntryWithMode(path, "", "greeting");
159 assertIsZip(archive);
160 }
161
162 @Test
163 public void testUnrecognizedExtensionMeansTar() throws Exception {
164 File archive = new File(db.getWorkTree(), "example.txt");
165 String path = archive.getAbsolutePath();
166
167 commitGreeting();
168 assertArrayEquals(new String[] { "" },
169 execute("git archive " +
170 shellQuote("--output=" + path) + " " +
171 "HEAD"));
172 assertTarContainsEntry(path, "", "greeting");
173 assertIsTar(archive);
174 }
175
176 @Test
177 public void testNoExtensionMeansTar() throws Exception {
178 File archive = new File(db.getWorkTree(), "example");
179 String path = archive.getAbsolutePath();
180
181 commitGreeting();
182 assertArrayEquals(new String[] { "" },
183 execute("git archive " +
184 shellQuote("--output=" + path) + " " +
185 "HEAD"));
186 assertIsTar(archive);
187 }
188
189 @Test
190 public void testExtensionMatchIsAnchored() throws Exception {
191 File archive = new File(db.getWorkTree(), "two-extensions.zip.bak");
192 String path = archive.getAbsolutePath();
193
194 commitGreeting();
195 assertArrayEquals(new String[] { "" },
196 execute("git archive " +
197 shellQuote("--output=" + path) + " " +
198 "HEAD"));
199 assertIsTar(archive);
200 }
201
202 @Test
203 public void testZipExtension() throws Exception {
204 File archiveWithDot = new File(db.getWorkTree(), "greeting.zip");
205 File archiveNoDot = new File(db.getWorkTree(), "greetingzip");
206
207 commitGreeting();
208 execute("git archive " +
209 shellQuote("--output=" + archiveWithDot.getAbsolutePath()) + " " +
210 "HEAD");
211 execute("git archive " +
212 shellQuote("--output=" + archiveNoDot.getAbsolutePath()) + " " +
213 "HEAD");
214 assertIsZip(archiveWithDot);
215 assertIsTar(archiveNoDot);
216 }
217
218 @Test
219 public void testTarExtension() throws Exception {
220 File archive = new File(db.getWorkTree(), "tarball.tar");
221 String path = archive.getAbsolutePath();
222
223 commitGreeting();
224 assertArrayEquals(new String[] { "" },
225 execute("git archive " +
226 shellQuote("--output=" + path) + " " +
227 "HEAD"));
228 assertIsTar(archive);
229 }
230
231 @Test
232 public void testTgzExtensions() throws Exception {
233 commitGreeting();
234
235 for (String ext : Arrays.asList("tar.gz", "tgz")) {
236 File archiveWithDot = new File(db.getWorkTree(), "tarball." + ext);
237 File archiveNoDot = new File(db.getWorkTree(), "tarball" + ext);
238
239 execute("git archive " +
240 shellQuote("--output=" + archiveWithDot.getAbsolutePath()) + " " +
241 "HEAD");
242 execute("git archive " +
243 shellQuote("--output=" + archiveNoDot.getAbsolutePath()) + " " +
244 "HEAD");
245 assertIsGzip(archiveWithDot);
246 assertIsTar(archiveNoDot);
247 }
248 }
249
250 @Test
251 public void testTbz2Extension() throws Exception {
252 commitGreeting();
253
254 for (String ext : Arrays.asList("tar.bz2", "tbz", "tbz2")) {
255 File archiveWithDot = new File(db.getWorkTree(), "tarball." + ext);
256 File archiveNoDot = new File(db.getWorkTree(), "tarball" + ext);
257
258 execute("git archive " +
259 shellQuote("--output=" + archiveWithDot.getAbsolutePath()) + " " +
260 "HEAD");
261 execute("git archive " +
262 shellQuote("--output=" + archiveNoDot.getAbsolutePath()) + " " +
263 "HEAD");
264 assertIsBzip2(archiveWithDot);
265 assertIsTar(archiveNoDot);
266 }
267 }
268
269 @Test
270 public void testTxzExtension() throws Exception {
271 commitGreeting();
272
273 for (String ext : Arrays.asList("tar.xz", "txz")) {
274 File archiveWithDot = new File(db.getWorkTree(), "tarball." + ext);
275 File archiveNoDot = new File(db.getWorkTree(), "tarball" + ext);
276
277 execute("git archive " +
278 shellQuote("--output=" + archiveWithDot.getAbsolutePath()) + " " +
279 "HEAD");
280 execute("git archive " +
281 shellQuote("--output=" + archiveNoDot.getAbsolutePath()) + " " +
282 "HEAD");
283 assertIsXz(archiveWithDot);
284 assertIsTar(archiveNoDot);
285 }
286 }
287
288 @Test
289 public void testArchiveWithSubdir() throws Exception {
290 writeTrashFile("a", "a file with content!");
291 writeTrashFile("b.c", "before subdir in git sort order");
292 writeTrashFile("b0c", "after subdir in git sort order");
293 writeTrashFile("c", "");
294 git.add().addFilepattern("a").call();
295 git.add().addFilepattern("b.c").call();
296 git.add().addFilepattern("b0c").call();
297 git.add().addFilepattern("c").call();
298 git.commit().setMessage("populate toplevel").call();
299 writeTrashFile("b/b", "file in subdirectory");
300 writeTrashFile("b/a", "another file in subdirectory");
301 git.add().addFilepattern("b").call();
302 git.commit().setMessage("add subdir").call();
303
304 byte[] result = CLIGitCommand.executeRaw(
305 "git archive --format=zip master", db).outBytes();
306 String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" };
307 String[] actual = listZipEntries(result);
308
309 Arrays.sort(expect);
310 Arrays.sort(actual);
311 assertArrayEquals(expect, actual);
312 }
313
314 @Test
315 public void testTarWithSubdir() throws Exception {
316 writeTrashFile("a", "a file with content!");
317 writeTrashFile("b.c", "before subdir in git sort order");
318 writeTrashFile("b0c", "after subdir in git sort order");
319 writeTrashFile("c", "");
320 git.add().addFilepattern("a").call();
321 git.add().addFilepattern("b.c").call();
322 git.add().addFilepattern("b0c").call();
323 git.add().addFilepattern("c").call();
324 git.commit().setMessage("populate toplevel").call();
325 writeTrashFile("b/b", "file in subdirectory");
326 writeTrashFile("b/a", "another file in subdirectory");
327 git.add().addFilepattern("b").call();
328 git.commit().setMessage("add subdir").call();
329
330 byte[] result = CLIGitCommand.executeRaw(
331 "git archive --format=tar master", db).outBytes();
332 String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" };
333 String[] actual = listTarEntries(result);
334
335 Arrays.sort(expect);
336 Arrays.sort(actual);
337 assertArrayEquals(expect, actual);
338 }
339
340 private void commitBazAndFooSlashBar() throws Exception {
341 writeTrashFile("baz", "a file");
342 writeTrashFile("foo/bar", "another file");
343 git.add().addFilepattern("baz").call();
344 git.add().addFilepattern("foo").call();
345 git.commit().setMessage("sample commit").call();
346 }
347
348 @Test
349 public void testArchivePrefixOption() throws Exception {
350 commitBazAndFooSlashBar();
351 byte[] result = CLIGitCommand.executeRaw(
352 "git archive --prefix=x/ --format=zip master", db).outBytes();
353 String[] expect = { "x/", "x/baz", "x/foo/", "x/foo/bar" };
354 String[] actual = listZipEntries(result);
355
356 Arrays.sort(expect);
357 Arrays.sort(actual);
358 assertArrayEquals(expect, actual);
359 }
360
361 @Test
362 public void testTarPrefixOption() throws Exception {
363 commitBazAndFooSlashBar();
364 byte[] result = CLIGitCommand.executeRaw(
365 "git archive --prefix=x/ --format=tar master", db).outBytes();
366 String[] expect = { "x/", "x/baz", "x/foo/", "x/foo/bar" };
367 String[] actual = listTarEntries(result);
368
369 Arrays.sort(expect);
370 Arrays.sort(actual);
371 assertArrayEquals(expect, actual);
372 }
373
374 private void commitFoo() throws Exception {
375 writeTrashFile("foo", "a file");
376 git.add().addFilepattern("foo").call();
377 git.commit().setMessage("boring commit").call();
378 }
379
380 @Test
381 public void testPrefixDoesNotNormalizeDoubleSlash() throws Exception {
382 commitFoo();
383 byte[] result = CLIGitCommand.executeRaw(
384 "git archive --prefix=x// --format=zip master", db).outBytes();
385 String[] expect = { "x/", "x//foo" };
386 assertArrayEquals(expect, listZipEntries(result));
387 }
388
389 @Test
390 public void testPrefixDoesNotNormalizeDoubleSlashInTar() throws Exception {
391 commitFoo();
392 byte[] result = CLIGitCommand.executeRaw(
393 "git archive --prefix=x// --format=tar master", db).outBytes();
394 String[] expect = { "x/", "x//foo" };
395 assertArrayEquals(expect, listTarEntries(result));
396 }
397
398
399
400
401
402
403
404
405
406
407 @Test
408 public void testPrefixWithoutTrailingSlash() throws Exception {
409 commitBazAndFooSlashBar();
410 byte[] result = CLIGitCommand.executeRaw(
411 "git archive --prefix=my- --format=zip master", db).outBytes();
412 String[] expect = { "my-baz", "my-foo/", "my-foo/bar" };
413 String[] actual = listZipEntries(result);
414
415 Arrays.sort(expect);
416 Arrays.sort(actual);
417 assertArrayEquals(expect, actual);
418 }
419
420 @Test
421 public void testTarPrefixWithoutTrailingSlash() throws Exception {
422 commitBazAndFooSlashBar();
423 byte[] result = CLIGitCommand.executeRaw(
424 "git archive --prefix=my- --format=tar master", db).outBytes();
425 String[] expect = { "my-baz", "my-foo/", "my-foo/bar" };
426 String[] actual = listTarEntries(result);
427
428 Arrays.sort(expect);
429 Arrays.sort(actual);
430 assertArrayEquals(expect, actual);
431 }
432
433 @Test
434 public void testArchiveIncludesSubmoduleDirectory() throws Exception {
435 writeTrashFile("a", "a file with content!");
436 writeTrashFile("c", "after submodule");
437 git.add().addFilepattern("a").call();
438 git.add().addFilepattern("c").call();
439 git.commit().setMessage("initial commit").call();
440 git.submoduleAdd().setURI("./.").setPath("b").call().close();
441 git.commit().setMessage("add submodule").call();
442
443 byte[] result = CLIGitCommand.executeRaw(
444 "git archive --format=zip master", db).outBytes();
445 String[] expect = { ".gitmodules", "a", "b/", "c" };
446 String[] actual = listZipEntries(result);
447
448 Arrays.sort(expect);
449 Arrays.sort(actual);
450 assertArrayEquals(expect, actual);
451 }
452
453 @Test
454 public void testTarIncludesSubmoduleDirectory() throws Exception {
455 writeTrashFile("a", "a file with content!");
456 writeTrashFile("c", "after submodule");
457 git.add().addFilepattern("a").call();
458 git.add().addFilepattern("c").call();
459 git.commit().setMessage("initial commit").call();
460 git.submoduleAdd().setURI("./.").setPath("b").call().close();
461 git.commit().setMessage("add submodule").call();
462
463 byte[] result = CLIGitCommand.executeRaw(
464 "git archive --format=tar master", db).outBytes();
465 String[] expect = { ".gitmodules", "a", "b/", "c" };
466 String[] actual = listTarEntries(result);
467
468 Arrays.sort(expect);
469 Arrays.sort(actual);
470 assertArrayEquals(expect, actual);
471 }
472
473 @Test
474 public void testArchivePreservesMode() throws Exception {
475 writeTrashFile("plain", "a file with content");
476 writeTrashFile("executable", "an executable file");
477 writeTrashFile("symlink", "plain");
478 writeTrashFile("dir/content", "clutter in a subdir");
479 git.add().addFilepattern("plain").call();
480 git.add().addFilepattern("executable").call();
481 git.add().addFilepattern("symlink").call();
482 git.add().addFilepattern("dir").call();
483
484 DirCache cache = db.lockDirCache();
485 cache.getEntry("executable").setFileMode(FileMode.EXECUTABLE_FILE);
486 cache.getEntry("symlink").setFileMode(FileMode.SYMLINK);
487 cache.write();
488 cache.commit();
489 cache.unlock();
490
491 git.commit().setMessage("three files with different modes").call();
492
493 byte[] zipData = CLIGitCommand.executeRaw(
494 "git archive --format=zip master", db).outBytes();
495 writeRaw("zip-with-modes.zip", zipData);
496 assertContainsEntryWithMode("zip-with-modes.zip", "-rw-", "plain");
497 assertContainsEntryWithMode("zip-with-modes.zip", "-rwx", "executable");
498 assertContainsEntryWithMode("zip-with-modes.zip", "l", "symlink");
499 assertContainsEntryWithMode("zip-with-modes.zip", "-rw-", "dir/");
500 }
501
502 @Test
503 public void testTarPreservesMode() throws Exception {
504 writeTrashFile("plain", "a file with content");
505 writeTrashFile("executable", "an executable file");
506 writeTrashFile("symlink", "plain");
507 writeTrashFile("dir/content", "clutter in a subdir");
508 git.add().addFilepattern("plain").call();
509 git.add().addFilepattern("executable").call();
510 git.add().addFilepattern("symlink").call();
511 git.add().addFilepattern("dir").call();
512
513 DirCache cache = db.lockDirCache();
514 cache.getEntry("executable").setFileMode(FileMode.EXECUTABLE_FILE);
515 cache.getEntry("symlink").setFileMode(FileMode.SYMLINK);
516 cache.write();
517 cache.commit();
518 cache.unlock();
519
520 git.commit().setMessage("three files with different modes").call();
521
522 byte[] archive = CLIGitCommand.executeRaw(
523 "git archive --format=tar master", db).outBytes();
524 writeRaw("with-modes.tar", archive);
525 assertTarContainsEntry("with-modes.tar", "-rw-r--r--", "plain");
526 assertTarContainsEntry("with-modes.tar", "-rwxr-xr-x", "executable");
527 assertTarContainsEntry("with-modes.tar", "l", "symlink -> plain");
528 assertTarContainsEntry("with-modes.tar", "drwxr-xr-x", "dir/");
529 }
530
531 @Test
532 public void testArchiveWithLongFilename() throws Exception {
533 StringBuilder filename = new StringBuilder();
534 List<String> l = new ArrayList<>();
535 for (int i = 0; i < 20; i++) {
536 filename.append("1234567890/");
537 l.add(filename.toString());
538 }
539 filename.append("1234567890");
540 l.add(filename.toString());
541 writeTrashFile(filename.toString(), "file with long path");
542 git.add().addFilepattern("1234567890").call();
543 git.commit().setMessage("file with long name").call();
544
545 byte[] result = CLIGitCommand.executeRaw(
546 "git archive --format=zip HEAD", db).outBytes();
547 assertArrayEquals(l.toArray(new String[0]),
548 listZipEntries(result));
549 }
550
551 @Test
552 public void testTarWithLongFilename() throws Exception {
553 StringBuilder filename = new StringBuilder();
554 List<String> l = new ArrayList<>();
555 for (int i = 0; i < 20; i++) {
556 filename.append("1234567890/");
557 l.add(filename.toString());
558 }
559 filename.append("1234567890");
560 l.add(filename.toString());
561 writeTrashFile(filename.toString(), "file with long path");
562 git.add().addFilepattern("1234567890").call();
563 git.commit().setMessage("file with long name").call();
564
565 byte[] result = CLIGitCommand.executeRaw(
566 "git archive --format=tar HEAD", db).outBytes();
567 assertArrayEquals(l.toArray(new String[0]),
568 listTarEntries(result));
569 }
570
571 @Test
572 public void testArchivePreservesContent() throws Exception {
573 String payload = "“The quick brown fox jumps over the lazy dog!”";
574 writeTrashFile("xyzzy", payload);
575 git.add().addFilepattern("xyzzy").call();
576 git.commit().setMessage("add file with content").call();
577
578 byte[] result = CLIGitCommand.executeRaw(
579 "git archive --format=zip HEAD", db).outBytes();
580 assertArrayEquals(new String[] { payload },
581 zipEntryContent(result, "xyzzy"));
582 }
583
584 @Test
585 public void testTarPreservesContent() throws Exception {
586 String payload = "“The quick brown fox jumps over the lazy dog!”";
587 writeTrashFile("xyzzy", payload);
588 git.add().addFilepattern("xyzzy").call();
589 git.commit().setMessage("add file with content").call();
590
591 byte[] result = CLIGitCommand.executeRaw(
592 "git archive --format=tar HEAD", db).outBytes();
593 assertArrayEquals(new String[] { payload },
594 tarEntryContent(result, "xyzzy"));
595 }
596
597 private Process spawnAssumingCommandPresent(String... cmdline) {
598 File cwd = db.getWorkTree();
599 ProcessBuilder procBuilder = new ProcessBuilder(cmdline)
600 .directory(cwd)
601 .redirectErrorStream(true);
602 Process proc = null;
603 try {
604 proc = procBuilder.start();
605 } catch (IOException e) {
606
607 assumeNoException(e);
608 }
609
610 return proc;
611 }
612
613 private BufferedReader readFromProcess(Process proc) throws Exception {
614 return new BufferedReader(
615 new InputStreamReader(proc.getInputStream(), UTF_8));
616 }
617
618 private void grepForEntry(String name, String mode, String... cmdline)
619 throws Exception {
620 Process proc = spawnAssumingCommandPresent(cmdline);
621 proc.getOutputStream().close();
622 BufferedReader reader = readFromProcess(proc);
623 try {
624 String line;
625 while ((line = reader.readLine()) != null)
626 if (line.startsWith(mode) && line.endsWith(name))
627
628 return;
629 fail("expected entry " + name + " with mode " + mode + " but found none");
630 } finally {
631 proc.getOutputStream().close();
632 proc.destroy();
633 }
634 }
635
636 private void assertMagic(long offset, byte[] magicBytes, File file) throws Exception {
637 try (BufferedInputStream in = new BufferedInputStream(
638 new FileInputStream(file))) {
639 if (offset > 0) {
640 long skipped = in.skip(offset);
641 assertEquals(offset, skipped);
642 }
643
644 byte[] actual = new byte[magicBytes.length];
645 in.read(actual);
646 assertArrayEquals(magicBytes, actual);
647 }
648 }
649
650 private void assertMagic(byte[] magicBytes, File file) throws Exception {
651 assertMagic(0, magicBytes, file);
652 }
653
654 private void assertIsTar(File file) throws Exception {
655 assertMagic(257, new byte[] { 'u', 's', 't', 'a', 'r', 0 }, file);
656 }
657
658 private void assertIsZip(File file) throws Exception {
659 assertMagic(new byte[] { 'P', 'K', 3, 4 }, file);
660 }
661
662 private void assertIsGzip(File file) throws Exception {
663 assertMagic(new byte[] { 037, (byte) 0213 }, file);
664 }
665
666 private void assertIsBzip2(File file) throws Exception {
667 assertMagic(new byte[] { 'B', 'Z', 'h' }, file);
668 }
669
670 private void assertIsXz(File file) throws Exception {
671 assertMagic(new byte[] { (byte) 0xfd, '7', 'z', 'X', 'Z', 0 }, file);
672 }
673
674 private void assertContainsEntryWithMode(String zipFilename, String mode, String name)
675 throws Exception {
676 grepForEntry(name, mode, "zipinfo", zipFilename);
677 }
678
679 private void assertTarContainsEntry(String tarfile, String mode, String name)
680 throws Exception {
681 grepForEntry(name, mode, "tar", "tvf", tarfile);
682 }
683
684 private void writeRaw(String filename, byte[] data)
685 throws IOException {
686 File path = new File(db.getWorkTree(), filename);
687 try (OutputStream out = new FileOutputStream(path)) {
688 out.write(data);
689 }
690 }
691
692 private static String[] listZipEntries(byte[] zipData) throws IOException {
693 List<String> l = new ArrayList<>();
694 try (ZipInputStream in = new ZipInputStream(
695 new ByteArrayInputStream(zipData))) {
696 ZipEntry e;
697 while ((e = in.getNextEntry()) != null)
698 l.add(e.getName());
699 }
700 return l.toArray(new String[0]);
701 }
702
703 private static Future<Object> writeAsync(OutputStream stream, byte[] data) {
704 ExecutorService executor = Executors.newSingleThreadExecutor();
705
706 return executor.submit(new Callable<Object>() {
707 @Override
708 public Object call() throws IOException {
709 try {
710 stream.write(data);
711 return null;
712 } finally {
713 stream.close();
714 }
715 }
716 });
717 }
718
719 private String[] listTarEntries(byte[] tarData) throws Exception {
720 List<String> l = new ArrayList<>();
721 Process proc = spawnAssumingCommandPresent("tar", "tf", "-");
722 try (BufferedReader reader = readFromProcess(proc)) {
723 OutputStream out = proc.getOutputStream();
724
725
726 Future<?> writing = writeAsync(out, tarData);
727
728 try {
729 String line;
730 while ((line = reader.readLine()) != null)
731 l.add(line);
732
733 return l.toArray(new String[0]);
734 } finally {
735 writing.get();
736 proc.destroy();
737 }
738 }
739 }
740
741 private static String[] zipEntryContent(byte[] zipData, String path)
742 throws IOException {
743 ZipInputStream in = new ZipInputStream(
744 new ByteArrayInputStream(zipData));
745 ZipEntry e;
746 while ((e = in.getNextEntry()) != null) {
747 if (!e.getName().equals(path))
748 continue;
749
750
751 List<String> l = new ArrayList<>();
752 BufferedReader reader = new BufferedReader(
753 new InputStreamReader(in, UTF_8));
754 String line;
755 while ((line = reader.readLine()) != null)
756 l.add(line);
757 return l.toArray(new String[0]);
758 }
759
760
761 return null;
762 }
763
764 private String[] tarEntryContent(byte[] tarData, String path)
765 throws Exception {
766 List<String> l = new ArrayList<>();
767 Process proc = spawnAssumingCommandPresent("tar", "Oxf", "-", path);
768 try (BufferedReader reader = readFromProcess(proc)) {
769 OutputStream out = proc.getOutputStream();
770 Future<?> writing = writeAsync(out, tarData);
771
772 try {
773 String line;
774 while ((line = reader.readLine()) != null)
775 l.add(line);
776
777 return l.toArray(new String[0]);
778 } finally {
779 writing.get();
780 proc.destroy();
781 }
782 }
783 }
784 }