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